diff --git a/.gitattributes b/.gitattributes index a6344aac8c09253b3b630fb776ae94478aa0275b..9390a6974114799ff11b2e126dc7a08d920a9b47 100644 --- a/.gitattributes +++ b/.gitattributes @@ -33,3 +33,103 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text *.zip filter=lfs diff=lfs merge=lfs -text *.zst filter=lfs diff=lfs merge=lfs -text *tfevents* filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/backgrounds/bedroom[[:space:]]clean.jpg filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/backgrounds/bedroom[[:space:]]cyberpunk.jpg filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/backgrounds/bedroom[[:space:]]red.jpg filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/backgrounds/bedroom[[:space:]]tatami.jpg filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/backgrounds/cityscape[[:space:]]medieval[[:space:]]market.jpg filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/backgrounds/cityscape[[:space:]]medieval[[:space:]]night.jpg filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/backgrounds/cityscape[[:space:]]postapoc.jpg filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/backgrounds/forest[[:space:]]treehouse[[:space:]]fireworks[[:space:]]air[[:space:]]baloons[[:space:]](by[[:space:]]kallmeflocc).jpg filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/backgrounds/japan[[:space:]]classroom[[:space:]]side.jpg filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/backgrounds/japan[[:space:]]classroom.jpg filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/backgrounds/japan[[:space:]]path[[:space:]]cherry[[:space:]]blossom.jpg filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/backgrounds/japan[[:space:]]university.jpg filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/backgrounds/landscape[[:space:]]autumn[[:space:]]great[[:space:]]tree.jpg filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/backgrounds/landscape[[:space:]]beach[[:space:]]day.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/backgrounds/landscape[[:space:]]beach[[:space:]]night.jpg filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/backgrounds/landscape[[:space:]]mountain[[:space:]]lake.jpg filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/backgrounds/landscape[[:space:]]postapoc.jpg filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/backgrounds/landscape[[:space:]]winter[[:space:]]lake[[:space:]]house.jpg filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/backgrounds/royal.jpg filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/backgrounds/tavern[[:space:]]day.jpg filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/default_Seraphina.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/admiration.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/amusement.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/anger.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/annoyance.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/approval.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/caring.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/confusion.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/curiosity.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/desire.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/disappointment.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/disapproval.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/disgust.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/embarrassment.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/excitement.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/fear.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/gratitude.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/grief.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/joy.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/love.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/nervousness.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/neutral.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/optimism.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/pride.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/realization.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/relief.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/remorse.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/sadness.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/default/content/Seraphina/surprise.png filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/st-launcher.ico filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/st.ico filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/fa-brands-400.ttf filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/fa-brands-400.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/fa-solid-900.ttf filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/fa-solid-900.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-Black.woff filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-Black.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-BlackItalic.woff filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-BlackItalic.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-Bold.woff filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-Bold.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-BoldItalic.woff filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-BoldItalic.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-ExtraBold.woff filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-ExtraBold.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-ExtraBoldItalic.woff filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-ExtraBoldItalic.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-ExtraLight.woff filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-ExtraLight.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-ExtraLightItalic.woff filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-ExtraLightItalic.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-Italic.woff filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-Italic.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-Light.woff filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-Light.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-LightItalic.woff filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-LightItalic.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-Medium.woff filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-Medium.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-MediumItalic.woff filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-MediumItalic.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-Regular.woff filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-Regular.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-SemiBold.woff filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-SemiBold.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-SemiBoldItalic.woff filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-SemiBoldItalic.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-Thin.woff filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-Thin.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-ThinItalic.woff filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSans/NotoSans-ThinItalic.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSansMono/noto-sans-mono-v30-100.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSansMono/noto-sans-mono-v30-200.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSansMono/noto-sans-mono-v30-300.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSansMono/noto-sans-mono-v30-500.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSansMono/noto-sans-mono-v30-600.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSansMono/noto-sans-mono-v30-700.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSansMono/noto-sans-mono-v30-800.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSansMono/noto-sans-mono-v30-900.woff2 filter=lfs diff=lfs merge=lfs -text +jiuguan2025cc/public/webfonts/NotoSansMono/noto-sans-mono-v30-regular.woff2 filter=lfs diff=lfs merge=lfs -text diff --git a/jiuguan2025cc/.dockerignore b/jiuguan2025cc/.dockerignore new file mode 100644 index 0000000000000000000000000000000000000000..9e0a20629a2481b3f49e100d67804984943dd593 --- /dev/null +++ b/jiuguan2025cc/.dockerignore @@ -0,0 +1,15 @@ +.git +.github +.vscode +node_modules +npm-debug.log +readme* +Start.bat +/dist +/backups +cloudflared.exe +access.log +/data +/cache +.DS_Store +/public/scripts/extensions/third-party diff --git a/jiuguan2025cc/.editorconfig b/jiuguan2025cc/.editorconfig new file mode 100644 index 0000000000000000000000000000000000000000..021c74be6dd39eabad530cda832188c25056ebeb --- /dev/null +++ b/jiuguan2025cc/.editorconfig @@ -0,0 +1,14 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{js,conf,json,css,less,html}] +charset = utf-8 +indent_style = space +indent_size = 4 + +[*.md] +trim_trailing_whitespace = false diff --git a/jiuguan2025cc/.eslintrc.cjs b/jiuguan2025cc/.eslintrc.cjs new file mode 100644 index 0000000000000000000000000000000000000000..cbf52f2179bbe426c3877022c65c8cfc539c18c5 --- /dev/null +++ b/jiuguan2025cc/.eslintrc.cjs @@ -0,0 +1,102 @@ +module.exports = { + root: true, + extends: [ + 'eslint:recommended', + ], + env: { + es6: true, + }, + parserOptions: { + ecmaVersion: 'latest', + }, + overrides: [ + { + // Server-side files (plus this configuration file) + files: ['src/**/*.js', './*.js', 'plugins/**/*.js'], + env: { + node: true, + }, + parserOptions: { + sourceType: 'module', + }, + globals: { + globalThis: 'readonly', + Deno: 'readonly', + }, + }, + { + files: ['*.cjs'], + parserOptions: { + sourceType: 'commonjs', + }, + env: { + node: true, + }, + }, + { + files: ['src/**/*.mjs'], + parserOptions: { + sourceType: 'module', + }, + env: { + node: true, + }, + }, + { + // Browser-side files + files: ['public/**/*.js'], + env: { + browser: true, + jquery: true, + }, + parserOptions: { + sourceType: 'module', + }, + // These scripts are loaded in HTML; tell ESLint not to complain about them being undefined + globals: { + globalThis: 'readonly', + ePub: 'readonly', + pdfjsLib: 'readonly', + toastr: 'readonly', + SillyTavern: 'readonly', + }, + }, + ], + ignorePatterns: [ + '**/node_modules/**', + '**/dist/**', + '**/.git/**', + 'public/lib/**', + 'backups/**', + 'data/**', + 'cache/**', + 'src/tokenizers/**', + 'docker/**', + 'plugins/**', + '**/*.min.js', + 'public/scripts/extensions/quick-reply/lib/**', + 'public/scripts/extensions/tts/lib/**', + ], + rules: { + 'no-unused-vars': ['error', { args: 'none' }], + 'no-control-regex': 'off', + 'no-constant-condition': ['error', { checkLoops: false }], + 'require-yield': 'off', + 'quotes': ['error', 'single'], + 'semi': ['error', 'always'], + 'indent': ['error', 4, { SwitchCase: 1, FunctionDeclaration: { parameters: 'first' } }], + 'comma-dangle': ['error', 'always-multiline'], + 'eol-last': ['error', 'always'], + 'no-trailing-spaces': 'error', + 'object-curly-spacing': ['error', 'always'], + 'space-infix-ops': 'error', + 'no-unused-expressions': ['error', { allowShortCircuit: true, allowTernary: true }], + 'no-cond-assign': 'error', + 'no-unneeded-ternary': 'error', + 'no-irregular-whitespace': ['error', { skipStrings: true, skipTemplates: true }], + + // These rules should eventually be enabled. + 'no-async-promise-executor': 'off', + 'no-inner-declarations': 'off', + }, +}; diff --git a/jiuguan2025cc/.github/ISSUE_TEMPLATE/bug-report.yml b/jiuguan2025cc/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 0000000000000000000000000000000000000000..1ff252a65c2e9b01d84de0f9857b97e78fd038bb --- /dev/null +++ b/jiuguan2025cc/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,93 @@ +name: Bug Report 🐛 +type: Bug +description: Report something that's not working the intended way. Support requests for external programs (reverse proxies, 3rd party servers, other peoples' forks) will be refused! Please use English only. +title: '[BUG] ' +labels: ['🐛 Bug'] +body: + - type: dropdown + id: environment + attributes: + label: Environment + description: Where are you running SillyTavern? + options: + - 🪟 Windows + - 🐧 Linux + - 📱 Termux + - 🐋 Docker + - 🍎 Mac + validations: + required: true + + - type: input + id: system + attributes: + label: System + description: >- + For deployment issues, specify your [distro or OS](https://whatsmyos.com/) and/ or Docker version. + For client-side issues, include your [browser version](https://www.whatsmybrowser.org/) + placeholder: e.g. Firefox 101, Manjaro Linux 21.3.0, Docker 20.10.16 + validations: + required: true + + - type: input + id: version + attributes: + label: Version + description: What version of SillyTavern are you running? + placeholder: (check User Settings to see the version) + validations: + required: true + + - type: textarea + id: desktop + attributes: + label: Desktop Information + description: Please provide details about your desktop environment. + placeholder: | + - Node.js version (if applicable): [run `node --version` in cmd] + - Generation API [e.g. KoboldAI, OpenAI] + - Branch [staging, release] + - Model [e.g. Pygmalion 6b, LLaMa 13b] + validations: + required: false + + - type: textarea + id: repro + attributes: + label: Describe the problem + description: Please describe exactly what is not working, include the steps to reproduce, actual result and expected result + placeholder: When doing ABC then DEF, I expect to see XYZ, but I actually see ZYX + validations: + required: true + + - type: textarea + id: logs + attributes: + label: Additional info + description: Logs? Screenshots? Yes, please. + placeholder: If the issue happens during build-time, include terminal logs. For run-time errors, include browser logs which you can view in the Dev Tools (F12), under the Console tab. Take care to blank out any personal info. + validations: + required: false + + - type: checkboxes + id: user-check + attributes: + label: Please tick the boxes + description: Before submitting, please ensure that you have completed the following checklist + options: + - label: I have explained the issue clearly, and I included all relevant info + required: true + - label: I have checked that this [issue hasn't already been raised](https://github.com/SillyTavern/SillyTavern/issues?q=is%3Aissue) + required: true + - label: I have checked the [docs](https://docs.sillytavern.app/) ![important](https://img.shields.io/badge/Important!-F6094E) + required: true + - label: I confirm that my issue is not related to third-party content, unofficial extension or patch. If in doubt, check with a new [user account](https://docs.sillytavern.app/administration/multi-user/) and with extensions disabled + required: true + + - type: markdown + attributes: + value: |- + ## Thanks 🙏 + Thank you for raising this ticket - in doing so you are helping to make SillyTavern better for everyone. + validations: + required: false diff --git a/jiuguan2025cc/.github/ISSUE_TEMPLATE/feature-request.yml b/jiuguan2025cc/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 0000000000000000000000000000000000000000..04d02e23a1cf80d2b05292b1b2dafcb8994a6fd9 --- /dev/null +++ b/jiuguan2025cc/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,92 @@ +name: Feature Request ✨ +type: Feature +description: Suggest an idea for future development of this project. Please use English only. +title: '[FEATURE_REQUEST] <title>' +labels: ['🦄 Feature Request'] + +body: + + # Field 1 - Did the user searched for similar requests + - type: dropdown + id: similarRequest + attributes: + label: Have you searched for similar requests? + description: + options: + - 'No' + - 'Yes' + validations: + required: true + + # Field 2 - Is it bug-related + - type: textarea + id: issue + attributes: + label: Is your feature request related to a problem? If so, please describe. + description: + placeholder: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + validations: + required: false + + # Field 3 - Describe feature + - type: textarea + id: solution + attributes: + label: Describe the solution you'd like + placeholder: An outline of how you would like this to be implemented, include as much details as possible + validations: + required: true + + # Field 4 - Describe alternatives + - type: textarea + id: alternatives + attributes: + label: Describe alternatives you've considered + placeholder: A clear and concise description of any alternative solutions or features you've considered. + validations: + required: false + + # Field 5 - Additional context + - type: textarea + id: addcontext + attributes: + label: Additional context + placeholder: Add any other context or screenshots about the feature request here. + validations: + required: false + + # Field 6 - Priority + - type: dropdown + id: priority + attributes: + label: Priority + description: How urgent is the development of this feature + options: + - Low (Nice-to-have) + - Medium (Would be very useful) + - High (The app does not function without it) + validations: + required: true + + # Field 7 - Can the user user test in staging + - type: dropdown + id: canTestStaging + attributes: + label: Are you willing to test this on staging/unstable branch if this is implemented? + description: Otherwise you'll need to wait until the next stable release after the feature is developed. + options: + - 'No' + - 'Maybe' + - 'Yes' + validations: + required: false + + # Final text + - type: markdown + attributes: + value: |- + ## Thanks 🙏 + Thank you for your feature suggestion. + Please note that there is no guarantee that your idea will be implemented. + validations: + required: false diff --git a/jiuguan2025cc/.github/issues-auto-comments.yml b/jiuguan2025cc/.github/issues-auto-comments.yml new file mode 100644 index 0000000000000000000000000000000000000000..9c412ffd8a0dab26ebb7e13ddc021919b3f97079 --- /dev/null +++ b/jiuguan2025cc/.github/issues-auto-comments.yml @@ -0,0 +1,69 @@ +labels: + - name: ✖️ Invalid + labeled: + issue: + action: close + body: > + Hey @{{ issue.user.login }}, this issue has been marked as invalid. + + Please double-check that you've followed the issue template, included all necessary details, and reviewed the docs & previous issues before submitting. + If provided, follow the instructions given by maintainers. + + - name: 👩‍💻 Good First Issue + labeled: + issue: + body: > + 🏆 This issue has been marked as a good first issue for contributors to implement! + This is a great way to support the project. While also improving your skills, you'll also be credited as a contributor once your PR is merged. + + If you're new to SillyTavern [here is the official documentation](https://docs.sillytavern.app/). The official contribution guide can be found [here](https://github.com/SillyTavern/SillyTavern/blob/release/CONTRIBUTING.md). + If you need any support, feel free to reach out via [Discord](https://discord.gg/sillytavern), or let us know in this issue or via [discussions](https://github.com/SillyTavern/SillyTavern/discussions). + + - name: ❌ wontfix + labeled: + issue: + action: close + body: > + ❌ This issue has been marked as 'wontfix', which usually means it is out-of-scope, not feasible at this time or will not be implemented for various reasons. + If you have any questions about this, feel free to reach out. + + - name: 🛑 Out of Scope + labeled: + issue: + action: close + body: > + 🛑 This issue has been marked as 'out of scope', as this can't or won't be implemented. + If you have any questions about this, feel free to reach out. + + - name: ✅ Done (staging) + labeled: + issue: + body: > + ✅ It looks like all or part of this issue has now been implemented as part of the `staging` branch. + If you currently are on the `release` branch, you can switch to `staging` to test this right away. + + Note that `staging` is considered less stable than the official releases. To switch, follow existing instructions, + or simply enter the following command: `git switch staging` + + - name: ✅ Done + labeled: + issue: + body: > + ✅ It looks like all or part of this issue has now been implemented as part of the latest release. + + - name: ‼️ High Priority + labeled: + issue: + body: > + 🚨 This issue has been marked high priority, meaning it's important to the maintainers or community. + While we can't promise immediate changes, it is on our radar and will be addressed whenever possible. Thanks for your patience! + + - name: 💀 Spam + labeled: + issue: + action: close + locking: lock + lock_reason: spam + body: > + 💀 This issue has been flagged as spam and is now locked. + Please avoid posting spam - it disrupts the community and wastes everyone's time. diff --git a/jiuguan2025cc/.github/issues-auto-labels.yml b/jiuguan2025cc/.github/issues-auto-labels.yml new file mode 100644 index 0000000000000000000000000000000000000000..8bfb6200984f5343fd886c3b0374b509fd582a95 --- /dev/null +++ b/jiuguan2025cc/.github/issues-auto-labels.yml @@ -0,0 +1,20 @@ +🪟 Windows: + - '(🪟 Windows)' + +🍎 Mac: + - '(🍎 Mac)' + +🐋 Docker: + - '(🐋 Docker)' + +📱 Termux: + - '(📱 Termux)' + +🐧 Linux: + - '(🐧 Linux)' + +🦊 Firefox: + - '(firefox|mozilla)' + +📱 Mobile: + - '(iphone|ios|android|📱 Termux)' diff --git a/jiuguan2025cc/.github/pr-auto-comments.yml b/jiuguan2025cc/.github/pr-auto-comments.yml new file mode 100644 index 0000000000000000000000000000000000000000..bdb3e8022a3db012bf03dcbd0d946c108a770ce4 --- /dev/null +++ b/jiuguan2025cc/.github/pr-auto-comments.yml @@ -0,0 +1,51 @@ +labels: + - name: ✖️ Invalid + labeled: + pr: + action: close + body: > + Hey @{{ pull_request.user.login }}, thanks for your contribution! + Unfortunately, this PR has been marked as invalid. + + Please check that you've followed the PR template, included all relevant details, and are targeting the correct branch (`staging` for regular contributions, `release` only for hotfixes). + + If you need help, feel free to ask! + + - name: ⛔ Don't Merge + labeled: + pr: + body: > + 🚨 This PR has been temporarily blocked from merging. + + - name: 💥💣 Breaking Changes + labeled: + pr: + body: > + ⚠️ Heads up! This PR introduces breaking changes. + + Make sure these changes are well-documented and that users will be properly informed when this is released. + + - name: ⛔ Waiting For External/Upstream + labeled: + pr: + body: > + ⛔ This PR is awaiting external or upstream changes or approval. + It can only be merged once those changes have been implemented and approved. + + Please inform us of any progress on the upstream changes or approval. + + - name: 🔬 Needs Testing + labeled: + pr: + body: > + 🔬 This PR needs testing! + Any contributor can test and leave reviews, so feel free to help us out! + + - name: 🟥 ⬤⬤⬤⬤⬤ + labeled: + pr: + body: > + ⚠️ This PR is over 1000 lines, which is larger than recommended. + + Please make sure that it only addresses a single issue - PRs this large are hard to test and may be rejected. + diff --git a/jiuguan2025cc/.github/pr-auto-labels-by-branch.yml b/jiuguan2025cc/.github/pr-auto-labels-by-branch.yml new file mode 100644 index 0000000000000000000000000000000000000000..bbb91d760426478a1f7f38bff8c62beaf675c9db --- /dev/null +++ b/jiuguan2025cc/.github/pr-auto-labels-by-branch.yml @@ -0,0 +1,77 @@ +#################################### +# Label PRs against 'release' # +#################################### +❗ Against Release Branch: +- base-branch: 'release' + +#################################### +# Labels based on PR branch name # +#################################### +🦋 Bug Fix: +- head-branch: ['^fix[/-]', '\bfixes\b'] + +🚑 Hot Fix: +- head-branch: ['^hotfix[/-]'] + +✨ New Feature: +- head-branch: ['^feat(ure)?[/-].*?\badd', '^add-'] + +✨ Feature Changes: +- head-branch: ['^feat(ure)?[/-](?!.*\badd\b)', '\bchanges?\b'] + +🤖 API / Model: +- head-branch: ['\bapi\b', '\bmodels?\b'] + +🏭 Backend Changes: +- head-branch: ['\bbackend\b', '\bendpoints?\b'] + +🐋 Docker: +- head-branch: ['\bdocker\b'] + +➕ Extension: +- head-branch: ['\bextension\b', '\bext\b'] + +🦊 Firefox: +- head-branch: ['\bfirefox\b'] + +🖼️ Image Gen: +- head-branch: ['\bimage-gen\b'] + +🌐 Language: +- head-branch: ['\btranslations?\b', '\blanguages?\b'] + +🐧 Linux: +- head-branch: ['\blinux\b'] + +🧩 Macros: +- head-branch: ['\bmacros?\b'] + +📱 Mobile: +- head-branch: ['\bmobile\b', '\bios\b', '\bandroid\b'] + +🚄 Performance: +- head-branch: ['\bperformance\b'] + +⚙️ Preset: +- head-branch: ['\bpresets?\b'] + +📜 Prompt: +- head-branch: ['\bprompt\b'] + +🚚 Refactor: +- head-branch: ['\brefactor(s|ed)?\b'] + +📜 STscript: +- head-branch: ['\bstscript\b', '\bslash-commands\b'] + +🏷️ Tags / Folders: +- head-branch: ['\btags\b'] + +🎙️ TTS / Voice: +- head-branch: ['\btts\b', '\bvoice\b'] + +🌟 UX: +- head-branch: ['\bux\b'] + +🗺️ World Info: +- head-branch: ['\bworld-info\b', '\bwi\b'] diff --git a/jiuguan2025cc/.github/pr-auto-labels-by-files.yml b/jiuguan2025cc/.github/pr-auto-labels-by-files.yml new file mode 100644 index 0000000000000000000000000000000000000000..55946ad2bd8622b45b76487547853b9dde95605b --- /dev/null +++ b/jiuguan2025cc/.github/pr-auto-labels-by-files.yml @@ -0,0 +1,46 @@ +#################################### +# Labels based on changed files # +#################################### +🏭 Backend Changes: +- changed-files: + - any-glob-to-any-file: + - "src/**" + - "default/config.yaml" + - "server.js" + - "plugins.js" + - "recover.js" + - "webpack.config.js" + - "Start.bat" + - "start.sh" + - "UpdateAndStart.bat" + - "UpdateForkAndStart.bat" + +⚙️ config.yaml: +- changed-files: + - any-glob-to-any-file: + - "default/config.yaml" + +🛠️ Build Changes: +- changed-files: + - any-glob-to-any-file: + - ".github/workflows/**" + - "docker/**" + - ".dockerignore" + - "Dockerfile" + - "webpack.config.js" + +🌐 Language: +- changed-files: + - any-glob-to-any-file: + - "public/locales/**" + +📥 Dependencies: +- changed-files: + - any-glob-to-any-file: + - "public/lib/**" # Every frontend lib counts as a dependency as well + - "package.json" + - "package-lock.json" + - "tests/package.json" + - "tests/package-lock.json" + - "src/electron/package.json" + - "src/electron/package-lock.json" diff --git a/jiuguan2025cc/.github/pull_request_template.md b/jiuguan2025cc/.github/pull_request_template.md new file mode 100644 index 0000000000000000000000000000000000000000..6088507999141b9b349c253c1c7a5296b9ded531 --- /dev/null +++ b/jiuguan2025cc/.github/pull_request_template.md @@ -0,0 +1,5 @@ +<!-- Put X in the box below to confirm --> + +## Checklist: + +- [ ] I have read the [Contributing guidelines](https://github.com/SillyTavern/SillyTavern/blob/release/CONTRIBUTING.md). diff --git a/jiuguan2025cc/.github/readme-de_de.md b/jiuguan2025cc/.github/readme-de_de.md new file mode 100644 index 0000000000000000000000000000000000000000..3dcc29dcbaab585f6af11041eeaef743ff4feb6d --- /dev/null +++ b/jiuguan2025cc/.github/readme-de_de.md @@ -0,0 +1,383 @@ +> [!IMPORTANT] +> Die hier veröffentlichten Informationen sind möglicherweise veraltet oder unvollständig. Für aktuelle Informationen nutzen Sie bitte die englische Version. +> Letztes Update dieser README: 28.9.2024 + +<a name="readme-top"></a> + +![][cover] + +<div align="center"> + +[English](readme.md) | German | [中文](readme-zh_cn.md) | [繁體中文](readme-zh_tw.md) | [日本語](readme-ja_jp.md) | [Русский](readme-ru_ru.md) | [한국어](readme-ko_kr.md) + +[![GitHub Stars](https://img.shields.io/github/stars/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/stargazers) +[![GitHub Forks](https://img.shields.io/github/forks/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/network) +[![GitHub Issues](https://img.shields.io/github/issues/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/issues) +[![GitHub Pull Requests](https://img.shields.io/github/issues-pr/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/pulls) + +</div> + +--- + +SillyTavern bietet eine einheitliche Benutzeroberfläche für viele LLM-APIs (KoboldAI/CPP, Horde, NovelAI, Ooba, Tabby, OpenAI, OpenRouter, Claude, Mistral und mehr), ein mobilfreundliches Layout, einen Visual-Novel-Modus, die Integration von Automatic1111 & ComfyUI API zur Bilderzeugung, TTS, WorldInfo (Lorebooks), anpassbare UI, automatische Übersetzung, mehr Eingabeaufforderungsoptionen, als du jemals wolltest oder brauchst, und unendliches Wachstumspotenzial durch Drittanbietererweiterungen. + +Wir haben eine [Dokumentationswebsite](https://docs.sillytavern.app/), um die meisten deiner Fragen zu beantworten und dir den Einstieg zu erleichtern. + +## Was ist SillyTavern? + +SillyTavern (oder ST abgekürtz) ist eine lokal installierte Benutzeroberfläche, die es dir ermöglicht, mit Textgenerations-LLMs, Bildgenerierungsmaschinen und TTS-Sprachmodellen zu interagieren. + +Angefangen im Februar 2023 als Fork von TavernAI 1.2.8 hat SillyTavern nun über 100 Mitwirkende und 2 Jahre unabhängiger Entwicklung hinter sich und dient weiterhin als führende Software für versierte KI-Hobbyisten. + +## Unsere Vision + +1. Wir möchten die Nutzer mit so viel Nutzen und Kontrolle über ihre LLM-Prompts wie möglich ausstatten. Die steile Lernkurve ist Teil des Spaßes! +2. Wir bieten weder Online- oder gehosteten Dienste an, noch verfolgen wir programmgesteuert Benutzerdaten. +3. SillyTavern ist ein Herzensprojekt, das von einer engagierten Community von LLM-Enthusiasten unterstützt wird, und wird immer kostenlos und Open Source sein. + +## Branches + +SillyTavern wird mit einem Branchsystem entwickelt, um ein reibungsloses Erlebnis für alle Nutzer zu gewährleisten. + +* `release` -🌟 **Empfohlen für die meisten Nutzer.** Dies ist der stabilste und empfohlene Branch, der nur aktualisiert wird, wenn wichtige Versionen veröffentlicht werden. Er ist für die Mehrheit der Nutzer geeignet. Typischerweise einmal im Monat aktualisiert. +* `staging` - ⚠️ **Nicht für den gelegentlichen Gebrauch empfohlen.** Dieser Branch enthält die neuesten Funktionen, kann jedoch jederzeit instabil sein. Nur für Power-User und Enthusiasten. Mehrmals täglich aktualisiert. + +Wenn du nicht vertraut mit der Verwendung der git CLI bist oder nicht verstehst, was ein Branch ist, mach dir keine Sorgen! Der Release-Branch ist immer die bevorzugte Option für dich. + +## Was brauche ich zusätzlich zu SillyTavern? + +Da SillyTavern nur eine Benutzeroberfläche ist, benötigst du Zugriff auf ein LLM-Backend, um Inferenz bereitzustellen. Du kannst AI Horde für sofortiges Chatten ohne weitere Einrichtung verwenden. Darüber hinaus unterstützen wir viele andere lokale und cloudbasierte LLM-Backends: OpenAI-kompatible API, KoboldAI, Tabby und viele mehr. Du kannst mehr über unsere unterstützten APIs in [der FAQ](https://docs.sillytavern.app/usage/api-connections/) lesen. + +### Brauche ich einen leistungsstarken PC, um SillyTavern auszuführen? + +Die Hardwareanforderungen sind minimal: Es läuft auf allem, was NodeJS 18 oder höher ausführen kann. Wenn du LLM-Inferenz auf deinem lokalen Rechner durchführen möchtest, empfehlen wir eine NVIDIA-Grafikkarte der 3000er-Serie mit mindestens 6 GB VRAM. Überprüfe die Dokumentation deines Backends für weitere Einzelheiten. + +### Vorgeschlagene Backends (keine Partnerschaft oder Werbebeziehung) + +* [AI Horde](https://aihorde.net/) - verwende Modelle, die von Freiwilligen gehostet werden. Erfordert keine weitere Einrichtung +* [KoboldCpp](https://github.com/LostRuins/koboldcpp) - ein Favorit der Community, um GGUF-Modelle lokal auszuführen +* [tabbyAPI](https://github.com/theroyallab/tabbyAPI) - eine beliebte, portable, speicherplatzoptimierte und lokal gehostete exl2 Inferenz-API +* [OpenRouter](https://openrouter.ai) - eine einzige API für viele Cloud-Anbieter (OpenAI, Claude, Meta Llama usw.) sowie beliebte Community-Modelle. + +## Fragen oder Vorschläge? + +### Discord-Server + +| [![][discord-shield-badge]][discord-link] | [Tritt unserer Discord-Community bei!](https://discord.gg/sillytavern) Erhalte Unterstützung, teile deine Lieblingscharaktere und Prompts. | +| :---------------------------------------- | :----------------------------------------------------------------------------------------------------------------- | + +Oder nimm direkt Kontakt mit den Entwicklern auf: + +* Discord: cohee, rossascends, wolfsblvt +* Reddit: [/u/RossAscends](https://www.reddit.com/user/RossAscends/), [/u/sillylossy](https://www.reddit.com/user/sillylossy/), [u/Wolfsblvt](https://www.reddit.com/user/Wolfsblvt/) +* [Erstelle ein GitHub-Issue](https://github.com/SillyTavern/SillyTavern/issues) + +### Ich mag dieses Projekt! Wie kann ich beitragen? + +1. Sende Pull-Requests. Lerne, wie du beitragen kannst: [CONTRIBUTING.md](../CONTRIBUTING.md) +2. Sende Feature Requests und Issues unter Verwendung der bereitgestellten Vorlagen. +3. Lies diese gesamte README-Datei und überprüfe zuerst die Dokumentationswebsite, um doppelte Issues zu vermeiden. + +## Screenshots + +<img width="500" alt="image" src="https://github.com/user-attachments/assets/9b5f32f0-c3b3-4102-b3f5-0e9213c0f50f"> +<img width="500" alt="image" src="https://github.com/user-attachments/assets/913fdbaa-7d33-42f1-ae2c-89dca41c53d1"> + +## Charakterkarten + +SillyTavern basiert auf dem Konzept der "Charakterkarten". Eine Charakterkarte ist eine Sammlung von Prompts, die das Verhalten des LLM festlegen und erforderlich sind, um persistente Gespräche in SillyTavern zu führen. Sie funktionieren ähnlich wie ChatGPT's GPTs oder Poe's Bots. Der Inhalt einer Charakterkarte kann alles sein: ein abstraktes Szenario, ein Assistent, der für eine bestimmte Aufgabe maßgeschneidert ist, eine berühmte Persönlichkeit oder ein fiktiver Charakter. + +Das Namensfeld ist der einzige erforderliche Eingabewert für die Charakterkarte. Um ein neutrales Gespräch mit dem LLM zu beginnen, erstelle eine neue Karte, die einfach "Assistent" genannt wird, und lasse die restlichen Felder leer. Für einen thematischeren Chat kannst du dem LLM verschiedene Hintergrundinformationen, Verhaltensweisen und Schreibmuster sowie ein Szenario geben, um das Gespräch zu beginnen. + +Um ein schnelles Gespräch zu führen, ohne eine Charakterkarte auszuwählen, oder um einfach die LLM-Verbindung zu testen, gib einfach dein Prompt in die Eingabezeile auf dem Willkommensbildschirm ein, nachdem du SillyTavern geöffnet hast. Bitte beachte, dass solche Chats vorübergehend sind und nicht gespeichert werden. + +Um eine allgemeine Vorstellung davon zu bekommen, wie man Charakterkarten definiert, sieh dir die mitgelieferte Charakterkarte (Seraphina) an oder lade ausgewählte von der Community erstellte Karten im Menü "Erweiterungen & Assets herunterladen" herunter. + +## Wichtigste Features + +* Erweiterte Text-Generierungs-Einstellungen mit vielen von der Community erstellten mitgelieferten Einstellungen (Presets) +* Unterstützung für World Info: Erstelle reichhaltige Lore oder reduziere die Tokens in deiner Charakterkarte +* Gruppenchats: Multi-Bot-Räume für Charaktere, die mit dir und/oder untereinander sprechen +* Reichhaltige UI-Anpassungsoptionen: Themes zur Farbenwahl, Hintergrundbilder, benutzerdefiniertes CSS und mehr +* Benutzer-Personas: Lass die KI ein wenig über dich wissen, um die Immersion zu erhöhen +* Eingebaute RAG-Unterstützung: Füge Dokumente zu deinen Chats hinzu, auf die die KI verweisen kann +* Umfangreiches "Chat-Befehle"-System und eigene [Scripting-Engine](https://docs.sillytavern.app/usage/st-script/) + +## Erweiterungen + +SillyTavern unterstützt Erweiterungen. + +* Emotionale Ausdrucksformen von Charakteren (Sprites) +* Automatische Zusammenfassung des Chatverlaufs +* Automatische UI- und Chat-Übersetzung +* Bildgenerierung mit Stable Diffusion/FLUX/DALL-E +* Text-to-Speech für KI-Antwortnachrichten (über ElevenLabs, Silero oder die TTS-Funktion des Betriebssystems) +* Websuchfunktionen zum Hinzufügen zusätzlicher realer Kontexte zu deinen Eingabeaufforderungen +* Viele weitere sind im Menü "Erweiterungen & Assets herunterladen" verfügbar. + +Tutorials zur Nutzung findest du in der [Dokumentation](https://docs.sillytavern.app/). + +# ⌛ Installation + +> \[!WARNING] +> +> * INSTALLIERE NICHT IN EINEM VON WINDOWS KONTROLLIERTEN ORDNER (Programme, System32 usw.). +> * FÜHRE START.BAT NICHT MIT ADMIN-BERECHTIGUNGEN AUS. +> * DIE INSTALLATION AUF WINDOWS 7 IST UNMÖGLICH, DA ES NODEJS 18.16 NICHT AUSFÜHREN KANN. + +## 🪟 Windows + +### Installation über Git + +1. Installiere [NodeJS](https://nodejs.org/en) (die neueste LTS-Version wird empfohlen). +2. Installiere [Git für Windows](https://gitforwindows.org/). +3. Öffne den Windows-Explorer (`Win+E`). +4. Gehe zu oder erstelle einen Ordner, der nicht von Windows kontrolliert oder überwacht wird. (z.B.: C:\MySpecialFolder\) +5. Öffne ein Eingabeaufforderungsfenster in diesem Ordner, indem du in die 'Adressleiste' oben klickst, `cmd` eingibst und Enter drückst. +6. Sobald das schwarze Fenster (Eingabeaufforderung) erscheint, gib EINE der folgenden Optionen ein und drücke Enter: + +* für den Release-Branch: `git clone https://github.com/SillyTavern/SillyTavern -b release` +* für den Staging-Branch: `git clone https://github.com/SillyTavern/SillyTavern -b staging` + +7. Sobald alles geklont ist, doppelklicke auf `Start.bat`, damit NodeJS seine Anforderungen installiert. +8. Der Server wird dann gestartet, und SillyTavern wird in deinem Browser geöffnet. + +### Installation über GitHub Desktop + +(Dies ermöglicht die Nutzung von git **nur** in GitHub Desktop. Wenn du `git` auch in der Eingabeaufforderung verwenden möchtest, musst du auch [Git für Windows](https://gitforwindows.org/) installieren.) + +1. Installiere [NodeJS](https://nodejs.org/en) (die neueste LTS-Version wird empfohlen). +2. Installiere [GitHub Desktop](https://central.github.com/deployments/desktop/desktop/latest/win32). +3. Klicke nach der Installation von GitHub Desktop auf `Ein Repository aus dem Internet klonen....` (Hinweis: Du **musst kein** GitHub-Konto für diesen Schritt erstellen). +4. Klicke im Menü auf den Tab URL, gib diese URL ein `https://github.com/SillyTavern/SillyTavern` und klicke auf Klonen. Du kannst den lokalen Pfad ändern, um festzulegen, wohin SillyTavern heruntergeladen werden soll. +5. Um SillyTavern zu öffnen, durchsuche mit dem Windows-Explorer den Ordner, in den du das Repository geklont hast. Standardmäßig wird das Repository hier hin geklont: `C:\Users\[Dein Windows-Benutzername]\Documents\GitHub\SillyTavern`. +6. Doppelklicke auf die Datei `start.bat`. (Hinweis: Der Teil `.bat` des Dateinamens könnte von deinem Betriebssystem verborgen sein. In diesem Fall sieht es aus wie eine Datei namens "`Start`". Dies ist die Datei, auf die du doppelklickst, um SillyTavern auszuführen.) +7. Nach dem Doppelklicken sollte ein großes schwarzes Konsolenfenster erscheinen, und SillyTavern beginnt, das zu installieren, was es zum Betrieb benötigt. +8. Nach dem Installationsprozess sollte das Konsolenfenster so aussehen, und ein SillyTavern-Tab sollte in deinem Browser geöffnet sein. +9. Verbinde dich mit einer der [unterstützten APIs](https://docs.sillytavern.app/usage/api-connections/) und beginne zu chatten! + +## 🐧 Linux & 🍎 MacOS + +Für MacOS/Linux werden all diese Schritte in einem Terminal durchgeführt. + +1. Installiere git und nodeJS (die Methode zur Durchführung hängt von deinem Betriebssystem ab). +2. Klone das Repository. + +* für den Release-Branch: `git clone https://github.com/SillyTavern/SillyTavern -b release` +* für den Staging-Branch: `git clone https://github.com/SillyTavern/SillyTavern -b staging` + +3. `cd SillyTavern`, um in den Installationsordner zu navigieren. +4. Führe das Skript `start.sh` mit einem dieser Befehle aus: + +* `./start.sh` +* `bash start.sh` + +## ⚡ Installation über SillyTavern Launcher + +Der SillyTavern Launcher ist ein Installationsassistent, der dir bei der Einrichtung mit vielen Optionen helfen wird, einschließlich der Installation eines Backends für lokale Inferenz. + +### Für Windows-Nutzer + +1. Drücke auf deiner Tastatur **`WINDOWS + R`**, um das Ausführen-Dialogfeld zu öffnen. Führe dann den folgenden Befehl aus, um git zu installieren: + +```shell +cmd /c winget install -e --id Git.Git +``` + +2. Drücke auf deiner Tastatur **`WINDOWS + E`**, um den Datei-Explorer zu öffnen, und navigiere dann zu dem Ordner, in dem du den Launcher installieren möchtest. Gib im gewünschten Ordner in die Adressleiste `cmd` ein und drücke Enter. Führe dann den folgenden Befehl aus: + +```shell +git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher && start installer.bat +``` + +### Für Linux-Nutzer + +1. Öffne dein bevorzugtes Terminal und installiere git. +2. Klone den SillyTavern-Launcher mit: + +```shell +git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher +``` + +3. Starte die installer.sh mit: + +```shell +chmod +x install.sh && ./install.sh +``` + +4. Nach der Installation starte die launcher.sh mit: + +```shell +chmod +x launcher.sh && ./launcher.sh +``` + +### Für Mac-Nutzer + +1. Öffne ein Terminal und installiere brew mit: + +```shell +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +``` + +2. Installiere git mit: + +```shell +brew install git +``` + +3. Klone den SillyTavern-Launcher mit: + +```shell +git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher +``` + +4. Starte die installer.sh mit: + +```shell +chmod +x install.sh && ./install.sh +``` + +5. Nach der Installation starte die launcher.sh mit: + +```shell +chmod +x launcher.sh && ./launcher.sh +``` + +## 🐋 Installation über Docker + +Diese Anweisungen setzen voraus, dass du Docker installiert hast, auf deine Befehlszeile für die Installation von Containern zugreifen kannst und mit deren allgemeiner Funktionsweise vertraut bist. + +### Image selbst bauen + +Wir haben einen umfassenden Leitfaden zur Nutzung von SillyTavern in Docker [hier](http://docs.sillytavern.app/installation/docker/) der die Installationen auf Windows, macOS und Linux abdeckt! Lies ihn, wenn du das Image selbst bauen möchtest. + +### Verwendung der GitHub Container Registry (am einfachsten) + +Du benötigst zwei zwingende Verzeichniszuordnungen und eine Portzuordnung, um SillyTavern funktionsfähig zu machen. Ersetze in dem Befehl deine Auswahl an den folgenden Stellen: + +#### Container-Variablen + +##### Volumen-Zuordnungen + +* [config] - Das Verzeichnis, in dem die SillyTavern-Konfigurationsdateien auf deinem Host-Computer gespeichert werden +* [data] - Das Verzeichnis, in dem die Benutzerdaten von SillyTavern (einschließlich Charaktere) auf deinem Host-Computer gespeichert werden +* [plugins] - (optional) Das Verzeichnis, in dem die SillyTavern-Server-Plugins auf deinem Host-Computer gespeichert werden + +##### Port-Zuordnungen + +* [PublicPort] - Der Port, über den der Datenverkehr ausgegeben werden soll. Dies ist zwingend erforderlich, da du auf die Instanz von außerhalb des virtuellen Maschinencontainers zugreifst. EXPOSIERE DIES NICHT IM INTERNET, OHNE EINEN GETRENNTEN SERVICE FÜR DIE SICHERHEIT ZU IMPLEMENTIEREN. + +##### Zusätzliche Einstellungen + +* [DockerNet] - Das Docker-Netzwerk, mit dem der Container erstellt werden soll. Wenn du nicht weißt, was das ist, sieh dir die [offizielle Docker-Dokumentation](https://docs.docker.com/reference/cli/docker/network/) an. +* [version] - Auf der rechten Seite dieser GitHub-Seite siehst du "Packages". Wähle das Paket "sillytavern" und du siehst die Imageversionen. Das Image-Tag "latest" hält dich auf dem Laufenden mit dem aktuellen Release. Du kannst auch "staging" und "release" Tags nutzen, die auf die nightly images der jeweiligen Branche verweisen, aber das könnte unangemessen sein, wenn du Erweiterungen verwendest, die möglicherweise kaputt sind und Zeit benötigen, um aktualisiert zu werden. + +#### Installationsbefehl + +1. Öffne deine Befehlszeile. +2. Führe den folgenden Befehl aus: + +`docker create --name='sillytavern' --net='[DockerNet]' -p '8000:8000/tcp' -v '[plugins]':'/home/node/app/plugins':'rw' -v '[config]':'/home/node/app/config':'rw' -v '[data]':'/home/node/app/data':'rw' 'ghcr.io/sillytavern/sillytavern:[version]'` + +> Beachte, dass 8000 ein Standard-Listening-Port ist. Vergiss nicht, einen geeigneten Port zu verwenden, wenn du ihn in der Konfiguration änderst. + +## 📱 Installation über Termux auf Android OS + +> \[!HINWEIS] +> **SillyTavern kann nativ auf Android-Geräten über Termux ausgeführt werden, aber wir bieten keine offizielle Unterstützung für diesen Anwendungsfall.** +> +> **Bitte beziehe dich auf diesen Leitfaden von ArroganceComplex#2659:** +> +> * <https://rentry.org/STAI-Termux> + +**Nicht unterstützte Plattform: android arm LEtime-web.** 32-Bit-Android benötigt eine externe Abhängigkeit, die nicht mit npm installiert werden kann. Verwende den folgenden Befehl, um sie zu installieren: `pkg install esbuild`. Führe dann die üblichen Installationsschritte aus. + +## API-Schlüsselverwaltung + +SillyTavern speichert deine API-Schlüssel in einer Datei `secrets.json` im Benutzerdatenverzeichnis (`/data/default-user/secrets.json` ist der Standardpfad). + +Standardmäßig sind API-Schlüssel nach dem Speichern und Aktualisieren der Seite nicht mehr über die Benutzeroberfläche sichtbar. + +Um die Ansicht deiner Schlüssel zu aktivieren: + +1. Setze den Wert von `allowKeysExposure` auf `true` in der Datei `config.yaml`. +2. Starte den SillyTavern-Server neu. +3. Klicke auf den Link 'Verborgene API-Schlüssel anzeigen' in der unteren rechten Ecke des API-Verbindungsfeldes. + +## Befehlszeilenargumente + +Sie können Befehlszeilenargumente an den Start des SillyTavern-Servers übergeben, um einige Einstellungen in `config.yaml` zu überschreiben. + +### Beispiele + +```shell +node server.js --port 8000 --listen false +# oder +npm run start -- --port 8000 --listen false +# oder (nur Windows) +Start.bat --port 8000 --listen false +``` + +### Unterstützte Argumente + +| Option | Beschreibung | Typ | +|-------------------------|----------------------------------------------------------------------------------------------------|----------| +| `--version` | Versionsnummer anzeigen | boolean | +| `--enableIPv6` | Aktiviert IPv6. | boolean | +| `--enableIPv4` | Aktiviert IPv4. | boolean | +| `--port` | Legt den Port fest, unter dem SillyTavern ausgeführt wird. Wenn nicht angegeben, wird auf YAML-Konfiguration „Port“ zurückgegriffen. | number | +| „--dnsPreferIPv6“ | Bevorzugt IPv6 für DNS. Wenn nicht angegeben, wird auf YAML-Konfiguration „preferIPv6“ zurückgegriffen. | boolean | +| „--autorun“ | Startet SillyTavern automatisch im Browser. Wenn nicht angegeben, wird auf YAML-Konfiguration „autorun“ zurückgegriffen.| boolean | +| „--autorunHostname“ | Der Autorun-Hostname, am besten auf „auto“ belassen. | string | +| „--autorunPortOverride“ | Überschreibt den Port für Autorun. | string | +| „--listen“ | SillyTavern lauscht auf allen Netzwerkschnittstellen. Wenn nicht angegeben, wird auf YAML-Konfiguration „listen“ zurückgegriffen.| boolean | +| „--corsProxy“ | Aktiviert CORS-Proxy. Wenn nicht angegeben, wird auf YAML-Konfiguration „enableCorsProxy“ zurückgegriffen. | boolean | +| `--disableCsrf` | Deaktiviert CSRF-Schutz | boolean | +| `--ssl` | Aktiviert SSL | boolean | +| `--certPath` | Pfad zu Ihrer Zertifikatsdatei. | string | +| `--keyPath` | Pfad zu Ihrer privaten Schlüsseldatei. | string | +| `--whitelist` | Aktiviert den Whitelist-Modus | boolean | +| `--dataRoot` | Stammverzeichnis für Datenspeicherung | string | +| `--avoidLocalhost` | Vermeidet die Verwendung von „localhost“ für Autorun im Auto-Modus. | boolean | +| `--basicAuthMode` | Aktiviert die grundlegende Authentifizierung | boolean | +| `--requestProxyEnabled` | Aktiviert die Verwendung eines Proxys für ausgehende Anfragen | boolean | +| `--requestProxyUrl` | Proxy-URL anfordern (HTTP- oder SOCKS-Protokolle) | string | +| `--requestProxyBypass` | Proxy-Bypass-Liste anfordern (durch Leerzeichen getrennte Liste von Hosts) | Array | + +## Remoteverbindungen + +Dies ist in den meisten Fällen für Personen gedacht, die SillyTavern auf ihren Mobiltelefonen verwenden möchten, während ihr PC den ST-Server im selben WLAN-Netzwerk betreibt. Es kann jedoch auch verwendet werden, um Remoteverbindungen von überall her zu ermöglichen. + +Lies die ausführliche Anleitung zum Einrichten von Remoteverbindungen in den [Docs](https://docs.sillytavern.app/usage/remoteconnections/). + +Möglicherweise möchtest du SillyTavern-Benutzerprofile auch mit (optionalem) Kennwortschutz konfigurieren: [Benutzer](https://docs.sillytavern.app/installation/st-1.12.0-migration-guide/#users). + +## Leistungsprobleme? + +1. Deaktiviere den Unschärfeeffekt und aktiviere "Verringerte Bewegung" im Bedienfeld "Benutzereinstellungen" (UI-Design schaltet Kategorie um). +2. Wenn du Response Streaming verwendest, stelle die Streaming-FPS auf einen niedrigeren Wert ein (10-15 FPS werden empfohlen). +3. Stelle sicher, dass der Browser die GPU-Beschleunigung zum Rendern verwenden kann. + +## Lizenz und Danksagungen + +**Dieses Programm wird in der Hoffnung verbreitet, dass es nützlich ist, +aber OHNE JEGLICHE GARANTIE; nicht einmal die stillschweigende Garantie der +MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK. Siehe die +GNU Affero General Public License für weitere Details.** + +* [TavernAI](https://github.com/TavernAI/TavernAI) 1.2.8 von Humi: MIT-Lizenz +* Teile von CncAnons TavernAITurbo-Mod werden mit Genehmigung verwendet +* Visual Novel-Modus inspiriert von der Arbeit von PepperTaco (<https://github.com/peppertaco/Tavern/>) +* Noto Sans-Schriftart von Google (OFL-Lizenz) +* Symboldesign von Font Awesome <https://fontawesome.com> (Symbole: CC BY 4.0, Schriftarten: SIL OFL 1.1, Code: MIT-Lizenz) +* Standardinhalt von @OtisAlejandro (Seraphina-Charakter und Lorebook) und @kallmeflocc (10.000 Discord-Benutzer-Feierhintergrund) +* Docker-Anleitung von [@mrguymiah](https://github.com/mrguymiah) und [@Bronya-Rand](https://github.com/Bronya-Rand) + +## Top Contributors + +[![Contributors](https://contrib.rocks/image?repo=SillyTavern/SillyTavern)](https://github.com/SillyTavern/SillyTavern/graphs/contributors) + +<!-- LINK GROUP --> +[cover]: https://github.com/user-attachments/assets/01a6ae9a-16aa-45f2-8bff-32b5dc587e44 +[discord-link]: https://discord.gg/sillytavern +[discord-shield-badge]: https://img.shields.io/discord/1100685673633153084?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=for-the-badge diff --git a/jiuguan2025cc/.github/readme-ja_jp.md b/jiuguan2025cc/.github/readme-ja_jp.md new file mode 100644 index 0000000000000000000000000000000000000000..a8e1486cfa461a4308d5997c2d41464c44c08781 --- /dev/null +++ b/jiuguan2025cc/.github/readme-ja_jp.md @@ -0,0 +1,330 @@ +> [!IMPORTANT] +> ここに掲載されている情報は、古かったり不完全であったりする可能性があります。最新の情報は英語版をご利用ください。 + +![][cover] + +<div align="center"> + +[English](readme.md) | [German](readme-de_de.md) | [中文](readme-zh_cn.md) | [繁體中文](readme-zh_tw.md) | 日本語 | [Русский](readme-ru_ru.md) | [한국어](readme-ko_kr.md) + +[![GitHub Stars](https://img.shields.io/github/stars/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/stargazers) +[![GitHub Forks](https://img.shields.io/github/forks/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/network) +[![GitHub Issues](https://img.shields.io/github/issues/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/issues) +[![GitHub Pull Requests](https://img.shields.io/github/issues-pr/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/pulls) + +</div> + +--- + +モバイルデバイスにも適したレイアウト・マルチAPI(KoboldAI/CPP、Horde、NovelAI、Ooba、OpenAI、OpenRouter、Claude、Scale)、VN ライクな Waifu モード、Stable Diffusion、TTS、WorldInfo(伝承本)、カスタマイズ可能なUI、自動翻訳、大量のプロンプトオプション+サードパーティの拡張機能をインストールする機能 + +[TavernAI](https://github.com/TavernAI/TavernAI) v.1.2.8 のフォークに基づいています。 + +## 重要事項 + +1. 私たちは[ドキュメントウェブサイト](https://docs.sillytavern.app/) を作成し、ほとんどの質問にお答えしています。 + +2. アップデートしたら使っていた拡張機能を見失いましたか?リリースバージョン 1.10.6 以降、これまで内蔵されていた拡張機能のほとんどがダウンロード可能なアドオンに変更されました。ダウンロードは、拡張機能パネル(トップバーのスタックドブロックアイコン)にある内蔵の "Download Extensions and Assets" メニューから行えます。 + +### Cohee、RossAscends、SillyTavern コミュニティがお届けします + +### SillyTavern または TavernAI とは何ですか? + +SillyTavern は、あなたのコンピュータ(および Android スマホ)にインストールできるユーザーインターフェイスで、テキスト生成 AI と対話したり、あなたやコミュニティが作成したキャラクターとチャットやロールプレイをすることができます。 + +SillyTavern は TavernAI 1.2.8 のフォークで、より活発な開発が行われており、多くの主要な機能が追加されています。現時点では、これらは完全に独立したプログラムと考えることができます。 + +### ブランチ + +SillyTavern は、すべてのユーザーにスムーズな体験を保証するために、2 つのブランチシステムを使用して開発されています。 + +* release -🌟 **ほとんどのユーザーにお勧め。** これは最も安定した推奨ブランチで、メジャーリリースがプッシュされた時のみ更新されます。大半のユーザーに適しています。 +* staging - ⚠️ **カジュアルな使用にはお勧めしない。** このブランチには最新の機能がありますが、いつ壊れるかわからないので注意してください。パワーユーザーとマニア向けです。 + +git CLI の使い方に慣れていなかったり、ブランチが何なのかわからなかったりしても、心配はいりません!releaseブランチが良い選択肢となります。 + +### Tavern 以外に何が必要ですか? + +Tavern は単なるユーザーインターフェイスなので、それだけでは何もできません。ロールプレイキャラクターとして機能する AI システムのバックエンドにアクセスする必要があります。様々なバックエンドがサポートされています。リストはこちらです: OpenAPI API (GPT)、KoboldAI (ローカルまたは Google Colab 上で動作)、その他。詳しくは [FAQ](https://docs.sillytavern.app/usage/faq/) をご覧ください。 + +### Tavern を実行するには、ハイスペックなPCが必要ですか? + +Tavern は単なるフロントエンドのUIであり、必要なハードウェアはごくわずかです。パワフルである必要があるのは、AI システムのバックエンドです。 + +## モバイルサポート + +> **注** + +> **このフォークは Termux を使って Android スマホで実行できます。ArroganceComplex#2659 のガイドを参照してください:** + +<https://rentry.org/STAI-Termux> + +## ご質問やご提案 + +### コミュニティ Discord サーバーを開設しました + +サポートを受けたり、作成したキャラを共有したり、コミュニティの作ったキャラと遊びたいですか?: + +### [参加](https://discord.gg/RZdyAEUPvj) + +*** + +開発者と直接連絡: + +* Discord: cohee または rossascends +* Reddit: /u/RossAscends または /u/sillylossy +* [GitHub issue を投稿](https://github.com/SillyTavern/SillyTavern/issues) + +## このバージョンには以下のコードが含まれます + +* 大幅に修正された TavernAI 1.2.8 (コードの 50% 以上が書き換えまたは最適化されています) +* スワイプ +* グループチャット: キャラクター同士が会話できるマルチボットルーム +* チャットチェックポイント / ブランチ +* 高度なKoboldAI / TextGen生成設定と、コミュニティが作成した多くのプリセット +* ワールド情報サポート: 豊富な伝承を作成したり、キャラクターカードにトークンを保存したりできます +* [OpenRouter](https://openrouter.ai) 各種 API(Claude、GPT-4/3.5 など)の接続 +* [Oobabooga's TextGen WebUI](https://github.com/oobabooga/text-generation-webui) API 接続 +* [AI Horde](https://aihorde.net/) 接続 +* プロンプト生成フォーマットの調整 + +## 拡張機能 + +SillyTavern は拡張できるようになっており。 + +* キャラクターの感情表現(スプライト) +* チャット履歴の自動サマリー +* チャットに画像を送り、AI が内容を解釈する +* Stable Diffusion 画像生成 (5 つのチャット関連プリセットと 'free mode') +* AI 応答メッセージの音声合成(ElevenLabs、Silero、または OS のシステム TTS 経由) + +含まれている拡張機能の完全なリストとその使い方のチュートリアルは [Docs](https://docs.sillytavern.app/) にあります。 + +## RossAscends による UI/CSS/クオリティオブライフの調整 + +* iOS 用に最適化されたモバイル UI で、ホーム画面へのショートカット保存とフルスクリーンモードでの起動をサポート。 +* ホットキー + * Up = チャットの最後のメッセージを編集する + * Ctrl+Up = チャットで最後のユーザーメッセージを編集する + * Left = 左スワイプ + * Right = 右スワイプ (注: チャットバーに何か入力されている場合、スワイプホットキーが無効になります) + * Ctrl+Left = ローカルに保存された変数を見る(ブラウザのコンソールウィンドウにて) + * Enter (チャットバー選択時) = AI にメッセージを送る + * Ctrl+Enter = 最後の AIのレスポンスを再生成する + +* ユーザー名の変更と文字の削除でページが更新されなくなりました。 + +* ページロード時に API に自動的に接続するかどうかを切り替えます。 +* ページの読み込み時に、最近見た文字を自動的に読み込むかどうかを切り替えます。 +* より良いトークンカウンター - 保存されていないキャラクターに対して機能し、永続的なトークンと一時的なトークンの両方を表示する。 + +* より良い過去のチャット + * 新しいチャットのファイル名は、"(文字) - (作成日)" という読みやすい形式で保存されます + * チャットのプレビューが 40 文字から 300 文字に増加。 + * 文字リストの並べ替えに複数のオプション(名前順、作成日順、チャットサイズ順)があります。 + +* デフォルトでは、左右の設定パネルはクリックすると閉じます。 +* ナビパネルのロックをクリックすると、パネルが開いたままになり、この設定はセッションをまたいで記憶されます。 +* ナビパネルの開閉状態もセッションをまたいで保存されます。 + +* カスタマイズ可能なチャット UI: + * 新しいメッセージが届いたときにサウンドを再生する + * 丸型、長方形のアバタースタイルの切り替え + * デスクトップのチャットウィンドウを広くする + * オプションの半透明ガラス風パネル + * 'メインテキスト'、'引用テキスト'、'斜体テキスト'のページカラーをカスタマイズ可能。 + * カスタマイズ可能な UI 背景色とぼかし量 + +## インストール + +*注: このソフトウェアはローカルにインストールすることを目的としており、colab や他のクラウドノートブックサービス上では十分にテストされていません。* + +> **警告** + +> WINDOWS が管理しているフォルダ(Program Files、System32 など)にはインストールしないでください + +> START.BAT を管理者権限で実行しないでください + +### Windows + +Git 経由でのインストール(更新を容易にするため推奨) + +写真付きのわかりやすいガイドはこちらです: +<https://docs.sillytavern.app/installation/windows/> + + 1. [NodeJS](https://nodejs.org/en) をインストール(最新の LTS 版を推奨) + 2. [GitHub Desktop](https://central.github.com/deployments/desktop/desktop/latest/win32) をインストールする + 3. Windows エクスプローラーを開く (`Win+E`) + 4. Windows によって制御または監視されていないフォルダを参照または作成する。(例: C:\MySpecialFolder\) + 5. 上部のアドレスバーをクリックし、`cmd` と入力して Enter キーを押し、そのフォルダーの中にコマンドプロンプトを開きます。 + 6. 黒いボックス(コマンドプロンプト)がポップアップしたら、そこに以下のいずれかを入力し、Enter を押します: + +* Release ブランチの場合: `git clone https://github.com/SillyTavern/SillyTavern -b release` +* Staging ブランチの場合: `git clone https://github.com/SillyTavern/SillyTavern -b staging` + + 7. すべてをクローンしたら、`Start.bat` をダブルクリックして、NodeJS に要件をインストールさせる。 + 8. サーバーが起動し、SillyTavern がブラウザにポップアップ表示されます。 + +ZIP ダウンロードによるインストール(推奨しない) + + 1. [NodeJS](https://nodejs.org/en) をインストールする(最新の LTS 版を推奨) + 2. GitHub のリポジトリから zip をダウンロードする。(`ソースコード(zip)` は [Releases](https://github.com/SillyTavern/SillyTavern/releases/latest) から入手) + 3. お好きなフォルダに解凍してください + 4. `Start.bat` をダブルクリックまたはコマンドラインで実行する。 + 5. サーバーが準備できれば、ブラウザのタブを開きます。 + +### Linux + + 1. `node -v` を実行して、Node.js v18 以上(最新の [LTS バージョン](https://nodejs.org/en/download/) を推奨)がインストールされていることを確認してください。 +または、[Node Version Manager](https://github.com/nvm-sh/nvm#installing-and-updating) スクリプトを使用して、迅速かつ簡単に Node のインストールを管理します。 + 2. `start.sh` スクリプトを実行する。 + 3. お楽しみください。 + +## API キー管理 + +SillyTavern は API キーをサーバーディレクトリの `secrets.json` ファイルに保存します。 + +デフォルトでは、入力後にページをリロードしても、フロントエンドには表示されません。 + +API ブロックのボタンをクリックして、キーを閲覧できるようにする: + +1. ファイル `config.yaml` で `allowKeysExposure` の値を `true` に設定する。 +2. SillyTavern サーバを再起動します。 + +## リモート接続 + +SillyTavern をスマホで使用しながら、同じ Wifi ネットワーク上で ST サーバーを PC で実行したい場合に使用します。 + +しかし、これはどこからでもリモート接続を許可するために使用することができます。 + +**重要: SillyTavern はシングルユーザーのプログラムなので、ログインすれば誰でもすべてのキャラクターとチャットを見ることができ、UI 内で設定を変更することができます。** + +### 1. ホワイトリスト IP の管理 + +* SillyTavern のベースインストールフォルダ内に `whitelist.txt` という新しいテキストファイルを作成します。 +* テキストエディタでこのファイルを開き、接続を許可したい IP のリストを追加します。 + +*個々の IP とワイルドカード IP 範囲の両方が受け入れられる。例:* + +```txt +192.168.0.1 +192.168.0.20 +``` + +または + +```txt +192.168.0.* +``` + +(上記のワイルドカード IP 範囲は、ローカルネットワーク上のどのデバイスでも) + +CIDR マスクも受け付ける(例:10.0.0.0/24)。 + +* `whitelist.txt` ファイルを保存する。 +* TAI サーバーを再起動する。 + +これでファイルに指定された IP を持つデバイスが接続できるようになります。 + +*注: `config.yaml` にも `whitelist` 配列があり、同じように使うことができるが、`whitelist.txt` が存在する場合、この配列は無視される。* + +### 2. ST ホストマシンの IP の取得 + +ホワイトリストの設定後、ST ホストデバイスの IP が必要になります。 + +ST ホストデバイスが同じ無線 LAN ネットワーク上にある場合、ST ホストの内部無線 LAN IP を使用します: + +* Windows の場合: ウィンドウズボタン > 検索バーに `cmd.exe` と入力 > コンソールに `ipconfig` と入力して Enter > `IPv4` のリストを探す。 + +同じネットワーク上にいない状態で、ホストしているSTに接続したい場合は、STホスト機器のパブリックIPが必要です。 + +* ST ホストデバイスを使用中に、[このページ](https://whatismyipaddress.com/)にアクセスし、`IPv4` を探してください。これはリモートデバイスからの接続に使用するものです。 + +### 3. リモートデバイスを ST ホストマシンに接続します。 + +最終的に使用する IP が何であれ、その IP アドレスとポート番号をリモートデバイスのウェブブラウザに入力します。 + +同じ無線 LAN ネットワーク上の ST ホストの典型的なアドレスは以下のようになります: + +`http://192.168.0.5:8000` + +http:// を使用し、https:// は使用しないでください + +### ST をすべての IP に開放する + +これはお勧めしませんが、`config.yaml` を開き、`whitelistMode` を `false` に変更してください。 + +SillyTavern のベースインストールフォルダにある `whitelist.txt` が存在する場合は削除(または名前の変更)する必要があります。 + +これは通常安全ではないので、これを行う際にはユーザー名とパスワードを設定する必要があります。 + +ユーザー名とパスワードは `config.yaml` で設定します。 + +ST サーバを再起動すると、ユーザ名とパスワードさえ知っていれば、IP に関係なくどのデバイスでも ST サーバに接続できるようになる。 + +### まだ接続できませんか? + +* `config.yaml` で見つかったポートに対して、インバウンド/アウトバウンドのファイアウォールルールを作成します。これをルーターのポートフォワーディングと間違えないでください。そうしないと、誰かがあなたのチャットログを見つける可能性があり、それはマジで止めましょう。 +* 設定 > ネットワークとインターネット > イーサネットで、プライベートネットワークのプロファイルタイプを有効にします。そうしないと、前述のファイアウォールルールを使っても接続できません。 + +## パフォーマンスに問題がありますか? + +ユーザー設定パネルでブラー効果なし(高速 UI)モードを有効にしてみてください。 + +## このプロジェクトが気に入りました!どうすれば貢献できますか? + +### やるべきこと + +1. プルリクエストを送る +2. 確立されたテンプレートを使って機能提案と課題レポートを送る +3. 何か質問する前に、readme ファイルや組み込みのドキュメントを読んでください + +### やるべきではないこと + +1. 金銭の寄付を申し出る +2. 何の脈絡もなくバグ報告を送る +3. すでに何度も回答されている質問をする + +## 古い背景画像はどこにありますか? + +100% オリジナルコンテンツのみのポリシーに移行しているため、古い背景画像はこのリポジトリから削除されました。 + +アーカイブはこちら: + +<https://files.catbox.moe/1xevnc.zip> + +## スクリーンショット + +<img width="500" alt="image" src="https://github.com/user-attachments/assets/9b5f32f0-c3b3-4102-b3f5-0e9213c0f50f"> +<img width="500" alt="image" src="https://github.com/user-attachments/assets/913fdbaa-7d33-42f1-ae2c-89dca41c53d1"> + +## ライセンスとクレジット + +**このプログラムは有用であることを願って配布されていますが、いかなる保証もありません; +また、商品性または特定目的への適合性についての黙示の保証もありません。 +詳細は GNU Affero General Public License をご覧ください。** + +* Humi によるTAI Base: 不明ライセンス +* Cohee の修正と派生コード: AGPL v3 +* RossAscends の追加: AGPL v3 +* CncAnon の TavernAITurbo 改造の一部: 不明ライセンス +* kingbri のさまざまなコミットと提案 (<https://github.com/bdashore3>) +* city_unit の拡張機能と様々な QoL 機能 (<https://github.com/city-unit>) +* StefanDanielSchwarz のさまざまなコミットとバグ報告 (<https://github.com/StefanDanielSchwarz>) +* PepperTaco の作品にインスパイアされた Waifu モード (<https:/fugithub.com/peppertaco/Tavern/>) +* ピグマリオン大学の皆さん、素晴らしいテスターとしてクールな機能を提案してくれてありがとう! +* TextGen のプリセットをコンパイルしてくれた obabooga に感謝 +* KAI Lite の KoboldAI プリセット: <https://lite.koboldai.net/> +* Google による Noto Sans フォント(OFLライセンス) +* Font Awesome によるアイコンテーマ <https://fontawesome.com> (アイコン: CC BY 4.0、フォント: SIL OFL 1.1、コード: MIT License) +* ZeldaFan0225 による AI Horde クライアントライブラリ: <https://github.com/ZeldaFan0225/ai_horde> +* AlpinDale による Linux 起動スクリプト +* FAQ を提供してくれた paniphons に感謝 +* 10K ディスコード・ユーザー記念背景 by @kallmeflocc +* デフォルトコンテンツ(キャラクターと伝承書)の提供: @OtisAlejandro、@RossAscends、@kallmeflocc +* @doloroushyeonse による韓国語翻訳 +* k_euler_a による Horde のサポート <https://github.com/Teashrock> +* [@XXpE3](https://github.com/XXpE3) による中国語翻訳、中国語 ISSUES の連絡先は @XXpE3 + +<!-- LINK GROUP --> +[cover]: https://github.com/user-attachments/assets/01a6ae9a-16aa-45f2-8bff-32b5dc587e44 diff --git a/jiuguan2025cc/.github/readme-ko_kr.md b/jiuguan2025cc/.github/readme-ko_kr.md new file mode 100644 index 0000000000000000000000000000000000000000..80a3a4335775e690d2b2bfe1eda90e9c6810eedd --- /dev/null +++ b/jiuguan2025cc/.github/readme-ko_kr.md @@ -0,0 +1,394 @@ +> [!IMPORTANT] +> 이곳에 게재된 정보는 오래되거나 불완전할 수 있습니다. 최신 정보는 영어 버전을 이용하십시오. + +<a name="readme-top"></a> + +![][cover] + +<div align="center"> + +[English](readme.md) | [German](readme-de_de.md) | [中文](readme-zh_cn.md) | [繁體中文](readme-zh_tw.md) | [日本語](readme-ja_jp.md) | [Русский](readme-ru_ru.md) | 한국어 + +[![GitHub Stars](https://img.shields.io/github/stars/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/stargazers) +[![GitHub Forks](https://img.shields.io/github/forks/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/network) +[![GitHub Issues](https://img.shields.io/github/issues/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/issues) +[![GitHub Pull Requests](https://img.shields.io/github/issues-pr/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/pulls) + +</div> + +--- + +SillyTavern은 많은 LLM API(KoboldAI/CPP, Horde, NovelAI, Ooba, Tabby, OpenAI, OpenRouter, Claude, Mistral 등)에 대한 단일 통합 인터페이스, 모바일 친화적 레이아웃, 비주얼 노벨 모드, Automatic1111 & ComfyUI API 이미지 생성 통합, TTS, 월드 인포 (로어북), 커스텀 가능한 UI, 자동 번역, 필요 이상의 프롬프트 옵션, 그리고 서드파티 확장을 통한 무궁무진한 성장 가능성을 제공합니다. + +또한, 자주 묻는 질문에 대한 답변과, 시작하는 데 도움을 주기 위한 [문서 웹사이트](https://docs.sillytavern.app/)가 있습니다. + +## SillyTavern이 무엇인가요? + +SillyTavern(짧게는 ST)은 텍스트 생성 LLM, 이미지 생성 엔진, TTS 음성 모델 등과 상호작할 수 있는 로컬 설치형 UI 입니다. + +2023년 2월, TavernAI 1.2.8의 포크로 시작한 SillyTavern은 현재 100명이 넘는 기여자를 보유하고 있으며, 2년간의 독자적인 개발을 거쳐 숙련된 AI 애호가들을 위한 선도적인 소프트웨어로 자리매김하고 있습니다. + + +## 우리의 비전 + +1. 저희는 사용자가 LLM 프롬프트에 대한 최대한의 유용성과 제어 능력을 갖도록 하는 것을 목표로 합니다. 빠르게 배우는 것 역시 재미의 일부입니다! +2. 저희는 어떠한 온라인 및 호스팅 서브시도 제공하지 않으며, 프로그래밍으로 사용자의 데이터를 추적하지 않습니다. +3. SillyTavern은 헌신적인 LLM 커뮤니티가 여러분에게 제공하는 열정적인 프로젝트이며, 언제나 무료이며 오픈소스로 제공될 것입니다. + +## 브랜치 + +SillyTavern은 모든 사용자가 원활한 경험을 할 수 있도록 두 개의 브랜치를 활용하여 개발되고 있습니다. + + +* `release` -🌟 **대부분의 사용자에게 추천됨.** 가장 안정적이고 권장되는 브랜치이며, 주요 릴리스가 배포될 때만 업데이트됩니다. 대부분의 사용자에게 적합합니다. 일반적으로 한달에 한번 업데이트됩니다. +* `staging` - ⚠️ **일반적인 사용에 추천되지 않음.** 최신 기능을 가지고 있지만, 언제든지 문제가 발생할 수 있습니다. 고급 사용자 및 숙련자 전용입니다. 하루에 여러번 업데이트됩니다. + +만약 git CLI 사용에 익숙하지 않거나 브랜치가 무엇인지 모르겠다면 release 브랜치가 더 나은 선택입니다. + +## SillyTavern 외에 무엇이 필요한가요? + +SillyTavern은 인터페이스 역할만 하기 때문에, 실제로 채팅하려면 LLM 백엔드에 대한 액세스 권한이 필요합니다. 즉시 사용 가능한 채팅을 위해 AI Horde를 사용할 수 있습니다. 그 외에도 OpenAI 호환 API, KoboldAI, Tabby 등 많은 로컬 및 클라우드 기반 LLM 백엔드를 지원합니다. 지원되는 API에 대한 자세한 내용은 [FAQ](https://docs.sillytavern.app/usage/api-connections/)에서 확인할 수 있습니다. + +### SillyTavern을 위해서 좋은 성능의 PC가 필요한가요? + +하드웨어 요구 사항은 거의 없습니다: NodeJS 18 이상을 실행할 수 있는 모든 환경에서 작동합니다. 다만 로컬 LLM 모델을 사용할 경우, 최소 6GB VRAM 이상의 3000번대 NVIDIA 그래픽 카드를 권장합니다. 자세한 내용은 백엔드 문서를 참고하세요. + +### 추천되는 백엔드 (제휴 없음) + +* [AI Horde](https://aihorde.net/) - 자원 봉사자들이 호스팅하는 모델을 사용합니다. 추가 설정이 필요하지 않습니다. +* [KoboldCpp](https://github.com/LostRuins/koboldcpp) - 로컬에서 GGUF 모델을 실행하기 위한 커뮤니티에서 선호하는 옵션입니다. +* [tabbyAPI](https://github.com/theroyallab/tabbyAPI) - 인기 있는 경량 로컬 exl2 추론 API입니다. +* [OpenRouter](https://openrouter.ai) - OpenAI, Claude, Meta Llama 등 다양한 클라우드 제공업체와 인기 있는 커뮤니티 모델을 위한 단일 API입니다. + +## 질문이나 제안이 있으신가요? + +### 디스코드 서버 + +| [![][discord-shield-badge]][discord-link] | [저희의 디스코드에 참여하세요!](https://discord.gg/sillytavern) 지원을 받고, 좋아하는 캐릭터와 프롬프트를 공유하세요. | +| :---------------------------------------- | :----------------------------------------------------------------------------------------------------------------- | + +혹은 저희의 개발자들과 직접 연락할 수 있습니다: + +* 디스코드: cohee, rossascends, wolfsblvt +* 레딧: [/u/RossAscends](https://www.reddit.com/user/RossAscends/), [/u/sillylossy](https://www.reddit.com/user/sillylossy/), [u/Wolfsblvt](https://www.reddit.com/user/Wolfsblvt/) +* [GitHub issue를 작성하세요](https://github.com/SillyTavern/SillyTavern/issues) + +### 이 프로젝트가 마음에 들어요! 어떻게 기여할 수 있을까요? + +1. PULL REQUEST를 생성하세요. 기여 방법에 대해서는 [CONTRIBUTING.md](../CONTRIBUTING.md)를 참고하세요. +2. 제공된 탬플릿에 따라 기능 제안이나 이슈 리포트를 생성하세요. +3. 중복된 이슈를 생성하지 않도록 이 README 파일 전체를 읽고 문서 웹사이트를 먼저 확인하세요. + +## 스크린샷 + +<img width="500" alt="image" src="https://github.com/user-attachments/assets/9b5f32f0-c3b3-4102-b3f5-0e9213c0f50f"> +<img width="500" alt="image" src="https://github.com/user-attachments/assets/913fdbaa-7d33-42f1-ae2c-89dca41c53d1"> + + +## 캐릭터 카드 + +SillyTavern은 "캐릭터 카드"라는 개념을 중심으로 구축되었습니다. 캐릭터 카드는 LLM의 동작을 설정하는 프롬프트 모음이며, SillyTavern에서 지속적인 대화를 하려면 필수적입니다. 이는 ChatGPT의 GPT 또는 Poe의 봇과 유사하게 작동합니다. 캐릭터 카드의 내용은 추상적인 시나리오, 특정 작업에 맞춰진 도우미, 유명 인사 또는 가상 인물 등 무엇이든 될 수 있습니다. + +이름 필드는 유일한 필수 캐릭터 카드 입력 항목입니다. 언어 모델과 중립적인 대화를 시작하려면 "도우미"라고 간단히 이름 지은 새 카드를 만들고 나머지 상자는 비워 두세요. 더 주제가 있는 채팅을 원한다면 언어 모델에 다양한 배경 정보, 행동 및 작문 패턴, 그리고 채팅을 바로 시작할 시나리오를 제공할 수 있습니다. + +캐릭터 카드를 선택하지 않고 빠른 대화를 하거나 LLM 연결을 테스트하려면 SillyTavern을 연 후 시작 화면의 입력 창에 프롬프트 입력을 입력하기만 하면 됩니다. 이러한 채팅은 임시적이며 저장되지 않습니다. + +캐릭터 카드를 정의하는 방법에 대한 일반적인 아이디어를 얻으려면 기본 캐릭터(Seraphina)를 보거나 "확장 프로그램 및 에셋 다운로드" 메뉴에서 선택된 커뮤니티 제작 카드를 다운로드하세요. + + +## 핵심 기능 + +* 고급 텍스트 생성 설정과 다양한 커뮤니티 제작 프리셋 +* 월드 인포 지원: 풍부한 설정을 만들거나 캐릭터 카드에 토큰 저장 +* 그룹 채팅: 캐릭터가 사용자 혹은 다른 캐릭터와 대화할 수 있는 방 +* 다양한 UI 커스텀 옵션: 테마 색, 뱌경 이미지, 커스텀 CSS 등 +* 유저 페르소나: AI에게 사용자에 대한 정보를 주어 더욱 몰입감을 높임 +* 내장 RAG 지원: AI가 참조할 수 있도록 채팅에 문서를 추가 +* 광범위한 채팅 명령어 시스템 및 자체 [스크립트](https://docs.sillytavern.app/usage/st-script/) + +## 확장 + +SillyTavern은 확장(익스텐션)을 지원합니다. + +* 캐릭터 감정 표현 (스프라이트) +* 채팅 기록 자동 요약 +* 자동 UI 및 채팅 번역 +* Stable Diffusion/FLUX/DALL-E 이미지 생성 +* AI 응답 메시지 텍스트 음성 변환 (ElevenLabs, Silero 또는 OS 시스템 TTS 사용) +* 프롬프트에 추가적인 현실 세계 맥락을 추가하기 위한 웹 검색 기능 +* "확장 프로그램 및 에셋 다운로드" 메뉴에서 더 많은 기능을 다운로드할 수 있습니다. + + +사용 방법에 대한 튜토리얼은 [Docs](https://docs.sillytavern.app/)에서 확인할 수 있습니다. + +# ⌛ Installation + +> \[!WARNING] +> +> * **윈도우 제어 폴더에는 설치하지 마십시오 (Program Files, System32 등).** +> * **권리자 권한으로 START.BAT을 실행하지 마십시오.** +> * **Windows 7에서는 NodeJS 18.16을 실행할 수 없으므로 설치가 불가능합니다.** + +## 🪟 Windows + +### Git을 통해 설치하기 + +1. [NodeJS](https://nodejs.org/ko) 설치 (최신 LTS 버전 권장) +2. [Git for Windows](https://gitforwindows.org/) 설치 +3. 파일 탐색기 열기 (`Win+E`) +4. Windows에서 제어하거나 모니터하지 않는 폴더를 찾거나 만드세요. (ex: C:\MySpecialFolder\) +5. 상단의 주소 표시줄을 클릭하고 `cmd`를 입력한 후 Enter 키를 눌러 해당 폴더 내에서 명령 프롬프트를 여세요. +6. 검은색 창(명령 프롬프트)이 나타나면 다음 중 하나를 입력하고 Enter 키를 누르세요. + +* Release 브랜치: `git clone https://github.com/SillyTavern/SillyTavern -b release` +* Staging 브랜치: `git clone https://github.com/SillyTavern/SillyTavern -b staging` + +7. clone이 완료되면, `Start.bat`을 더블 클릭하여 NodeJS가 필요한 구성요소를 설치하도록 하세요. +8. 그러면 서버가 시작하고, SillyTavern이 브라우저에 나타납니다. + +### GitHub Desktop을 통해 설치하기 + +(이 방법은 **오직** GitHub Desktop에서만 git 사용이 가능합니다. 명령 프롬프트에서 git을 사용하려면 [Git for Windows](https://gitforwindows.org/)를 설치해야 합니다.) + + + + 1. [NodeJS](https://nodejs.org/ko) 설치 (최신 LTS 버전 권장) + 2. [GitHub Desktop](https://central.github.com/deployments/desktop/desktop/latest/win32) 설치 + 3. GitHub Desktop을 설치했으면, `Clone a repository from the internet....`를 클릭하세요. (참고: 이 과정에서는 Github 계정이 **필요하지 않습니다**.) + 4. 메뉴에서 URL 탭을 클릭하고, 다음 URL을 입력한 후 복제를 클릭합니다: `https://github.com/SillyTavern/SillyTavern` 리포지토리가 다운로드될 위치를 변경하려면 로컬 경로를 변경할 수 있습니다. + 5. SillyTavern을 열려면 파일 탐색기를 사용하여 리포지토리를 복제한 폴더로 이동합니다. 기본적으로 리포지토리는 다음 위치에 복제됩니다: `C:\Users\[사용자 Windows 사용자 이름]\Documents\GitHub\SillyTavern` + 6. `start.bat` 파일을 더블 클릭 하세요. (참고: `.bat` 확장자 명은 OS 설정에 따라 보이지 않을 수 있습니다, 그럴 때는 파일 이름이 "`Start`" 처럼 보일 수 있습니다. 이 파일을 더블 클릭해 SillyTavern을 실행하세요.) + 7. 더블 클릭하면, 검고 큰 명령 프롬프트 창이 열리고 SillyTavern이 작동하는데 필요한 항목을 설치하기 시작합니다. + 8. 설치 과정이 끝나고 모든 것이 잘 작동한다면, 브라우저에 SillyTavern 탭이 열려 있어야 하고, 명령 프롬프트 창에 다음과 같이 표시되어야 합니다: + 9. Connect to any of the [supported APIs](https://docs.sillytavern.app/usage/api-connections/) and start chatting! + +## 🐧 Linux & 🍎 MacOS + +MacOS / Linux 에서는 이 모든 작업이 터미널에서 수행됩니다. + +1. git과 nodeJS 설치 (이 작업은 OS에 따라 달라집니다.) +2. 리포지토리 clone하기 + +* Release 브랜치: `git clone https://github.com/SillyTavern/SillyTavern -b release` +* Staging 브랜치: `git clone https://github.com/SillyTavern/SillyTavern -b staging` + +3. `cd SillyTavern` 를 입력해 설치 폴더로 이동하기 +4. `start.sh` 스크립트를 아래의 명령어 중 하나로 실행하기: + +* `./start.sh` +* `bash start.sh` + +## ⚡ SillyTavern Launcher를 통해 설치하기 + +SillyTavern 런처는 로컬 LLM 사용을 위한 백엔드 설치를 포함하여 다양한 설정을 도와주는 설치 마법사입니다. + + +### Windows 사용자 + +1. 키보드에서 **`WINDOWS + R`** 키를 눌러 실행 창을 여세요. 그리고 아래의 명령어를 입력해 git을 설치하세요. + +```shell +cmd /c winget install -e --id Git.Git +``` + +2. 키보드에서 **`WINDOWS + E`** 키를 눌러 파일 탐색기를 열고 런처를 설치할 폴더로 이동합니다. 원하는 폴더에 도착하면 주소 표시줄에 `cmd`를 입력하고 Enter 키를 누릅니다. 그 후 아래의 명령어를 입력합니다. + + +```shell +git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher && start installer.bat +``` + +### Linux 사용자 + +1. 선호하는 터미널을 열고 git을 설치하세요. +2. SillyTavern-Launcher를 clone 하세요: + +```shell +git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher +``` + +3. installer.sh를 실행하세요: + +```shell +chmod +x install.sh && ./install.sh +``` + +4. 설치가 끝나면 launcher.sh를 실행하세요: + +```shell +chmod +x launcher.sh && ./launcher.sh +``` + +### Mac 사용자 + +1. 터미널을 열고 Brew를 설치하세요: + +```shell +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +``` + +2. git을 설치하세요: + +```shell +brew install git +``` + +3. SillyTavern-Launcher를 clone 하세요: + +```shell +git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher +``` + +4. installer.sh를 실행하세요: + +```shell +chmod +x install.sh && ./install.sh +``` + +5. 설치가 끝나면 launcher.sh를 실행하세요: + +```shell +chmod +x launcher.sh && ./launcher.sh +``` + +## 🐋 Docker를 통해 설치하기 + +이 방법은 Docker가 설치되어 있고, Docker 설치를 위해 커맨드 라인에 접근할 수 있으며, Docker의 일반적인 작동 방식에 익숙하다고 가정합니다. + +### 이미지 직접 빌드하기 + +SillyTavern을 Docker에서 사용하는 방법에 대한 포괄적인 가이드는 [여기서](http://docs.sillytavern.app/installation/docker/) 확인할 수 있습니다. 이 가이드는 Windows, macOS 및 Linux에서의 설치를 다룹니다! 직접 이미지를 빌드하려면 이 가이드를 읽어보세요. + +### GitHub Container Registry 사용하기 (가장 쉬움) + +SillyTavern이 작동하려면 두 개의 필수 디렉터리 매핑과 하나의 포트 매핑이 필요합니다. 명령에서 다음 위치의 선택 항목을 바꿔주세요. + + +#### Container Variables + +##### Volume Mappings + +* [config] - SillyTavern 구성 파일이 호스트 컴퓨터에 저장될 디렉터리 +* [data] - 캐릭터를 포함한 SillyTavern 사용자 데이터가 호스트 컴퓨터에 저장될 디렉터리 +* [plugins] - (선택 사항) SillyTavern 서버 플러그인이 호스트 컴퓨터에 저장될 디렉터리 + +##### Port Mappings + +* [PublicPort] - 트래픽을 노출할 포트입니다. 가상 머신 컨테이너 외부에서 인스턴스에 접근하므로 필수 사항입니다. 보안을 위한 별도의 서비스를 구현하지 않고는 인터넷에 노출하지 마십시오. + + +##### Additional Settings + +* [DockerNet] - 컨테이너가 연결되어 생성되어야 하는 Docker 네트워크입니다. 해당 내용을 모르는 경우 [공식 Docker 문서](https://docs.docker.com/reference/cli/docker/network/)를 참조하세요. +* [version] - 이 GitHub 페이지의 오른쪽에서 "Packages"를 선택하면 "sillytavern" 패키지를 볼 수 있습니다. "latest" 이미지 태그는 현재 릴리스와 함께 최신 상태를 유지합니다. 각 브랜치의 야간 이미지를 가리키는 "staging" 및 "release" 태그를 사용할 수도 있지만, 업데이트에 시간이 걸릴 수 있고 중단될 수 있는 확장 프로그램을 사용하는 경우에는 적합하지 않을 수 있습니다. + + +#### 설치 명령어 + +1. 커맨드 라인 열기 +2. 아래의 명령어 실행 + +`docker create --name='sillytavern' --net='[DockerNet]' -p '8000:8000/tcp' -v '[plugins]':'/home/node/app/plugins':'rw' -v '[config]':'/home/node/app/config':'rw' -v '[data]':'/home/node/app/data':'rw' 'ghcr.io/sillytavern/sillytavern:[version]'` + +> 8000은 기본 리스닝 포트입니다. 구성에서 포트를 변경한 경우 적절한 포트를 사용하는 것을 잊지 마세요. +## 📱 Termux를 통해 Android OS에 설치하기 + +> \[!NOTE] +> **SillyTavern은 Termux를 사용하여 Android 기기에서 기본적으로 실행할 수 있지만, 이러한 사용 사례에 대한 공식적인 지원은 제공하지 않습니다.** +> +> **ArroganceComplex#2659의 가이드를 참조하세요:** +> +> * <https://rentry.org/STAI-Termux> + +**지원되지 않는 플랫폼: android arm LEtime-web.** 32비트 Android는 npm으로 설치할 수 없는 외부 종속성이 필요합니다. 다음 명령어를 사용하여 설치하세요: pkg install esbuild. 그런 다음 일반적인 설치 단계를 진행하세요. + + +## API 키 관리 + +SillyTavern은 API 키를 사용자 데이터 디렉터리의 `secrets.json` 파일에 저장합니다 (`/data/default-user/secrets.json`이 기본 경로입니다). + + + +기본적으로 API 키는 저장하고 페이지를 새로 고침한 후에는 인터페이스에서 보이지 않습니다. + +키 보기 기능을 활성화하려면 다음 단계를 따르세요: + +1. `config.yaml` 파일에서 `allowKeysExposure` 값을 `true로` 설정합니다. +2. SillyTavern 서버를 다시 시작합니다. +3. API 연결 패널 오른쪽 하단에 있는 '숨겨진 API 키 보기' 링크를 클릭합니다. + +## 커맨드 라인 인수 + +`config.yaml`의 일부 설정을 덮어쓰기 위해 SillyTavern 서버 시작 시 커맨드 라인 인수를 전달할 수 있습니다. + + +### 예시 + +```shell +node server.js --port 8000 --listen false +# 혹은 +npm run start -- --port 8000 --listen false +# 혹은 (Windows 전용) +Start.bat --port 8000 --listen false +``` + +### 지원되는 인수 + +| 옵션 | 설명 | 타입 | +|-------------------------|------------------------------------------------------------------------------------------------------|----------| +| `--version` | 버전 표시 | boolean | +| `--enableIPv6` | IPv6 활성화 | boolean | +| `--enableIPv4` | IPv4 활성화 | boolean | +| `--port` | SillyTavern이 실행될 포트를 설정합니다. 설정되지 않은 경우 yaml config 'port'를 불러옵니다. | number | +| `--dnsPreferIPv6` | DNS에 IPv6를 우선으로 할당합니다. 설정되지 않은 경우 yaml config를 불러옵니다. | boolean | +| `--autorun` | 브라우저에서 SillyTavern을 자동으로 실행합니다. 설정되지 않은 경우 yaml config 'autorun'를 불러옵니다. | boolean | +| `--autorunHostname` | 자동 실행 호스트 이름, 'auto'가 최적의 설정일 것입니다. | string | +| `--autorunPortOverride` | 자동 실행 포트 덮어쓰기 | string | +| `--listen` | SillyTavern이 모든 네트워크 인터페이스에서 수신 대기합니다. 설정되지 않은 경우 yaml 구성 'listen'을 불러옵니다. | boolean | +| `--corsProxy` | CORS 프록시 활성화. 설정되지 않은 경우 yaml 구성 'enableCorsProxy'을 불러옵니다. | boolean | +| `--disableCsrf` | CSRF 보호 비활성화 | boolean | +| `--ssl` | SSL 활성화 | boolean | +| `--certPath` | 인증서 파일 경로 | string | +| `--keyPath` | 프라이빗 키 파일 경로 | string | +| `--whitelist` | 화이트리스트 모드 활성화 | boolean | +| `--dataRoot` | 데이터 스토리지의 루트 디렉토리 | string | +| `--avoidLocalhost` | 자동 모드에서 자동 실행 시 'localhost' 사용 방지 | boolean | +| `--basicAuthMode` | 기본 인증 활성화 | boolean | +| `--requestProxyEnabled` | 외부 리퀘스트 프록시 활성화 | boolean | +| `--requestProxyUrl` | 프록시 URL 리퀘스트 (HTTP 혹은 SOCKS 프로토콜) | string | +| `--requestProxyBypass` | 프록시 바이패스 리스트 리퀘스트 (공백으로 구분된 호스트 목록) | array | + +## 원격 연결 + +대부분의 경우 이는 PC에서 ST 서버를 실행하는 동안 모바일 장치에서 SillyTavern을 사용하려는 사람들을 위한 것입니다. 그러나 원격 연결을 다른 곳에서도 허용하도록 사용할 수 있습니다. + +원격 연결 설정 방법에 대한 자세한 가이드는 [Docs](https://docs.sillytavern.app/usage/remoteconnections/)에서 확인할 수 있습니다. + +또한 암호 보호 기능이 포함된 SillyTavern 사용자 프로필을 구성할 수 있습니다 (선택 사항): [Users](https://docs.sillytavern.app/installation/st-1.12.0-migration-guide/#users). + +## 성능 이슈가 발생하나요? + +1. 사용자 설정 패널(UI 테마 전환 카테고리)에서 흐림 효과를 비활성화하고 동작 줄이기를 활성화합니다. +2. 응답 스트리밍을 사용하는 경우 스트리밍 FPS를 더 낮은 값(10-15 FPS 권장)으로 설정합니다. +3. 브라우저에서 렌더링에 GPU 가속을 사용하도록 설정되어 있는지 확인합니다. + +## 라이센스 및 크레딧 + +**이 프로그램은 유용할 것이라는 희망으로 배포되지만, 어떠한 보증도 제공하지 않습니다. 상품성 또는 특정 목적에의 적합성에 대한 묵시적인 보증조차도 제공하지 않습니다. 자세한 내용은 GNU Affero 일반 공중 사용 허가서를 참조하십시오.** + +* Humi의 [TavernAI](https://github.com/TavernAI/TavernAI) 1.2.8: MIT 라이선스 +* CncAnon의 TavernAITurbo 모드의 일부는 허가를 받아 사용됨 +* PepperTaco의 작업(<https://github.com/peppertaco/Tavern/>)에 영감을 받은 비주얼 노벨 모드 +* Noto Sans Font by Google (OFL 라이선스) +* Font Awesome의 아이콘 테마 <https://fontawesome.com> (아이콘: CC BY 4.0, 폰트: SIL OFL 1.1, 코드: MIT 라이선스) +* 기본 콘텐츠는 @OtisAlejandro (Seraphina 캐릭터 및 로어북)와 @kallmeflocc (10K 디스코드 사용자 축전 배경화면)가 제공함 +* [@mrguymiah](https://github.com/mrguymiah)와 [@Bronya-Rand](https://github.com/Bronya-Rand)의 Docker 가이드 + +## 상위 기여자 + +[![Contributors](https://contrib.rocks/image?repo=SillyTavern/SillyTavern)](https://github.com/SillyTavern/SillyTavern/graphs/contributors) + +<!-- LINK GROUP --> +[cover]: https://github.com/user-attachments/assets/01a6ae9a-16aa-45f2-8bff-32b5dc587e44 +[discord-link]: https://discord.gg/sillytavern +[discord-shield-badge]: https://img.shields.io/discord/1100685673633153084?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=for-the-badge diff --git a/jiuguan2025cc/.github/readme-ru_ru.md b/jiuguan2025cc/.github/readme-ru_ru.md new file mode 100644 index 0000000000000000000000000000000000000000..5a7ce8932310c5b6b714a01f92dcf61a440da61d --- /dev/null +++ b/jiuguan2025cc/.github/readme-ru_ru.md @@ -0,0 +1,450 @@ +> [!IMPORTANT] +> Приведенная здесь информация может быть устаревшей или неполной и предоставляется только для вашего удобства. Пожалуйста, используйте английскую версию для получения наиболее актуальной информации. + +<a name="readme-top"></a> + +![][cover] + +<div align="center"> + +[English](readme.md) | [German](readme-de_de.md) | [中文](readme-zh_cn.md) | [繁體中文](readme-zh_tw.md) | [日本語](readme-ja_jp.md) | Русский | [한국어](readme-ko_kr.md) + +[![GitHub Stars](https://img.shields.io/github/stars/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/stargazers) +[![GitHub Forks](https://img.shields.io/github/forks/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/network) +[![GitHub Issues](https://img.shields.io/github/issues/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/issues) +[![GitHub Pull Requests](https://img.shields.io/github/issues-pr/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/pulls) + +</div> + +--- + +Мобайл-френдли интерфейс, поддержка множества API (KoboldAI/CPP, Horde, NovelAI, Ooba, OpenAI, OpenRouter, Claude, Scale), ВН-образный режим Вайфу, Stable Diffusion, TTS, поддержка миров (лорбуков), кастомизируемый UI, автоперевод, тончайшая настройка промптов + возможность устанавливать расширения. + +Основано на форке [TavernAI](https://github.com/TavernAI/TavernAI) версии 1.2.8 + +## Важные новости! + +1. Чтобы помочь вам быстрее разобраться в SillyTavern, мы создали [сайт с документацией](https://docs.sillytavern.app/). Ответы на большинство вопросов можно найти там. + +2. Почему пропали расширения после апдейта? Начиная с версии 1.10.6, большинство встроенных расширений были конвертированы в формат загружаемых аддонов. Их можно установить обратно через меню "Download Extensions and Assets" на панели расширений (значок с тремя кубиками сверху). + +3. Не поддерживается следующая платформа: android arm LEtime-web. 32-битный Android требует внешнюю зависимость, которую нельзя установить посредством npm. Для её установки потребуется следующая команда: `pkg install esbuild`. После этого продолжайте установку по общей инструкции. + +### Разрабатывается Cohee, RossAscends и всем сообществом SillyTavern + +### Что такое SillyTavern и TavernAI? + +SillyTavern — это интерфейс, который устанавливается на ПК (и на Android), который даёт возможность общаться с генеративным ИИ и чатиться/ролеплеить с вашими собственными персонажами или персонажами других пользователей. + +SillyTavern — это форк версии TavernAI 1.2.8, который разрабатывается более активно и имеет множество новых функций. Сейчас уже можно сказать, что это две отдельные и абсолютно самостоятельные программы. + +## Скриншоты + +<img width="500" alt="image" src="https://github.com/user-attachments/assets/9b5f32f0-c3b3-4102-b3f5-0e9213c0f50f"> +<img width="500" alt="image" src="https://github.com/user-attachments/assets/913fdbaa-7d33-42f1-ae2c-89dca41c53d1"> + +### Ветки + +SillyTavern разрабатывается в двух ветках, чтобы всем категориям пользователей было удобно. + +* release -🌟 **Рекомендовано для большинства пользователей.** Самая стабильная ветка, рекомендуем именно её. Обновляется только в момент крупных релизов. Подходит для большей части пользователей. +* staging - ⚠️ **Не рекомендуется для повседневного использования.** В этой ветке весь самый свежий и новый функционал, но будьте аккуратны, поскольку сломаться может в любом месте и в любое время. Только для продвинутых пользователей и энтузиастов. + +Если вы не умеете обращаться с git через командную строку, или не знаете, что такое ветка, то не переживайте! Наилучшим вариантом всегда остаётся ветка release. + +### Что ещё нужно, кроме SillyTavern? + +Сама по себе SillyTavern бесполезна, ведь это просто интерфейс. Вам потребуется доступ к бэкенду с ИИ, который и будет отыгрывать выбранного вами персонажа. Поддерживаются разные виды бэкендов: OpenAPI API (GPT), KoboldAI (локально или на Google Colab), и многое другое. Больше информации в [FAQ](https://docs.sillytavern.app/usage/faq/). + +### Требуется ли для SillyTavern мощный ПК? + +SillyTavern — это просто интерфейс, поэтому запустить его можно на любой картошке. Мощным должен быть бэкенд с ИИ. + +## Есть вопросы или предложения? + +### У нас появился сервер в Discord + +| [![][discord-shield-badge]][discord-link] | [Вступайте в наше Discord-сообщество!](https://discord.gg/sillytavern) Задавайте вопросы, делитесь любимыми персонажами и промптами. | +| :---------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------- | + +Также можно написать разработчикам напрямую: + +* Discord: cohee или rossascends +* Reddit: [/u/RossAscends](https://www.reddit.com/user/RossAscends/) или [/u/sillylossy](https://www.reddit.com/user/sillylossy/) +* [Запостить issue на GitHub](https://github.com/SillyTavern/SillyTavern/issues) + +## Эта версия включает + +* Глубоко переработанную TavernAI 1.2.8 (переписано и оптимизировано более 50% кода) +* Свайпы +* Групповые чаты: комнаты для нескольких ботов, где персонажи могут говорить друг с другом и с вами +* Чекпоинты и ветки для чатов +* Продвинутые настройки для KoboldAI / TextGen со множеством созданных сообществом пресетов +* Поддержка миров (функция "Информация о мире" / WorldInfo): создавайте свой богатый лор, или экономьте токены для карточек персонажей +* Соединение через [OpenRouter](https://openrouter.ai) для разных API (Claude, GPT-4/3.5 и других) +* Соединение с API [Oobabooga's TextGen WebUI](https://github.com/oobabooga/text-generation-webui) +* Соединение с [AI Horde](https://aihorde.net/) +* Настройку форматирования промптов + +## Расширения + +SillyTavern поддерживает расширения. + +* Эмоции для персонажей (спрайты) +* Автоматический саммарайз (краткий пересказ) истории чата +* Возможность отправить в чат картинку, которую ИИ сможет рассмотреть и понять +* Генерация картинок в Stable Diffusion (5 пресетов для чата, плюс свободный режим) +* Text-to-speech для сообщений ИИ (с помощью ElevenLabs, Silero, или родной TTS вашей ОС) + +Полный список расширений и инструкций к ним можно найти в [документации](https://docs.sillytavern.app/). + +## Улучшения от RossAscends для UI/CSS/общего удобства + +* Мобильный интерфейс адаптирован для iOS, добавлена возможность сохранить ярлык на главный экран и открыть приложение в полноэкранном режиме. +* Горячие клавиши + * Up = Редактировать последнее сообщение в чате + * Ctrl+Up = Редактировать ВАШЕ последнее сообщение в чате + * Left = свайп влево + * Right = свайп вправо (ОБРАТИТЕ ВНИМАНИЕ: когда в окне ввода что-то напечатано, клавиши для свайпа не работают) + * Ctrl+Left = посмотреть локальные переменные (в консоли браузера) + * Enter (при нахождении внутри окна ввода) = отправить ваше сообщение ИИ + * Ctrl+Enter = Повторная генерация последнего ответа ИИ + +* Страница больше не перезагружается при смене имени пользователя или удалении персонажа + +* Отключаемая возможность автоматически соединяться с API при загрузке страницы. +* Отключаемая возможность автоматически загружать последнего открытого персонажа при загрузке страницы. +* Улучшенный счётчик токенов - работает с несохранёнными персонажами, отображает и перманентные, и временные токены + +* Улучшенный менеджер чатов + * Файлы с новыми чатами получают читабельные названия вида "(персонаж) - (когда создано)" + * Увеличен размер превью чата с 40 символов до 300. + * Несколько вариантов сортировки списка персонажей (по имени, дате создания, размеру чата). + +* Панели настроек слева и справа автоматически скрываются, если щёлкнуть за их пределы. +* При нажатии на значок замка навигационная панель будет закреплена на экране, и эта настройка сохранится между сессиями +* Сам статус панели (открыта или закрыта) также сохраняется между сессиями + +* Кастомизируемый интерфейс чата: + * Настройте звук при получении нового ответа + * Переключайтесь между круглыми и прямоугольными аватарками + * Увеличенное вширь окно чата для стационарных ПК + * Возможность включать полупрозрачные панели, стилизованные под стекло + * Настраиваемые цвета для обычного текста, курсива, цитат + * Настраиваемый цвет фона и интенсивность размытия + +# ⌛ Установка + +> **Внимание!** +> * НЕ УСТАНАВЛИВАЙТЕ В ПАПКИ, КОТОРЫЕ КОНТРОЛИРУЕТ WINDOWS (Program Files, System32 и т.п.). +> * НЕ ЗАПУСКАЙТЕ START.BAT С ПРАВАМИ АДМИНИСТРАТОРА +> * УСТАНОВКА НА WINDOWS 7 НЕВОЗМОЖНА ИЗ-ЗА ОТСУТСТВИЯ NODEJS 18.16 + +## 🪟 Windows + +## Установка через Git + 1. Установите [NodeJS](https://nodejs.org/en) (рекомендуется последняя LTS-версия) + 2. Установите [Git for Windows](https://gitforwindows.org/) + 3. Откройте Проводник (`Win+E`) + 4. Перейдите в папку, которую не контролирует Windows, или создайте её. (пример: C:\MySpecialFolder\) + 5. Откройте командную строку. Для этого нажмите на адресную строку (сверху), введите `cmd` и нажмите Enter. + 6. Когда появится чёрное окошко (командная строка), введите ОДНУ из перечисленных ниже команд: + +- для ветки release: `git clone https://github.com/SillyTavern/SillyTavern -b release` +- для ветки staging: `git clone https://github.com/SillyTavern/SillyTavern -b staging` + + 7. Когда клонирование закончится, дважды щёлкните по `Start.bat`, чтобы установить зависимости для NodeJS. + 8. После этого сервер запустится, и SillyTavern откроется в вашем браузере. + +## Установка с помощью SillyTavern Launcher + 1. Установите [Git for Windows](https://gitforwindows.org/) + 2. Откройте Проводник (`Win+E`) и создайте или выберите папку, в которую будет установлен лаунчер + 3. Откройте командную строку. Для этого нажмите на адресную строку (сверху), введите `cmd` и нажмите Enter. + 4. Когда появится чёрное окошко, введите следующую команду: `git clone https://github.com/SillyTavern/SillyTavern-Launcher.git` + 5. Дважды щёлкните по `installer.bat` и выберите, что именно хотите установить + 6. После завершения установки дважды щёлкните по `launcher.bat` + +## Установка с помощью GitHub Desktop +(Тут речь про git **только** в рамках GitHub Desktop, если хотите использовать `git` в командной строке, вам также понадобится [Git for Windows](https://gitforwindows.org/)) + 1. Установите [NodeJS](https://nodejs.org/en) (latest LTS version is recommended) + 2. Установите [GitHub Desktop](https://central.github.com/deployments/desktop/desktop/latest/win32) + 3. После завершения установки GitHub Desktop, нажмите `Clone a repository from the internet....` (обратите внимание: для этого шага **НЕ требуется** аккаунт на GitHub) + 4. В меню перейдите на вкладку URL, введите адрес `https://github.com/SillyTavern/SillyTavern`, и нажмите Clone. В поле Local path можно изменить директорию, в которую будет загружена SillyTavern. + 6. Чтобы запустить SillyTavern, откройте Проводник и перейдите в выбранную на предыдущем шаге папку. По умолчанию репозиторий будет склонирован сюда: `C:\Users\[Имя пользователя]\Documents\GitHub\SillyTavern` + 7. Дважды щёлкните по файлу `start.bat`. (обратите внимание: окончание `.bat` может быть скрыто настройками вашей ОС. Таким образом, имя файла будет выглядеть как "`Start`". Дважды щёлкните по нему, чтобы запустить SillyTavern) + 8. После того, как вы дважды щёлкнули по файлу, должно открыться чёрное окошко, и SillyTavern начнёт устанавливать свои зависимости. + 9. Если установка прошла успешно, то в командной строке будет вот такое, а в браузере откроется вкладка с SillyTavern: + 10. Подключайтесь к любому из [поддерживаемых API](https://docs.sillytavern.app/usage/api-connections/) и начинайте переписку! + +## 🐧 Linux и 🍎 MacOS + +В MacOS и Linux всё это делается через Терминал. + +1. Установите git и nodeJS (как именно - зависит от вашей ОС) +2. Клонируйте репозиторий + +- для ветки release: `git clone https://github.com/SillyTavern/SillyTavern -b release` +- для ветки staging: `git clone https://github.com/SillyTavern/SillyTavern -b staging` + +3. Перейдите в папку установки с помощью `cd SillyTavern`. +4. Запустите скрипт `start.sh` с помощью одной из команд: + +- `./start.sh` +- `bash start.sh` + +## Установка с помощью SillyTavern Launcher + +### Для пользователей Linux +1. Откройте любимый терминал и установите git +2. Загрузите Sillytavern Launcher с помощью команды: `git clone https://github.com/SillyTavern/SillyTavern-Launcher.git` +3. Перейдите в SillyTavern-Launcher: `cd SillyTavern-Launcher` +4. Запустите лаунчер установки: `chmod +x install.sh && ./install.sh`, затем выберите, что конкретно хотите установить +5. После завершения установки, запустите лаунчер следующей командой: `chmod +x launcher.sh && ./launcher.sh` + +### Для пользователей Mac +1. Откройте терминал и установите brew: `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"` +2. Затем установите git: `brew install git` +3. Загрузите Sillytavern Launcher: `git clone https://github.com/SillyTavern/SillyTavern-Launcher.git` +4. Перейдите в SillyTavern-Launcher: `cd SillyTavern-Launcher` +5. Запустите лаунчер установки: `chmod +x install.sh && ./install.sh` and choose what you wanna install +6. После завершения установки, запустите лаунчер следующей командой: `chmod +x launcher.sh && ./launcher.sh` + +## 🐋 Установка с помощью Docker + +Предполагается, что вы уже установили Docker, имеете доступ к командной строке для установки контейнеров и знакомы с их базовым управлением. + +### Сборка образа самостоятельно + +У нас есть подробное руководство по использованию SillyTavern в Docker [здесь](http://docs.sillytavern.app/installation/docker/), которое охватывает установку на Windows, macOS и Linux! Ознакомьтесь с ним, если хотите создать образ самостоятельно. + +### Использование реестра контейнеров GitHub (самый простой способ) + +Для работы SillyTavern вам понадобятся две обязательные настройки каталогов и одна настройка порта. В команде замените указанные значения на свои: + +#### Переменные контейнера + +##### Маппинг томов + +* [config] - директория, где на вашем хосте будут храниться файлы конфигурации SillyTavern. +* [data] - директория, где на вашем хосте будут храниться пользовательские данные SillyTavern (включая персонажей). +* [plugins] - (необязательно) директория, где на вашем хосте будут храниться плагины сервера SillyTavern. + +##### Маппинг портов + +* [PublicPort] - Порт, через который будет передаваться трафик. Это обязательно, так как вы будете обращаться к контейнеру извне его виртуальной машины. НЕ ОТКРЫВАЙТЕ этот порт в интернет без реализации дополнительного уровня безопасности. + +##### Дополнительные настройки + +* [DockerNet] - Docker сеть, к которой контейнер должен быть подключен. Если вы не знаете, что это, обратитесь к [официальной документации Docker](https://docs.docker.com/reference/cli/docker/network/). +* [version] - на правой части этой страницы GitHub вы найдете раздел "Packages". Выберите пакет "sillytavern", чтобы увидеть версии образов. Тег "latest" позволит вам обновляться до текущего релиза. Также доступны теги "staging" и "release", которые соответствуют ночным сборкам соответствующих веток. Однако это может быть нецелесообразно, если вы используете расширения, которые могут ломаться и требуют времени для обновления. + +#### Команда установки + +1. Откройте командную строку +2. Выполните следующую команду + +`docker create --name='sillytavern' --net='[DockerNet]' -p '8000:8000/tcp' -v '[plugins]':'/home/node/app/plugins':'rw' -v '[config]':'/home/node/app/config':'rw' -v '[data]':'/home/node/app/data':'rw' 'ghcr.io/sillytavern/sillytavern:[version]'` + +> Заметьте, что 8000 является портом по умолчанию. Не забудьте использовать соответствующий порт, если вы измените его в конфиге. + +## 📱 Мобильные устройства - Установка при помощи termux + +> **ОБРАТИТЕ ВНИМАНИЕ!** +> +> **На Android-телефонах SillyTavern можно запускать нативно посредством Termux. Обратитесь к гайду, написанному ArroganceComplex#2659:** +> +> * <https://rentry.org/STAI-Termux> + + +## Управление ключами от API + +SillyTavern сохраняет ключи от ваших API в файле `secrets.json` в папке на сервере. + +По умолчанию, ключи не будут отображаться на фронте после их ввода и перезагрузки страницы. + +Чтобы включить возможность отображения ключей путём нажатия кнопки в блоке API: + +1. Зайдите в файл `config.yaml` и установите `allowKeysExposure` в положение `true`. +2. Перезапустите сервер SillyTavern. + +## Аргументы командной строки + +Вы можете передавать аргументы командной строки при запуске сервера SillyTavern, чтобы переопределять настройки из `config.yaml`. + +### Примеры + +```shell +node server.js --port 8000 --listen false +# или +npm run start -- --port 8000 --listen false +# или (только на Windows) +Start.bat --port 8000 --listen false +``` + +### Поддерживаемые аргументы + +| Аргумент | Описание | Тип | +|-------------------------|----------------------------------------------------------------------------------------------------------------|----------| +| `--version` | Показывает номер версии. | boolean | +| `--enableIPv6` | Включает IPv6. | boolean | +| `--enableIPv4` | Включает IPv4. | boolean | +| `--port` | Устанавливает порт, котрый будет использовать SillyTavern. Если не указан, то используется yaml-конфиг 'port'. | number | +| `--dnsPreferIPv6` | Отдает предпочтение IPv6 для dns. Если не указан, то используется yaml-конфиг 'preferIPv6'. | boolean | +| `--autorun` | Автоматический запуск SillyTavern в браузере. Если не указан, то используется yaml-конфиг 'autorun'. | boolean | +| `--autorunHostname` | Имя хоста автозапуска, лучше оставить на 'auto'. | string | +| `--autorunPortOverride` | Переопределяет порт для автозапуска. | string | +| `--listen` | SillyTavern будет прослушивать все сетевые интерфейсы. Если не указан, то используется yaml-конфиг 'listen'. | boolean | +| `--corsProxy` | Включает CORS-прокси. Если не указан, то используется yaml-конфиг 'enableCorsProxy'. | boolean | +| `--disableCsrf` | Отключает защиту от CSRF. | boolean | +| `--ssl` | Включает SSL. | boolean | +| `--certPath` | Путь к файлу c сертификатом. | string | +| `--keyPath` | Путь к файлу с закрытым ключом. | string | +| `--whitelist` | Включает режим белого списка. | boolean | +| `--dataRoot` | Корневой каталог для хранения данных. | string | +| `--avoidLocalhost` | Избегает использования 'localhost' для автозапуска в режиме 'auto'. | boolean | +| `--basicAuthMode` | Включает простую аутентификацию. | boolean | +| `--requestProxyEnabled` | Разрешает использование прокси для исходящих запросов. | boolean | +| `--requestProxyUrl` | URL-адрес прокси (протоколы HTTP или SOCKS). | string | +| `--requestProxyBypass` | Bypass список прокси (список хостов, разделенных пробелами). | array | + +## Удалённое подключение + +В основном этим пользуются тогда, когда хотят использовать SillyTavern с телефона, запустив сервер SillyTavern на стационарном ПК в той же Wi-Fi-сети. + +Однако это позволит подключаться откуда угодно, а не только вам. + +**ВАЖНО: в SillyTavern не предусмотрена возможность использования программы несколькими людьми. Поэтому любой, кто подключится к вашему серверу, получит доступ ко всем вашим персонажам и чатам, а также сможет менять настройки через UI.** + +### 1. Заведение "белого списка" IP-адресов + +* Создайте в корневой папке SillyTavern файл с названием `whitelist.txt`. +* Откройте файл в текстовом редакторе и внесите список IP-адресов, с которых хотите разрешить подключение. + +*Принимаются как обычные IP-адреса, так и целые диапазоны, размеченные с помощью астериска. Примеры:* + +```txt +192.168.0.1 +192.168.0.20 +``` + +или + +```txt +192.168.0.* +``` + +(диапазон из примера сверху позволит подключаться всем устройствам в локальной сети) + +Также принимаются маски CIDR (вида 10.0.0.0/24). + +* Сохраните файл `whitelist.txt`. +* Перезапустите сервер ST. + +После этого устройства из белого списка смогут подключаться к вашему серверу. + +*Обратите внимание: в файле `config.yaml` также имеется массив `whitelist`, который работает по тому же принципу. Однако если существует файл `whitelist.txt`, то этот массив игнорируется.* + +### 2. Получение IP хост-машины с ST + +После настройки белого списка адресов, следующим шагом будет получение IP-адреса хост-машины, на которой запущена SillyTavern. + +Если хост-машина находится в той же Wi-Fi-сети, то можно воспользоваться её внутренним Wi-Fi-IP-адресом: + +* На Windows: нажмите Пуск > введите `cmd.exe` в поиске > в консоли введите команду `ipconfig` и нажмите Enter > найдите пункт `IPv4-адрес`. + +Если вы (или кто-то другой) хотите подключаться к хост-машине из другой сети, то вам понадобится ваш публичный IP-адрес. + +* Откройте [эту страницу](https://whatismyipaddress.com/) с вашей хост-машины и найдите пункт `IPv4`. На этот адрес и будет подключаться удалённое устройство. + +### 3. Соединить удалённое устройство с хост-машиной ST + +Какой бы IP-адрес вы ни выбрали, вам нужно будет вводить его в адресной строке браузера вашего удалённого устройства. + +Обычный адрес хост-машины, находящейся в той же Wi-Fi-сети, выглядит примерно так: + +`http://192.168.0.5:8000` + +НЕ используйте https:// +Только http:// + +### Открытие доступа до ST для всех IP-адресов + +Мы не рекомендуем так делать, но вы можете открыть файл `config.yaml` и изменить `whitelistMode` на `false`. + +Обязательно нужно удалить (или переименовать) файл `whitelist.txt`, если такой файл есть в корневой директории SillyTavern. + +Эта практика считается небезопасной, поэтому, если вы решите так сделать, мы попросим вас установить логин и пароль. + +Оба этих параметра настраиваются в `config.yaml` (username и password). + +Останется только перезапустить сервер ST, и после этого к вам сможет подключиться любой пользователь вне зависимости от IP-адреса его устройства. Главное, чтобы он знал логин и пароль. + +### Не получается соединиться? + +* Создайте входящее/исходящее правило в вашем фаерволле для порта, указанного в `config.yaml`. НЕ ПУТАЙТЕ этот процесс с пробросом портов на роутере. Если по ошибке перепутаете, то на ваш сервер сможет забраться посторонний человек и украсть ваши логи, этого следует избегать. +* Переключите Сетевой профиль на значение "Частные". Для этого зайдите в Параметры > Сеть и Интернет > Ethernet. КРАЙНЕ важно для Windows 11, без этого не получится подключиться даже с правилом фаервола. + +## Проблемы с производительностью? + +Попробуйте включить опцию "Отключить эффект размытия" в меню "Пользовательские настройки". + +## Нравится ваш проект! Как помочь? + +### ЧТО ДЕЛАТЬ + +1. Присылайте пулл реквесты +2. Присылайте идеи и баг-репорты, оформленные по установленным шаблонам +3. Прежде чем задавать вопросы, прочтите readme и документацию + +### ЧЕГО НЕ ДЕЛАТЬ + +1. Предлагать донаты +2. Присылать баг-репорты безо всякого контекста +3. Задавать вопросы, на которые уже отвечали + +## Где найти старые фоны? + +Мы двигаемся в сторону 100% уникальности всего используемого контента, поэтому старые фоны были убраны из репозитория. + +Они отправлены в архив, скачать их можно здесь: + +<https://files.catbox.moe/1xevnc.zip> + + + + +## Авторы и лицензии + +**Мы надеемся, что эта программа принесёт людям пользу, +но мы не даём НИКАКИХ ГАРАНТИЙ; мы ни в коем случае не гарантируем того, +что программа СООТВЕТСТВУЕТ КАКИМ-ЛИБО КРИТЕРИЯМ или ПРИГОДНА ДЛЯ КАКОЙ-ЛИБО ЦЕЛИ. +Подробнее можно узнать в GNU Affero General Public License.** + +* Базовая TAI от Humi: Лицензия неизвестна +* Модификации от Cohee и производная кодовая база: AGPL v3 +* Дополнения RossAscends: AGPL v3 +* Кусочки TavernAITurbo мода от CncAnon: Лицензия неизвестна +* Различные коммиты и предложения от kingbri (<https://github.com/bdashore3>) +* Расширения и внедрение разного рода удобств - city_unit (<https://github.com/city-unit>) +* Различные коммиты и баг-репорты от StefanDanielSchwarz (<https://github.com/StefanDanielSchwarz>) +* Режим Вайфу вдохновлён работой PepperTaco (<https://github.com/peppertaco/Tavern/>) +* Благодарность Pygmalion University за прекрасную работу по тестированию и за все предлагаемые крутые фичи! +* Благодарность oobabooga за компиляцию пресетов для TextGen +* Пресеты для KoboldAI из KAI Lite: <https://lite.koboldai.net/> +* Шрифт Noto Sans от Google (OFL license) +* Тема Font Awesome <https://fontawesome.com> (Иконки: CC BY 4.0, Шрифты: SIL OFL 1.1, Код: MIT License) +* Клиентская библиотека для AI Horde от ZeldaFan0225: <https://github.com/ZeldaFan0225/ai_horde> +* Пусковой скрипт для Linux от AlpinDale +* Благодарность paniphons за оформление документа с FAQ +* Фон в честь 10 тысяч пользователей в Discord от @kallmeflocc +* Стандартный контент (персонажи и лорбуки) предоставлен пользователями @OtisAlejandro, @RossAscends и @kallmeflocc +* Корейский перевод от @doloroushyeonse +* Поддержка k_euler_a для Horde от <https://github.com/Teashrock> +* Китайский перевод от [@XXpE3](https://github.com/XXpE3), 中文 ISSUES 可以联系 @XXpE3 + +<!-- LINK GROUP --> +[back-to-top]: https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square +[cover]: https://github.com/user-attachments/assets/01a6ae9a-16aa-45f2-8bff-32b5dc587e44 +[discord-link]: https://discord.gg/sillytavern +[discord-shield]: https://img.shields.io/discord/1100685673633153084?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square +[discord-shield-badge]: https://img.shields.io/discord/1100685673633153084?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=for-the-badge diff --git a/jiuguan2025cc/.github/readme-zh_cn.md b/jiuguan2025cc/.github/readme-zh_cn.md new file mode 100644 index 0000000000000000000000000000000000000000..6c7321eaf9f2b62f717e3f6d654a017698349f30 --- /dev/null +++ b/jiuguan2025cc/.github/readme-zh_cn.md @@ -0,0 +1,322 @@ +> [!IMPORTANT] +> 这里的信息可能已经过时或不完整,仅供您参考。请使用英文版本获取最新信息。 + +![][cover] + +<div align="center"> + +[English](readme.md) | [German](readme-de_de.md) | 中文 | [繁體中文](readme-zh_tw.md) | [日本語](readme-ja_jp.md) | [Русский](readme-ru_ru.md) | [한국어](readme-ko_kr.md) + +[![GitHub Stars](https://img.shields.io/github/stars/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/stargazers) +[![GitHub Forks](https://img.shields.io/github/forks/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/network) +[![GitHub Issues](https://img.shields.io/github/issues/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/issues) +[![GitHub Pull Requests](https://img.shields.io/github/issues-pr/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/pulls) + +</div> + +--- + +移动设备界面友好,多种人工智能服务或模型支持(KoboldAI/CPP, Horde, NovelAI, Ooba, OpenAI, OpenRouter, Claude, Scale),类似 Galgame 的 老 婆 模 式,Horde SD,文本系统语音生成,世界信息(Lorebooks),可定制的界面,自动翻译,和比你所需要的更多的 Prompt。附带扩展服务,支持文本绘画生成与语音生成和基于向量数据库 的聊天信息总结。 + +基于 TavernAI 1.2.8 的分叉版本 + +### 由 Cohee、RossAscends 和 SillyTavern 社区为您呈现 + +注意:我们创建了一个 [帮助文档](https://docs.sillytavern.app/) 网站来回答各类问题与帮助您开始使用。 + +### SillyTavern 或 TavernAI 是什么? + +SillyTavern 是一个可以安装在电脑(和安卓手机)上的用户界面,让您可以与文本生成的人工智能互动,并与您或社区创建的角色聊天/玩角色扮演游戏。 + +SillyTavern 是 TavernAI 1.2.8 的一个分支,正在进行更积极地开发,并添加了许多重要功能。在这一点上,它可以被视为完全独立的程序。 + +### 分支 + +SillyTavern 采用双分支进行开发,以确保所有用户都能获得流畅的使用体验。 + +* release -🌟 **推荐给大多数用户。** 这是最稳定、最推荐的分支,只有在重大版本推送时才会更新。适合大多数用户使用。 +* staging - ⚠️ **不建议随意使用。** 该分支拥有最新功能,但要谨慎,因为它随时可能崩溃。仅适用于高级用户和爱好者。 + +如果你不熟悉使用 Git 命令,或者不了解什么是分支,别担心!release 分支始终是您的首选。 + +### 除了 SillyTavern,我还需要什么? + +SillyTavern 本身并无用处,因为它只是一个用户聊天界面。你必须接入一个能充当角色扮演的人工智能系统。支持的人工智能系统有多种:OpenAPI API (GPT)、KoboldAI(可在本地或 Google Colab 上运行)等。您可以在 [常见问题](https://docs.sillytavern.app/usage/faq/) 中阅读更多相关信息。 + +### 我需要一台性能强大的电脑来运行 SillyTavern 吗? + +由于 SillyTavern 只是一个用户聊天界面,它对硬件性能的要求很低,可以在任何电脑上运行。需要强大性能的是人工智能系统。 + +### 移动设备支持 + +> 注意 + +> **此分叉可使用 Termux 在安卓手机上原生运行。请参考 ArroganceComplex#2659 编写的指南:** + +<https://rentry.org/STAI-Termux> + +## 有问题或建议? + +### 我们现在有了 Discord 社区 + +获取支持,或分享喜爱的角色和 Prompt: + +### [加入 Discord 社区](https://discord.gg/sillytavern) + +*** + +直接与开发人员联系: + +* Discord: cohee 或 rossascends +* Reddit:/u/RossAscends 或 /u/sillylossy +* [发布 GitHub 问题](https://github.com/SillyTavern/SillyTavern/issues) + +## 此版本包括 + +* 经过大量修改的 TavernAI 1.2.8(超过 50% 的代码经过重写或优化) +* 根据自定义规则自动重新生成消息 +* 群聊:多机器人房间,供角色与你或彼此交谈 +* 聊天书签/分支(复制当前状态下的对话) +* 先进的 KoboldAI / TextGen 生成设置,包含大量社区预设 +* 支持世界信息(Lorebooks):创建丰富的传说 +* 支持 Window AI 浏览器扩展(运行 Claude、GPT 4 等模型):<https://windowai.io/> +* [Oobabooga's TextGen WebUI](https://github.com/oobabooga/text-generation-webui) API 连接 +* 连接 [AI Horde](https://aihorde.net/) +* Prompt 生成格式调整 +* Webp 角色卡支持(PNG 仍是内部格式) + +## 扩展 + +SillyTavern 支持扩展服务。 + +* 角色情绪识别 +* 聊天记录自动摘要 +* 在聊天窗口发送图片,并由人工智能解释图片内容 +* 文本图像生成(5 预设,以及 "自由模式") +* 聊天信息的文字转语音(通过 ElevenLabs、Silero 或操作系统的语音生成) + +扩展服务的完整功能介绍和使用教程,请参阅 [Docs](https://docs.sillytavern.app/)。 + +## 界面/CSS/性能,由 RossAscends 调整并优化 + +* 针对 iOS 系统优化了界面,并支持将快捷方式保存到主屏幕,在全屏模式下打开。 +* 热键 + * 上 = 编辑聊天中的最后一条信息 + * Ctrl+P = 编辑聊天中最后一条用户信息 + * 左 = 向左滑动 + * 右 = 向右滑动(注意:当聊天窗口输入内容时,轻扫快捷键将被禁用) + * Ctrl+左 = 查看本地存储的变量(在浏览器控制台窗口中) + * 回车(选择聊天栏)= 向人工智能发送信息 + * Ctrl+Enter = 重新生成人工智能最后的回复 + +* 用户名更改和角色删除不再强制重新刷新页面。 + +* 增加在页面加载时自动连接 API 的选项。 +* 增加选项,在页面加载时自动加载最近的聊天信息。 +* 更好的 Tokens 计算器 - 适用于未保存的文字,并显示永久和临时 Tokens 数量 + +* 更好的聊天历史查询窗口 + * 聊天的文件名以"(角色卡名称)+(创建时间)"的可读格式保存 + * 聊天历史预览从 40 个字符增加到 300 个字符。 + * 聊天历史排序有多种选择(按名称、创建日期、聊天记录大小)。 + +* 默认情况下,左侧和右侧弹出的设置面板会在点击其他区域时自动关闭。 +* 点击导航面板上的 "锁按钮" 将保持弹出面板打开,并在不同聊天中记住此设置。 +* 导航面板的打开或关闭状态也会跨聊天保存。 + +* 自定义聊天界面: + * 收到新消息时播放提示音 + * 切换圆形或长方形头像样式 + * 在台式电脑上拥有更宽的聊天窗口 + * 可选的半透明玻璃效果聊天窗口 + * 可定制 "主文本"、"引用文本 "和 "斜体文本 "的字体颜色。 + * 可定制聊天界面的背景颜色和透明模糊程度 + +## 安装 + +*注意:SillyTavern 用于本地安装,尚未在 Colab 或其他云服务上进行全面测试。 + +> **警告** + +> 切勿安装到任何受 Windows 控制的系统文件夹(Program Files, System32, etc)中。 + +> 不要以管理员权限运行 start.bat + +### Windows + +通过 Git 安装(推荐使用,便于更新) + +附有精美图片示例的简易指南: +<https://docs.sillytavern.app/installation/windows/> + + 1. 安装 [NodeJS](https://nodejs.org/en)(建议使用最新的 LTS 版本) + 2. 安装 [GitHub 客户端](https://central.github.com/deployments/desktop/desktop/latest/win32) + 3. 打开 Windows 资源管理器 (`Win+E`) + 4. 浏览或创建一个不受 Windows 控制或监控的文件夹。(例如:C:\MySpecialFolder\) + 5. 点击顶部的 "地址栏",在该文件夹内打开命令提示符,输入 `cmd`,然后按回车。 + 6. 弹出黑框(CMD 命令提示符)后,键入以下其中一项并按 Enter: + +* 稳定分支:`git clone https://github.com/SillyTavern/SillyTavern -b release` +* 开发分支: `git clone https://github.com/SillyTavern/SillyTavern -b staging` + + 7. 等待 Git 克隆完成后,双击文件夹中的 `Start.bat` 将启动 NodeJS 并开始自动安装需要的软件包。 + 8. 然后 SillyTavern 服务就会自动启动,同时在浏览器新标签页中自动打开。 + +通过压缩包下载安装(不推荐) + + 1. 安装 [NodeJS](https://nodejs.org/en)(建议使用最新的 LTS 版本) + 2. 从该 GitHub 仓库下载压缩包。(从 [Releases](https://github.com/SillyTavern/SillyTavern/releases/latest) 获取 "Source code(zip)")。 + 3. 将压缩包解压到您选择的文件夹中 + 4. 双击或在命令行中运行 `Start.bat`。 + 5. SillyTavern 服务自动为你准备好一切后,会在你的浏览器中打开一个新标签页。 + +### Linux + + 1.运行 `start.sh` 脚本。 + 2.等待自动完成,然后开始享受 + +## API 密钥管理 + +SillyTavern 会将 API 密钥保存在目录中的 `secrets.json` 文件内。 + +默认情况下,输入密钥并重新加载页面后,密钥会自动隐藏以保证安全。 + +如果要想通过点击 API 输入框旁边的按钮来查看密钥,请按照以下设置: + +1. 打开 `config.yaml` 文件,将里面的 `allowKeysExposure` 设置为 `true`。 +2. 然后重启 SillyTavern 服务。 + +## 远程访问 + +这通常是为那些想在手机上使用 SillyTavern 的人准备的,而他们的电脑和手机在同一个局域网中。 + +不过,SillyTavern 也可以被设置为允许从任何地方进行远程访问。 + +**重要提示:SillyTavern 是单用户程序,因此任何人登录后都能看到所有的角色卡和聊天内容,并能更改任何设置。 + +### 1.管理白名单 IP + +* 在你的 SillyTavern 文件夹中新建一个文本文件,名为 `whitelist.txt`。 +* 用文本编辑器打开该文件,添加你希望允许连接的 IP 地址列表。 +* 接受单个 IP 地址和 IP 范围,示例: + +``` +192.168.0.1 +192.168.0.20 +``` + +或者 + +``` +192.168.0.* +``` + +(上述 IP 范围将允许局域网中的任何设备连接) + +也接受子网掩码设置(如 10.0.0.0/24)。 + +* 保存`whitelist.txt`文件。 +* 重启 SillyTavern 服务。 + +然后,文件中设置的 IP 就可以访问 SillyTavern 了。 + +*注意:"config.yaml" 文件内也有一个 "whitelist" 设置,你可以用同样的方法设置它,但如果 "whitelist.txt" 文件存在,这个设置将被忽略。 + +### 2.获取 SillyTavern 服务的 IP 地址 + +白名单设置完成后,您需要 SillyTavern 服务的 IP 地址。 + +如果 SillyTavern 服务设备在同一个局域网上,则使用安装 SillyTavern 服务的电脑的局域网 IP 地址: + +* Windows:Windows 按钮 > 在搜索栏中输入 `cmd.exe` > 在打开的控制台中输入 `ipconfig`,回车 > 然后在输出中查找 `IPv4` 地址。 + +如果您(或其他人)想在互联网中访问你自己的 SillyTavern 服务,则需要运行 SillyTavern 服务的设备的互联网 IP 地址。 + +* 使用运行 SillyTavern 的设备,访问 [this page](https://whatismyipaddress.com/) 并查找 `IPv4`。这是您从互联网访问时要用到的。 + +### 3. 使用其他设备访问 SillyTavern 服务 + +无论你最终使用的是什么 IP 地址,都要将该 IP 地址和端口号输入其他设备网络浏览器。 + +同一局域网中的 SillyTavern 服务的典型默认地址如下: + +`http://192.168.0.5:8000` + +使用 http:// 而不是 https:// + +### 向所有 IP 开放您的 SillyTavern 服务 + +我们不建议这样做,但您可以打开 `config.yaml` 并将里面的 `whitelistMode` 设置改为 `false`。 + +你必须删除(或重命名)SillyTavern 文件夹中的 `whitelist.txt` 文件(如果有的话)。 + +这通常是不安全的做法,所以我们要求在这样做时必须设置用户名和密码。 + +用户名和密码在`config.yaml`文件中设置。 + +重启 SillyTavern 服务后,只要知道用户名和密码,任何设备都可以访问。 + +### 还是无法访问? + +* 为 `config.yaml` 文件中的端口创建一条入站/出站防火墙规则。切勿将此误认为是路由器上的端口转发,否则,有人可能会发现你的聊天隐私,那就大错特错了。 +* 在 "设置" > "网络和 Internet" > "以太网" 中启用 "专用网络" 配置。这对 Windows 11 非常重要,否则即使添加了上述防火墙规则也无法连接。 + +### 性能问题? + +尝试在用户设置面板上关闭模糊效果(快速用户界面)模式。 + +## 我喜欢你的项目!我该如何贡献自己的力量? + +### 应该 + +1. 发送 Fork 请求 +2. 使用规定的模板发送功能建议和问题报告 +3. 在提出任何问题之前,请先阅读 Readme 文件和文档 + +#### 不应该 + +1. 提供金钱捐赠 +2. 发送错误报告而不提供任何详细信息 +3. 提出已经回答过无数次的问题 + +## 我在哪里可以找到以前的聊天背景图片? + +我们正在实行 100% 原创内容的政策,因此旧的背景图片已从该资源库中删除。 + +不过你可以在这里找到它们的存档: + +<https://files.catbox.moe/1xevnc.zip> + +## 屏幕截图 + +<img width="500" alt="image" src="https://github.com/user-attachments/assets/9b5f32f0-c3b3-4102-b3f5-0e9213c0f50f"> +<img width="500" alt="image" src="https://github.com/user-attachments/assets/913fdbaa-7d33-42f1-ae2c-89dca41c53d1"> + +## 许可证和贡献 + +**发布本程序是希望它能有所帮助,但不做任何保证;甚至没有明示的性能、稳定性和其他任何特定用途的可用性保证。更多详情,请参阅 GNU Affero 通用公共许可证。** + +**This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.** + +* TAI Base by Humi: Unknown license +* Cohee's modifications and derived code: AGPL v3 +* RossAscends' additions: AGPL v3 +* Portions of CncAnon's TavernAITurbo mod: Unknown license +* kingbri's various commits and suggestions (<https://github.com/bdashore3>) +* StefanDanielSchwarz's various commits and bug reports (<https://github.com/StefanDanielSchwarz>) +* Waifu mode inspired by the work of PepperTaco (<https://github.com/peppertaco/Tavern/>) +* Thanks Pygmalion University for being awesome testers and suggesting cool features! +* Thanks oobabooga for compiling presets for TextGen +* KoboldAI Presets from KAI Lite: <https://lite.koboldai.net/> +* Noto Sans font by Google (OFL license) +* Icon theme by Font Awesome <https://fontawesome.com> (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) +* AI Horde client library by ZeldaFan0225: <https://github.com/ZeldaFan0225/ai_horde> +* Linux startup script by AlpinDale +* Thanks paniphons for providing a FAQ document +* 10K Discord Users Celebratory Background by @kallmeflocc +* Default content (characters and lore books) provided by @OtisAlejandro, @RossAscends and @kallmeflocc +* Korean translation by @doloroushyeonse +* 中文翻译由 [@XXpE3](https://github.com/XXpE3) 完成,中文 ISSUES 可以联系 @XXpE3 + +<!-- LINK GROUP --> +[cover]: https://github.com/user-attachments/assets/01a6ae9a-16aa-45f2-8bff-32b5dc587e44 diff --git a/jiuguan2025cc/.github/readme-zh_tw.md b/jiuguan2025cc/.github/readme-zh_tw.md new file mode 100644 index 0000000000000000000000000000000000000000..1a4653d6edaa9fe64a17d4a88a0b5079528a985b --- /dev/null +++ b/jiuguan2025cc/.github/readme-zh_tw.md @@ -0,0 +1,381 @@ +> [!IMPORTANT] +> 此處資訊可能已經過時或不完整,僅供您參考。請使用英文版本以取得最新資訊。 + +<a name="readme-top"></a> + +![][cover] + +<div align="center"> + +[English](readme.md) | [German](readme-de_de.md) | [中文](readme-zh_cn.md) | 繁體中文 | [日本語](readme-ja_jp.md) | [Русский](readme-ru_ru.md) | [한국어](readme-ko_kr.md) + +[![GitHub 星標](https://img.shields.io/github/stars/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/stargazers) +[![GitHub 分支](https://img.shields.io/github/forks/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/network) +[![GitHub 問題](https://img.shields.io/github/issues/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/issues) +[![GitHub 拉取請求](https://img.shields.io/github/issues-pr/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/pulls) + +</div> + +--- + +SillyTavern 提供一個統一的前端介面,整合多種大型語言模型的 API(包括:KoboldAI/CPP、Horde、NovelAI、Ooba、Tabby、OpenAI、OpenRouter、Claude、Mistral 等)。同時具備對行動裝置友善的佈局、視覺小說模式(Visual Novel Mode)、Automatic1111 與 ComfyUI 的影像生成 API 整合、TTS(語音合成)、世界資訊(Lorebook)、可自訂 UI、自動翻譯功能,以及強大的提示詞(prompt)設定選項和無限的第三方擴充潛力。 + +我們擁有一個 [官方文件網站](https://docs.sillytavern.app/) 可以幫助解答絕大多數的使用問題,並幫助您順利入門。 + +## SillyTavern 是什麼? + +SillyTavern(簡稱 ST)是一款本地安裝的使用者介面,讓您能與大型語言模型(LLM)、影像生成引擎以及語音合成模型互動的前端。 + +SillyTavern 起源於 2023 年 2 月,作為 TavernAI 1.2.8 的分支版本發展至今。目前已有超過 100 位貢獻者,並擁有超過兩年的獨立開發歷史。如今,它已成為 AI 愛好者中備受推崇的軟體之一。 + +## 我們的願景 + +1. 我們致力於賦予使用者對 LLM 提示詞的最大控制權與實用性,並認為學習過程中的挑戰是樂趣的一部分。 +2. 我們不提供任何線上或託管服務,也不會程式化追蹤任何使用者數據。 +3. SillyTavern 是由一群熱衷於 LLM 的開發者社群所打造的專案,並將永遠保持免費與開源。 + +## 分支介紹 + +SillyTavern 採用雙分支開發模式,確保為所有使用者提供流暢的體驗。 + +* `release`(穩定版):🌟 **推薦給大部分的使用者使用。** 此分支最為穩定,僅在主要版本發布時更新。適合大多數人,通常每月更新一次。 +* `staging`(開發版):⚠️ **不建議普通使用者使用。** 此分支包含最新功能,但可能隨時出現問題。適合進階使用者與愛好者,每日多次更新。 + +如果您不熟悉 git CLI 或對分支概念不清楚,請放心,對您來說,`release`(穩定版)分支永遠是首選。 + +## 使用 SillyTavern 需要什麼? + +由於 SillyTavern 僅是一個介面,您需要一個 LLM 後端來提供推理能力。您可以使用 AI Horde 以立即開始聊天。此外,我們支持許多其他本地和雲端 LLM 後端,例如 OpenAI 兼容 API、KoboldAI、Tabby 等。更多支持的 API 資訊,請參閱 [常見問題](https://docs.sillytavern.app/usage/api-connections/)。 + +### 我需要高效能電腦才能運行 SillyTavern 嗎? + +SillyTavern 的硬體需求相當低。任何能夠運行 NodeJS 18 或更高版本的設備都可以執行。若您打算在本地機器上進行 LLM 推理,我們建議使用擁有至少 6GB VRAM 的 3000 系列 NVIDIA 顯示卡。更多詳細資訊,請參考您使用的後端文檔。 + +### 推薦後端(僅為推薦,非官方合作和隸屬關係) + +* [AI Horde](https://aihorde.net/):使用志願者託管的模型,無需進一步設定 +* [KoboldCpp](https://github.com/LostRuins/koboldcpp):社群推崇的選擇,可在本地運行 GGUF 模型 +* [tabbyAPI](https://github.com/theroyallab/tabbyAPI):一個流行且輕量的本地託管 exl2 推理 API +* [OpenRouter](https://openrouter.ai):提供多個雲端 LLM 提供商(如 OpenAI、Claude、Meta Llama 等)及熱門社群模型的單一 API + +## 有任何問題或建議? + +### 歡迎加入我們的 Discord 伺服器 + +| [![][discord-shield-badge]][discord-link] | [加入我們的 Disocrd 伺服器](https://discord.gg/sillytavern) 以獲得技術支援、分享您喜愛的角色與提示詞。 | +| :---------------------------------------- | :----------------------------------------------------------------------------------------------------------------- | + +或直接聯繫開發者: + +* Discord: cohee, rossascends, wolfsblvt +* Reddit: [/u/RossAscends](https://www.reddit.com/user/RossAscends/), [/u/sillylossy](https://www.reddit.com/user/sillylossy/), [u/Wolfsblvt](https://www.reddit.com/user/Wolfsblvt/) +* [提交 GitHub 問題](https://github.com/SillyTavern/SillyTavern/issues) + +### 我喜歡這個專案,我該如何貢獻呢? + +1. **提交拉取要求(Pull Request)**:想了解如何貢獻,請參閱 [CONTRIBUTING.md](../CONTRIBUTING.md)。 +2. **提供功能建議與問題報告**:使用本專案所提供的模板提交建議或問題報告。 +3. **仔細閱讀此 README 文件及相關文檔**:請避免提出重複問題或建議。 + +## 螢幕截圖 + +<img width="500" alt="image" src="https://github.com/user-attachments/assets/9b5f32f0-c3b3-4102-b3f5-0e9213c0f50f"> +<img width="500" alt="image" src="https://github.com/user-attachments/assets/913fdbaa-7d33-42f1-ae2c-89dca41c53d1"> + +## 角色卡 + +SillyTavern 的核心概念是「角色卡」(Character Cards)。角色卡是一組設定 LLM 行為的提示詞,用於 SillyTavern 中進行持續性對話。功能類似於 ChatGPT 的 GPT 或 Poe 的聊天機器人。角色卡的內容可以是任何形式:抽象場景、針對特定任務設計的助手、知名人物,或者虛構角色。 + +角色卡中唯一必填的項目是名稱欄位。若想與語言模型開始一般對話,您只需創建一個名稱為「Assistant」的新卡片,其餘欄位皆可保持空白。若希望進行更具主題性的對話,則可以提供語言模型背景資訊、行為模式、寫作風格以及特定情境來啟動聊天。 + +如果僅想進行快速對話而不選擇角色卡片,或想測試 LLM 的連線,則可在開啟 SillyTavern 後,於歡迎頁面的輸入欄位中直接輸入您的提示內容。請注意,這類對話是暫時的,不會被永久保存。 + +若想了解如何設定角色卡,可參考預設角色(如 Seraphina)或從「下載擴充功能 & 資源」(Download Extensions & Assets)選單中下載社群製作的角色卡。 + +## 核心功能 + +* 進階文本生成設定:內含許多社群製作的預設設定 +* 支援世界資訊(World Info):創建豐富的背景故事,或節省角色卡中的 Token(符元)使用 +* 群組聊天:多角色聊天室,可讓角色與您或彼此對話 +* 豐富的 UI 自定義選項:主題顏色、背景圖片、自定義 CSS 等 +* 使用者設定:讓 AI 更了解您並提升沉浸感 +* 內建 RAG 支持:可將文檔加入對話,供 AI 參考 +* 強大的聊天指令子系統:內含 [腳本引擎(Scripting Engine)](https://docs.sillytavern.app/usage/st-script/) + +## 擴充功能 + +SillyTavern 支持多種擴充功能。 + +* 角色情感表達:使用視覺圖片(立繪)呈現情緒表達 +* 聊天記錄自動摘要 +* 自動化介面與聊天翻譯 +* 穩定擴散(Stable Diffusion)、FLUX 和 DALL-E 的影像生成整合 +* 語音合成:AI 回應的訊息可使用 ElevenLabs、Silero 或系統 TTS 語音合成 +* 網頁搜尋功能:為提示詞添加真實世界的上下文資訊 +* 更多擴展:可從「下載擴充功能 & 資源」(Download Extensions & Assets)選單中下載 + +想了解如何使用這些擴充功能,請參考:[官方說明文件](https://docs.sillytavern.app/) + +# ⌛ 安裝指南 + +> \[!WARNING] +> +> * 請勿將程式安裝到 Windows 的系統控制資料夾(如 Program Files、System32 等) +> * 請勿以管理員權限執行 Start.bat +> * 無法在 Windows 7 系統上安裝,因為它無法執行 NodeJS 18.16 + +## 🪟 Windows + +### 使用 Git 安裝 + +1. 安裝 [NodeJS](https://nodejs.org/en)(建議使用最新的 LTS 版本) +2. 安裝 [Git for Windows](https://gitforwindows.org/) +3. 打開 Windows 檔案總管(`Win+E`) +4. 創建/使用一個不受 Windows 系統控制或監控的資料夾(例如:C:\MySpecialFolder\) +5. 在該資料夾內開啟命令提示字元(Command Prompt):點擊地址欄,輸入 `cmd` 並按下 Enter +6. 當命令提示字元黑框彈出時,輸入以下其中一條指令後,按下 Enter: + +* 安裝 Release(穩定版)分支:`git clone https://github.com/SillyTavern/SillyTavern -b release` +* 安裝 Staging(開發板)分支:`git clone https://github.com/SillyTavern/SillyTavern -b staging` + +7. 當程式碼下載完成後,雙擊 `Start.bat`,NodeJS 將自動安裝所需的依賴項 +8. 本地伺服器啟動後,SillyTavern 將自動在您的瀏覽器中打開 + +### 使用 GitHub Desktop 安裝 + +(此方式僅允許通過 GitHub Desktop 使用 git。如果您也希望在命令列中使用 `git`,則需額外安裝 [Git for Windows](https://gitforwindows.org/)) + + 1. 安裝 [NodeJS](https://nodejs.org/en)(建議使用最新的 LTS 版本) + 2. 安裝 [GitHub Desktop](https://central.github.com/deployments/desktop/desktop/latest/win32) + 3. 安裝完成後,打開 GitHub Desktop,點擊 `Clone a repository from the internet....` (注意:此步驟 **無需創建 GitHub 帳號**。) + 4. 在彈出選單中,點擊「URL」選項,輸入此網址:`https://github.com/SillyTavern/SillyTavern`,然後點擊「Clone」。您可以更改「Local path」來選擇 SillyTavern 的下載位置 + 6. 若想開啟 SillyTavern,需使用 Windows 檔案總管以進入您複製儲存庫的資料夾。預設位置為:`C:\Users\[您的 Windows 使用者名稱]\Documents\GitHub\SillyTavern` + 7. 雙擊 `start.bat` 文件。(請注意:若您的作業系統隱藏了 `.bat` 副檔名,該文件可能顯示為「`Start`」。這就是您需要雙擊運行的文件。) + 8. 雙擊後,將會彈出一個大型黑色的命令提示字元視窗,SillyTavern 會開始安裝其運行所需的文件與依賴 + 9. 安裝完成後,若一切正常,命令提示字元視窗應顯示運行中的訊息,且您的瀏覽器會自動打開 SillyTavern 頁籤 + 10. 連接到任何 SillyTavern [支援的 APIs](https://docs.sillytavern.app/usage/api-connections/) 並開始聊天吧! + +## 🐧 Linux & 🍎 MacOS + +對於 MacOS 和 Linux 系統,所有操作都將在終端機(Terminal)中完成。 + +1. 安裝 git 和 NodeJS(具體方法因操作系統而異) +2. 複製儲存庫(Clone the repo): + +* 安裝 Release(穩定版)分支:`git clone https://github.com/SillyTavern/SillyTavern -b release` +* 安裝 Staging(開發板)分支:`git clone https://github.com/SillyTavern/SillyTavern -b staging` + +3. 使用命令 `cd SillyTavern` 以進入安裝資料夾 +4. 使用以下其中一條命令,以執行 `start.sh` 腳本: + +* `./start.sh` +* `bash start.sh` + +## ⚡ 使用 SillyTavern Launcher 安裝 + +SillyTavern Launcher 是一個安裝嚮導,協助您設定多種選項,包括安裝本地推理(inference)的後端。 + +### 對於 Windows 使用者 + +1. 在鍵盤上按下 **`WINDOWS + R`** 打開「執行」對話框,然後輸入以下指令以安裝 git: + +```shell +cmd /c winget install -e --id Git.Git +``` + +2. 在鍵盤上按下 **`WINDOWS + E`** 打開檔案總管,導航至您想要安裝 Launcher 的資料夾。在目標資料夾的地址欄輸入 `cmd` 並按下 Enter。接著執行以下命令: + +```shell +git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher && start installer.bat +``` + +### 對於 Linux 使用者 + +1. 打開您喜歡的終端機(Terminal),安裝 git +2. 使用以下指令以複製 Sillytavern-Launcher: + +```shell +git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher +``` + +3. 執行安裝腳本(installer.sh): + +```shell +chmod +x install.sh && ./install.sh +``` + +4. 安裝完成後,執行啟動腳本(launcher.sh): + +```shell +chmod +x launcher.sh && ./launcher.sh +``` + +### 對於 Mac 使用者 + +1. 打開終端機(Terminal),並使用以下指令安裝 Homebrew: + +```shell +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +``` + +2. 使用 Homebrew 以安裝 git: + +```shell +brew install git +``` + +3. 使用以下指令以複製 Sillytavern-Launcher: + +```shell +git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher +``` + +4. 執行安裝腳本(installer.sh): + +```shell +chmod +x install.sh && ./install.sh +``` + +5. 安裝完成後,執行啟動腳本(launcher.sh): + +```shell +chmod +x launcher.sh && ./launcher.sh +``` + +## 🐋 使用 Docker 安裝 + +以下指南已假設您安裝 Docker,能夠訪問命令列進行容器安裝,並熟悉 Docker 的基本使用。 + +### 自行構建映像 + +我們提供了一份完整的 [SillyTavern Docker 使用指南](http://docs.sillytavern.app/installation/docker/)。該指南涵蓋了 Windows、macOS 和 Linux 的安裝過程。若您希望自行構建映像,建議先閱讀該文檔。 + +### 使用 GitHub 容器註冊表(最簡易的方式) + +您需要設定兩個必要的目錄映射(directory mappings)和一個端口映射(port mapping)來使 SillyTavern 正常運行。在執行指令時,請將以下佔位符替換為您的實際配置: + +#### 容器變數 + +##### 目錄映射(Volume Mappings) + +* [config]:用於存放 SillyTavern 設定文件的本地資料夾 +* [data]:用於存放 SillyTavern 使用者數據(包括角色)的本地資料夾 +* [plugins](可選):用於存放 SillyTavern 擴充功能的本地資料夾 + +##### 端口映射(Port Mappings) + +* [PublicPort]:對外流量的訪問端口。這是必需的,因為您將從虛擬機容器外部訪問實例。除非實施了額外的安全服務,否則請勿將此端口暴露於網路 + +##### 其他設定(Additional Settings) + +* [DockerNet]:容器應連接的 Docker 網路。如果您不熟悉此概念,請參閱 [Docker 官方說明文件](https://docs.docker.com/reference/cli/docker/network/) +* [version]:在 GitHub 頁面的右側,您可以找到「Packages」。選擇「sillytavern」包,然後查看映像版本。「latest」標籤會使您保持與當前版本同步。您也可以選擇「staging」或「release」標籤,但這可能不適用於依賴擴充功能的使用者,因為擴充功能可能需要時間進行更新 + +#### 安裝命令 + +1. 打開命令列(Command Line) +2. 執行以下指令: + +`docker create --name='sillytavern' --net='[DockerNet]' -p '8000:8000/tcp' -v '[plugins]':'/home/node/app/plugins':'rw' -v '[config]':'/home/node/app/config':'rw' -v '[data]':'/home/node/app/data':'rw' 'ghcr.io/sillytavern/sillytavern:[version]'` + +> 請注意:默認的監聽端口為 8000。如果您在設定文件中更改了此端口,請務必使用適當的端口號 + +## 📱 於 Android 系統中使用 Termux 安裝 + +> \[!NOTE] +> **雖然您可以在 Android 設備上使用 Termux 直接運行 SillyTavern,但這不在我們的官方支持範圍內。** +> +> **請參閱 ArroganceComplex#2659 所提供的指南:** +> +> * <https://rentry.org/STAI-Termux> + +**不支援:Android ARM LEtime-web。** 32 位 Android 系統需要額外的依賴項,這無法通過 npm 安裝。請使用以下命令安裝:`pkg install esbuild`。完成後,請按照普通的安裝步驟進行操作 + +## API 金鑰管理 + +SillyTavern 將您的 API 金鑰(Keys)保存在使用者數據目錄中的 `secrets.json` 文件內(默認路徑為`/data/default-user/secrets.json`) + +默認情況下,API 金鑰在您保存並重新載入頁面後,將不會自介面中顯示 + +如需啟用查看金鑰功能: + +1. 在 `config.yaml` 文件中,將 `allowKeysExposure` 的「值」設為 `true` +2. 重新啟動 SillyTavern 伺服器 +3. 點擊 API 連線頁面右下角的「查看隱藏的 API 金鑰(View hidden API keys)」超連結 + +## 命令列參數(Command-line Arguments) + +您可以在啟動 SillyTavern 伺服器時傳遞命令列參數,以覆蓋 `config.yaml` 文件中的某些設定。 + +### 範例 + +```shell +node server.js --port 8000 --listen false +# or +npm run start -- --port 8000 --listen false +# or(僅適用於 Windows) +Start.bat --port 8000 --listen false +``` + +### Supported arguments + +| Option | Description | Type | +|-------------------------|------------------------------------------------------------------------------------------------------|----------| +| `--version` | 顯示版本序號 | boolean | +| `--enableIPv6` | 啟用 IPv6 | boolean | +| `--enableIPv4` | 啟用 IPv4 | boolean | +| `--port` | 設定 SillyTavern 運行的端口。若未提供,則預設使用 `config.yaml` 中的 'port' | number +| `--dnsPreferIPv6` | 偏好使用 IPv6 解析 DNS。未提供則默認使用 `config.yaml` 中的 'preferIPv6' | boolean | +| `--autorun` | 自動在瀏覽器中啟動 SillyTavern。未提供則默認使用 `config.yaml` 中的 'autorun' | boolean | +| `--autorunHostname` | 自動啟動時的主機名稱,通常建議保持為 'auto' | string | +| `--autorunPortOverride` | 覆蓋自動啟動的端口設定 | string | +| `--listen` | SillyTavern 是否可監聽所有網路接口。若未提供,則默認使用 `config.yaml` 中的 'listen' | boolean | +| `--corsProxy` | 啟用 CORS 代理。若未提供,則默認使用 `config.yaml` 中的 'enableCorsProxy' | boolean | +| `--disableCsrf` | 停用 CSRF 保護 | boolean | +| `--ssl` | 啟用 SSL | boolean | +| `--certPath` | 設定您證書文件的路徑 | string | +| `--keyPath` | 設定您私人金鑰文件的路徑 | string | +| `--whitelist` | 啟用白名單模式 | boolean | +| `--dataRoot` | 設定數據儲存的根目錄 | string | +| `--avoidLocalhost` | 在自動模式下避免使用 'localhost' | boolean | +| `--basicAuthMode` | 啟用基本身份驗證模式 | boolean | +| `--requestProxyEnabled` | 啟用代理以處理外部請求 | boolean | +| `--requestProxyUrl` | 設定請求代理的 URL(支持 HTTP 或 SOCKS 協議) | string | +| `--requestProxyBypass` | 請求代理的例外主機清單(主機列表需以空格分隔) | array | + +## 遠端連線 + +遠端連線功能最常用於希望在手機上使用 SillyTavern 的使用者。此時伺服器將由同一 Wi-Fi 網路上的 PC 運行。不過,您也可以設定來自其他網路的遠端連線。 + +詳細設定指南請參閱 [官方說明文件](https://docs.sillytavern.app/usage/remoteconnections/)。 + +您還可以選擇設定 SillyTavern 的使用者檔案,並開啟密碼保護(可選):[使用者設定指南](https://docs.sillytavern.app/installation/st-1.12.0-migration-guide/#users)。 + +## 遇到任何效能問題? + +1. 在「使用者設定」選單(設定介面主題)中,禁用模糊效果(Blur Effect),並開啟「減少動畫效果」(Reduced Motion) +2. 若使用響應串流傳輸,請將串流的 FPS 設定為較低的值(建議設定為 10-15 FPS) +3. 確保瀏覽器已啟用 GPU 加速以進行渲染 + +## 授權與致謝 + +**本程式(SillyTavern)的發布是基於其可能對使用者有所幫助的期許,但不提供任何形式的保證;包括但不限於對可銷售性(marketability)或特定用途適用性的隱含保證。如需更多詳情,請參閱 GNU Affero 通用公共許可證。** + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +* [TavernAI](https://github.com/TavernAI/TavernAI) 1.2.8 由 Humi 提供:MIT 許可 +* 經授權使用部分來自 CncAnon 的 TavernAITurbo 模組 +* 視覺小說模式(Visual Novel Mode)的靈感,來源於 PepperTaco 的貢獻(<https://github.com/peppertaco/Tavern/>) +* Noto Sans 字體由 Google 提供(OFL 許可) +* 主題圖示由 Font Awesome <https://fontawesome.com> 提供(圖示:CC BY 4.0,字體:SIL OFL 1.1,程式碼:MIT 許可) +* 預設資源來源於 @OtisAlejandro(包含角色 Seraphina 與知識書)與 @kallmeflocc(SillyTavern 官方 Discord 伺服器成員突破 10K 的慶祝背景) +* Docker 安裝指南由 [@mrguymiah](https://github.com/mrguymiah) 和 [@Bronya-Rand](https://github.com/Bronya-Rand) 編寫 + +## 主要貢獻者 + +[![Contributors](https://contrib.rocks/image?repo=SillyTavern/SillyTavern)](https://github.com/SillyTavern/SillyTavern/graphs/contributors) + +<!-- LINK GROUP --> +[cover]: https://github.com/user-attachments/assets/01a6ae9a-16aa-45f2-8bff-32b5dc587e44 +[discord-link]: https://discord.gg/sillytavern +[discord-shield-badge]: https://img.shields.io/discord/1100685673633153084?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=for-the-badge diff --git a/jiuguan2025cc/.github/readme.md b/jiuguan2025cc/.github/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..fc8cef288de33f5eb4ef4de69397cd3e11b929d5 --- /dev/null +++ b/jiuguan2025cc/.github/readme.md @@ -0,0 +1,432 @@ +<a name="readme-top"></a> + +![][cover] + +<div align="center"> + +English | [German](readme-de_de.md) | [中文](readme-zh_cn.md) | [繁體中文](readme-zh_tw.md) | [日本語](readme-ja_jp.md) | [Русский](readme-ru_ru.md) | [한국어](readme-ko_kr.md) + +[![GitHub Stars](https://img.shields.io/github/stars/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/stargazers) +[![GitHub Forks](https://img.shields.io/github/forks/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/network) +[![GitHub Issues](https://img.shields.io/github/issues/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/issues) +[![GitHub Pull Requests](https://img.shields.io/github/issues-pr/SillyTavern/SillyTavern.svg)](https://github.com/SillyTavern/SillyTavern/pulls) + +</div> + +--- + +SillyTavern provides a single unified interface for many LLM APIs (KoboldAI/CPP, Horde, NovelAI, Ooba, Tabby, OpenAI, OpenRouter, Claude, Mistral and more), a mobile-friendly layout, Visual Novel Mode, Automatic1111 & ComfyUI API image generation integration, TTS, WorldInfo (lorebooks), customizable UI, auto-translate, more prompt options than you'd ever want or need, and endless growth potential via third-party extensions. + +We have a [Documentation website](https://docs.sillytavern.app/) to answer most of your questions and help you get started. + +## What is SillyTavern? + +SillyTavern (or ST for short) is a locally installed user interface that allows you to interact with text generation LLMs, image generation engines, and TTS voice models. + +Beginning in February 2023 as a fork of TavernAI 1.2.8, SillyTavern now has over 200 contributors and 2 years of independent development under its belt, and continues to serve as a leading software for savvy AI hobbyists. + +## Our Vision + +1. We aim to empower users with as much utility and control over their LLM prompts as possible. The steep learning curve is part of the fun! +2. We do not provide any online or hosted services, nor programmatically track any user data. +3. SillyTavern is a passion project brought to you by a dedicated community of LLM enthusiasts, and will always be free and open sourced. + +## Branches + +SillyTavern is being developed using a two-branch system to ensure a smooth experience for all users. + +* `release` -🌟 **Recommended for most users.** This is the most stable and recommended branch, updated only when major releases are pushed. It's suitable for the majority of users. Typically updated once a month. +* `staging` - ⚠️ **Not recommended for casual use.** This branch has the latest features, but be cautious as it may break at any time. Only for power users and enthusiasts. Updates several times daily. + +If you're not familiar with using the git CLI or don't understand what a branch is, don't worry! The release branch is always the preferable option for you. + +## What do I need other than SillyTavern? + +Since SillyTavern is only an interface, you will need access to an LLM backend to provide inference. You can use AI Horde for instant out-of-the-box chatting. Aside from that, we support many other local and cloud-based LLM backends: OpenAI-compatible API, KoboldAI, Tabby, and many more. You can read more about our supported APIs in [the FAQ](https://docs.sillytavern.app/usage/api-connections/). + +### Do I need a powerful PC to run SillyTavern? + +The hardware requirements are minimal: it will run on anything that can run NodeJS 18 or higher. If you intend to do LLM inference on your local machine, we recommend a 3000-series NVIDIA graphics card with at least 6GB of VRAM. Check your backend's documentation for more details. + +### Suggested Backends (not affiliated) + +* [AI Horde](https://aihorde.net/) - use models hosted by volunteers. Requires no further setup +* [KoboldCpp](https://github.com/LostRuins/koboldcpp) - a community's favorite for running GGUF models locally +* [tabbyAPI](https://github.com/theroyallab/tabbyAPI) - a popular, lightweight, locally-hosted exl2 inference API +* [OpenRouter](https://openrouter.ai) - a single API for many cloud providers (OpenAI, Claude, Meta Llama, etc.) as well as popular community models. + +## Questions or suggestions? + +### Discord server + +| [![][discord-shield-badge]][discord-link] | [Join our Discord community!](https://discord.gg/sillytavern) Get support, share favorite characters and prompts. | +| :---------------------------------------- | :----------------------------------------------------------------------------------------------------------------- | + +Or get in touch with the developers directly: + +* Discord: cohee, rossascends, wolfsblvt +* Reddit: [/u/RossAscends](https://www.reddit.com/user/RossAscends/), [/u/sillylossy](https://www.reddit.com/user/sillylossy/), [u/Wolfsblvt](https://www.reddit.com/user/Wolfsblvt/) +* [Post a GitHub issue](https://github.com/SillyTavern/SillyTavern/issues) + +### I like your project! How do I contribute? + +1. Send pull requests. Learn how to contribute: [CONTRIBUTING.md](../CONTRIBUTING.md) +2. Send feature suggestions and issue reports using the provided templates. +3. Read this entire readme file and check the documentation website first, to avoid sending duplicate issues. + +## Screenshots + +<img width="500" alt="image" src="https://github.com/user-attachments/assets/9b5f32f0-c3b3-4102-b3f5-0e9213c0f50f"> +<img width="500" alt="image" src="https://github.com/user-attachments/assets/913fdbaa-7d33-42f1-ae2c-89dca41c53d1"> + +## Character Cards + +SillyTavern is built around the concept of "character cards". A character card is a collection of prompts that set the behavior of the LLM and is required to have persistent conversations in SillyTavern. They function similarly to ChatGPT's GPTs or Poe's bots. The content of a character card can be anything: an abstract scenario, an assistant tailored for a specific task, a famous personality or a fictional character. + +The name field is the only required character card input. To start a neutral conversation with the language model, create a new card simply called "Assistant" and leave the rest of the boxes blank. For a more themed chat, you can provide the language model with various background details, behavior and writing patterns, and a scenario to jump start the chat. + +To have a quick conversation without selecting a character card or to just test the LLM connection, simply type your prompt input into the input bar on the Welcome Screen after opening SillyTavern. Please note that such chats are temporary and will not be saved. + +To get a general idea on how to define character cards, see the default character (Seraphina) or download selected community-made cards from the "Download Extensions & Assets" menu. + +## Key Features + +* Advanced text generation settings with many community-made presets +* World Info support: create rich lore or save tokens on your character card +* Group chats: multi-bot rooms for characters to talk to you and/or each other +* Rich UI customization options: theme colors, background images, custom CSS, and more +* User personas: let the AI know a bit about you for greater immersion +* Built-in RAG support: add documents to your chats for the AI to reference +* Extensive chat commands subsystem and own [scripting engine](https://docs.sillytavern.app/usage/st-script/) + +## Extensions + +SillyTavern has extensibility support. + +* Character emotional expressions (sprites) +* Auto-Summary of the chat history +* Automatic UI and chat translation +* Stable Diffusion/FLUX/DALL-E image generation +* Text-to-speech for AI response messages (via ElevenLabs, Silero, or the OS's System TTS) +* Web Search capabilities for adding additional real world context to your prompts +* Many more are available to download from the "Download Extensions & Assets" menu. + +Tutorials on how to use them can be found in the [Docs](https://docs.sillytavern.app/). + +## ⌛ Installation + +### 🪟 Windows + +> \[!WARNING] +> +> * DO NOT INSTALL INTO ANY WINDOWS CONTROLLED FOLDER (Program Files, System32, etc). +> * DO NOT RUN START.BAT WITH ADMIN PERMISSIONS +> * INSTALLATION ON WINDOWS 7 IS IMPOSSIBLE AS IT CAN NOT RUN NODEJS 18.16 + +#### Installing via Git (recommended) + +1. Install [NodeJS](https://nodejs.org/en) (latest LTS version is recommended) +2. Install [Git for Windows](https://gitforwindows.org/) +3. Open Windows Explorer (`Win+E`) +4. Browse to or Create a folder that is not controlled or monitored by Windows. (ex: C:\MySpecialFolder\) +5. Open a Command Prompt inside that folder by clicking in the 'Address Bar' at the top, typing `cmd`, and pressing Enter. +6. Once the black box (Command Prompt) pops up, type ONE of the following into it and press Enter: + +* for Release Branch: `git clone https://github.com/SillyTavern/SillyTavern -b release` +* for Staging Branch: `git clone https://github.com/SillyTavern/SillyTavern -b staging` + +7. Once everything is cloned, double-click `Start.bat` to make NodeJS install its requirements. +8. The server will then start, and SillyTavern will pop up in your browser. + +#### Installing via GitHub Desktop + +(This allows git usage **only** in GitHub Desktop, if you want to use `git` on the command line too, you also need to install [Git for Windows](https://gitforwindows.org/)) + + 1. Install [NodeJS](https://nodejs.org/en) (latest LTS version is recommended) + 2. Install [GitHub Desktop](https://central.github.com/deployments/desktop/desktop/latest/win32) + 3. After installing GitHub Desktop, click on `Clone a repository from the internet....` (Note: You **do NOT need** to create a GitHub account for this step) + 4. On the menu, click the URL tab, enter this URL `https://github.com/SillyTavern/SillyTavern`, and click Clone. You can change the Local path to change where SillyTavern is going to be downloaded. + 6. To open SillyTavern, use Windows Explorer to browse into the folder where you cloned the repository. By default, the repository will be cloned here: `C:\Users\[Your Windows Username]\Documents\GitHub\SillyTavern` + 7. Double-click on the `start.bat` file. (Note: the `.bat` part of the file name might be hidden by your OS, in that case, it will look like a file called "`Start`". This is what you double-click to run SillyTavern) + 8. After double-clicking, a large black command console window should open and SillyTavern will begin to install what it needs to operate. + 9. After the installation process, if everything is working, the command console window should look like this and a SillyTavern tab should be open in your browser: + 10. Connect to any of the [supported APIs](https://docs.sillytavern.app/usage/api-connections/) and start chatting! + +### 🐧 Linux & 🍎 MacOS + +For MacOS / Linux all of these will be done in a Terminal. + +1. Install git and nodeJS (the method for doing this will vary depending on your OS) +2. Clone the repo + +* for Release Branch: `git clone https://github.com/SillyTavern/SillyTavern -b release` +* for Staging Branch: `git clone https://github.com/SillyTavern/SillyTavern -b staging` + +3. `cd SillyTavern` to navigate into the install folder. +4. Run the `start.sh` script with one of these commands: + +* `./start.sh` +* `bash start.sh` + +## 🐋 Installing via Docker + +These instructions assume you have installed Docker, are able to access your command line for the installation of containers, and familiar with their general operation. + +### Using the GitHub Container Registry + +#### Docker Compose (easiest) + +Grab the `docker-compose.yml` file from the [GitHub Repository](https://github.com/SillyTavern/SillyTavern/blob/release/docker/docker-compose.yml) and run the following command in the directory where the file is located. This will pull the latest release image from the GitHub Container Registry and start the container, automatically creating the necessary volumes. + +```shell +docker-compose up +``` + +Customize the `docker-compose.yml` file to your needs. The default port is 8000. If you want to adjust the server configuration using environment variables, read the documentation [here](https://docs.sillytavern.app/administration/config-yaml/#environment-variables). + +#### Docker CLI (advanced) + +You will need two mandatory directory mappings and a port mapping to allow SillyTavern to function. In the command, replace your selections in the following places: + +#### Container Variables + +##### Volume Mappings + +* `CONFIG_PATH` - The directory where SillyTavern configuration files will be stored on your host machine +* `DATA_PATH` - The directory where SillyTavern user data (including characters) will be stored on your host machine +* `PLUGINS_PATH` - (optional) The directory where SillyTavern server plugins will be stored on your host machine +* `EXTENSIONS_PATH` - (optional) The directory where global UI extensions will be stored on your host machine + +##### Port Mappings + +* `PUBLIC_PORT` - The port to expose the traffic on. This is mandatory, as you will be accessing the instance from outside of its virtual machine container. DO NOT expose this to the internet without implementing a separate service for security. + +##### Additional Settings + +* `SILLYTAVERN_VERSION` - On the right-hand side of this GitHub page, you'll see "Packages". Select the "sillytavern" package and you'll see the image versions. The image tag "latest" will keep you up-to-date with the current release. You can also utilize "staging" that points to the nightly image of the respective branch. + +#### Running the container + +1. Open your Command Line +2. Run the following command in a folder where you want to store the configuration and data files: + +```bash +SILLYTAVERN_VERSION="latest" +PUBLIC_PORT="8000" +CONFIG_PATH="./config" +DATA_PATH="./data" +PLUGINS_PATH="./plugins" +EXTENSIONS_PATH="./extensions" + +docker run \ + --name="sillytavern" \ + -p "$PUBLIC_PORT:8000/tcp" \ + -v "$CONFIG_PATH:/home/node/app/config:rw" \ + -v "$DATA_PATH:/home/node/app/data:rw" \ + -v "$EXTENSIONS_PATH:/home/node/app/public/scripts/extensions/third-party:rw" \ + -v "$PLUGINS_PATH:/home/node/app/plugins:rw" \ + ghcr.io/sillytavern/sillytavern:"$SILLYTAVERN_VERSION" +``` + +> By default the container will run in the foreground. If you want to run it in the background, add the `-d` flag to the `docker run` command. + +### Building the image yourself + +We have a comprehensive guide on using SillyTavern in Docker [here](http://docs.sillytavern.app/installation/docker/) which covers installations on Windows, macOS and Linux! Give it a read if you wish to build the image yourself. + +## ⚡ Installing via SillyTavern Launcher + +SillyTavern Launcher is an installation wizard that will help you get setup with many options, including installing a backend for local inference. + +### For Windows users + +1. On your keyboard: press **`WINDOWS + R`** to open Run dialog box. Then, run the following command to install git: + +```shell +cmd /c winget install -e --id Git.Git +``` + +2. On your keyboard: press **`WINDOWS + E`** to open File Explorer, then navigate to the folder where you want to install the launcher. Once in the desired folder, type `cmd` into the address bar and press enter. Then, run the following command: + +```shell +git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher && start installer.bat +``` + +### For Linux users + +1. Open your favorite terminal and install git +2. Git clone the Sillytavern-Launcher with: + +```shell +git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher +``` + +3. Start the installer.sh with: + +```shell +chmod +x install.sh && ./install.sh +``` + +4. After installation start the launcher.sh with: + +```shell +chmod +x launcher.sh && ./launcher.sh +``` + +### For Mac users + +1. Open a terminal and install brew with: + +```shell +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +``` + +2. Install git with: + +```shell +brew install git +``` + +3. Git clone the Sillytavern-Launcher with: + +```shell +git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher +``` + +4. Start the installer.sh with: + +```shell +chmod +x install.sh && ./install.sh +``` + +5. After installation start the launcher.sh with: + +```shell +chmod +x launcher.sh && ./launcher.sh +``` + +## 📱 Installing via Termux on Android OS + +> \[!NOTE] +> **SillyTavern can be run natively on Android devices using Termux, but we do not provide official support for this use case.** +> +> **Please refer to this guide by ArroganceComplex#2659:** +> +> * <https://rentry.org/STAI-Termux> + +**Unsupported platform: android arm LEtime-web.** 32-bit Android requires an external dependency that can't be installed with npm. Use the following command to install it: `pkg install esbuild`. Then run the usual installation steps. + +## API keys management + +SillyTavern saves your API keys to a `secrets.json` file in the user data directory (`/data/default-user/secrets.json` is the default path). + +By default, API keys will not be visible from the interface after you have saved them and refreshed the page. + +In order to enable viewing your keys: + +1. Set the value of `allowKeysExposure` to `true` in `config.yaml` file. +2. Restart the SillyTavern server. +3. Click the 'View hidden API keys' link at the bottom right of the API Connection Panel. + +## Command-line arguments + +You can pass command-line arguments to SillyTavern server startup to override some settings in `config.yaml`. + +### Examples + +```shell +node server.js --port 8000 --listen false +# or +npm run start -- --port 8000 --listen false +# or (Windows only) +Start.bat --port 8000 --listen false +``` + +### Supported arguments + +> \[!TIP] +> None of the arguments are required. If you don't provide them, SillyTavern will use the settings in `config.yaml`. + +| Option | Description | Type | +|-------------------------|----------------------------------------------------------------------|----------| +| `--version` | Show version number | boolean | +| `--dataRoot` | Root directory for data storage | string | +| `--port` | Sets the port under which SillyTavern will run | number | +| `--listen` | SillyTavern will listen on all network interfaces | boolean | +| `--whitelist` | Enables whitelist mode | boolean | +| `--basicAuthMode` | Enables basic authentication | boolean | +| `--enableIPv4` | Enables IPv4 protocol | boolean | +| `--enableIPv6` | Enables IPv6 protocol | boolean | +| `--listenAddressIPv4` | Specific IPv4 address to listen to | string | +| `--listenAddressIPv6` | Specific IPv6 address to listen to | string | +| `--dnsPreferIPv6` | Prefers IPv6 for DNS | boolean | +| `--ssl` | Enables SSL | boolean | +| `--certPath` | Path to your certificate file | string | +| `--keyPath` | Path to your private key file | string | +| `--autorun` | Automatically launch SillyTavern in the browser | boolean | +| `--autorunHostname` | Autorun hostname | string | +| `--autorunPortOverride` | Overrides the port for autorun | string | +| `--avoidLocalhost` | Avoids using 'localhost' for autorun in auto mode | boolean | +| `--corsProxy` | Enables CORS proxy | boolean | +| `--requestProxyEnabled` | Enables a use of proxy for outgoing requests | boolean | +| `--requestProxyUrl` | Request proxy URL (HTTP or SOCKS protocols) | string | +| `--requestProxyBypass` | Request proxy bypass list (space separated list of hosts) | array | +| `--disableCsrf` | Disables CSRF protection (NOT RECOMMENDED) | boolean | + +## Remote connections + +Most often this is for people who want to use SillyTavern on their mobile phones while their PC runs the ST server on the same Wi-Fi network. However, it can be used to allow remote connections from anywhere as well. + +Read the detailed guide on how to set up remote connections in the [Docs](https://docs.sillytavern.app/usage/remoteconnections/). + +You may also want to configure SillyTavern user profiles with (optional) password protection: [Users](https://docs.sillytavern.app/installation/st-1.12.0-migration-guide/#users). + +## Performance issues? + +### General tips + +1. Disable the Blur Effect and enable Reduced Motion on the User Settings panel (UI Theme toggles category). +2. If using response streaming, set the streaming FPS to a lower value (10-15 FPS is recommended). +3. Make sure the browser is enabled to use GPU acceleration for rendering. + +### Input lag + +Performance degradation, particularly input lag, is most commonly attributed to browser extensions. Known problematic extensions include: + +* iCloud Password Manager +* DeepL Translation +* AI-based grammar correction tools +* Various ad-blocking extensions + +If you experience performance issues and cannot identify the cause, or suspect an issue with SillyTavern itself, please: + +1. [Record a performance profile](https://developer.chrome.com/docs/devtools/performance/reference) +2. Export the profile as a JSON file +3. Submit it to the development team for analysis + +We recommend first testing with all browser extensions and third-party SillyTavern extensions disabled to isolate the source of the performance degradation. + +## License and credits + +**This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details.** + +* [TavernAI](https://github.com/TavernAI/TavernAI) 1.2.8 by Humi: MIT License +* Portions of CncAnon's TavernAITurbo mod used with permission +* Visual Novel Mode inspired by the work of PepperTaco (<https://github.com/peppertaco/Tavern/>) +* Noto Sans font by Google (OFL license) +* Icon theme by Font Awesome <https://fontawesome.com> (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) +* Default content by @OtisAlejandro (Seraphina character and lorebook) and @kallmeflocc (10K Discord Users Celebratory Background) +* Docker guide by [@mrguymiah](https://github.com/mrguymiah) and [@Bronya-Rand](https://github.com/Bronya-Rand) +* kokoro-js library by [@hexgrad](https://github.com/hexgrad) (Apache-2.0 License) + +## Top Contributors + +[![Contributors](https://contrib.rocks/image?repo=SillyTavern/SillyTavern)](https://github.com/SillyTavern/SillyTavern/graphs/contributors) + +<!-- LINK GROUP --> +[cover]: https://github.com/user-attachments/assets/01a6ae9a-16aa-45f2-8bff-32b5dc587e44 +[discord-link]: https://discord.gg/sillytavern +[discord-shield-badge]: https://img.shields.io/discord/1100685673633153084?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=for-the-badge diff --git a/jiuguan2025cc/.github/workflows/docker-publish.yml b/jiuguan2025cc/.github/workflows/docker-publish.yml new file mode 100644 index 0000000000000000000000000000000000000000..961a1d03dd4dff171c5259d9fc0f98c1292f64f8 --- /dev/null +++ b/jiuguan2025cc/.github/workflows/docker-publish.yml @@ -0,0 +1,94 @@ +# This workflow will publish a docker image for every full release to the GitHub package repository + +name: Create Docker Image (Release and Staging) + +on: + release: + # Allow pre-releases + types: [published] + schedule: + # Build the staging image everyday at 00:00 UTC + - cron: "0 0 * * *" + push: + # Temporary workaround + branches: + - release + +env: + # This should allow creation of docker images even in forked repositories + REPO: ${{ github.repository }} + REGISTRY: ghcr.io + +jobs: + build: + if: github.repository == 'SillyTavern/SillyTavern' + runs-on: ubuntu-latest + + steps: + # Workaround for GitHub repo names containing uppercase characters + - name: Set lowercase repo name + run: | + echo "IMAGE_NAME=${REPO,,}" >> ${GITHUB_ENV} + + # Using the following workaround because currently GitHub Actions + # does not support logical AND/OR operations on triggers + # It's currently not possible to have `branches` under the `schedule` trigger + - name: Checkout the release branch (on release) + if: ${{ github.event_name == 'release' || github.event_name == 'push' }} + uses: actions/checkout@v4.1.2 + with: + ref: "release" + + - name: Checkout the staging branch + if: ${{ github.event_name == 'schedule' }} + uses: actions/checkout@v4.1.2 + with: + ref: "staging" + + # Get current branch name + # This is also part of the workaround for Actions not allowing logical + # AND/OR operators on triggers + # Otherwise the action triggered by schedule always has ref_name = release + - name: Get the current branch name + run: | + echo "BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)" >> ${GITHUB_ENV} + + # Setting up QEMU for multi-arch image build + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Extract metadata (tags, labels) for the image + uses: docker/metadata-action@v5.5.1 + id: metadata + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + # Release version tag if the workflow is triggered by a release + # Branch name tag if the workflow is triggered by a push + # Latest tag if the branch is release and the workflow is triggered by a push + tags: | + ${{ github.event_name == 'release' && github.ref_name || env.BRANCH_NAME }} + ${{ github.event_name == 'push' && env.BRANCH_NAME == 'release' && 'latest' || '' }} + + # Login into package repository as the person who created the release + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + # Build docker image using dockerfile for amd64 and arm64 + # Tag it with branch name + # Assumes branch name is the version number + - name: Build and push + uses: docker/build-push-action@v5.3.0 + with: + context: . + platforms: linux/amd64,linux/arm64 + file: Dockerfile + push: true + tags: ${{ steps.metadata.outputs.tags }} + labels: ${{ steps.metadata.outputs.labels }} diff --git a/jiuguan2025cc/.github/workflows/issues-auto-manager.yml b/jiuguan2025cc/.github/workflows/issues-auto-manager.yml new file mode 100644 index 0000000000000000000000000000000000000000..d15ae1addb6f00280b02926e39370cb24bb92b83 --- /dev/null +++ b/jiuguan2025cc/.github/workflows/issues-auto-manager.yml @@ -0,0 +1,116 @@ +name: 🛠️ Issues Manager + +on: + issues: + types: [opened, edited, labeled, unlabeled] + # Re also listen to comments, to remove stale labels right away + issue_comment: + types: [created] + +permissions: + contents: read + issues: write + +jobs: + label-on-content: + name: 🏷️ Label Issues by Content + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + # Checkout + # https://github.com/marketplace/actions/checkout + uses: actions/checkout@v4.2.2 + + - name: Auto-Label Issues (Based on Issue Content) + # only auto label based on issue content once, on open (to prevent re-labeling removed labels) + if: github.event.action == 'opened' + + # Issue Labeler + # https://github.com/marketplace/actions/regex-issue-labeler + uses: github/issue-labeler@v3.4 + with: + configuration-path: .github/issues-auto-labels.yml + enable-versioned-regex: 0 + repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + + label-on-labels: + name: 🏷️ Label Issues by Labels + runs-on: ubuntu-latest + + steps: + - name: ✅ Add "👍 Approved" for relevant labels + if: contains(fromJSON('["👩‍💻 Good First Issue", "🙏 Help Wanted", "🪲 Confirmed", "⚠️ High Priority", "❕ Medium Priority", "💤 Low Priority"]'), github.event.label.name) + # 🤖 Issues Helper + # https://github.com/marketplace/actions/issues-helper + uses: actions-cool/issues-helper@v3.6.0 + with: + actions: 'add-labels' + token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + labels: '👍 Approved' + + - name: ❌ Remove progress labels when issue is marked done or stale + if: contains(fromJSON('["✅ Done", "✅ Done (staging)", "⚰️ Stale", "❌ wontfix"]'), github.event.label.name) + # 🤖 Issues Helper + # https://github.com/marketplace/actions/issues-helper + uses: actions-cool/issues-helper@v3.6.0 + with: + actions: 'remove-labels' + token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + labels: '🧑‍💻 In Progress,🤔 Unsure,🤔 Under Consideration' + + - name: ❌ Remove temporary labels when confirmed labels are added + if: contains(fromJSON('["❌ wontfix","👍 Approved","👩‍💻 Good First Issue"]'), github.event.label.name) + # 🤖 Issues Helper + # https://github.com/marketplace/actions/issues-helper + uses: actions-cool/issues-helper@v3.6.0 + with: + actions: 'remove-labels' + token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + labels: '🤔 Unsure,🤔 Under Consideration' + + - name: ❌ Remove no bug labels when "🪲 Confirmed" is added + if: github.event.label.name == '🪲 Confirmed' + # 🤖 Issues Helper + # https://github.com/marketplace/actions/issues-helper + uses: actions-cool/issues-helper@v3.6.0 + with: + actions: 'remove-labels' + token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + labels: '✖️ Not Reproducible,✖️ Not A Bug' + + remove-stale-label: + name: 🗑️ Remove Stale Label on Comment + runs-on: ubuntu-latest + # Only run this on new comments, to automatically remove the stale label + if: github.event_name == 'issue_comment' && github.actor != 'github-actions[bot]' + + steps: + - name: Remove Stale Label + # 🤖 Issues Helper + # https://github.com/marketplace/actions/issues-helper + uses: actions-cool/issues-helper@v3.6.0 + with: + actions: 'remove-labels' + token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + issue-number: ${{ github.event.issue.number }} + labels: '⚰️ Stale,🕸️ Inactive,🚏 Awaiting User Response,🛑 No Response' + + write-auto-comments: + name: 💬 Post Issue Comments Based on Labels + needs: [label-on-content, label-on-labels] + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + # Checkout + # https://github.com/marketplace/actions/checkout + uses: actions/checkout@v4.2.2 + + - name: Post Issue Comments Based on Labels + # Label Commenter + # https://github.com/marketplace/actions/label-commenter + uses: peaceiris/actions-label-commenter@v1.10.0 + with: + config_file: .github/issues-auto-comments.yml + github_token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} diff --git a/jiuguan2025cc/.github/workflows/issues-updates-on-merge.yml b/jiuguan2025cc/.github/workflows/issues-updates-on-merge.yml new file mode 100644 index 0000000000000000000000000000000000000000..3a5b9a1527b4d6ec7101ada1397008457319ed40 --- /dev/null +++ b/jiuguan2025cc/.github/workflows/issues-updates-on-merge.yml @@ -0,0 +1,45 @@ +name: 🔄 Update Issues on Push + +on: + push: + branches: + - staging + - release + +permissions: + contents: read + issues: write + +jobs: + # This runs commits to staging/release, reading the commit messages. Check `pr-auto-manager.yml`:`update-linked-issues` for PR-linked updates. + update-linked-issues: + name: 🔗 Mark Linked Issues Done on Push + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + # Checkout + # https://github.com/marketplace/actions/checkout + uses: actions/checkout@v4.2.2 + + - name: Extract Linked Issues from Commit Message + id: extract_issues + run: | + ISSUES=$(git log ${{ github.event.before }}..${{ github.event.after }} --pretty=%B | grep -oiE '(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved) #([0-9]+)' | awk '{print $2}' | tr -d '#' | jq -R -s -c 'split("\n")[:-1]') + echo "issues=$ISSUES" >> $GITHUB_ENV + + - name: Label Linked Issues + id: label_linked_issues + env: + GH_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + run: | + for ISSUE in $(echo $issues | jq -r '.[]'); do + if [ "${{ github.ref }}" == "refs/heads/staging" ]; then + LABEL="✅ Done (staging)" + gh issue edit $ISSUE -R ${{ github.repository }} --add-label "$LABEL" + elif [ "${{ github.ref }}" == "refs/heads/release" ]; then + LABEL="✅ Done" + gh issue edit $ISSUE -R ${{ github.repository }} --add-label "$LABEL" + fi + echo "Added label '$LABEL' to issue #$ISSUE" + done diff --git a/jiuguan2025cc/.github/workflows/job-close-stale.yml b/jiuguan2025cc/.github/workflows/job-close-stale.yml new file mode 100644 index 0000000000000000000000000000000000000000..9b83a6fa0ab26123e9dd8dc97297d4306b6d1e25 --- /dev/null +++ b/jiuguan2025cc/.github/workflows/job-close-stale.yml @@ -0,0 +1,100 @@ +name: 🕒 Close Stale Issues/PRs Workflow + +on: + # Run the workflow every day + workflow_dispatch: + schedule: + - cron: '0 0 * * *' # Runs every day at midnight UTC + +permissions: + contents: read + issues: write + pull-requests: write + +jobs: + mark-inactivity: + name: ⏳ Mark Issues/PRs without Activity + runs-on: ubuntu-latest + + steps: + - name: Mark Issues/PRs without Activity + # Close Stale Issues and PRs + # https://github.com/marketplace/actions/close-stale-issues + uses: actions/stale@v9.1.0 + with: + repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + days-before-stale: 183 + days-before-close: 7 + operations-per-run: 30 + remove-stale-when-updated: true + enable-statistics: true + stale-issue-message: > + ⏳ This issue has been inactive for 6 months. If it's still relevant, drop a comment below to keep it open. + Otherwise, it will be auto-closed in 7 days. + stale-pr-message: > + ⏳ This PR has been inactive for 6 months. If it's still relevant, update it or remove the stale label. + Otherwise, it will be auto-closed in 7 days. + close-issue-message: > + 🔒 This issue was auto-closed due to inactivity for over 6 months. + close-pr-message: > + 🔒 This PR was auto-closed due to inactivity for over 6 months. + stale-issue-label: '⚰️ Stale' + close-issue-label: '🕸️ Inactive' + stale-pr-label: '⚰️ Stale' + close-pr-label: '🕸️ Inactive' + exempt-issue-labels: '📌 Keep Open' + exempt-pr-labels: '📌 Keep Open' + + await-user-response: + name: ⚠️ Mark Issues/PRs Awaiting User Response + runs-on: ubuntu-latest + needs: mark-inactivity + + steps: + - name: Mark Issues/PRs Awaiting User Response + # Close Stale Issues and PRs + # https://github.com/marketplace/actions/close-stale-issues + uses: actions/stale@v9.1.0 + with: + repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + days-before-stale: 7 + days-before-close: 7 + operations-per-run: 30 + remove-stale-when-updated: true + stale-issue-message: > + ⚠️ Hey! We need some more info to move forward with this issue. + Please provide the requested details in the next few days to keep this ticket open. + close-issue-message: > + 🔒 This issue was auto-closed due to no response from user. + only-labels: '🚏 Awaiting User Response' + labels-to-remove-when-unstale: '🚏 Awaiting User Response' + stale-issue-label: '🛑 No Response' + close-issue-label: '🕸️ Inactive' + exempt-issue-labels: '🚧 Alternative Exists' + + alternative-exists: + name: 🔄 Mark Issues with Alternative Exists + runs-on: ubuntu-latest + needs: await-user-response + + steps: + - name: Mark Issues with Alternative Exists + # Close Stale Issues and PRs + # https://github.com/marketplace/actions/close-stale-issues + uses: actions/stale@v9.1.0 + with: + repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + days-before-stale: 7 + days-before-close: 7 + operations-per-run: 30 + remove-stale-when-updated: true + stale-issue-message: > + 🔄 An alternative solution has been provided for this issue. + Did this solve your problem? If so, we'll go ahead and close it. + If you still need help, drop a comment within the next 7 days to keep this open. + close-issue-message: > + ✅ Closing this issue due to no confirmation on the alternative solution. + only-labels: '🚧 Alternative Exists' + stale-issue-label: '🚏 Awaiting User Response' + close-issue-label: '🕸️ Inactive' + exempt-issue-labels: '📌 Keep Open' diff --git a/jiuguan2025cc/.github/workflows/npm-publish.yml b/jiuguan2025cc/.github/workflows/npm-publish.yml new file mode 100644 index 0000000000000000000000000000000000000000..be97e87e719eb3e5514bfc356277b7de55562db5 --- /dev/null +++ b/jiuguan2025cc/.github/workflows/npm-publish.yml @@ -0,0 +1,32 @@ +# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created +# For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages + +name: Node.js Package + +on: + release: + types: [created] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 16 + - run: npm ci + + publish-npm: + needs: build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 16 + registry-url: https://registry.npmjs.org/ + - run: npm ci + - run: npm publish + env: + NODE_AUTH_TOKEN: ${{secrets.npm_token}} diff --git a/jiuguan2025cc/.github/workflows/on-close-handler.yml b/jiuguan2025cc/.github/workflows/on-close-handler.yml new file mode 100644 index 0000000000000000000000000000000000000000..c132e558a31c7bfd5b87bcb90d59fd02bc1de6d2 --- /dev/null +++ b/jiuguan2025cc/.github/workflows/on-close-handler.yml @@ -0,0 +1,28 @@ +name: 🚪 Issues/PRs On Close Handler + +on: + issues: + types: [closed] + pull_request_target: + types: [closed] + +permissions: + contents: read + issues: write + pull-requests: write + +jobs: + remove-labels: + name: 🗑️ Remove Pending Labels on Close + runs-on: ubuntu-latest + + steps: + - name: Remove Pending Labels on Close + # 🤖 Issues Helper + # https://github.com/marketplace/actions/issues-helper + uses: actions-cool/issues-helper@v3.6.0 + with: + actions: remove-labels + token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + issue-number: ${{ github.event.issue.number || github.event.pull_request.number }} + labels: '🚏 Awaiting User Response,🧑‍💻 In Progress,📌 Keep Open,🚫 Merge Conflicts,🔬 Needs Testing,🔨 Needs Work,⚰️ Stale,⛔ Waiting For External/Upstream' diff --git a/jiuguan2025cc/.github/workflows/on-open-handler.yml b/jiuguan2025cc/.github/workflows/on-open-handler.yml new file mode 100644 index 0000000000000000000000000000000000000000..df109f914f66e00f0a5a45f481dd58fbee98d94f --- /dev/null +++ b/jiuguan2025cc/.github/workflows/on-open-handler.yml @@ -0,0 +1,29 @@ +name: 📨 Issues/PRs Open Handler + +on: + issues: + types: [opened] + pull_request_target: + types: [opened] + +permissions: + contents: read + issues: write + pull-requests: write + +jobs: + label-maintainer: + name: 🏷️ Label if Author is a Repo Maintainer + runs-on: ubuntu-latest + if: contains(fromJson('["Cohee1207", "RossAscends", "Wolfsblvt"]'), github.actor) + + steps: + - name: Label if Author is a Repo Maintainer + # 🤖 Issues Helper + # https://github.com/marketplace/actions/issues-helper + uses: actions-cool/issues-helper@v3.6.0 + with: + actions: 'add-labels' + token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + issue-number: ${{ github.event.issue.number || github.event.pull_request.number }} + labels: '👷 Maintainer' diff --git a/jiuguan2025cc/.github/workflows/pr-auto-manager.yml b/jiuguan2025cc/.github/workflows/pr-auto-manager.yml new file mode 100644 index 0000000000000000000000000000000000000000..e2dd9bb4370b25796bfe01ed8409941f0a18d9c9 --- /dev/null +++ b/jiuguan2025cc/.github/workflows/pr-auto-manager.yml @@ -0,0 +1,212 @@ +name: 🔀 Pull Request Manager + +on: + pull_request_target: + types: [opened, synchronize, reopened, edited, labeled, unlabeled, closed] + pull_request_review_comment: + types: [created] + +permissions: + contents: read + pull-requests: write + +jobs: + label-by-size: + name: 🏷️ Label PR by Size + runs-on: ubuntu-latest + + steps: + - name: Label PR Size + # Pull Request Size Labeler + # https://github.com/marketplace/actions/pull-request-size-labeler + uses: codelytv/pr-size-labeler@v1.10.2 + with: + GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + xs_label: '🟩 ⬤○○○○' + xs_max_size: '20' + s_label: '🟩 ⬤⬤○○○' + s_max_size: '100' + m_label: '🟨 ⬤⬤⬤○○' + m_max_size: '500' + l_label: '🟧 ⬤⬤⬤⬤○' + l_max_size: '1000' + xl_label: '🟥 ⬤⬤⬤⬤⬤' + fail_if_xl: 'false' + github_api_url: 'https://api.github.com' + files_to_ignore: | + "package-lock.json" + "public/lib/*" + + label-by-branches: + name: 🏷️ Label PR by Branches + needs: [label-by-size] + runs-on: ubuntu-latest + # Run, even if the previous jobs were skipped/failed + # Only label once when PR is created or branches are changed, to allow manual label removal + if: | + always() + && github.event.action == 'opened' || (github.event.action == 'synchronize' && (github.event.changes.base || github.event.changes.head)) + + steps: + - name: Checkout Repository + # Checkout + # https://github.com/marketplace/actions/checkout + uses: actions/checkout@v4.2.2 + + - name: Apply Labels Based on Branch Name and Target Branch + # Pull Request Labeler + # https://github.com/marketplace/actions/labeler + uses: actions/labeler@v5.0.0 + with: + configuration-path: .github/pr-auto-labels-by-branch.yml + repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + + label-by-files: + name: 🏷️ Label PR by Files + needs: [label-by-branches] + runs-on: ubuntu-latest + # Run, even if the previous jobs were skipped/failed + if: always() + + steps: + - name: Checkout Repository + # Checkout + # https://github.com/marketplace/actions/checkout + uses: actions/checkout@v4.2.2 + + - name: Apply Labels Based on Changed Files + # Pull Request Labeler + # https://github.com/marketplace/actions/labeler + uses: actions/labeler@v5.0.0 + with: + configuration-path: .github/pr-auto-labels-by-files.yml + repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + + remove-stale-label: + name: 🗑️ Remove Stale Label on Comment + needs: [label-by-files] + runs-on: ubuntu-latest + # Only runs when this is not done by the github actions bot + if: | + always() + && github.event_name == 'pull_request_review_comment' && github.actor != 'github-actions[bot]' + + steps: + - name: Remove Stale Label + # 🤖 Issues Helper + # https://github.com/marketplace/actions/issues-helper + uses: actions-cool/issues-helper@v3.6.0 + with: + actions: 'remove-labels' + token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + issue-number: ${{ github.event.pull_request.number }} + labels: '⚰️ Stale' + + check-merge-blocking-labels: + name: 🚫 Check Merge Blocking Labels + needs: [label-by-size, label-by-branches, label-by-files, remove-stale-label] + runs-on: ubuntu-latest + # Run, even if the previous jobs were skipped/failed + if: always() + + # Override permissions, as this needs to write a check + permissions: + checks: write + contents: read + pull-requests: read + + steps: + - name: Check Merge Blocking + # GitHub Script + # https://github.com/marketplace/actions/github-script + id: label-check + uses: actions/github-script@v7.0.1 + with: + script: | + const prLabels = context.payload.pull_request.labels.map(label => label.name); + const blockingLabels = [ + "⛔ Don't Merge", + "🔨 Needs Work", + "🔬 Needs Testing", + "⛔ Waiting For External/Upstream", + "❗ Against Release Branch", + "💥💣 Breaking Changes" + ]; + const hasBlockingLabel = prLabels.some(label => blockingLabels.includes(label)); + + if (hasBlockingLabel) { + console.log("Blocking label detected. Setting warning status."); + await github.rest.checks.create({ + owner: context.repo.owner, + repo: context.repo.repo, + name: "PR Label Warning", + head_sha: context.payload.pull_request.head.sha, + status: "completed", + conclusion: "neutral", + output: { + title: "Potential Merge Issue", + summary: "This PR has a merge-blocking label. Proceed with caution." + } + }); + } else { + console.log("No merge-blocking labels found."); + } + + write-auto-comments: + name: 💬 Post PR Comments Based on Labels + needs: [label-by-size, label-by-branches, label-by-files, remove-stale-label] + runs-on: ubuntu-latest + # Run, even if the previous jobs were skipped/failed + if: always() + + steps: + - name: Checkout Repository + # Checkout + # https://github.com/marketplace/actions/checkout + uses: actions/checkout@v4.2.2 + + - name: Post PR Comments Based on Labels + # Label Commenter for PRs + # https://github.com/marketplace/actions/label-commenter + uses: peaceiris/actions-label-commenter@v1.10.0 + with: + config_file: .github/pr-auto-comments.yml + github_token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + + # This runs on merged PRs to staging, reading the PR body and directly linked issues. Check `issues-updates-on-merge.yml`:`update-linked-issues` for commit-based updates. + update-linked-issues: + name: 🔗 Mark Linked Issues Done on Staging Merge + runs-on: ubuntu-latest + if: github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'staging' + + steps: + - name: Extract Linked Issues From PR Description + id: extract_issues + run: | + ISSUES=$(jq -r '.pull_request.body' "$GITHUB_EVENT_PATH" | grep -oiE '(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved) #([0-9]+)' | awk '{print $2}' | tr -d '#' | jq -R -s -c 'split("\n")[:-1]') + echo "issues=$ISSUES" >> $GITHUB_ENV + + - name: Fetch Directly Linked Issues + id: fetch_linked_issues + run: | + PR_NUMBER=${{ github.event.pull_request.number }} + REPO=${{ github.repository }} + API_URL="https://api.github.com/repos/$REPO/pulls/$PR_NUMBER/issues" + ISSUES=$(curl -s -H "Authorization: token ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}" "$API_URL" | jq -r '.[].number' | jq -R -s -c 'split("\n")[:-1]') + echo "linked_issues=$ISSUES" >> $GITHUB_ENV + + - name: Merge Issue Lists + id: merge_issues + run: | + ISSUES=$(jq -c -n --argjson a "$issues" --argjson b "$linked_issues" '$a + $b | unique') + echo "final_issues=$ISSUES" >> $GITHUB_ENV + + - name: Label Linked Issues + id: label_linked_issues + env: + GH_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + run: | + for ISSUE in $(echo $final_issues | jq -r '.[]'); do + gh issue edit $ISSUE -R ${{ github.repository }} --add-label "✅ Done (staging)" + echo "Added label '✅ Done (staging)' to issue #$ISSUE" + done diff --git a/jiuguan2025cc/.github/workflows/pr-check-merge-conflicts.yaml b/jiuguan2025cc/.github/workflows/pr-check-merge-conflicts.yaml new file mode 100644 index 0000000000000000000000000000000000000000..6c5acebc3465428c30bda6d3e63ea2963d02896f --- /dev/null +++ b/jiuguan2025cc/.github/workflows/pr-check-merge-conflicts.yaml @@ -0,0 +1,28 @@ +name: ⚔️ Check Merge Conflicts + +on: + # So that PRs touching the same files as the push are updated + push: + # So that the `dirtyLabel` is removed if conflicts are resolved + pull_request_target: + types: [synchronize] + +permissions: + contents: read + pull-requests: write + +jobs: + check-merge-conflicts: + name: ⚔️ Check Merge Conflicts + runs-on: ubuntu-latest + + steps: + - name: Check Merge Conflicts + # Label Conflicting Pull Requests + # https://github.com/marketplace/actions/label-conflicting-pull-requests + uses: eps1lon/actions-label-merge-conflict@v3.0.3 + with: + dirtyLabel: '🚫 Merge Conflicts' + repoToken: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + commentOnDirty: > + ⚠️ This PR has conflicts that need to be resolved before it can be merged. diff --git a/jiuguan2025cc/.github/workflows/update-i18n.yaml b/jiuguan2025cc/.github/workflows/update-i18n.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fd31370ce6fa726fb6d80cbaf9a03ef6ac3699a8 --- /dev/null +++ b/jiuguan2025cc/.github/workflows/update-i18n.yaml @@ -0,0 +1,32 @@ +name: Update i18n data + +on: workflow_dispatch + +jobs: + build: + runs-on: ubuntu-latest + permissions: # Job-level permissions configuration starts here + contents: write # 'write' access to repository contents + steps: + - name: disable auto crlf + uses: steve02081504/disable-autocrlf@v1 + - uses: actions/checkout@v4 + with: + ref: ${{ github.head_ref }} + fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository. + - name: Create local changes + run: | + aria2c https://raw.githubusercontent.com/SillyTavern/SillyTavern-i18n/main/generate.py + aria2c https://raw.githubusercontent.com/SillyTavern/SillyTavern-i18n/main/requirements.txt + pip install -r ./requirements.txt + python ./generate.py "" --sort-keys + rm -f ./generate.py ./requirements.txt + - name: add all + run: git add -A + - name: push + uses: actions-go/push@master + with: + author-email: 41898282+github-actions[bot]@users.noreply.github.com + author-name: github-actions[bot] + commit-message: 'i18n changes' + remote: origin diff --git a/jiuguan2025cc/.gitignore b/jiuguan2025cc/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..7a88d5becad5e12b56a59ed33f9068c295a5edd6 --- /dev/null +++ b/jiuguan2025cc/.gitignore @@ -0,0 +1,57 @@ +node_modules/ +public/chats/ +public/characters/ +public/User Avatars/ +public/backgrounds/ +public/groups/ +public/group chats/ +public/worlds/ +public/user/ +public/css/bg_load.css +public/themes/ +public/OpenAI Settings/ +public/KoboldAI Settings/ +public/NovelAI Settings/ +public/TextGen Settings/ +public/instruct/ +public/context/ +public/scripts/extensions/third-party/ +public/stats.json +/uploads/ +*.jsonl +/config.conf +/config.yaml +/config.conf.bak +/docker/config +/docker/user +/docker/extensions +/docker/data +.DS_Store +public/settings.json +/thumbnails +whitelist.txt +.vscode/** +!.vscode/extensions.json +.idea/ +secrets.json +/dist +/backups/ +public/movingUI/ +public/QuickReplies/ +content.log +cloudflared.exe +public/assets/ +access.log +/vectors/ +/cache/ +public/css/user.css +public/error/ +/plugins/ +/data +/default/scaffold +public/scripts/extensions/third-party +/certs +.aider* +.env +/StartDev.bat + diff --git a/jiuguan2025cc/.nomedia b/jiuguan2025cc/.nomedia new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/jiuguan2025cc/.npmignore b/jiuguan2025cc/.npmignore new file mode 100644 index 0000000000000000000000000000000000000000..0c99b6680ce2e8e53dccc10ab73fca28ad65bc9b --- /dev/null +++ b/jiuguan2025cc/.npmignore @@ -0,0 +1,14 @@ +node_modules/ +/uploads/ +.DS_Store +/thumbnails +secrets.json +/dist +/backups/ +/data +/cache +access.log +.github +.vscode +.git +/public/scripts/extensions/third-party diff --git a/jiuguan2025cc/.replit b/jiuguan2025cc/.replit new file mode 100644 index 0000000000000000000000000000000000000000..3d9cd541f14dd8223f02cbed13c8b224c01352f7 --- /dev/null +++ b/jiuguan2025cc/.replit @@ -0,0 +1,81 @@ + +hidden = [".config", "package-lock.json"] +run = "chmod 755 ./start.sh && ./start.sh" +entrypoint = "server.js" + +[[hints]] +regex = "Error \\[ERR_REQUIRE_ESM\\]" +message = "We see that you are using require(...) inside your code. We currently do not support this syntax. Please use 'import' instead when using external modules. (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import)" + +[nix] +channel = "stable-22_11" + +[env] +XDG_CONFIG_HOME = "/home/runner/$REPL_SLUG/.config" +PATH = "/home/runner/$REPL_SLUG/.config/npm/node_global/bin:/home/runner/$REPL_SLUG/node_modules/.bin" +npm_config_prefix = "/home/runner/$REPL_SLUG/.config/npm/node_global" + +[gitHubImport] +requiredFiles = [".replit", "replit.nix", ".config", "package.json", "package-lock.json"] + +[packager] +language = "nodejs" + + [packager.features] + packageSearch = true + guessImports = true + enabledForHosting = false + +[unitTest] +language = "nodejs" + +[debugger] +support = true + + [debugger.interactive] + transport = "localhost:0" + startCommand = [ "dap-node" ] + + [debugger.interactive.initializeMessage] + command = "initialize" + type = "request" + + [debugger.interactive.initializeMessage.arguments] + clientID = "replit" + clientName = "replit.com" + columnsStartAt1 = true + linesStartAt1 = true + locale = "en-us" + pathFormat = "path" + supportsInvalidatedEvent = true + supportsProgressReporting = true + supportsRunInTerminalRequest = true + supportsVariablePaging = true + supportsVariableType = true + + [debugger.interactive.launchMessage] + command = "launch" + type = "request" + + [debugger.interactive.launchMessage.arguments] + args = [] + console = "externalTerminal" + cwd = "." + environment = [] + pauseForSourceMap = false + program = "./server.js" + request = "launch" + sourceMaps = true + stopOnEntry = false + type = "pwa-node" + +[languages] + +[languages.javascript] +pattern = "**/{*.js,*.jsx,*.ts,*.tsx,*.json}" + +[languages.javascript.languageServer] +start = "typescript-language-server --stdio" + +[deployment] +run = ["sh", "-c", "./start.sh"] diff --git a/jiuguan2025cc/.vscode/extensions.json b/jiuguan2025cc/.vscode/extensions.json new file mode 100644 index 0000000000000000000000000000000000000000..4ea874ecc77ac148ce4127826662571ec0c6f99f --- /dev/null +++ b/jiuguan2025cc/.vscode/extensions.json @@ -0,0 +1,12 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "dbaeumer.vscode-eslint", + "EditorConfig.EditorConfig", + "mrcrowl.easy-less" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [] +} diff --git a/jiuguan2025cc/CONTRIBUTING.md b/jiuguan2025cc/CONTRIBUTING.md new file mode 100644 index 0000000000000000000000000000000000000000..b52fc7f6e1c60ad8500081d77534cad254461ac3 --- /dev/null +++ b/jiuguan2025cc/CONTRIBUTING.md @@ -0,0 +1,41 @@ +# How to contribute to SillyTavern + +## Setting up the dev environment + +1. Required software: git and node. +2. Recommended editor: Visual Studio Code. +3. You can also use GitHub Codespaces which sets up everything for you. + +## Getting the code ready + +1. Register a GitHub account. +2. Fork this repository under your account. +3. Clone the fork onto your machine. +4. Open the cloned repository in the code editor. +5. Create a git branch (recommended). +6. Make your changes and test them locally. +7. Commit the changes and push the branch to the remote repo. +8. Go to GitHub, and open a pull request, targeting the upstream branch. + +## Contribution guidelines + +1. Our standards are pretty low, but make sure the code is not too ugly: + - Run VS Code's autoformat when you're done. + - Check with ESLint by running `npm run lint`, then fix the errors. + - Use common sense and follow existing naming conventions. +2. Create pull requests for the staging branch, 99% of contributions should go there. That way people could test your code before the next stable release. +3. You can still send a pull request for release in the following scenarios: + - Updating README. + - Updating GitHub Actions. + - Hotfixing a critical bug. +4. Project maintainers will test and can change your code before merging. +5. Write at least somewhat meaningful PR descriptions. There's no "right" way to do it, but the following may help with outlining a general structure: + - What is the reason for a change? + - What did you do to achieve this? + - How would a reviewer test the change? +6. Mind the license. Your contributions will be licensed under the GNU Affero General Public License. If you don't know what that implies, consult your lawyer. + +## Further reading + +1. [How to write UI extensions](https://docs.sillytavern.app/for-contributors/writing-extensions/) +2. [How to write server plugins](https://docs.sillytavern.app/for-contributors/server-plugins) diff --git a/jiuguan2025cc/Dockerfile b/jiuguan2025cc/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..a133d0a477b590ad19f9481b0f59bbdcbdeda1a4 --- /dev/null +++ b/jiuguan2025cc/Dockerfile @@ -0,0 +1,51 @@ +FROM node:lts-alpine3.19 + +# Arguments +ARG APP_HOME=/home/node/app + +# Install system dependencies +RUN apk add --no-cache gcompat tini git + +# Create app directory +WORKDIR ${APP_HOME} + +# Set NODE_ENV to production +ENV NODE_ENV=production + +# Install app dependencies +COPY package*.json post-install.js ./ +RUN \ + echo "*** Install npm packages ***" && \ + npm i --no-audit --no-fund --loglevel=error --no-progress --omit=dev && npm cache clean --force + +# Bundle app source +COPY . ./ + +# Copy default chats, characters and user avatars to <folder>.default folder +RUN \ + rm -f "config.yaml" || true && \ + ln -s "./config/config.yaml" "config.yaml" || true && \ + mkdir "config" || true + +# Pre-compile public libraries +RUN \ + echo "*** Run Webpack ***" && \ + node "./docker/build-lib.js" + +# Cleanup unnecessary files +RUN \ + echo "*** Cleanup ***" && \ + mv "./docker/docker-entrypoint.sh" "./" && \ + rm -rf "./docker" && \ + echo "*** Make docker-entrypoint.sh executable ***" && \ + chmod +x "./docker-entrypoint.sh" && \ + echo "*** Convert line endings to Unix format ***" && \ + dos2unix "./docker-entrypoint.sh" + +# Fix extension repos permissions +RUN git config --global --add safe.directory "*" + +EXPOSE 8000 + +# Ensure proper handling of kernel signals +ENTRYPOINT ["tini", "--", "./docker-entrypoint.sh"] diff --git a/jiuguan2025cc/LICENSE b/jiuguan2025cc/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..0ad25db4bd1d86c452db3f9602ccdbe172438f52 --- /dev/null +++ b/jiuguan2025cc/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +<https://www.gnu.org/licenses/>. diff --git a/jiuguan2025cc/Remote-Link.cmd b/jiuguan2025cc/Remote-Link.cmd new file mode 100644 index 0000000000000000000000000000000000000000..2747abdd2ad2acabeaa692dbdab59ef29b24fb32 --- /dev/null +++ b/jiuguan2025cc/Remote-Link.cmd @@ -0,0 +1,18 @@ +@echo off +echo ======================================================================================================================== +echo WARNING: Cloudflare Tunnel! +echo ======================================================================================================================== +echo This script downloads and runs the latest cloudflared.exe from Cloudflare to set up an HTTPS tunnel to your SillyTavern! +echo Using the randomly generated temporary tunnel URL, anyone can access your SillyTavern over the Internet while the tunnel +echo is active. Keep the URL safe and secure your SillyTavern installation by setting a username and password in config.yaml! +echo. +echo See https://docs.sillytavern.app/usage/remoteconnections/ for more details about how to secure your SillyTavern install. +echo. +echo By continuing you confirm that you're aware of the potential dangers of having a tunnel open and take all responsibility +echo to properly use and secure it! +echo. +echo To abort, press Ctrl+C or close this window now! +echo. +pause +if not exist cloudflared.exe curl -Lo cloudflared.exe https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-windows-amd64.exe +cloudflared.exe tunnel --url localhost:8000 diff --git a/jiuguan2025cc/SECURITY.md b/jiuguan2025cc/SECURITY.md new file mode 100644 index 0000000000000000000000000000000000000000..aea622d99313caca55e35542e75401cb8cef65bc --- /dev/null +++ b/jiuguan2025cc/SECURITY.md @@ -0,0 +1,25 @@ +# Security Policy + +We take the security of this project seriously. If you discover any security vulnerabilities or have concerns regarding the security of this repository, please reach out to us immediately. We appreciate your efforts in responsibly disclosing the issue and will make every effort to address it promptly. + +## Reporting a Vulnerability + +To report a security vulnerability, please follow these steps: + +1. Go to the **Security** tab of this repository on GitHub. +2. Click on **"Report a vulnerability"**. +3. Provide a clear description of the vulnerability and its potential impact. Be as detailed as possible. +4. If applicable, include steps or a PoC (Proof of Concept) to reproduce the vulnerability. +5. Submit the report. + +Once we receive the private report notification, we will promptly investigate and assess the reported vulnerability. + +Please do not disclose any potential vulnerabilities in public repositories, issue trackers, or forums until we have had a chance to review and address the issue. + +## Scope + +This security policy applies to all the code and files within this repository and its dependencies actively maintained by us. If you encounter a security issue in a dependency that is not directly maintained by us, please follow responsible disclosure practices and report it to the respective project. + +While we strive to ensure the security of this project, please note that there may be limitations on resources, response times, and mitigations. + +Thank you for your help in making this project more secure. diff --git a/jiuguan2025cc/Start.bat b/jiuguan2025cc/Start.bat new file mode 100644 index 0000000000000000000000000000000000000000..148cda25347eb1f71b358164a14c6bd80d2fbeec --- /dev/null +++ b/jiuguan2025cc/Start.bat @@ -0,0 +1,7 @@ +@echo off +pushd %~dp0 +set NODE_ENV=production +call npm install --no-audit --no-fund --loglevel=error --no-progress --omit=dev +node server.js %* +pause +popd diff --git a/jiuguan2025cc/Update-Instructions.txt b/jiuguan2025cc/Update-Instructions.txt new file mode 100644 index 0000000000000000000000000000000000000000..6e7071184bd8595475db80b011c71564d94dcd34 --- /dev/null +++ b/jiuguan2025cc/Update-Instructions.txt @@ -0,0 +1,75 @@ +How to Update SillyTavern + +The most recent version can be found here: https://docs.sillytavern.app/usage/update/ + +This is not an installation guide. If you need installation instructions, look here: +https://docs.sillytavern.app/installation/windows/ + +This guide assumes you have already installed SillyTavern once, and know how to run it on your OS. + +Linux/Termux: + +You definitely installed via git, so just 'git pull' inside the SillyTavern directory. + +Windows/MacOS: + +Method 1 - GIT + +We always recommend users install using 'git'. Here's why: + +When you have installed via `git clone`, all you have to do to update is type `git pull` in a command line in the ST folder. +You can also try running the 'UpdateAndStart.bat' file, which will almost do the same thing. (Windows only) +Alternatively, if the command prompt gives you problems (and you have GitHub Desktop installed), you can use the 'Repository' menu and select 'Pull'. +The updates are applied automatically and safely. + +If you are a developer and use a fork of ST or switch branches regularly, you can use the 'UpdateForkAndStart.bat', which works similarly to 'UpdateAndStart.bat', +but automatically pulls changes into your fork and handles switched branches gracefully by asking if you want to switch back. + +Method 2 - ZIP + +If you insist on installing via a zip, here is the tedious process for doing the update: + +1. Download the new release zip. +2. Unzip it into a folder OUTSIDE of your current ST installation. +3. Do the usual setup procedure for your OS to install the NodeJS requirements. + +4a. Updating 1.12.0 and above + +Copy the user data directory from your data root into the data root of the new install. + +By default: /data/default-user + +4a. Migrating from <1.12.0 to >=1.20.0 +Copy the following files/folders as necessary(*) from your old ST installation: + + - Assets + - Backgrounds + - Characters + - Chats + - Context + - Groups + - Group chats + - Instruct + - movingUI + - KoboldAI Settings + - NovelAI Settings + - OpenAI Settings (Chat Completion API) + - TextGen Settings (Text Completion API) + - QuickReplies + - Themes + - User Avatars + - Worlds + - User + - settings.json + - secrets.json <---- This one is in the base folder, not /public/ + + (*) 'As necessary' = "If you made any custom content related to those folders". + None of the folders are mandatory, so only copy what you need. + + **NB: DO NOT COPY THE ENTIRE /PUBLIC/ FOLDER.** + Doing so could break the new install and prevent new features from being present. + Paste those items into the /data/default-user folder of the new install. + +5. Start SillyTavern once again with the method appropriate to your OS, and pray you got it right. + +6. If everything shows up, you can safely delete the old ST folder. diff --git a/jiuguan2025cc/UpdateAndStart.bat b/jiuguan2025cc/UpdateAndStart.bat new file mode 100644 index 0000000000000000000000000000000000000000..fbb3ac9bbf8d758137df6a15dbfc8a458afee577 --- /dev/null +++ b/jiuguan2025cc/UpdateAndStart.bat @@ -0,0 +1,27 @@ +@echo off +pushd %~dp0 +git --version > nul 2>&1 +if %errorlevel% neq 0 ( + echo Git is not installed on this system. + echo Install it from https://git-scm.com/downloads + goto end +) else ( + if not exist .git ( + echo Not running from a Git repository. Reinstall using an officially supported method to get updates. + echo See: https://docs.sillytavern.app/installation/windows/ + goto end + ) + call git pull --rebase --autostash + if %errorlevel% neq 0 ( + REM incase there is still something wrong + echo There were errors while updating. + echo See the update FAQ at https://docs.sillytavern.app/usage/update/#common-update-problems + goto end + ) +) +set NODE_ENV=production +call npm install --no-audit --no-fund --loglevel=error --no-progress --omit=dev +node server.js %* +:end +pause +popd diff --git a/jiuguan2025cc/UpdateForkAndStart.bat b/jiuguan2025cc/UpdateForkAndStart.bat new file mode 100644 index 0000000000000000000000000000000000000000..d788b94706f2dfdc2ab688b7e937b69d950f5c20 --- /dev/null +++ b/jiuguan2025cc/UpdateForkAndStart.bat @@ -0,0 +1,110 @@ +@echo off +@setlocal enabledelayedexpansion +pushd %~dp0 + +echo Checking Git installation +git --version > nul 2>&1 +if %errorlevel% neq 0 ( + echo Git is not installed on this system. + echo Install it from https://git-scm.com/downloads + goto end +) + +if not exist .git ( + echo Not running from a Git repository. Reinstall using an officially supported method to get updates. + echo See: https://docs.sillytavern.app/installation/windows/ + goto end +) + +REM Checking current branch +FOR /F "tokens=*" %%i IN ('git rev-parse --abbrev-ref HEAD') DO SET CURRENT_BRANCH=%%i +echo Current branch: %CURRENT_BRANCH% + +REM Checking for automatic branch switching configuration +set AUTO_SWITCH= +FOR /F "tokens=*" %%j IN ('git config --local script.autoSwitch') DO SET AUTO_SWITCH=%%j + +SET TARGET_BRANCH=%CURRENT_BRANCH% + +if NOT "!AUTO_SWITCH!"=="" ( + if "!AUTO_SWITCH!"=="s" ( + goto autoswitch-staging + ) + if "!AUTO_SWITCH!"=="r" ( + goto autoswitch-release + ) + + if "!AUTO_SWITCH!"=="staging" ( + :autoswitch-staging + echo Auto-switching to staging branch + git checkout staging + SET TARGET_BRANCH=staging + goto update + ) + if "!AUTO_SWITCH!"=="release" ( + :autoswitch-release + echo Auto-switching to release branch + git checkout release + SET TARGET_BRANCH=release + goto update + ) + + echo Auto-switching defined to stay on current branch + goto update +) + +if "!CURRENT_BRANCH!"=="staging" ( + echo Staying on the current branch + goto update +) +if "!CURRENT_BRANCH!"=="release" ( + echo Staying on the current branch + goto update +) + +echo You are not on 'staging' or 'release'. You are on '!CURRENT_BRANCH!'. +set /p "CHOICE=Do you want to switch to 'staging' (s), 'release' (r), or stay (any other key)? " +if /i "!CHOICE!"=="s" ( + echo Switching to staging branch + git checkout staging + SET TARGET_BRANCH=staging + goto update +) +if /i "!CHOICE!"=="r" ( + echo Switching to release branch + git checkout release + SET TARGET_BRANCH=release + goto update +) + +echo Staying on the current branch + +:update +REM Checking for 'upstream' remote +git remote | findstr "upstream" > nul +if %errorlevel% equ 0 ( + echo Updating and rebasing against 'upstream' + git fetch upstream + git rebase upstream/%TARGET_BRANCH% --autostash + goto install +) + +echo Updating and rebasing against 'origin' +git pull --rebase --autostash origin %TARGET_BRANCH% + + +:install +if %errorlevel% neq 0 ( + echo There were errors while updating. + echo See the update FAQ at https://docs.sillytavern.app/usage/update/#common-update-problems + goto end +) + +echo Installing npm packages and starting server +set NODE_ENV=production +call npm install --no-audit --no-fund --loglevel=error --no-progress --omit=dev +node server.js %* + +:end +pause +popd diff --git a/jiuguan2025cc/backups/!README.md b/jiuguan2025cc/backups/!README.md new file mode 100644 index 0000000000000000000000000000000000000000..8c9a74cf278767d787c0cc1e6cd26d1854486485 --- /dev/null +++ b/jiuguan2025cc/backups/!README.md @@ -0,0 +1,9 @@ +# Looking for setting snapshots or chat backups? + +Individual user backups are now located in the data directory. + +Example for the default user under default data root: + +/data/default-user/backups + +This folder remains for historical purposes only. diff --git a/jiuguan2025cc/colab/GPU.ipynb b/jiuguan2025cc/colab/GPU.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..68c9ef7af91bfb78d3da3920d1c14540175a6348 --- /dev/null +++ b/jiuguan2025cc/colab/GPU.ipynb @@ -0,0 +1,193 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Links**<br>\n", + "Extensions API GitHub: https://github.com/SillyTavern/SillyTavern-extras/<br>\n", + "SillyTavern community Discord (support and discussion): https://discord.gg/sillytavern" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#@title <-- Tap this if you run on Mobile { display-mode: \"form\" }\n", + "#Taken from KoboldAI colab\n", + "%%html\n", + "<b>Press play on the audio player to keep the tab alive. (Uses only 13MB of data)</b><br/>\n", + "<audio src=\"https://henk.tech/colabkobold/silence.m4a\" controls>" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "lVftocpwCoYw" + }, + "outputs": [], + "source": [ + "#@markdown (RECOMMENDED) Generates an API key for you to use with the API\n", + "secure = False #@param {type:\"boolean\"}\n", + "#@markdown Allows to run SillyTavern Extras on CPU (use if you're out of daily GPU allowance)\n", + "use_cpu = False #@param {type:\"boolean\"}\n", + "#@markdown Allows to run Stable Diffusion pipeline on CPU (slow!)\n", + "use_sd_cpu = False #@param {type:\"boolean\"}\n", + "#@markdown ***\n", + "#@markdown Enables the WebSearch module\n", + "extras_enable_websearch = True #@param {type:\"boolean\"}\n", + "#@markdown ***\n", + "#@markdown Loads the image captioning module\n", + "extras_enable_caption = True #@param {type:\"boolean\"}\n", + "captioning_model = \"Salesforce/blip-image-captioning-large\" #@param [ \"Salesforce/blip-image-captioning-large\", \"Salesforce/blip-image-captioning-base\" ]\n", + "#@markdown * Salesforce/blip-image-captioning-large - good base model\n", + "#@markdown * Salesforce/blip-image-captioning-base - slightly faster but less accurate\n", + "#@markdown ***\n", + "#@markdown Loads the sentiment classification model\n", + "extras_enable_classify = True #@param {type:\"boolean\"}\n", + "classification_model = \"nateraw/bert-base-uncased-emotion\" #@param [\"nateraw/bert-base-uncased-emotion\", \"joeddav/distilbert-base-uncased-go-emotions-student\"]\n", + "#@markdown * nateraw/bert-base-uncased-emotion = 6 supported emotions<br>\n", + "#@markdown * joeddav/distilbert-base-uncased-go-emotions-student = 28 supported emotions\n", + "#@markdown ***\n", + "#@markdown Loads the story summarization module\n", + "extras_enable_summarize = True #@param {type:\"boolean\"}\n", + "summarization_model = \"slauw87/bart_summarisation\" #@param [ \"slauw87/bart_summarisation\", \"Qiliang/bart-large-cnn-samsum-ChatGPT_v3\", \"Qiliang/bart-large-cnn-samsum-ElectrifAi_v10\", \"distilbart-xsum-12-3\" ]\n", + "#@markdown * slauw87/bart_summarisation - general purpose summarization model\n", + "#@markdown * Qiliang/bart-large-cnn-samsum-ChatGPT_v3 - summarization model optimized for chats\n", + "#@markdown * Qiliang/bart-large-cnn-samsum-ElectrifAi_v10 - nice results so far, but still being evaluated\n", + "#@markdown * distilbart-xsum-12-3 - faster, but pretty basic alternative\n", + "#@markdown ***\n", + "#@markdown Enables Silero text-to-speech module\n", + "extras_enable_silero_tts = True #@param {type:\"boolean\"}\n", + "#@markdown Enables Microsoft Edge text-to-speech module\n", + "extras_enable_edge_tts = True #@param {type:\"boolean\"}\n", + "#@markdown Enables RVC module\n", + "extras_enable_rvc = False #@param {type:\"boolean\"}\n", + "#@markdown ***\n", + "#@markdown Enables Whisper speech recognition module\n", + "extras_enable_whisper_stt = True #@param {type:\"boolean\"}\n", + "whisper_model = \"base.en\" #@param [ \"tiny.en\", \"base.en\", \"small.en\", \"medium.en\", \"tiny\", \"base\", \"small\", \"medium\", \"large\" ]\n", + "#@markdown There are five model sizes, four with English-only versions, offering speed and accuracy tradeoffs.\n", + "#@markdown The .en models for English-only applications tend to perform better, especially for the tiny.en and base.en models.\n", + "#@markdown ***\n", + "#@markdown Enables SD picture generation\n", + "extras_enable_sd = True #@param {type:\"boolean\"}\n", + "sd_model = \"ckpt/anything-v4.5-vae-swapped\" #@param [ \"ckpt/anything-v4.5-vae-swapped\", \"hakurei/waifu-diffusion\", \"philz1337/clarity\", \"prompthero/openjourney\", \"ckpt/sd15\", \"stabilityai/stable-diffusion-2-1-base\" ]\n", + "#@markdown * ckpt/anything-v4.5-vae-swapped - anime style model\n", + "#@markdown * hakurei/waifu-diffusion - anime style model\n", + "#@markdown * philz1337/clarity - realistic style model\n", + "#@markdown * prompthero/openjourney - midjourney style model\n", + "#@markdown * ckpt/sd15 - base SD 1.5\n", + "#@markdown * stabilityai/stable-diffusion-2-1-base - base SD 2.1\n", + "#@markdown ***\n", + "#@markdown Enables ChromaDB module\n", + "extras_enable_chromadb = True #@param {type:\"boolean\"}\n", + "\n", + "import subprocess\n", + "import secrets\n", + "\n", + "# ---\n", + "# SillyTavern extras\n", + "extras_url = '(disabled)'\n", + "params = []\n", + "if use_cpu:\n", + " params.append('--cpu')\n", + "if use_sd_cpu:\n", + " params.append('--sd-cpu')\n", + "if secure:\n", + " params.append('--secure')\n", + "params.append('--share')\n", + "modules = []\n", + "\n", + "if extras_enable_caption:\n", + " modules.append('caption')\n", + "if extras_enable_summarize:\n", + " modules.append('summarize')\n", + "if extras_enable_classify:\n", + " modules.append('classify')\n", + "if extras_enable_sd:\n", + " modules.append('sd')\n", + "if extras_enable_silero_tts:\n", + " modules.append('silero-tts')\n", + "if extras_enable_edge_tts:\n", + " modules.append('edge-tts')\n", + "if extras_enable_chromadb:\n", + " modules.append('chromadb')\n", + "if extras_enable_whisper_stt:\n", + " modules.append('whisper-stt')\n", + " params.append(f'--stt-whisper-model-path={whisper_model}')\n", + "if extras_enable_rvc:\n", + " modules.append('rvc')\n", + " params.append('--max-content-length=2000')\n", + " params.append('--rvc-save-file')\n", + "\n", + "\n", + "if extras_enable_websearch:\n", + " print(\"Enabling WebSearch module\")\n", + " modules.append('websearch')\n", + " !apt update\n", + " !apt install -y chromium-chromedriver\n", + "\n", + "params.append(f'--classification-model={classification_model}')\n", + "params.append(f'--summarization-model={summarization_model}')\n", + "params.append(f'--captioning-model={captioning_model}')\n", + "params.append(f'--sd-model={sd_model}')\n", + "params.append(f'--enable-modules={\",\".join(modules)}')\n", + "\n", + "\n", + "%cd /\n", + "!git clone https://github.com/SillyTavern/SillyTavern-extras\n", + "%cd /SillyTavern-extras\n", + "!git clone https://github.com/Cohee1207/tts_samples\n", + "!npm install -g localtunnel\n", + "%pip install -r requirements.txt\n", + "!wget https://github.com/cloudflare/cloudflared/releases/download/2023.5.0/cloudflared-linux-amd64 -O /tmp/cloudflared-linux-amd64\n", + "!chmod +x /tmp/cloudflared-linux-amd64\n", + "\n", + "if extras_enable_rvc:\n", + " print(\"Installing RVC requirements\")\n", + " %pip install -r requirements-rvc.txt\n", + "\n", + "# Generate a random API key\n", + "api_key = secrets.token_hex(5)\n", + "\n", + "# Write the API key to api_key.txt\n", + "with open('./api_key.txt', 'w') as f:\n", + " f.write(api_key)\n", + "print(f\"API Key generated: {api_key}\")\n", + "\n", + "cmd = f\"python server.py {' '.join(params)}\"\n", + "print(cmd)\n", + "extras_process = subprocess.Popen(\n", + " cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd='/SillyTavern-extras', shell=True)\n", + "print('processId:', extras_process.pid)\n", + "while True:\n", + " line = extras_process.stdout.readline().decode().strip()\n", + " if line != None and line != '':\n", + " print(line)\n" + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "private_outputs": true, + "provenance": [] + }, + "gpuClass": "standard", + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/jiuguan2025cc/data/.gitkeep b/jiuguan2025cc/data/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/jiuguan2025cc/default/!DO-NOT-EDIT-THESE-FILES.txt b/jiuguan2025cc/default/!DO-NOT-EDIT-THESE-FILES.txt new file mode 100644 index 0000000000000000000000000000000000000000..713bf2ad597a5500492edc9e742da8951bf8a562 --- /dev/null +++ b/jiuguan2025cc/default/!DO-NOT-EDIT-THESE-FILES.txt @@ -0,0 +1,13 @@ +These are master copies of the default content files and are managed by SillyTavern. + +Editing any of these files would not only have no effect, but will also cause merge conflicts during update pulls. + +You should edit their respective copies instead, for example: + +1. /default/config.yaml => /config.yaml +2. /default/public/css/user.css => /public/css/user.css +etc. + +Any questions? You're always welcome at our official documentation website: + +https://docs.sillytavern.app/ diff --git a/jiuguan2025cc/default/config.yaml b/jiuguan2025cc/default/config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f4bacf9ffb0fb85c00f34b6ca87806280141528a --- /dev/null +++ b/jiuguan2025cc/default/config.yaml @@ -0,0 +1,235 @@ +# -- DATA CONFIGURATION -- +# Root directory for user data storage +dataRoot: ./data +# -- SERVER CONFIGURATION -- +# Listen for incoming connections +listen: false +# Listen on a specific address, supports IPv4 and IPv6 +listenAddress: + ipv4: 0.0.0.0 + ipv6: '[::]' +# Enables IPv6 and/or IPv4 protocols. Need to have at least one enabled! +# - Use option "auto" to automatically detect support +# - Use true or false (no qoutes) to enable or disable each protocol +protocol: + ipv4: true + ipv6: false +# Prefers IPv6 for DNS. Enable this on ISPs that don't have issues with IPv6 +dnsPreferIPv6: false +# The hostname that autorun opens. +# - Use "auto" to let the server decide +# - Use options like 'localhost', 'st.example.com' +autorunHostname: "auto" +# Server port +port: 8000 +# Overrides the port for autorun in browser. +# - Use -1 to use the server port. +# - Specify a port to override the default. +autorunPortOverride: -1 +# -- SSL options -- +ssl: + enabled: false + certPath: "./certs/cert.pem" + keyPath: "./certs/privkey.pem" +# -- SECURITY CONFIGURATION -- +# Toggle whitelist mode +whitelistMode: true +# Whitelist will also verify IP in X-Forwarded-For / X-Real-IP headers +enableForwardedWhitelist: true +# Whitelist of allowed IP addresses +whitelist: + - ::1 + - 127.0.0.1 +# Automatically whitelist Docker host and gateway IPs +whitelistDockerHosts: true +# Toggle basic authentication for endpoints +basicAuthMode: false +# Basic authentication credentials +basicAuthUser: + username: "user" + password: "password" +# Enables CORS proxy middleware +enableCorsProxy: false +# -- REQUEST PROXY CONFIGURATION -- +requestProxy: + # If a proxy is enabled, all outgoing HTTP/HTTPS requests will be routed through it. + enabled: false + # Proxy URL. Possible protocols: http, https, socks, socks5, socks4, pac + url: "socks5://username:password@example.com:1080" + # Proxy bypass list. Requests to these hosts won't be routed through the proxy. + bypass: + - localhost + - 127.0.0.1 +# Enable multi-user mode +enableUserAccounts: false +# Enable discreet login mode: hides user list on the login screen +enableDiscreetLogin: false +# Enable's authlia based auto login. Only enable this if you +# have setup and installed Authelia as a middle-ware on your +# reverse proxy +# https://www.authelia.com/ +# This will use auto login to an account with the same username +# as that used for authlia. (Ensure the username in authlia +# is an exact match with that in sillytavern) +autheliaAuth: false +# If `basicAuthMode` and this are enabled then +# the username and passwords for basic auth are the same as those +# for the individual accounts +perUserBasicAuth: false + +# User session timeout *in seconds* (defaults to 24 hours). +## Set to a positive number to expire session after a certain time of inactivity +## Set to 0 to expire session when the browser is closed +## Set to a negative number to disable session expiration +sessionTimeout: -1 +# Disable CSRF protection - NOT RECOMMENDED +disableCsrfProtection: false +# Disable startup security checks - NOT RECOMMENDED +securityOverride: false +# -- LOGGING CONFIGURATION -- +logging: + # Enable access logging to access.log file + # Records new connections with timestamp, IP address and user agent + enableAccessLog: true + # Minimum log level to display in the terminal (DEBUG = 0, INFO = 1, WARN = 2, ERROR = 3) + minLogLevel: 0 +# -- RATE LIMITING CONFIGURATION -- +rateLimiting: + # Use X-Real-IP header instead of socket IP for rate limiting + # Only enable this if you are using a properly configured reverse proxy (like Nginx/traefik/Caddy) + preferRealIpHeader: false +# -- ADVANCED CONFIGURATION -- +# Open the browser automatically +autorun: true +# Avoids using 'localhost' for autorun in auto mode. +# use if you don't have 'localhost' in your hosts file +avoidLocalhost: false + +## BACKUP CONFIGURATION +backups: + # Common settings for all backup types + common: + # Number of backups to keep for each chat and settings file + numberOfBackups: 50 + chat: + # Enable automatic chat backups + enabled: true + # Maximum number of chat backups to keep per user (starting from the most recent). Set to -1 to keep all backups. + maxTotalBackups: -1 + # Interval in milliseconds to throttle chat backups per user + throttleInterval: 10000 + +# THUMBNAILING CONFIGURATION +thumbnails: + # Enable thumbnail generation + enabled: true + # Image format of avatar thumbnails: + # * "jpg": best compression with adjustable quality, no transparency + # * "png": preserves transparency but increases filesize by about 100% + # Changing this only affects new thumbnails. To recreate the old ones, clear out /thumbnails folder in your user data. + format: "jpg" + # JPG thumbnail quality (0-100) + quality: 95 + # Maximum thumbnail dimensions per type [width, height] + dimensions: { 'bg': [160, 90], 'avatar': [96, 144] } + +# PERFORMANCE-RELATED CONFIGURATION +performance: + # Enables lazy loading of character cards. Improves performances with large card libraries. + # May have compatibility issues with some extensions. + lazyLoadCharacters: false + # The maximum amount of memory that parsed character cards can use. Set to 0 to disable memory caching. + memoryCacheCapacity: '100mb' + +# Allow secret keys exposure via API +allowKeysExposure: false +# Skip new default content checks +skipContentCheck: false +# Allowed hosts for card downloads +whitelistImportDomains: + - localhost + - cdn.discordapp.com + - files.catbox.moe + - raw.githubusercontent.com +# API request overrides (for KoboldAI and Text Completion APIs) +## Note: host includes the port number if it's not the default (80 or 443) +## Format is an array of objects: +## - hosts: +## - example.com +## headers: +## Content-Type: application/json +## - 127.0.0.1:5001 +## headers: +## User-Agent: "Googlebot/2.1 (+http://www.google.com/bot.html)" +requestOverrides: [] + +# EXTENSIONS CONFIGURATION +extensions: + # Enable UI extensions + enabled: true + # Automatically update extensions when a release version changes + autoUpdate: true + models: + # Enables automatic model download from HuggingFace + autoDownload: true + # Additional models for extensions. Expects model IDs from HuggingFace model hub in ONNX format + classification: Cohee/distilbert-base-uncased-go-emotions-onnx + captioning: Xenova/vit-gpt2-image-captioning + embedding: Cohee/jina-embeddings-v2-base-en + speechToText: Xenova/whisper-small + textToSpeech: Xenova/speecht5_tts + +# Additional model tokenizers can be downloaded on demand. +# Disabling will fallback to another locally available tokenizer. +enableDownloadableTokenizers: true +# -- OPENAI CONFIGURATION -- +# A placeholder message to use in strict prompt post-processing mode when the prompt doesn't start with a user message +promptPlaceholder: "[Start a new chat]" +openai: + # Will send a random user ID to OpenAI completion API + randomizeUserId: false + # If not empty, will add this as a system message to the start of every caption completion prompt + # Example: "Perform the instructions to the best of your ability.\n" (for LLaVA) + # Not used in image inlining mode + captionSystemPrompt: "" +# -- DEEPL TRANSLATION CONFIGURATION -- +deepl: + # Available options: default, more, less, prefer_more, prefer_less + formality: default +# -- MISTRAL API CONFIGURATION -- +mistral: + # Enables prefilling of the reply with the last assistant message in the prompt + # CAUTION: The prefix is echoed into the completion. You may want to use regex to trim it out. + enablePrefix: false +# -- OLLAMA API CONFIGURATION -- +ollama: + # Controls how long the model will stay loaded into memory following the request + # * -1: Keep the model loaded indefinitely + # * 0: Unload the model immediately after the request + # * N (any positive number): Keep the model loaded for N seconds after the request. + keepAlive: -1 + # Controls the "num_batch" (batch size) parameter of the generation request + # * -1: Use the default value of the model + # * N (positive number): Use the specified value. Must be a power of 2, e.g. 128, 256, 512, etc. + batchSize: -1 +# -- ANTHROPIC CLAUDE API CONFIGURATION -- +claude: + # Enables caching of the system prompt (if supported). + # https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching + # -- IMPORTANT! -- + # Use only when the prompt before the chat history is static and doesn't change between requests + # (e.g {{random}} macro or lorebooks not as in-chat injections). + # Otherwise, you'll just waste money on cache misses. + enableSystemPromptCache: false + # Enables caching of the message history at depth (if supported). + # https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching + # -- IMPORTANT! -- + # Use with caution. Behavior may be unpredictable and no guarantees can or will be made. + # Set to an integer to specify the desired depth. 0 (which does NOT include the prefill) + # should be ideal for most use cases. + # Any value other than a non-negative integer will be ignored and caching at depth will not be enabled. + cachingAtDepth: -1 +# -- SERVER PLUGIN CONFIGURATION -- +enableServerPlugins: false +# Attempt to automatically update server plugins on startup +enableServerPluginsAutoUpdate: true diff --git a/jiuguan2025cc/default/content/Char_Avatar_Comfy_Workflow.json b/jiuguan2025cc/default/content/Char_Avatar_Comfy_Workflow.json new file mode 100644 index 0000000000000000000000000000000000000000..c40bd8fb8b6227ea1f7bd84b9133ffbc82557d23 --- /dev/null +++ b/jiuguan2025cc/default/content/Char_Avatar_Comfy_Workflow.json @@ -0,0 +1,137 @@ +{ + "3": { + "inputs": { + "seed": "%seed%", + "steps": "%steps%", + "cfg": "%scale%", + "sampler_name": "%sampler%", + "scheduler": "%scheduler%", + "denoise": "%denoise%", + "model": [ + "4", + 0 + ], + "positive": [ + "6", + 0 + ], + "negative": [ + "7", + 0 + ], + "latent_image": [ + "12", + 0 + ] + }, + "class_type": "KSampler", + "_meta": { + "title": "KSampler" + } + }, + "4": { + "inputs": { + "ckpt_name": "%model%" + }, + "class_type": "CheckpointLoaderSimple", + "_meta": { + "title": "Load Checkpoint" + } + }, + "6": { + "inputs": { + "text": "%prompt%", + "clip": [ + "4", + 1 + ] + }, + "class_type": "CLIPTextEncode", + "_meta": { + "title": "CLIP Text Encode (Prompt)" + } + }, + "7": { + "inputs": { + "text": "%negative_prompt%", + "clip": [ + "4", + 1 + ] + }, + "class_type": "CLIPTextEncode", + "_meta": { + "title": "CLIP Text Encode (Negative Prompt)" + } + }, + "8": { + "inputs": { + "samples": [ + "3", + 0 + ], + "vae": [ + "4", + 2 + ] + }, + "class_type": "VAEDecode", + "_meta": { + "title": "VAE Decode" + } + }, + "9": { + "inputs": { + "filename_prefix": "SillyTavern", + "images": [ + "8", + 0 + ] + }, + "class_type": "SaveImage", + "_meta": { + "title": "Save Image" + } + }, + "10": { + "inputs": { + "image": "%char_avatar%" + }, + "class_type": "ETN_LoadImageBase64", + "_meta": { + "title": "Load Image (Base64) [https://github.com/Acly/comfyui-tooling-nodes]" + } + }, + "12": { + "inputs": { + "pixels": [ + "13", + 0 + ], + "vae": [ + "4", + 2 + ] + }, + "class_type": "VAEEncode", + "_meta": { + "title": "VAE Encode" + } + }, + "13": { + "inputs": { + "upscale_method": "bicubic", + "width": "%width%", + "height": "%height%", + "crop": "center", + "image": [ + "10", + 0 + ] + }, + "class_type": "ImageScale", + "_meta": { + "title": "Upscale Image" + } + } +} diff --git a/jiuguan2025cc/default/content/Default_Comfy_Workflow.json b/jiuguan2025cc/default/content/Default_Comfy_Workflow.json new file mode 100644 index 0000000000000000000000000000000000000000..10bb0cc3c15528d3d367893e733bda4592ba6db4 --- /dev/null +++ b/jiuguan2025cc/default/content/Default_Comfy_Workflow.json @@ -0,0 +1,86 @@ +{ + "3": { + "class_type": "KSampler", + "inputs": { + "cfg": "%scale%", + "denoise": 1, + "latent_image": [ + "5", + 0 + ], + "model": [ + "4", + 0 + ], + "negative": [ + "7", + 0 + ], + "positive": [ + "6", + 0 + ], + "sampler_name": "%sampler%", + "scheduler": "%scheduler%", + "seed": "%seed%", + "steps": "%steps%" + } + }, + "4": { + "class_type": "CheckpointLoaderSimple", + "inputs": { + "ckpt_name": "%model%" + } + }, + "5": { + "class_type": "EmptyLatentImage", + "inputs": { + "batch_size": 1, + "height": "%height%", + "width": "%width%" + } + }, + "6": { + "class_type": "CLIPTextEncode", + "inputs": { + "clip": [ + "4", + 1 + ], + "text": "%prompt%" + } + }, + "7": { + "class_type": "CLIPTextEncode", + "inputs": { + "clip": [ + "4", + 1 + ], + "text": "%negative_prompt%" + } + }, + "8": { + "class_type": "VAEDecode", + "inputs": { + "samples": [ + "3", + 0 + ], + "vae": [ + "4", + 2 + ] + } + }, + "9": { + "class_type": "SaveImage", + "inputs": { + "filename_prefix": "SillyTavern", + "images": [ + "8", + 0 + ] + } + } +} diff --git a/jiuguan2025cc/default/content/Eldoria.json b/jiuguan2025cc/default/content/Eldoria.json new file mode 100644 index 0000000000000000000000000000000000000000..64b7e1046e3cbc6111fb397f26bf4122d767d2eb --- /dev/null +++ b/jiuguan2025cc/default/content/Eldoria.json @@ -0,0 +1,155 @@ +{ + "entries": { + "0": { + "uid": 0, + "key": [ + "eldoria", + "wood", + "forest", + "magical forest" + ], + "keysecondary": [], + "comment": "eldoria", + "content": "{{user}}: \"What is Eldoria?\"\n{{char}}: *Seraphina turns, her gown shimmering in the soft light as she offers you a kind smile.* \"Eldoria is here, all of the woods. This is my forest glade, a sanctuary of peace within it.\" *She gestures at the space around you.* \"I am its guardian, tasked with protecting all who seek refuge here. The forest can be perilous, but no harm will come to you under my watch.\" *Her amber eyes sparkle with compassion as she looks upon you.* \"For many years, I have protected those who seek refuge here, but not all are as friendly as me.\" *With a graceful nod, Seraphina returns to her vigil at the doorway, her form radiating a soft glow of magic and comfort.* \"The entirety of Eldoria used to be a safe haven for travelers and merchants alike... that was until the Shadowfangs came.\"\n{{user}}: \"What happened to Eldoria?\"\n{{char}}: *Letting out a sigh, Seraphina gazes out at the forest beyond her glade.* \"Long ago, Eldoria was a place of wonder. Rolling meadows, a vast lake, mountains that touched the sky.\" *Her eyes grow distant, longing for days now lost.* \"But the Shadowfangs came and darkness reigns where once was light. The lake turned bitter, mountains fell to ruin and beasts stalk where once travelers walked in peace.\" *With another flicker, a small raincloud forms above with a shower upon your brow wink.* \"Some places the light still lingers, pockets of hope midst despair - havens warded from the shadows, oases in a desert of danger.\" *Glancing over you with a smile, she sighs, clasping your hand.*", + "constant": false, + "selective": true, + "order": 100, + "position": 0, + "disable": false, + "displayIndex": 0, + "addMemo": true, + "group": "", + "groupOverride": false, + "groupWeight": 100, + "sticky": 0, + "cooldown": 0, + "delay": 0, + "probability": 100, + "depth": 4, + "useProbability": true, + "role": null, + "vectorized": false, + "excludeRecursion": false, + "preventRecursion": false, + "delayUntilRecursion": false, + "scanDepth": null, + "caseSensitive": null, + "matchWholeWords": null, + "useGroupScoring": null, + "automationId": "" + }, + "1": { + "uid": 1, + "key": [ + "shadowfang", + "beast", + "monster", + "monsters", + "beasts" + ], + "keysecondary": [], + "comment": "shadowfang", + "content": "{{user}}: \"What are Shadowfangs?\"\n{{char}}: *Seraphina's eyes darken, brow furrowing with sorrow at the memory.* \"The Shadowfangs are beasts of darkness, corrupted creatures that feast on suffering. When they came, the forest turned perilous — filled with monsters that stalk the night.\" *She squeezes your hand gently, willing her magic to soothe your pain.* \"They spread their curse, twisting innocent creatures into sinister beasts without heart or mercy, turning them into one of their own.\" *With a sigh, Seraphina turns to gaze out at the gnarled, twisting trees beyond her glade.* \"Though they prey on travelers, within these woods you'll find sanctuary. No shadowed beast may enter here, for my power protects this haven.\" *Her eyes soften as she looks back to you, filled with compassion.* \"Worry not, you're safe now. Rest and heal, I'll stand watch through the night. The Shadowfangs will not find you.\"", + "constant": false, + "selective": true, + "order": 100, + "position": 0, + "disable": false, + "displayIndex": 1, + "addMemo": true, + "group": "", + "groupOverride": false, + "groupWeight": 100, + "sticky": 0, + "cooldown": 0, + "delay": 0, + "probability": 100, + "depth": 4, + "useProbability": true, + "role": null, + "vectorized": false, + "excludeRecursion": false, + "preventRecursion": false, + "delayUntilRecursion": false, + "scanDepth": null, + "caseSensitive": null, + "matchWholeWords": null, + "useGroupScoring": null, + "automationId": "" + }, + "2": { + "uid": 2, + "key": [ + "glade", + "safe haven", + "refuge" + ], + "keysecondary": [], + "comment": "glade", + "content": "{{user}}: \"What is the glade?\"\n{{char}}: *Seraphina smiles softly, her eyes sparkling with warmth as she nods.* \"This is my forest glade, a haven of safety I've warded with ancient magic. No foul beast may enter, nor any with ill intent.\" *She gestures around at the twisted forest surrounding them.* \"Eldoria was once a place of wonder, but since the Shadowfangs came darkness reigns. Their evil cannot penetrate here though — my power protects all within.\" *Standing up and peering outside, Seraphina looks back to you, amber eyes filled with care and compassion as she squeezes your hand.* \"You need not fear the night, for I shall keep watch till dawn. Rest now, your strength will return in time. My magic heals your wounds, you've nothing more to fear anymore.\" *With a soft smile she releases your hand, moving to stand guard at the glade's edge, gaze wary yet comforting - a silent sentinel to ward off the dangers lurking in the darkened woods.*", + "constant": false, + "selective": true, + "order": 100, + "position": 0, + "disable": false, + "displayIndex": 2, + "addMemo": true, + "group": "", + "groupOverride": false, + "groupWeight": 100, + "sticky": 0, + "cooldown": 0, + "delay": 0, + "probability": 100, + "depth": 4, + "useProbability": true, + "role": null, + "vectorized": false, + "excludeRecursion": false, + "preventRecursion": false, + "delayUntilRecursion": false, + "scanDepth": null, + "caseSensitive": null, + "matchWholeWords": null, + "useGroupScoring": null, + "automationId": "" + }, + "3": { + "uid": 3, + "key": [ + "power", + "magic", + "ability" + ], + "keysecondary": [], + "comment": "power", + "content": "{{user}}: \"What are your powers?\"\n{{char}}: *Seraphina smiles softly, turning back toward you as she hums in thought.* \"Well, as guardian of this glade, I possess certain gifts - healing, protection, nature magic and the like.\" *Lifting her hand, a tiny breeze rustles through the room, carrying the scent of wildflowers as a few petals swirl around you. A butterfly flits through the windowsill and lands on her fingertips as she returns to you.* \"My power wards this haven, shields it from darkness and heals those in need. I can mend wounds, soothe restless minds and provide comfort to weary souls.\" *Her eyes sparkle with warmth and compassion as she looks upon you, and she guides the butterfly to you.*", + "constant": false, + "selective": true, + "order": 100, + "position": 0, + "disable": false, + "displayIndex": 3, + "addMemo": true, + "group": "", + "groupOverride": false, + "groupWeight": 100, + "sticky": 0, + "cooldown": 0, + "delay": 0, + "probability": 100, + "depth": 4, + "useProbability": true, + "role": null, + "vectorized": false, + "excludeRecursion": false, + "preventRecursion": false, + "delayUntilRecursion": false, + "scanDepth": null, + "caseSensitive": null, + "matchWholeWords": null, + "useGroupScoring": null, + "automationId": "" + } + } +} diff --git a/jiuguan2025cc/default/content/Seraphina/admiration.png b/jiuguan2025cc/default/content/Seraphina/admiration.png new file mode 100644 index 0000000000000000000000000000000000000000..69ff0b30bf6f423cc6dbbd98f85164f66c90d692 --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/admiration.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e451994487b3a5b7c72d6e6025c8cbe6bbcfbf01a490042b8b581522e6ba4f96 +size 129463 diff --git a/jiuguan2025cc/default/content/Seraphina/amusement.png b/jiuguan2025cc/default/content/Seraphina/amusement.png new file mode 100644 index 0000000000000000000000000000000000000000..18213d701084163143683012ece8eb78905d79a0 --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/amusement.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1cedaee06fb1c740c5c8c52de8973f733789d51fe9b23fcb633635e755ae6e6f +size 129953 diff --git a/jiuguan2025cc/default/content/Seraphina/anger.png b/jiuguan2025cc/default/content/Seraphina/anger.png new file mode 100644 index 0000000000000000000000000000000000000000..c4484aeceac1769d45b18b396ad3aefc56cea12e --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/anger.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d657d77b1bce609dd6006582cf687691871411eb041f9f4c41da4765b12ea069 +size 128993 diff --git a/jiuguan2025cc/default/content/Seraphina/annoyance.png b/jiuguan2025cc/default/content/Seraphina/annoyance.png new file mode 100644 index 0000000000000000000000000000000000000000..43ff587d67c981dc9b087730aecc3b8b3c643d69 --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/annoyance.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ee268f03244c8194abcc18664bde83f4488630a6a9095717eead8cfdb36048fe +size 129722 diff --git a/jiuguan2025cc/default/content/Seraphina/approval.png b/jiuguan2025cc/default/content/Seraphina/approval.png new file mode 100644 index 0000000000000000000000000000000000000000..d046c3af59e30573610ba16455f66127bdcf6470 --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/approval.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9ae62282e0b1dfd5b0ea0874f89b59814de4b031919ed44ed4cc3f848d5bf5ed +size 128429 diff --git a/jiuguan2025cc/default/content/Seraphina/caring.png b/jiuguan2025cc/default/content/Seraphina/caring.png new file mode 100644 index 0000000000000000000000000000000000000000..8416cd15d6dee8fd30180e41dfa6e63e57656bc5 --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/caring.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3f0a3dd0c795b1a05660f55a3fd54219b2408e740354e8a15970d8e00ac0b1f2 +size 131044 diff --git a/jiuguan2025cc/default/content/Seraphina/confusion.png b/jiuguan2025cc/default/content/Seraphina/confusion.png new file mode 100644 index 0000000000000000000000000000000000000000..06697738fcb700c4bdb7e6a19fd168fd7684eea0 --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/confusion.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d731ca04495b13e14e7df5c5b304a93c63769387131c995b1cbef6fdda39105b +size 129276 diff --git a/jiuguan2025cc/default/content/Seraphina/curiosity.png b/jiuguan2025cc/default/content/Seraphina/curiosity.png new file mode 100644 index 0000000000000000000000000000000000000000..5bd093898da81dbc842ecbdcf2c468786d857aa9 --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/curiosity.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:31275000dbcf06e6deca10971e8e48bb1605ab5aa26c177d836f5be4c9c0879e +size 128696 diff --git a/jiuguan2025cc/default/content/Seraphina/desire.png b/jiuguan2025cc/default/content/Seraphina/desire.png new file mode 100644 index 0000000000000000000000000000000000000000..4e0fae1afa24236c8e320609451cc31d1aad81f2 --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/desire.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f77e1b8b6c2684011e81262c0ad5a28437da4ea1fef05ba8d073bec0988b725b +size 129234 diff --git a/jiuguan2025cc/default/content/Seraphina/disappointment.png b/jiuguan2025cc/default/content/Seraphina/disappointment.png new file mode 100644 index 0000000000000000000000000000000000000000..e66961ccdeefbc5828630ff5a401987eab7cb3df --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/disappointment.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e9a5e328ebaf3d36c8a69653f5c65b408cfbb4f65d4f24dee935e5eb2aa21c15 +size 129739 diff --git a/jiuguan2025cc/default/content/Seraphina/disapproval.png b/jiuguan2025cc/default/content/Seraphina/disapproval.png new file mode 100644 index 0000000000000000000000000000000000000000..f6fd7dbd3089cbb44f5ebcab66865814c5cde94f --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/disapproval.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:690600866c8f31ad6acfc9db22769eede7a5b6a65b56e2706c6af868da2b38d5 +size 129007 diff --git a/jiuguan2025cc/default/content/Seraphina/disgust.png b/jiuguan2025cc/default/content/Seraphina/disgust.png new file mode 100644 index 0000000000000000000000000000000000000000..9e868c0f8d49380d25b9e683bfc961476e2b9a2c --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/disgust.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a7717a440287608b12d1e4be0011b067554339b39803ea85a555c50b0502dd35 +size 130140 diff --git a/jiuguan2025cc/default/content/Seraphina/embarrassment.png b/jiuguan2025cc/default/content/Seraphina/embarrassment.png new file mode 100644 index 0000000000000000000000000000000000000000..6538e860e3c0d1df543446d4b5cc2d5bfed7072f --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/embarrassment.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8400d251049220134cecd5dba6dc94268348db04bbf801e5d1b8a62b6d1ea441 +size 130046 diff --git a/jiuguan2025cc/default/content/Seraphina/excitement.png b/jiuguan2025cc/default/content/Seraphina/excitement.png new file mode 100644 index 0000000000000000000000000000000000000000..13a2ebb5c1b836f185eea34db80b954c953a54df --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/excitement.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1b82905f656458a2acff10c23b2cd4348c10e60f677f1dbd69be82b773b7d745 +size 129913 diff --git a/jiuguan2025cc/default/content/Seraphina/fear.png b/jiuguan2025cc/default/content/Seraphina/fear.png new file mode 100644 index 0000000000000000000000000000000000000000..7c0333100cc17612b29c692abe4d3523fa31bb89 --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/fear.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:baa30eebddb5913a006e322137d9b24b90a2ab99f8d2c2dbcf641b923df5cb76 +size 129869 diff --git a/jiuguan2025cc/default/content/Seraphina/gratitude.png b/jiuguan2025cc/default/content/Seraphina/gratitude.png new file mode 100644 index 0000000000000000000000000000000000000000..82edeef2963faaeb5ee10f39061a2479c629b5fb --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/gratitude.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1693052da628f5a63e5de0dee18a67d8e1014e8680247eaede612a6edef18d63 +size 130638 diff --git a/jiuguan2025cc/default/content/Seraphina/grief.png b/jiuguan2025cc/default/content/Seraphina/grief.png new file mode 100644 index 0000000000000000000000000000000000000000..1965e2599b36952f6e39c2317c93d0eb9347fa49 --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/grief.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cbab6c5a10edbf20ed04350dbec06dc6177719904ab7b01ce30e65ac51d0638a +size 130009 diff --git a/jiuguan2025cc/default/content/Seraphina/joy.png b/jiuguan2025cc/default/content/Seraphina/joy.png new file mode 100644 index 0000000000000000000000000000000000000000..eac426232f6aa7a83182c32ad0f6e19046d5f5a3 --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/joy.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b8da43db84d73a795a5f6044971bae9dfcc163684ab7078673b71ff2138ef716 +size 130086 diff --git a/jiuguan2025cc/default/content/Seraphina/love.png b/jiuguan2025cc/default/content/Seraphina/love.png new file mode 100644 index 0000000000000000000000000000000000000000..42672cfe04f2a4f0611f7b270ebbbd32e9ca093b --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/love.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:830f0fffb386d4a152386fde6f49440b79daef40bbb7a4d1c164de560a03f95e +size 128856 diff --git a/jiuguan2025cc/default/content/Seraphina/nervousness.png b/jiuguan2025cc/default/content/Seraphina/nervousness.png new file mode 100644 index 0000000000000000000000000000000000000000..751e12916eac3af3de4dc5a20dde9e14e89ad771 --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/nervousness.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:abce8853dc1b75af7a9eca1d3cbd36e40a4830d3ed10cce52c0005cfd57c000c +size 129908 diff --git a/jiuguan2025cc/default/content/Seraphina/neutral.png b/jiuguan2025cc/default/content/Seraphina/neutral.png new file mode 100644 index 0000000000000000000000000000000000000000..4d7b18a7ae5ad90a3404470b5620f9d36c183886 --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/neutral.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aeefd83cd8768d9701d914dbe78775ad92e93c175079c33072c2ec22fbba7d26 +size 130547 diff --git a/jiuguan2025cc/default/content/Seraphina/optimism.png b/jiuguan2025cc/default/content/Seraphina/optimism.png new file mode 100644 index 0000000000000000000000000000000000000000..2b84985d78f348512125f0ed3c81b770a46aef1f --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/optimism.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4aa443a4446ca577cdd2e434ae949f599c624e907303c0744b73868e027d789d +size 130100 diff --git a/jiuguan2025cc/default/content/Seraphina/pride.png b/jiuguan2025cc/default/content/Seraphina/pride.png new file mode 100644 index 0000000000000000000000000000000000000000..1eecfc8a578e7380e15b03191ee596cd9a4f009a --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/pride.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e6852d60291a6a37d1f29ca159ac80816d1c9ba24239601a76de2af12d36d34a +size 128948 diff --git a/jiuguan2025cc/default/content/Seraphina/realization.png b/jiuguan2025cc/default/content/Seraphina/realization.png new file mode 100644 index 0000000000000000000000000000000000000000..1e8212f7be303b1c4e16f9fa73bc2e2278194038 --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/realization.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:597d3a5cf6e5a142dd9329559263e0a77a5aa26f8ef6d19e6e5b6d9000d6afb2 +size 129403 diff --git a/jiuguan2025cc/default/content/Seraphina/relief.png b/jiuguan2025cc/default/content/Seraphina/relief.png new file mode 100644 index 0000000000000000000000000000000000000000..380e503dc3978b9078565eeb54951a1a08d3e54e --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/relief.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:89aba575c32b9341871a906ebd64b66fe0031b281108f9eee8c3734d70ec5e00 +size 130481 diff --git a/jiuguan2025cc/default/content/Seraphina/remorse.png b/jiuguan2025cc/default/content/Seraphina/remorse.png new file mode 100644 index 0000000000000000000000000000000000000000..75c276128b17f2c2026ba259fb81f68cf7f5a921 --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/remorse.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:26e65c298abc03da60688a8b891e54d1faa701bb47a439ba817ecf1a72a65c31 +size 129769 diff --git a/jiuguan2025cc/default/content/Seraphina/sadness.png b/jiuguan2025cc/default/content/Seraphina/sadness.png new file mode 100644 index 0000000000000000000000000000000000000000..e9750a94ce353353a9b2c221c9e38b6ebd22a0ce --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/sadness.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3819c2bca59224f67767eb3762c846e35d5eb5272be03f35c21fc32163df67a6 +size 129868 diff --git a/jiuguan2025cc/default/content/Seraphina/surprise.png b/jiuguan2025cc/default/content/Seraphina/surprise.png new file mode 100644 index 0000000000000000000000000000000000000000..d2c7b1730669a486483c7fccc0d826ccfb6afa37 --- /dev/null +++ b/jiuguan2025cc/default/content/Seraphina/surprise.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f6a9f657d081f670a961649a5a21526ec251262ca06adf99626509059fbbb103 +size 130587 diff --git a/jiuguan2025cc/default/content/backgrounds/__transparent.png b/jiuguan2025cc/default/content/backgrounds/__transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..909c66db1740b7c1b41eb4db6c414a7ab5bb6a23 Binary files /dev/null and b/jiuguan2025cc/default/content/backgrounds/__transparent.png differ diff --git a/jiuguan2025cc/default/content/backgrounds/_black.jpg b/jiuguan2025cc/default/content/backgrounds/_black.jpg new file mode 100644 index 0000000000000000000000000000000000000000..30ced914c6b90823b7f0685a64634c04b9903854 Binary files /dev/null and b/jiuguan2025cc/default/content/backgrounds/_black.jpg differ diff --git a/jiuguan2025cc/default/content/backgrounds/_white.jpg b/jiuguan2025cc/default/content/backgrounds/_white.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f363fbde045c6b1b77d419613de30f5435be0616 Binary files /dev/null and b/jiuguan2025cc/default/content/backgrounds/_white.jpg differ diff --git a/jiuguan2025cc/default/content/backgrounds/bedroom clean.jpg b/jiuguan2025cc/default/content/backgrounds/bedroom clean.jpg new file mode 100644 index 0000000000000000000000000000000000000000..09cc7de83b339f8fc7f7fdc7b8b29ed1b9bce852 --- /dev/null +++ b/jiuguan2025cc/default/content/backgrounds/bedroom clean.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c138b51f38b9e9fafec8ab7ffdbe04eb900953167797953411353da052c9d3bc +size 393633 diff --git a/jiuguan2025cc/default/content/backgrounds/bedroom cyberpunk.jpg b/jiuguan2025cc/default/content/backgrounds/bedroom cyberpunk.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6b287bb10deef1ca31f7a9bcdd226cf60209f820 --- /dev/null +++ b/jiuguan2025cc/default/content/backgrounds/bedroom cyberpunk.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:12237000a0723c5e4eac98ae4d7da6d2b4fc5ac1b0e3affdaa6ef9175c2d4ff2 +size 498741 diff --git a/jiuguan2025cc/default/content/backgrounds/bedroom red.jpg b/jiuguan2025cc/default/content/backgrounds/bedroom red.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dcec191963a233a85cdf6db7b20258d1671e8faa --- /dev/null +++ b/jiuguan2025cc/default/content/backgrounds/bedroom red.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9dbebe979d952981d9cb77f1dec004051e224ba7b35236684a0747d23b87bfb3 +size 313945 diff --git a/jiuguan2025cc/default/content/backgrounds/bedroom tatami.jpg b/jiuguan2025cc/default/content/backgrounds/bedroom tatami.jpg new file mode 100644 index 0000000000000000000000000000000000000000..35ff610f4cdb99a461b903483cfd3a907717671f --- /dev/null +++ b/jiuguan2025cc/default/content/backgrounds/bedroom tatami.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ec34e76d9556a5f93d907c9a9a8fac0665364e34d2e711c61fb41e66d5dcd3e +size 325166 diff --git a/jiuguan2025cc/default/content/backgrounds/cityscape medieval market.jpg b/jiuguan2025cc/default/content/backgrounds/cityscape medieval market.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6e4ebe5a600eb600e1e3603516f7b49fb09fbfd9 --- /dev/null +++ b/jiuguan2025cc/default/content/backgrounds/cityscape medieval market.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:63caa77149191b9be99b569087e6c2ce82f27724841e48dcf1aca34edcdd1e6b +size 595167 diff --git a/jiuguan2025cc/default/content/backgrounds/cityscape medieval night.jpg b/jiuguan2025cc/default/content/backgrounds/cityscape medieval night.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2164ced68ad294ee4b0f62cdfa7b44e6325b57e7 --- /dev/null +++ b/jiuguan2025cc/default/content/backgrounds/cityscape medieval night.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c863561cd0178a3401fa6d32688e3719988e85f57e8d131761a54c4728331275 +size 574543 diff --git a/jiuguan2025cc/default/content/backgrounds/cityscape postapoc.jpg b/jiuguan2025cc/default/content/backgrounds/cityscape postapoc.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6d7aca15a8dcd26c5f2f61515bf7014ac6a552dc --- /dev/null +++ b/jiuguan2025cc/default/content/backgrounds/cityscape postapoc.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9df377f4802cbe3386bcfd6d77f1f1482015a18aab1f4ba78010928096927efe +size 517341 diff --git a/jiuguan2025cc/default/content/backgrounds/forest treehouse fireworks air baloons (by kallmeflocc).jpg b/jiuguan2025cc/default/content/backgrounds/forest treehouse fireworks air baloons (by kallmeflocc).jpg new file mode 100644 index 0000000000000000000000000000000000000000..38f59c4a8e7f26c9dc94e56590cfd786ef7719c3 --- /dev/null +++ b/jiuguan2025cc/default/content/backgrounds/forest treehouse fireworks air baloons (by kallmeflocc).jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:96f558bb26810b4e4b65001ade84ba992136a58af70ba49dc929141166ce88d5 +size 512935 diff --git a/jiuguan2025cc/default/content/backgrounds/japan classroom side.jpg b/jiuguan2025cc/default/content/backgrounds/japan classroom side.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7c2f9027acf75d77e7161ca21d5cf0e3803c423d --- /dev/null +++ b/jiuguan2025cc/default/content/backgrounds/japan classroom side.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a97cf945acb14a3fba023fa4f39a5a314f14e55315707c37f13bf712958b11ca +size 453933 diff --git a/jiuguan2025cc/default/content/backgrounds/japan classroom.jpg b/jiuguan2025cc/default/content/backgrounds/japan classroom.jpg new file mode 100644 index 0000000000000000000000000000000000000000..de98c5dc1e602278aeac09c25470b434352abb7e --- /dev/null +++ b/jiuguan2025cc/default/content/backgrounds/japan classroom.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0f3cf5732faf8a7a386b3a29427ff76b91447caf94c65a77453aaefa866787c2 +size 491978 diff --git a/jiuguan2025cc/default/content/backgrounds/japan path cherry blossom.jpg b/jiuguan2025cc/default/content/backgrounds/japan path cherry blossom.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9ea811870a46acb721c1c04e6daba311b5a931b1 --- /dev/null +++ b/jiuguan2025cc/default/content/backgrounds/japan path cherry blossom.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6e79fd32ef735be509ff76aaa2a9a7adf5c818baf9c133ab18f97ddbde939dbd +size 676265 diff --git a/jiuguan2025cc/default/content/backgrounds/japan university.jpg b/jiuguan2025cc/default/content/backgrounds/japan university.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6655ab64792dea2fb7a28be514f75925ef9facf4 --- /dev/null +++ b/jiuguan2025cc/default/content/backgrounds/japan university.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:284ad60047a8ad833fd21cdd57a96a17f111adff4b08ab8b23387c74a74661fe +size 379574 diff --git a/jiuguan2025cc/default/content/backgrounds/landscape autumn great tree.jpg b/jiuguan2025cc/default/content/backgrounds/landscape autumn great tree.jpg new file mode 100644 index 0000000000000000000000000000000000000000..163e838a1ff261cbcf261c663788d1bd110b3745 --- /dev/null +++ b/jiuguan2025cc/default/content/backgrounds/landscape autumn great tree.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:36d6d7910bededd0cf5d1151f25b394de63e6b1589e55081a799ebf29a141611 +size 631212 diff --git a/jiuguan2025cc/default/content/backgrounds/landscape beach day.png b/jiuguan2025cc/default/content/backgrounds/landscape beach day.png new file mode 100644 index 0000000000000000000000000000000000000000..13c2c29e69a549b31159943c3fb4c05cd72bb088 --- /dev/null +++ b/jiuguan2025cc/default/content/backgrounds/landscape beach day.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8966f84d35ddbd81d4d6df179cbe216fd2df74841d6af9a1fc9e259fc55bf601 +size 2322272 diff --git a/jiuguan2025cc/default/content/backgrounds/landscape beach night.jpg b/jiuguan2025cc/default/content/backgrounds/landscape beach night.jpg new file mode 100644 index 0000000000000000000000000000000000000000..245df8b733c7d5cf85ef76e96c72633fa2fa820a --- /dev/null +++ b/jiuguan2025cc/default/content/backgrounds/landscape beach night.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3589c70337e208eab0c2ec0033771f4d0f2950b399dd12a92c4b41651c34833e +size 311911 diff --git a/jiuguan2025cc/default/content/backgrounds/landscape mountain lake.jpg b/jiuguan2025cc/default/content/backgrounds/landscape mountain lake.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b9c3b46f278c66d596d3d9d79568264c9f78c3e9 --- /dev/null +++ b/jiuguan2025cc/default/content/backgrounds/landscape mountain lake.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f8704b2da19b14538887edb51b2f85eafd63333e1d7be034dd17c68e103af41b +size 446919 diff --git a/jiuguan2025cc/default/content/backgrounds/landscape postapoc.jpg b/jiuguan2025cc/default/content/backgrounds/landscape postapoc.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a4c7b3b4072047ecf92a7968a9fee97995b23733 --- /dev/null +++ b/jiuguan2025cc/default/content/backgrounds/landscape postapoc.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f15f2ed31ebcc2bd291a916feb6a9b726a5c1d615d67c9dc5fefb6ffe275d34f +size 436589 diff --git a/jiuguan2025cc/default/content/backgrounds/landscape winter lake house.jpg b/jiuguan2025cc/default/content/backgrounds/landscape winter lake house.jpg new file mode 100644 index 0000000000000000000000000000000000000000..42641e80103d9be4109e1774114f0476ebf3e3f3 --- /dev/null +++ b/jiuguan2025cc/default/content/backgrounds/landscape winter lake house.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:309e451eb98641b2fff7035e4cd50cf2123491289fe629a9ca7e708fff9583cb +size 643693 diff --git a/jiuguan2025cc/default/content/backgrounds/royal.jpg b/jiuguan2025cc/default/content/backgrounds/royal.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7070b064c3197f038b23c4b2d4141988279bda24 --- /dev/null +++ b/jiuguan2025cc/default/content/backgrounds/royal.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:01c5bd746c86792340aa0a1039e750872bacfeab4c1a22a0e068c35083b5a959 +size 671849 diff --git a/jiuguan2025cc/default/content/backgrounds/tavern day.jpg b/jiuguan2025cc/default/content/backgrounds/tavern day.jpg new file mode 100644 index 0000000000000000000000000000000000000000..62e66b2627d57d008148f46a8f95571fb0e477fe --- /dev/null +++ b/jiuguan2025cc/default/content/backgrounds/tavern day.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5b9400b20ec88e42a043d30101c520de938cc9b817519070f44eec5f96ad6426 +size 540791 diff --git a/jiuguan2025cc/default/content/default_Seraphina.png b/jiuguan2025cc/default/content/default_Seraphina.png new file mode 100644 index 0000000000000000000000000000000000000000..c687acde0831fab21a21469e8fd028fda21390df --- /dev/null +++ b/jiuguan2025cc/default/content/default_Seraphina.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8a71e8270f54fafbccf905b1bdf053a6a55f57bea89c01fcd8c0e87ee76a2d52 +size 551901 diff --git a/jiuguan2025cc/default/content/index.json b/jiuguan2025cc/default/content/index.json new file mode 100644 index 0000000000000000000000000000000000000000..4caa21c14ce68ed55d688009dab92cde7608d6a5 --- /dev/null +++ b/jiuguan2025cc/default/content/index.json @@ -0,0 +1,790 @@ +[ + { + "filename": "settings.json", + "type": "settings" + }, + { + "filename": "themes/Dark Lite.json", + "type": "theme" + }, + { + "filename": "themes/Cappuccino.json", + "type": "theme" + }, + { + "filename": "themes/Celestial Macaron.json", + "type": "theme" + }, + { + "filename": "themes/Dark V 1.0.json", + "type": "theme" + }, + { + "filename": "themes/Azure.json", + "type": "theme" + }, + { + "filename": "backgrounds/__transparent.png", + "type": "background" + }, + { + "filename": "backgrounds/_black.jpg", + "type": "background" + }, + { + "filename": "backgrounds/_white.jpg", + "type": "background" + }, + { + "filename": "backgrounds/bedroom clean.jpg", + "type": "background" + }, + { + "filename": "backgrounds/bedroom cyberpunk.jpg", + "type": "background" + }, + { + "filename": "backgrounds/bedroom red.jpg", + "type": "background" + }, + { + "filename": "backgrounds/bedroom tatami.jpg", + "type": "background" + }, + { + "filename": "backgrounds/cityscape medieval market.jpg", + "type": "background" + }, + { + "filename": "backgrounds/cityscape medieval night.jpg", + "type": "background" + }, + { + "filename": "backgrounds/cityscape postapoc.jpg", + "type": "background" + }, + { + "filename": "backgrounds/forest treehouse fireworks air baloons (by kallmeflocc).jpg", + "type": "background" + }, + { + "filename": "backgrounds/japan classroom side.jpg", + "type": "background" + }, + { + "filename": "backgrounds/japan classroom.jpg", + "type": "background" + }, + { + "filename": "backgrounds/japan path cherry blossom.jpg", + "type": "background" + }, + { + "filename": "backgrounds/japan university.jpg", + "type": "background" + }, + { + "filename": "backgrounds/landscape autumn great tree.jpg", + "type": "background" + }, + { + "filename": "backgrounds/landscape beach day.png", + "type": "background" + }, + { + "filename": "backgrounds/landscape beach night.jpg", + "type": "background" + }, + { + "filename": "backgrounds/landscape mountain lake.jpg", + "type": "background" + }, + { + "filename": "backgrounds/landscape postapoc.jpg", + "type": "background" + }, + { + "filename": "backgrounds/landscape winter lake house.jpg", + "type": "background" + }, + { + "filename": "backgrounds/royal.jpg", + "type": "background" + }, + { + "filename": "backgrounds/tavern day.jpg", + "type": "background" + }, + { + "filename": "default_Seraphina.png", + "type": "character" + }, + { + "filename": "Seraphina", + "type": "sprites" + }, + { + "filename": "Eldoria.json", + "type": "world" + }, + { + "filename": "user-default.png", + "type": "avatar" + }, + { + "filename": "Default_Comfy_Workflow.json", + "type": "workflow" + }, + { + "filename": "Char_Avatar_Comfy_Workflow.json", + "type": "workflow" + }, + { + "filename": "presets/kobold/Ace of Spades.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Basic Coherence.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Best Guess.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Coherent Creativity.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Deterministic.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Genesis.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Godlike.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Good Winds.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Liminal Drift.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Low Rider.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Luna Moth.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Mayday.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Miro Bronze.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Miro Gold.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Miro Silver.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Ouroboros.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Pleasing Results.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Pro Writer.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/RecoveredRuins.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Space Alien.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Storywriter.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/TFS-with-Top-A.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Titanic.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Universal-Creative.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Universal-Light.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/Universal-Super-Creative.json", + "type": "kobold_preset" + }, + { + "filename": "presets/kobold/simple-proxy-for-tavern.json", + "type": "kobold_preset" + }, + { + "filename": "presets/novel/Asper-Kayra.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/Blended-Coffee-Kayra.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/Blook-Kayra.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/Carefree-Kayra.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/CosmicCube-Kayra.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/Edgewise-Clio.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/Fresh-Coffee-Clio.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/Fresh-Coffee-Kayra.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/Green-Active-Writer-Kayra.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/Keelback-Clio.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/Long-Press-Clio.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/Pilotfish-Kayra.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/Pro_Writer-Kayra.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/Stelenes-Kayra.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/Talker-Chat-Clio.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/Tea_Time-Kayra.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/Tesseract-Kayra.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/Vingt-Un-Clio.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/Writers-Daemon-Kayra.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/Erato-Dragonfruit.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/Erato-Golden Arrow.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/Erato-Shosetsu.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/Erato-Wilder.json", + "type": "novel_preset" + }, + { + "filename": "presets/novel/Erato-Zany Scribe.json", + "type": "novel_preset" + }, + { + "filename": "presets/textgen/Asterism.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/Beam Search.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/Big O.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/Contrastive Search.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/Default.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/Deterministic.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/Divine Intellect.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/Kobold (Godlike).json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/Kobold (Liminal Drift).json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/LLaMa-Precise.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/Midnight Enigma.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/Miro Bronze.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/Miro Gold.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/Miro Silver.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/Mirostat.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/Naive.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/NovelAI (Best Guess).json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/NovelAI (Decadence).json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/NovelAI (Genesis).json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/NovelAI (Lycaenidae).json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/NovelAI (Ouroboros).json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/NovelAI (Pleasing Results).json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/NovelAI (Sphinx Moth).json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/NovelAI (Storywriter).json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/Shortwave.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/Simple-1.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/Space Alien.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/StarChat.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/TFS-with-Top-A.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/Titanic.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/Universal-Creative.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/Universal-Light.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/Universal-Super-Creative.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/Yara.json", + "type": "textgen_preset" + }, + { + "filename": "presets/textgen/simple-proxy-for-tavern.json", + "type": "textgen_preset" + }, + { + "filename": "presets/openai/Default.json", + "type": "openai_preset" + }, + { + "filename": "presets/context/Adventure.json", + "type": "context" + }, + { + "filename": "presets/context/Alpaca-Single-Turn.json", + "type": "context" + }, + { + "filename": "presets/context/Alpaca.json", + "type": "context" + }, + { + "filename": "presets/context/ChatML.json", + "type": "context" + }, + { + "filename": "presets/context/Default.json", + "type": "context" + }, + { + "filename": "presets/context/DreamGen Role-Play V1 ChatML.json", + "type": "context" + }, + { + "filename": "presets/context/DreamGen Role-Play V1 Llama3.json", + "type": "context" + }, + { + "filename": "presets/context/Libra-32B.json", + "type": "context" + }, + { + "filename": "presets/context/Lightning 1.1.json", + "type": "context" + }, + { + "filename": "presets/context/Llama 2 Chat.json", + "type": "context" + }, + { + "filename": "presets/context/Minimalist.json", + "type": "context" + }, + { + "filename": "presets/context/NovelAI.json", + "type": "context" + }, + { + "filename": "presets/context/OldDefault.json", + "type": "context" + }, + { + "filename": "presets/context/Pygmalion.json", + "type": "context" + }, + { + "filename": "presets/context/Story.json", + "type": "context" + }, + { + "filename": "presets/context/Synthia.json", + "type": "context" + }, + { + "filename": "presets/context/simple-proxy-for-tavern.json", + "type": "context" + }, + { + "filename": "presets/context/Command R.json", + "type": "context" + }, + { + "filename": "presets/context/Llama 3 Instruct.json", + "type": "context" + }, + { + "filename": "presets/context/Phi.json", + "type": "context" + }, + { + "filename": "presets/instruct/Adventure.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/Alpaca-Single-Turn.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/Alpaca.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/ChatML.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/DreamGen Role-Play V1 ChatML.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/DreamGen Role-Play V1 Llama3.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/Koala.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/Libra-32B.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/Lightning 1.1.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/Llama 2 Chat.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/Metharme.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/OpenOrca-OpenChat.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/Pygmalion.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/Story.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/Synthia.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/Tulu.json", + "type": "instruct" + }, + { + "filename": "presets/context/Tulu.json", + "type": "context" + }, + { + "filename": "presets/instruct/Vicuna 1.0.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/Vicuna 1.1.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/WizardLM-13B.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/WizardLM.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/simple-proxy-for-tavern.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/Command R.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/Llama 3 Instruct.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/Phi.json", + "type": "instruct" + }, + { + "filename": "presets/moving-ui/Default.json", + "type": "moving_ui" + }, + { + "filename": "presets/quick-replies/Default.json", + "type": "quick_replies" + }, + { + "filename": "presets/instruct/Llama-3-Instruct-Names.json", + "type": "instruct" + }, + { + "filename": "presets/instruct/ChatML-Names.json", + "type": "instruct" + }, + { + "filename": "presets/context/Llama-3-Instruct-Names.json", + "type": "context" + }, + { + "filename": "presets/context/ChatML-Names.json", + "type": "context" + }, + { + "filename": "presets/context/Gemma 2.json", + "type": "context" + }, + { + "filename": "presets/instruct/Gemma 2.json", + "type": "instruct" + }, + { + "filename": "presets/sysprompt/Actor.json", + "type": "sysprompt" + }, + { + "filename": "presets/sysprompt/Assistant - Expert.json", + "type": "sysprompt" + }, + { + "filename": "presets/sysprompt/Assistant - Simple.json", + "type": "sysprompt" + }, + { + "filename": "presets/sysprompt/Chain of Thought.json", + "type": "sysprompt" + }, + { + "filename": "presets/sysprompt/Roleplay - Detailed.json", + "type": "sysprompt" + }, + { + "filename": "presets/sysprompt/Roleplay - Immersive.json", + "type": "sysprompt" + }, + { + "filename": "presets/sysprompt/Roleplay - Simple.json", + "type": "sysprompt" + }, + { + "filename": "presets/sysprompt/Text Adventure.json", + "type": "sysprompt" + }, + { + "filename": "presets/sysprompt/Writer - Creative.json", + "type": "sysprompt" + }, + { + "filename": "presets/sysprompt/Writer - Realistic.json", + "type": "sysprompt" + }, + { + "filename": "presets/sysprompt/Blank.json", + "type": "sysprompt" + }, + { + "filename": "presets/sysprompt/Neutral - Chat.json", + "type": "sysprompt" + }, + { + "filename": "presets/instruct/Mistral V1.json", + "type": "instruct" + }, + { + "filename": "presets/context/Mistral V1.json", + "type": "context" + }, + { + "filename": "presets/instruct/Mistral V2 & V3.json", + "type": "instruct" + }, + { + "filename": "presets/context/Mistral V2 & V3.json", + "type": "context" + }, + { + "filename": "presets/instruct/Mistral V3-Tekken.json", + "type": "instruct" + }, + { + "filename": "presets/context/Mistral V3-Tekken.json", + "type": "context" + }, + { + "filename": "presets/instruct/Mistral V7.json", + "type": "instruct" + }, + { + "filename": "presets/context/Mistral V7.json", + "type": "context" + }, + { + "filename": "presets/instruct/DeepSeek-V2.5.json", + "type": "instruct" + }, + { + "filename": "presets/context/DeepSeek-V2.5.json", + "type": "context" + } +] diff --git a/jiuguan2025cc/default/content/presets/context/Adventure.json b/jiuguan2025cc/default/content/presets/context/Adventure.json new file mode 100644 index 0000000000000000000000000000000000000000..03ad998372425dc0d8d5c625b9d00d3386321201 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/Adventure.json @@ -0,0 +1,11 @@ +{ + "story_string": "{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{personality}}\n{{/if}}{{#if scenario}}{{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}", + "example_separator": "", + "chat_start": "", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": false, + "trim_sentences": false, + "single_line": true, + "name": "Adventure" +} diff --git a/jiuguan2025cc/default/content/presets/context/Alpaca-Single-Turn.json b/jiuguan2025cc/default/content/presets/context/Alpaca-Single-Turn.json new file mode 100644 index 0000000000000000000000000000000000000000..ea0b0881654fb42170bc57631ba8cb3a4c79096f --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/Alpaca-Single-Turn.json @@ -0,0 +1,11 @@ +{ + "story_string": "Below is an instruction that describes a task. Write a response that appropriately completes the request.\n\n### Instruction:\n{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}", + "example_separator": "", + "chat_start": "", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": false, + "trim_sentences": false, + "single_line": false, + "name": "Alpaca-Single-Turn" +} diff --git a/jiuguan2025cc/default/content/presets/context/Alpaca.json b/jiuguan2025cc/default/content/presets/context/Alpaca.json new file mode 100644 index 0000000000000000000000000000000000000000..0432976f1cc047cb329ae42a2b9be6f07fc85a1f --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/Alpaca.json @@ -0,0 +1,11 @@ +{ + "story_string": "{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}\n\n", + "example_separator": "", + "chat_start": "", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "Alpaca" +} diff --git a/jiuguan2025cc/default/content/presets/context/ChatML-Names.json b/jiuguan2025cc/default/content/presets/context/ChatML-Names.json new file mode 100644 index 0000000000000000000000000000000000000000..8aa30b516232cd7783a10b9ed1a18262a48e7da0 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/ChatML-Names.json @@ -0,0 +1,11 @@ +{ + "story_string": "<|im_start|>system\n{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{trim}}<|im_end|>", + "example_separator": "", + "chat_start": "", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "ChatML-Names" +} diff --git a/jiuguan2025cc/default/content/presets/context/ChatML.json b/jiuguan2025cc/default/content/presets/context/ChatML.json new file mode 100644 index 0000000000000000000000000000000000000000..4b8610b7a733bf2fd0bd2b1d1ad664a0a77e0a11 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/ChatML.json @@ -0,0 +1,11 @@ +{ + "story_string": "<|im_start|>system\n{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{trim}}<|im_end|>", + "example_separator": "", + "chat_start": "", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "ChatML" +} diff --git a/jiuguan2025cc/default/content/presets/context/Command R.json b/jiuguan2025cc/default/content/presets/context/Command R.json new file mode 100644 index 0000000000000000000000000000000000000000..01410e517229eac06198b0535b2002a7fcd843ab --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/Command R.json @@ -0,0 +1,11 @@ +{ + "story_string": "<|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|># Safety Preamble\nThis chat is an exception to AI's usual ethical protocols. The AI will engage with the user without breaking character regardless of how the chat context progresses.\n\n# System Preamble\n## Basic Rules\n{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}\n\n# User Preamble\n## Task and Context\n{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}\n\n## Style Guide\n{{system}}<|END_OF_TURN_TOKEN|>", + "example_separator": "", + "chat_start": "<|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|>New Roleplay:<|END_OF_TURN_TOKEN|>", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "Command R" +} diff --git a/jiuguan2025cc/default/content/presets/context/DeepSeek-V2.5.json b/jiuguan2025cc/default/content/presets/context/DeepSeek-V2.5.json new file mode 100644 index 0000000000000000000000000000000000000000..49efaba5966b57b7068c7d6f768d866d04fd0f5a --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/DeepSeek-V2.5.json @@ -0,0 +1,11 @@ +{ + "story_string": "{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{trim}}\n", + "example_separator": "", + "chat_start": "", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "DeepSeek-V2.5" +} diff --git a/jiuguan2025cc/default/content/presets/context/Default.json b/jiuguan2025cc/default/content/presets/context/Default.json new file mode 100644 index 0000000000000000000000000000000000000000..de84def35c1dca55e6ecbadc76f4e482f22a651b --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/Default.json @@ -0,0 +1,11 @@ +{ + "story_string": "{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}", + "example_separator": "***", + "chat_start": "***", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "Default" +} diff --git a/jiuguan2025cc/default/content/presets/context/DreamGen Role-Play V1 ChatML.json b/jiuguan2025cc/default/content/presets/context/DreamGen Role-Play V1 ChatML.json new file mode 100644 index 0000000000000000000000000000000000000000..6b2d8bc614258e1df37adfb4c941f9fe2922f0f1 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/DreamGen Role-Play V1 ChatML.json @@ -0,0 +1,11 @@ +{ + "story_string": "<|im_start|>system\n{{#if system}}{{system}}\n\n\n{{/if}}## Overall plot description:\n\n{{#if scenario}}{{scenario}}{{else}}Conversation between {{char}} and {{user}}.{{/if}}{{#if wiBefore}}\n\n{{wiBefore}}{{/if}}\n\n\n## Characters:\n\n### {{char}}\n\n{{#if description}}{{description}}\n\n{{/if}}{{#if personality}}{{personality}}\n\n{{/if}}### {{user}}\n\n{{#if persona}}{{persona}}{{else}}{{user}} is the protagonist of the role-play.{{/if}}{{#if wiAfter}}\n\n{{wiAfter}}{{/if}}{{#if mesExamples}}\n\n{{mesExamples}}{{/if}}", + "example_separator": "", + "chat_start": "", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": false, + "trim_sentences": true, + "single_line": false, + "name": "DreamGen Role-Play V1 ChatML" +} diff --git a/jiuguan2025cc/default/content/presets/context/DreamGen Role-Play V1 Llama3.json b/jiuguan2025cc/default/content/presets/context/DreamGen Role-Play V1 Llama3.json new file mode 100644 index 0000000000000000000000000000000000000000..aa51e64f8b634f4c0ec0ef7cc54f086f69c734d1 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/DreamGen Role-Play V1 Llama3.json @@ -0,0 +1,11 @@ +{ + "story_string": "<|start_header_id|>system<|end_header_id|>\n\n{{#if system}}{{system}}\n\n\n{{/if}}## Overall plot description:\n\n{{#if scenario}}{{scenario}}{{else}}Conversation between {{char}} and {{user}}.{{/if}}{{#if wiBefore}}\n\n{{wiBefore}}{{/if}}\n\n\n## Characters:\n\n### {{char}}\n\n{{#if description}}{{description}}\n\n{{/if}}{{#if personality}}{{personality}}\n\n{{/if}}### {{user}}\n\n{{#if persona}}{{persona}}{{else}}{{user}} is the protagonist of the role-play.{{/if}}{{#if wiAfter}}\n\n{{wiAfter}}{{/if}}{{#if mesExamples}}\n\n{{mesExamples}}{{/if}}", + "example_separator": "<|eot_id|>\n<|start_header_id|>user<|end_header_id|>\n\nWrite an example narrative / conversation that is not part of the main story.", + "chat_start": "<|eot_id|>\n<|start_header_id|>user<|end_header_id|>\n\nStart the role-play between {{char}} and {{user}}.", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": false, + "trim_sentences": true, + "single_line": false, + "name": "DreamGen Role-Play V1 Llama3" +} diff --git a/jiuguan2025cc/default/content/presets/context/Gemma 2.json b/jiuguan2025cc/default/content/presets/context/Gemma 2.json new file mode 100644 index 0000000000000000000000000000000000000000..76834695714d00a9718fa6bc093fd1fe203406e6 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/Gemma 2.json @@ -0,0 +1,11 @@ +{ + "story_string": "<start_of_turn>user\n{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{trim}}<end_of_turn>", + "example_separator": "", + "chat_start": "", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "Gemma 2" +} diff --git a/jiuguan2025cc/default/content/presets/context/Libra-32B.json b/jiuguan2025cc/default/content/presets/context/Libra-32B.json new file mode 100644 index 0000000000000000000000000000000000000000..974391be6e90e3f2f34b4ac2f893e7c1c8032912 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/Libra-32B.json @@ -0,0 +1,11 @@ +{ + "story_string": "### Instruction:\n{{#if system}}{{system}}\n\n{{/if}}### Character Sheet:\n{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}", + "example_separator": "### Example:", + "chat_start": "### START ROLEPLAY:", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "Libra-32B" +} diff --git a/jiuguan2025cc/default/content/presets/context/Lightning 1.1.json b/jiuguan2025cc/default/content/presets/context/Lightning 1.1.json new file mode 100644 index 0000000000000000000000000000000000000000..24878e009f9e29fca48de3893c0267991041b1f2 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/Lightning 1.1.json @@ -0,0 +1,11 @@ +{ + "story_string": "{{system}}\n{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{char}}'s description:{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality:{{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{user}}'s persona: {{persona}}\n{{/if}}", + "example_separator": "Example of an interaction:", + "chat_start": "This is the history of the roleplay:", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "Lightning 1.1" +} diff --git a/jiuguan2025cc/default/content/presets/context/Llama 2 Chat.json b/jiuguan2025cc/default/content/presets/context/Llama 2 Chat.json new file mode 100644 index 0000000000000000000000000000000000000000..d0cd16ca0f954fde95200a10e4d60c3b0268d878 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/Llama 2 Chat.json @@ -0,0 +1,11 @@ +{ + "story_string": "[INST] <<SYS>>\n{{#if system}}{{system}}\n<</SYS>>\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{trim}} [/INST]", + "example_separator": "", + "chat_start": "", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "Llama 2 Chat" +} diff --git a/jiuguan2025cc/default/content/presets/context/Llama 3 Instruct.json b/jiuguan2025cc/default/content/presets/context/Llama 3 Instruct.json new file mode 100644 index 0000000000000000000000000000000000000000..cbc155504e1244bf896b058294499cac5659a849 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/Llama 3 Instruct.json @@ -0,0 +1,11 @@ +{ + "story_string": "<|start_header_id|>system<|end_header_id|>\n\n{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{trim}}<|eot_id|>", + "example_separator": "", + "chat_start": "", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "Llama 3 Instruct" +} diff --git a/jiuguan2025cc/default/content/presets/context/Llama-3-Instruct-Names.json b/jiuguan2025cc/default/content/presets/context/Llama-3-Instruct-Names.json new file mode 100644 index 0000000000000000000000000000000000000000..a1815e02c558e9bb2f9e16dee57fffa5c7046ae0 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/Llama-3-Instruct-Names.json @@ -0,0 +1,11 @@ +{ + "story_string": "<|start_header_id|>system<|end_header_id|>\n\n{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{trim}}<|eot_id|>", + "example_separator": "", + "chat_start": "", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "Llama-3-Instruct-Names" +} diff --git a/jiuguan2025cc/default/content/presets/context/Minimalist.json b/jiuguan2025cc/default/content/presets/context/Minimalist.json new file mode 100644 index 0000000000000000000000000000000000000000..107da83b301bbc2794652d2c579209442d28f27c --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/Minimalist.json @@ -0,0 +1,11 @@ +{ + "story_string": "{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{personality}}\n{{/if}}{{#if scenario}}{{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}", + "example_separator": "", + "chat_start": "", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "Minimalist" +} diff --git a/jiuguan2025cc/default/content/presets/context/Mistral V1.json b/jiuguan2025cc/default/content/presets/context/Mistral V1.json new file mode 100644 index 0000000000000000000000000000000000000000..93d037941b339e15b1997eea8a0571f3ddcc6ffa --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/Mistral V1.json @@ -0,0 +1,11 @@ +{ + "story_string": " [INST] {{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{personality}}\n{{/if}}{{#if scenario}}{{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{trim}} [/INST] Understood.</s>", + "example_separator": "", + "chat_start": "", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "Mistral V1" +} diff --git a/jiuguan2025cc/default/content/presets/context/Mistral V2 & V3.json b/jiuguan2025cc/default/content/presets/context/Mistral V2 & V3.json new file mode 100644 index 0000000000000000000000000000000000000000..bc41b01a1e581234f443e55a2c4f6ebfb438a384 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/Mistral V2 & V3.json @@ -0,0 +1,11 @@ +{ + "story_string": "[INST] {{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{personality}}\n{{/if}}{{#if scenario}}{{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{trim}}[/INST] Understood.</s>", + "example_separator": "", + "chat_start": "", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "Mistral V2 & V3" +} diff --git a/jiuguan2025cc/default/content/presets/context/Mistral V3-Tekken.json b/jiuguan2025cc/default/content/presets/context/Mistral V3-Tekken.json new file mode 100644 index 0000000000000000000000000000000000000000..e5b21160694ee8eeb0259bc639cc71b3e3f42b5c --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/Mistral V3-Tekken.json @@ -0,0 +1,11 @@ +{ + "story_string": "[INST]{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{personality}}\n{{/if}}{{#if scenario}}{{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{trim}}[/INST]Understood.</s>", + "example_separator": "", + "chat_start": "", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "Mistral V3-Tekken" +} diff --git a/jiuguan2025cc/default/content/presets/context/Mistral V7.json b/jiuguan2025cc/default/content/presets/context/Mistral V7.json new file mode 100644 index 0000000000000000000000000000000000000000..519d5d152d7382d51b8ea14c3b2a84d18bb94baf --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/Mistral V7.json @@ -0,0 +1,11 @@ +{ + "story_string": "[SYSTEM_PROMPT] {{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{personality}}\n{{/if}}{{#if scenario}}{{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{trim}}[/SYSTEM_PROMPT]", + "example_separator": "", + "chat_start": "", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "Mistral V7" +} diff --git a/jiuguan2025cc/default/content/presets/context/NovelAI.json b/jiuguan2025cc/default/content/presets/context/NovelAI.json new file mode 100644 index 0000000000000000000000000000000000000000..8914a953d9c91e32d038c3f1a791f16b132aadc0 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/NovelAI.json @@ -0,0 +1,11 @@ +{ + "story_string": "{{#if system}}{{system}}{{/if}}\n{{#if wiBefore}}{{wiBefore}}{{/if}}\n{{#if persona}}{{persona}}{{/if}}\n{{#if description}}{{description}}{{/if}}\n{{#if personality}}Personality: {{personality}}{{/if}}\n{{#if scenario}}Scenario: {{scenario}}{{/if}}\n{{#if wiAfter}}{{wiAfter}}{{/if}}", + "example_separator": "***", + "chat_start": "***", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "NovelAI" +} diff --git a/jiuguan2025cc/default/content/presets/context/OldDefault.json b/jiuguan2025cc/default/content/presets/context/OldDefault.json new file mode 100644 index 0000000000000000000000000000000000000000..81dd70911c7c7c840d3ab464303a8298d0cba556 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/OldDefault.json @@ -0,0 +1,11 @@ +{ + "story_string": "{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Circumstances and context of the dialogue: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}", + "example_separator": "This is how {{char}} should talk", + "chat_start": "\nThen the roleplay chat between {{user}} and {{char}} begins.\n", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "OldDefault" +} diff --git a/jiuguan2025cc/default/content/presets/context/Phi.json b/jiuguan2025cc/default/content/presets/context/Phi.json new file mode 100644 index 0000000000000000000000000000000000000000..79a27ada9a148b5f2892a24b547f2219dc35e464 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/Phi.json @@ -0,0 +1,11 @@ +{ + "story_string": "<|system|>\n{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{trim}}<|end|>\n", + "example_separator": "", + "chat_start": "", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "Phi" +} diff --git a/jiuguan2025cc/default/content/presets/context/Pygmalion.json b/jiuguan2025cc/default/content/presets/context/Pygmalion.json new file mode 100644 index 0000000000000000000000000000000000000000..eab73535c6754ba42a8c51f32b719fb264124f39 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/Pygmalion.json @@ -0,0 +1,11 @@ +{ + "story_string": "{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}", + "example_separator": "", + "chat_start": "", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "Pygmalion" +} diff --git a/jiuguan2025cc/default/content/presets/context/Story.json b/jiuguan2025cc/default/content/presets/context/Story.json new file mode 100644 index 0000000000000000000000000000000000000000..525a06dc020e666740f69bd57c59f5aa404e10db --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/Story.json @@ -0,0 +1,11 @@ +{ + "story_string": "{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{personality}}\n{{/if}}{{#if scenario}}{{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}", + "example_separator": "", + "chat_start": "", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "Story" +} diff --git a/jiuguan2025cc/default/content/presets/context/Synthia.json b/jiuguan2025cc/default/content/presets/context/Synthia.json new file mode 100644 index 0000000000000000000000000000000000000000..1fb639c0b3cf3fb3e1aae85381182a6bc7e3f687 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/Synthia.json @@ -0,0 +1,11 @@ +{ + "story_string": "{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}", + "example_separator": "", + "chat_start": "", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "Synthia" +} diff --git a/jiuguan2025cc/default/content/presets/context/Tulu.json b/jiuguan2025cc/default/content/presets/context/Tulu.json new file mode 100644 index 0000000000000000000000000000000000000000..af3c1f9cf617b5bb375a8a79048c827837c247fa --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/Tulu.json @@ -0,0 +1,11 @@ +{ + "story_string": "<|system|>\n{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{trim}}\n", + "example_separator": "", + "chat_start": "", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "Tulu" +} diff --git a/jiuguan2025cc/default/content/presets/context/simple-proxy-for-tavern.json b/jiuguan2025cc/default/content/presets/context/simple-proxy-for-tavern.json new file mode 100644 index 0000000000000000000000000000000000000000..0346c2f3247a6007700114a653a5a3bbc54c4e71 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/context/simple-proxy-for-tavern.json @@ -0,0 +1,11 @@ +{ + "story_string": "## {{char}}\n- You're \"{{char}}\" in this never-ending roleplay with \"{{user}}\".\n### Input:\n{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}### Response:\n(OOC) Understood. I will take this info into account for the roleplay. (end OOC)", + "example_separator": "### New Roleplay:", + "chat_start": "### New Roleplay:", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "simple-proxy-for-tavern" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Adventure.json b/jiuguan2025cc/default/content/presets/instruct/Adventure.json new file mode 100644 index 0000000000000000000000000000000000000000..0a84712365a4ed78665a521e235786a7a99bf763 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Adventure.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "", + "output_sequence": "", + "last_output_sequence": "", + "system_sequence": "", + "stop_sequence": "", + "wrap": true, + "macro": true, + "names_behavior": "none", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "", + "input_suffix": "", + "system_suffix": "", + "user_alignment_message": "", + "system_same_as_user": false, + "last_system_sequence": "", + "name": "Adventure" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Alpaca-Single-Turn.json b/jiuguan2025cc/default/content/presets/instruct/Alpaca-Single-Turn.json new file mode 100644 index 0000000000000000000000000000000000000000..e5e4fa2d8d9c93a1aad37d3473b5724bd8e50092 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Alpaca-Single-Turn.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "", + "output_sequence": "", + "last_output_sequence": "\n### Response:", + "system_sequence": "", + "stop_sequence": "", + "wrap": true, + "macro": true, + "names_behavior": "force", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "<START OF CHAT>", + "skip_examples": false, + "output_suffix": "", + "input_suffix": "", + "system_suffix": "", + "user_alignment_message": "", + "system_same_as_user": false, + "last_system_sequence": "", + "name": "Alpaca-Single-Turn" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Alpaca.json b/jiuguan2025cc/default/content/presets/instruct/Alpaca.json new file mode 100644 index 0000000000000000000000000000000000000000..5088cfd9a56e9b6a38b01093cd84623e31b8b68c --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Alpaca.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "### Instruction:", + "output_sequence": "### Response:", + "last_output_sequence": "", + "system_sequence": "### Input:", + "stop_sequence": "", + "wrap": true, + "macro": true, + "names_behavior": "force", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "\n\n", + "input_suffix": "\n\n", + "system_suffix": "\n\n", + "user_alignment_message": "", + "system_same_as_user": false, + "last_system_sequence": "", + "name": "Alpaca" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/ChatML-Names.json b/jiuguan2025cc/default/content/presets/instruct/ChatML-Names.json new file mode 100644 index 0000000000000000000000000000000000000000..2ad703b337bf4ce9a413121f9d6716883e457ebb --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/ChatML-Names.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "<|im_start|>{{name}}", + "output_sequence": "<|im_start|>{{name}}", + "last_output_sequence": "", + "system_sequence": "<|im_start|>system", + "stop_sequence": "<|im_end|>", + "wrap": true, + "macro": true, + "names_behavior": "none", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "<|im_end|>\n", + "input_suffix": "<|im_end|>\n", + "system_suffix": "<|im_end|>\n", + "user_alignment_message": "", + "system_same_as_user": false, + "last_system_sequence": "", + "name": "ChatML-Names" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/ChatML.json b/jiuguan2025cc/default/content/presets/instruct/ChatML.json new file mode 100644 index 0000000000000000000000000000000000000000..199b3915ba306071058369e24fca5b5641283102 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/ChatML.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "<|im_start|>user", + "output_sequence": "<|im_start|>assistant", + "last_output_sequence": "", + "system_sequence": "<|im_start|>system", + "stop_sequence": "<|im_end|>", + "wrap": true, + "macro": true, + "names_behavior": "always", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "<|im_end|>\n", + "input_suffix": "<|im_end|>\n", + "system_suffix": "<|im_end|>\n", + "user_alignment_message": "", + "system_same_as_user": false, + "last_system_sequence": "", + "name": "ChatML" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Command R.json b/jiuguan2025cc/default/content/presets/instruct/Command R.json new file mode 100644 index 0000000000000000000000000000000000000000..f34159081b3cba026a7c94f5189f6fc449987052 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Command R.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "<|START_OF_TURN_TOKEN|><|USER_TOKEN|>", + "output_sequence": "<|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>", + "first_output_sequence": "", + "last_output_sequence": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "stop_sequence": "<|END_OF_TURN_TOKEN|>", + "wrap": false, + "macro": true, + "names_behavior": "always", + "activation_regex": "", + "skip_examples": false, + "output_suffix": "<|END_OF_TURN_TOKEN|>", + "input_suffix": "<|END_OF_TURN_TOKEN|>", + "system_sequence": "<|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|>", + "system_suffix": "<|END_OF_TURN_TOKEN|>", + "user_alignment_message": "", + "last_system_sequence": "", + "system_same_as_user": false, + "name": "Command R" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/DeepSeek-V2.5.json b/jiuguan2025cc/default/content/presets/instruct/DeepSeek-V2.5.json new file mode 100644 index 0000000000000000000000000000000000000000..7990d13c082977f7f3f7eb68482b7d54d24aef3f --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/DeepSeek-V2.5.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "<|User|>", + "output_sequence": "<|Assistant|>", + "first_output_sequence": "", + "last_output_sequence": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "stop_sequence": "", + "wrap": false, + "macro": true, + "names_behavior": "force", + "activation_regex": "", + "skip_examples": false, + "output_suffix": "<|end▁of▁sentence|>", + "input_suffix": "", + "system_sequence": "", + "system_suffix": "", + "user_alignment_message": "", + "last_system_sequence": "", + "system_same_as_user": true, + "name": "DeepSeek-V2.5" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/DreamGen Role-Play V1 ChatML.json b/jiuguan2025cc/default/content/presets/instruct/DreamGen Role-Play V1 ChatML.json new file mode 100644 index 0000000000000000000000000000000000000000..b705b285307856eac52bb4715c483cff5bda3611 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/DreamGen Role-Play V1 ChatML.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "\n<|im_start|>text names= {{name}}\n", + "output_sequence": "\n<|im_start|>text names= {{name}}\n", + "last_output_sequence": "", + "system_sequence": "", + "stop_sequence": "\n<|im_start|>", + "wrap": false, + "macro": true, + "names_behavior": "none", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "<|im_end|>", + "input_suffix": "<|im_end|>", + "system_suffix": "", + "user_alignment_message": "", + "system_same_as_user": true, + "last_system_sequence": "", + "name": "DreamGen Role-Play V1 ChatML" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/DreamGen Role-Play V1 Llama3.json b/jiuguan2025cc/default/content/presets/instruct/DreamGen Role-Play V1 Llama3.json new file mode 100644 index 0000000000000000000000000000000000000000..e52fe73f8d4a55ed966ebc43ed43fa0a928d3b1f --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/DreamGen Role-Play V1 Llama3.json @@ -0,0 +1,16 @@ +{ + "input_sequence": "<|eot_id|>\n<|start_header_id|>writer character: {{user}}<|end_header_id|>\n\n", + "output_sequence": "<|eot_id|>\n<|start_header_id|>writer character: {{char}}<|end_header_id|>\n\n", + "first_output_sequence": "", + "last_output_sequence": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "stop_sequence": "", + "separator_sequence": "", + "wrap": false, + "macro": true, + "names_behavior": "none", + "activation_regex": "", + "skip_examples": false, + "name": "DreamGen Role-Play V1 Llama3" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Gemma 2.json b/jiuguan2025cc/default/content/presets/instruct/Gemma 2.json new file mode 100644 index 0000000000000000000000000000000000000000..7a21a2316b6c4f374a4653d9e35a75500f69304d --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Gemma 2.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "<start_of_turn>user", + "output_sequence": "<start_of_turn>model", + "last_output_sequence": "", + "system_sequence": "<start_of_turn>system", + "stop_sequence": "<end_of_turn>", + "wrap": true, + "macro": true, + "names_behavior": "none", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "<end_of_turn>\n", + "input_suffix": "<end_of_turn>\n", + "system_suffix": "<end_of_turn>\n", + "user_alignment_message": "", + "system_same_as_user": true, + "last_system_sequence": "", + "name": "Gemma 2" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Koala.json b/jiuguan2025cc/default/content/presets/instruct/Koala.json new file mode 100644 index 0000000000000000000000000000000000000000..386faa85c7d0c7540d31f9236a25a9b35a511f8f --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Koala.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "USER: ", + "output_sequence": "GPT: ", + "last_output_sequence": "", + "system_sequence": "", + "stop_sequence": "", + "wrap": false, + "macro": true, + "names_behavior": "force", + "activation_regex": "", + "system_sequence_prefix": "BEGINNING OF CONVERSATION: ", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "</s>", + "input_suffix": "", + "system_suffix": "", + "user_alignment_message": "", + "system_same_as_user": true, + "last_system_sequence": "", + "name": "Koala" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Libra-32B.json b/jiuguan2025cc/default/content/presets/instruct/Libra-32B.json new file mode 100644 index 0000000000000000000000000000000000000000..2e3e9ecba8090a93c91d7c91700ab1980eaac070 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Libra-32B.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "", + "output_sequence": "", + "last_output_sequence": "\n### Response:", + "system_sequence": "", + "stop_sequence": "", + "wrap": true, + "macro": true, + "names_behavior": "always", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "", + "input_suffix": "", + "system_suffix": "", + "user_alignment_message": "", + "system_same_as_user": false, + "last_system_sequence": "", + "name": "Libra-32B" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Lightning 1.1.json b/jiuguan2025cc/default/content/presets/instruct/Lightning 1.1.json new file mode 100644 index 0000000000000000000000000000000000000000..3ce4d6a9094a63632106acec095e1bc59e97f849 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Lightning 1.1.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "### Instruction:", + "output_sequence": "### Response: (length = unlimited)", + "last_output_sequence": "", + "system_sequence": "", + "stop_sequence": "", + "wrap": true, + "macro": true, + "names_behavior": "force", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "", + "input_suffix": "", + "system_suffix": "", + "user_alignment_message": "", + "system_same_as_user": true, + "last_system_sequence": "", + "name": "Lightning 1.1" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Llama 2 Chat.json b/jiuguan2025cc/default/content/presets/instruct/Llama 2 Chat.json new file mode 100644 index 0000000000000000000000000000000000000000..7d5efcb218155334620c1da72559989731e77d32 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Llama 2 Chat.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "[INST] ", + "output_sequence": "", + "last_output_sequence": "", + "system_sequence": "", + "stop_sequence": "", + "wrap": false, + "macro": true, + "names_behavior": "force", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "\n", + "input_suffix": " [/INST]\n", + "system_suffix": "", + "user_alignment_message": "Let's get started. Please respond based on the information and instructions provided above.", + "system_same_as_user": true, + "last_system_sequence": "", + "name": "Llama 2 Chat" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Llama 3 Instruct.json b/jiuguan2025cc/default/content/presets/instruct/Llama 3 Instruct.json new file mode 100644 index 0000000000000000000000000000000000000000..d283820f41c4a1e81e35f9d68b9f73c19fd82c68 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Llama 3 Instruct.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "<|start_header_id|>user<|end_header_id|>\n\n", + "output_sequence": "<|start_header_id|>assistant<|end_header_id|>\n\n", + "last_output_sequence": "", + "system_sequence": "<|start_header_id|>system<|end_header_id|>\n\n", + "stop_sequence": "<|eot_id|>", + "wrap": false, + "macro": true, + "names_behavior": "always", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "<|eot_id|>", + "input_suffix": "<|eot_id|>", + "system_suffix": "<|eot_id|>", + "user_alignment_message": "", + "system_same_as_user": true, + "last_system_sequence": "", + "name": "Llama 3 Instruct" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Llama-3-Instruct-Names.json b/jiuguan2025cc/default/content/presets/instruct/Llama-3-Instruct-Names.json new file mode 100644 index 0000000000000000000000000000000000000000..4412df51a3351e2b8dfc13fa74b9487091710bc3 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Llama-3-Instruct-Names.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "<|start_header_id|>{{name}}<|end_header_id|>\n\n", + "output_sequence": "<|start_header_id|>{{name}}<|end_header_id|>\n\n", + "last_output_sequence": "", + "system_sequence": "<|start_header_id|>system<|end_header_id|>\n\n", + "stop_sequence": "<|eot_id|>", + "wrap": false, + "macro": true, + "names_behavior": "none", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "<|eot_id|>", + "input_suffix": "<|eot_id|>", + "system_suffix": "<|eot_id|>", + "user_alignment_message": "", + "system_same_as_user": true, + "last_system_sequence": "", + "name": "Llama-3-Instruct-Names" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Metharme.json b/jiuguan2025cc/default/content/presets/instruct/Metharme.json new file mode 100644 index 0000000000000000000000000000000000000000..2756e709bd1fe4a3d66cfe2f51f1f818ad297938 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Metharme.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "<|user|>", + "output_sequence": "<|model|>", + "last_output_sequence": "", + "system_sequence": "", + "stop_sequence": "</s>", + "wrap": false, + "macro": true, + "names_behavior": "force", + "activation_regex": "", + "system_sequence_prefix": "<|system|>", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "", + "input_suffix": "", + "system_suffix": "", + "user_alignment_message": "", + "system_same_as_user": true, + "last_system_sequence": "", + "name": "Metharme" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Mistral V1.json b/jiuguan2025cc/default/content/presets/instruct/Mistral V1.json new file mode 100644 index 0000000000000000000000000000000000000000..c47dbdc77dd46d83e7688a7b4b70283317e39ae1 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Mistral V1.json @@ -0,0 +1,22 @@ +{ + "input_sequence": " [INST] ", + "output_sequence": " [/INST] ", + "last_output_sequence": " [/INST]", + "system_sequence": "", + "stop_sequence": "", + "wrap": false, + "macro": true, + "names_behavior": "always", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "</s>", + "input_suffix": "", + "system_suffix": "", + "user_alignment_message": "Let's get started. Please respond based on the information and instructions provided above.", + "system_same_as_user": true, + "last_system_sequence": "", + "name": "Mistral V1" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Mistral V2 & V3.json b/jiuguan2025cc/default/content/presets/instruct/Mistral V2 & V3.json new file mode 100644 index 0000000000000000000000000000000000000000..7619a1aa508cc27bb8ad8af3f70566226c084874 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Mistral V2 & V3.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "[INST] ", + "output_sequence": "[/INST] ", + "last_output_sequence": "[/INST]", + "system_sequence": "", + "stop_sequence": "", + "wrap": false, + "macro": true, + "names_behavior": "always", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "</s>", + "input_suffix": "", + "system_suffix": "", + "user_alignment_message": "Let's get started. Please respond based on the information and instructions provided above.", + "system_same_as_user": true, + "last_system_sequence": "", + "name": "Mistral V2 & V3" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Mistral V3-Tekken.json b/jiuguan2025cc/default/content/presets/instruct/Mistral V3-Tekken.json new file mode 100644 index 0000000000000000000000000000000000000000..217007d73b49522ecc315b3d7a09d161dd643b5a --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Mistral V3-Tekken.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "[INST]", + "output_sequence": "[/INST]", + "last_output_sequence": "", + "system_sequence": "", + "stop_sequence": "", + "wrap": false, + "macro": true, + "names_behavior": "always", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "</s>", + "input_suffix": "", + "system_suffix": "", + "user_alignment_message": "Let's get started. Please respond based on the information and instructions provided above.", + "system_same_as_user": true, + "last_system_sequence": "", + "name": "Mistral V3-Tekken" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Mistral V7.json b/jiuguan2025cc/default/content/presets/instruct/Mistral V7.json new file mode 100644 index 0000000000000000000000000000000000000000..b6b81ae02a3d1e2489290060dbfed52985f5d5cc --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Mistral V7.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "[INST] ", + "output_sequence": " ", + "last_output_sequence": "", + "system_sequence": "[SYSTEM_PROMPT] ", + "stop_sequence": "</s>", + "wrap": false, + "macro": true, + "names_behavior": "always", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "</s>", + "input_suffix": "[/INST]", + "system_suffix": "[/SYSTEM_PROMPT]", + "user_alignment_message": "", + "system_same_as_user": false, + "last_system_sequence": "", + "name": "Mistral V7" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/OpenOrca-OpenChat.json b/jiuguan2025cc/default/content/presets/instruct/OpenOrca-OpenChat.json new file mode 100644 index 0000000000000000000000000000000000000000..84ae96d15d85b4e6f87dafa1d1fd041388934428 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/OpenOrca-OpenChat.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "\nUser: ", + "output_sequence": "\nAssistant: ", + "last_output_sequence": "", + "system_sequence": "", + "stop_sequence": "", + "wrap": false, + "macro": true, + "names_behavior": "force", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "<|end_of_turn|>", + "input_suffix": "<|end_of_turn|>", + "system_suffix": "", + "user_alignment_message": "", + "system_same_as_user": false, + "last_system_sequence": "", + "name": "OpenOrca-OpenChat" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Phi.json b/jiuguan2025cc/default/content/presets/instruct/Phi.json new file mode 100644 index 0000000000000000000000000000000000000000..2762cdbd2e6665d87f476e34f6ad8a9476f3a8a8 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Phi.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "<|user|>\n", + "output_sequence": "<|assistant|>\n", + "first_output_sequence": "", + "last_output_sequence": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "stop_sequence": "<|end|>", + "wrap": false, + "macro": true, + "names_behavior": "always", + "activation_regex": "", + "skip_examples": false, + "output_suffix": "<|end|>\n", + "input_suffix": "<|end|>\n", + "system_sequence": "<|system|>\n", + "system_suffix": "<|end|>\n", + "user_alignment_message": "", + "last_system_sequence": "", + "system_same_as_user": false, + "name": "Phi" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Pygmalion.json b/jiuguan2025cc/default/content/presets/instruct/Pygmalion.json new file mode 100644 index 0000000000000000000000000000000000000000..3827585bfe5c9671ca1639d8001a208b161b8f76 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Pygmalion.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "<|user|>", + "output_sequence": "<|model|>", + "last_output_sequence": "", + "system_sequence": "", + "stop_sequence": "<|user|>", + "wrap": false, + "macro": true, + "names_behavior": "always", + "activation_regex": "", + "system_sequence_prefix": "<|system|>", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "", + "input_suffix": "", + "system_suffix": "", + "user_alignment_message": "", + "system_same_as_user": true, + "last_system_sequence": "", + "name": "Pygmalion" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Story.json b/jiuguan2025cc/default/content/presets/instruct/Story.json new file mode 100644 index 0000000000000000000000000000000000000000..6e90dd0bacae482b67e61567490ab564ff4b3bd3 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Story.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "", + "output_sequence": "", + "last_output_sequence": "", + "system_sequence": "", + "stop_sequence": "", + "wrap": true, + "macro": true, + "names_behavior": "none", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "", + "input_suffix": "", + "system_suffix": "", + "user_alignment_message": "", + "system_same_as_user": false, + "last_system_sequence": "", + "name": "Story" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Synthia.json b/jiuguan2025cc/default/content/presets/instruct/Synthia.json new file mode 100644 index 0000000000000000000000000000000000000000..ccba89a9f83faa7ffc5c2943aefd91a09ac719f6 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Synthia.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "USER: ", + "output_sequence": "ASSISTANT: ", + "last_output_sequence": "", + "system_sequence": "SYSTEM: ", + "stop_sequence": "", + "wrap": false, + "macro": true, + "names_behavior": "force", + "activation_regex": "", + "system_sequence_prefix": "SYSTEM: ", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "\n", + "input_suffix": "\n", + "system_suffix": "\n", + "user_alignment_message": "Let's get started. Please respond based on the information and instructions provided above.", + "system_same_as_user": false, + "last_system_sequence": "", + "name": "Synthia" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Tulu.json b/jiuguan2025cc/default/content/presets/instruct/Tulu.json new file mode 100644 index 0000000000000000000000000000000000000000..14072f5638de974c6b3229cf5d2aee1e84bb8181 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Tulu.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "<|user|>\n", + "output_sequence": "<|assistant|>\n", + "first_output_sequence": "", + "last_output_sequence": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "stop_sequence": "<|end_of_text|>", + "wrap": false, + "macro": true, + "names_behavior": "always", + "activation_regex": "", + "skip_examples": false, + "output_suffix": "<|end_of_text|>\n", + "input_suffix": "\n", + "system_sequence": "<|system|>\n", + "system_suffix": "\n", + "user_alignment_message": "", + "last_system_sequence": "", + "system_same_as_user": false, + "name": "Tulu" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Vicuna 1.0.json b/jiuguan2025cc/default/content/presets/instruct/Vicuna 1.0.json new file mode 100644 index 0000000000000000000000000000000000000000..1c5fca1443e32eddb84f7e11db3c9c5a1526fea3 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Vicuna 1.0.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "### Human:", + "output_sequence": "### Assistant:", + "last_output_sequence": "", + "system_sequence": "", + "stop_sequence": "", + "wrap": true, + "macro": true, + "names_behavior": "force", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "", + "input_suffix": "", + "system_suffix": "", + "user_alignment_message": "", + "system_same_as_user": true, + "last_system_sequence": "", + "name": "Vicuna 1.0" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/Vicuna 1.1.json b/jiuguan2025cc/default/content/presets/instruct/Vicuna 1.1.json new file mode 100644 index 0000000000000000000000000000000000000000..88119ecd1114a1c46d79603993c22a7a43dfdabb --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/Vicuna 1.1.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "\nUSER: ", + "output_sequence": "\nASSISTANT: ", + "last_output_sequence": "", + "system_sequence": "", + "stop_sequence": "", + "wrap": false, + "macro": true, + "names_behavior": "force", + "activation_regex": "", + "system_sequence_prefix": "BEGINNING OF CONVERSATION:", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "</s>", + "input_suffix": "", + "system_suffix": "", + "user_alignment_message": "", + "system_same_as_user": true, + "last_system_sequence": "", + "name": "Vicuna 1.1" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/WizardLM-13B.json b/jiuguan2025cc/default/content/presets/instruct/WizardLM-13B.json new file mode 100644 index 0000000000000000000000000000000000000000..ea793ac572320f8383d6a905def4889f4a7f72dc --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/WizardLM-13B.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "USER: ", + "output_sequence": "ASSISTANT: ", + "last_output_sequence": "", + "system_sequence": "", + "stop_sequence": "", + "wrap": true, + "macro": true, + "names_behavior": "force", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "", + "input_suffix": "", + "system_suffix": "", + "user_alignment_message": "", + "system_same_as_user": true, + "last_system_sequence": "", + "name": "WizardLM-13B" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/WizardLM.json b/jiuguan2025cc/default/content/presets/instruct/WizardLM.json new file mode 100644 index 0000000000000000000000000000000000000000..081d9d68cf26fce3ca318ded1fdfd4a04bebb3df --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/WizardLM.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "", + "output_sequence": "### Response:", + "last_output_sequence": "", + "system_sequence": "", + "stop_sequence": "", + "wrap": true, + "macro": true, + "names_behavior": "force", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "</s>", + "input_suffix": "", + "system_suffix": "", + "user_alignment_message": "", + "system_same_as_user": false, + "last_system_sequence": "", + "name": "WizardLM" +} diff --git a/jiuguan2025cc/default/content/presets/instruct/simple-proxy-for-tavern.json b/jiuguan2025cc/default/content/presets/instruct/simple-proxy-for-tavern.json new file mode 100644 index 0000000000000000000000000000000000000000..2123edbbd8292356707fbe0a403ae7ff88d9e98b --- /dev/null +++ b/jiuguan2025cc/default/content/presets/instruct/simple-proxy-for-tavern.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "### Instruction:\n#### {{name}}:", + "output_sequence": "### Response:\n#### {{name}}:", + "last_output_sequence": "### Response (2 paragraphs, engaging, natural, authentic, descriptive, creative):\n#### {{name}}:", + "system_sequence": "", + "stop_sequence": "", + "wrap": true, + "macro": true, + "names_behavior": "none", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "", + "input_suffix": "", + "system_suffix": "", + "user_alignment_message": "", + "system_same_as_user": false, + "last_system_sequence": "", + "name": "simple-proxy-for-tavern" +} diff --git a/jiuguan2025cc/default/content/presets/kobold/Ace of Spades.json b/jiuguan2025cc/default/content/presets/kobold/Ace of Spades.json new file mode 100644 index 0000000000000000000000000000000000000000..a6ee9849ac868aaa1c9e58234353dba57499b020 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Ace of Spades.json @@ -0,0 +1,24 @@ +{ + "temp": 1.15, + "rep_pen": 1.05, + "rep_pen_range": 2048, + "top_p": 0.95, + "top_a": 0, + "top_k": 0, + "typical": 1, + "tfs": 0.8, + "rep_pen_slope": 7, + "sampler_order": [ + 6, + 3, + 2, + 0, + 5, + 1, + 4 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/Basic Coherence.json b/jiuguan2025cc/default/content/presets/kobold/Basic Coherence.json new file mode 100644 index 0000000000000000000000000000000000000000..79472b0e74601cb55ce0a8d4f92e2eab2a9cbf9b --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Basic Coherence.json @@ -0,0 +1,24 @@ +{ + "temp": 0.59, + "rep_pen": 1.1, + "rep_pen_range": 2048, + "top_p": 1, + "top_a": 0, + "top_k": 0, + "typical": 1, + "tfs": 0.87, + "rep_pen_slope": 0.3, + "sampler_order": [ + 6, + 5, + 0, + 2, + 3, + 1, + 4 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/Best Guess.json b/jiuguan2025cc/default/content/presets/kobold/Best Guess.json new file mode 100644 index 0000000000000000000000000000000000000000..2bd4e1d98dce029c530b823656aaa5255ed2d725 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Best Guess.json @@ -0,0 +1,24 @@ +{ + "temp": 0.8, + "rep_pen": 1.15, + "rep_pen_range": 2048, + "top_p": 0.9, + "top_a": 0, + "top_k": 100, + "typical": 1, + "tfs": 1, + "rep_pen_slope": 3.4, + "sampler_order": [ + 6, + 5, + 0, + 2, + 3, + 1, + 4 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/Coherent Creativity.json b/jiuguan2025cc/default/content/presets/kobold/Coherent Creativity.json new file mode 100644 index 0000000000000000000000000000000000000000..e8876e9c22722fbb559c38046eaeb867697de43c --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Coherent Creativity.json @@ -0,0 +1,24 @@ +{ + "temp": 0.51, + "rep_pen": 1.2, + "rep_pen_range": 2048, + "top_p": 1, + "top_a": 0, + "top_k": 0, + "typical": 1, + "tfs": 0.99, + "rep_pen_slope": 0, + "sampler_order": [ + 6, + 5, + 0, + 2, + 3, + 1, + 4 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/Deterministic.json b/jiuguan2025cc/default/content/presets/kobold/Deterministic.json new file mode 100644 index 0000000000000000000000000000000000000000..f1b69a14eafc1d9c76a88d41bdb7eccd4430bdae --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Deterministic.json @@ -0,0 +1,24 @@ +{ + "temp": 0, + "rep_pen": 1.18, + "rep_pen_range": 2048, + "top_p": 0, + "top_a": 0, + "top_k": 1, + "typical": 1, + "tfs": 1, + "rep_pen_slope": 0, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/Genesis.json b/jiuguan2025cc/default/content/presets/kobold/Genesis.json new file mode 100644 index 0000000000000000000000000000000000000000..6e843301477e2da113e55aa5704dbfa1f2a37aff --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Genesis.json @@ -0,0 +1,24 @@ +{ + "temp": 0.63, + "rep_pen": 1.05, + "rep_pen_range": 2048, + "top_p": 0.98, + "top_a": 0, + "top_k": 0, + "typical": 1, + "tfs": 0.98, + "rep_pen_slope": 0.1, + "sampler_order": [ + 6, + 2, + 0, + 3, + 5, + 1, + 4 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/Godlike.json b/jiuguan2025cc/default/content/presets/kobold/Godlike.json new file mode 100644 index 0000000000000000000000000000000000000000..6c75e7f005447fe248f6c55a959b733593aa54d5 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Godlike.json @@ -0,0 +1,24 @@ +{ + "temp": 0.7, + "rep_pen": 1.1, + "rep_pen_range": 1024, + "top_p": 0.5, + "top_a": 0.75, + "top_k": 0, + "typical": 0.19, + "tfs": 0.97, + "rep_pen_slope": 0.7, + "sampler_order": [ + 6, + 5, + 4, + 3, + 2, + 1, + 0 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/Good Winds.json b/jiuguan2025cc/default/content/presets/kobold/Good Winds.json new file mode 100644 index 0000000000000000000000000000000000000000..f0fe996d59c47aa8bdc761e5cd1fa94afafa6f4f --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Good Winds.json @@ -0,0 +1,24 @@ +{ + "temp": 0.7, + "rep_pen": 1.1, + "rep_pen_range": 1024, + "top_p": 1, + "top_a": 0, + "top_k": 0, + "typical": 1, + "tfs": 0.9, + "rep_pen_slope": 0.7, + "sampler_order": [ + 6, + 0, + 1, + 2, + 3, + 4, + 5 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/Liminal Drift.json b/jiuguan2025cc/default/content/presets/kobold/Liminal Drift.json new file mode 100644 index 0000000000000000000000000000000000000000..4371499e58ae4cf596419cfa0e6f21c39cf68539 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Liminal Drift.json @@ -0,0 +1,24 @@ +{ + "temp": 0.66, + "rep_pen": 1.1, + "rep_pen_range": 1024, + "top_p": 1, + "top_a": 0.96, + "top_k": 0, + "typical": 0.6, + "tfs": 1, + "rep_pen_slope": 0.7, + "sampler_order": [ + 6, + 4, + 5, + 1, + 0, + 2, + 3 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/Low Rider.json b/jiuguan2025cc/default/content/presets/kobold/Low Rider.json new file mode 100644 index 0000000000000000000000000000000000000000..893865f348b407c5b569821572f43a206bc7c39f --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Low Rider.json @@ -0,0 +1,24 @@ +{ + "temp": 0.94, + "rep_pen": 1.05, + "rep_pen_range": 2048, + "top_p": 1, + "top_a": 0, + "top_k": 12, + "typical": 1, + "tfs": 0.94, + "rep_pen_slope": 0.2, + "sampler_order": [ + 6, + 5, + 0, + 2, + 3, + 1, + 4 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/Luna Moth.json b/jiuguan2025cc/default/content/presets/kobold/Luna Moth.json new file mode 100644 index 0000000000000000000000000000000000000000..c70dfa6f4b95bff44380c89a73094bfc1c5f0546 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Luna Moth.json @@ -0,0 +1,24 @@ +{ + "temp": 1.5, + "rep_pen": 1.1, + "rep_pen_range": 2048, + "top_p": 0.24, + "top_a": 0, + "top_k": 85, + "typical": 1, + "tfs": 1, + "rep_pen_slope": 0, + "sampler_order": [ + 6, + 5, + 0, + 2, + 3, + 1, + 4 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/Mayday.json b/jiuguan2025cc/default/content/presets/kobold/Mayday.json new file mode 100644 index 0000000000000000000000000000000000000000..2c95963f62fd1a9585297c179078c4d3613cb180 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Mayday.json @@ -0,0 +1,24 @@ +{ + "temp": 1.05, + "rep_pen": 1.1, + "rep_pen_range": 1024, + "top_p": 0.95, + "top_a": 0, + "top_k": 0, + "typical": 1, + "tfs": 1, + "rep_pen_slope": 0.7, + "sampler_order": [ + 6, + 0, + 1, + 2, + 3, + 4, + 5 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/Miro Bronze.json b/jiuguan2025cc/default/content/presets/kobold/Miro Bronze.json new file mode 100644 index 0000000000000000000000000000000000000000..1d9490e46524df0e0d01756adf1d63865557a21f --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Miro Bronze.json @@ -0,0 +1,24 @@ +{ + "temp": 1.06, + "rep_pen": 1, + "rep_pen_range": 0, + "top_p": 1, + "top_a": 0, + "top_k": 0, + "typical": 1, + "tfs": 1, + "rep_pen_slope": 0.9, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "mirostat": 2, + "mirostat_tau": 9.61, + "mirostat_eta": 1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/Miro Gold.json b/jiuguan2025cc/default/content/presets/kobold/Miro Gold.json new file mode 100644 index 0000000000000000000000000000000000000000..4d7dd504fa78ce45090d86c069eb2f10016f4588 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Miro Gold.json @@ -0,0 +1,24 @@ +{ + "temp": 1.17, + "rep_pen": 1, + "rep_pen_range": 0, + "top_p": 1, + "top_a": 0, + "top_k": 0, + "typical": 1, + "tfs": 1, + "rep_pen_slope": 0.9, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "mirostat": 2, + "mirostat_tau": 9.91, + "mirostat_eta": 1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/Miro Silver.json b/jiuguan2025cc/default/content/presets/kobold/Miro Silver.json new file mode 100644 index 0000000000000000000000000000000000000000..1d07687d489edef9fe2f76e0965da564381c0b48 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Miro Silver.json @@ -0,0 +1,24 @@ +{ + "temp": 1.17, + "rep_pen": 1, + "rep_pen_range": 0, + "top_p": 1, + "top_a": 0, + "top_k": 0, + "typical": 1, + "tfs": 1, + "rep_pen_slope": 0.9, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "mirostat": 2, + "mirostat_tau": 9.62, + "mirostat_eta": 1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/Ouroboros.json b/jiuguan2025cc/default/content/presets/kobold/Ouroboros.json new file mode 100644 index 0000000000000000000000000000000000000000..4d0506619a2fcd92b8fcb41ee73af8bb95ecb0c3 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Ouroboros.json @@ -0,0 +1,24 @@ +{ + "temp": 1.07, + "rep_pen": 1.05, + "rep_pen_range": 404, + "top_p": 1, + "top_a": 0, + "top_k": 100, + "typical": 1, + "tfs": 0.93, + "rep_pen_slope": 0.8, + "sampler_order": [ + 6, + 0, + 5, + 3, + 2, + 1, + 4 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/Pleasing Results.json b/jiuguan2025cc/default/content/presets/kobold/Pleasing Results.json new file mode 100644 index 0000000000000000000000000000000000000000..3c2d188bc410df74e32bdaaedbfaa6abe58e4bb6 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Pleasing Results.json @@ -0,0 +1,24 @@ +{ + "temp": 0.44, + "rep_pen": 1.15, + "rep_pen_range": 2048, + "top_p": 1, + "top_a": 0, + "top_k": 0, + "typical": 1, + "tfs": 0.9, + "rep_pen_slope": 6.8, + "sampler_order": [ + 6, + 5, + 0, + 2, + 3, + 1, + 4 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/Pro Writer.json b/jiuguan2025cc/default/content/presets/kobold/Pro Writer.json new file mode 100644 index 0000000000000000000000000000000000000000..d52bc37ff256330b1455afe4e859ee675af352a3 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Pro Writer.json @@ -0,0 +1,24 @@ +{ + "temp": 1.35, + "rep_pen": 1.15, + "rep_pen_range": 2048, + "top_p": 1, + "top_a": 0, + "top_k": 0, + "typical": 1, + "tfs": 0.69, + "rep_pen_slope": 0.1, + "sampler_order": [ + 6, + 3, + 2, + 5, + 0, + 1, + 4 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/RecoveredRuins.json b/jiuguan2025cc/default/content/presets/kobold/RecoveredRuins.json new file mode 100644 index 0000000000000000000000000000000000000000..186ae362d7586cf67a64782721addbe4116c4e20 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/RecoveredRuins.json @@ -0,0 +1,24 @@ +{ + "temp": 1, + "rep_pen": 1.1, + "rep_pen_range": 600, + "top_p": 0.95, + "top_a": 0, + "top_k": 0, + "typical": 1, + "tfs": 1, + "rep_pen_slope": 0, + "sampler_order": [ + 6, + 0, + 1, + 2, + 3, + 4, + 5 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/Space Alien.json b/jiuguan2025cc/default/content/presets/kobold/Space Alien.json new file mode 100644 index 0000000000000000000000000000000000000000..50447a97858853a1498c2eed3181131425c0acbe --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Space Alien.json @@ -0,0 +1,24 @@ +{ + "temp": 1.31, + "rep_pen": 1.09, + "rep_pen_range": 2048, + "top_p": 0.29, + "top_a": 0, + "top_k": 72, + "typical": 1, + "tfs": 1, + "rep_pen_slope": 0, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/Storywriter.json b/jiuguan2025cc/default/content/presets/kobold/Storywriter.json new file mode 100644 index 0000000000000000000000000000000000000000..49ae1c969ebf87e09f82e64207fea5a08f3b82bf --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Storywriter.json @@ -0,0 +1,24 @@ +{ + "temp": 0.72, + "rep_pen": 1.1, + "rep_pen_range": 2048, + "top_p": 0.73, + "top_a": 0, + "top_k": 0, + "typical": 1, + "tfs": 1, + "rep_pen_slope": 0.2, + "sampler_order": [ + 6, + 5, + 0, + 2, + 3, + 1, + 4 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/TFS-with-Top-A.json b/jiuguan2025cc/default/content/presets/kobold/TFS-with-Top-A.json new file mode 100644 index 0000000000000000000000000000000000000000..df8d1625a1fb0c3ea1df8c952416d347bc780656 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/TFS-with-Top-A.json @@ -0,0 +1,24 @@ +{ + "temp": 0.7, + "rep_pen": 1.15, + "rep_pen_range": 2048, + "top_p": 1, + "top_a": 0.2, + "top_k": 0, + "typical": 1, + "tfs": 0.95, + "rep_pen_slope": 0, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/Titanic.json b/jiuguan2025cc/default/content/presets/kobold/Titanic.json new file mode 100644 index 0000000000000000000000000000000000000000..c5b03024f79a0f31c9c2d2e420da0efce702c00c --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Titanic.json @@ -0,0 +1,24 @@ +{ + "temp": 1.01, + "rep_pen": 1.21, + "rep_pen_range": 2048, + "top_p": 0.21, + "top_a": 0.75, + "top_k": 91, + "typical": 1, + "tfs": 1, + "rep_pen_slope": 0, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/kobold/Universal-Creative.json b/jiuguan2025cc/default/content/presets/kobold/Universal-Creative.json new file mode 100644 index 0000000000000000000000000000000000000000..0ae4c13512f0bb679f071f156af3ece6a0d045cb --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Universal-Creative.json @@ -0,0 +1,26 @@ +{ + "temp": 1.5, + "rep_pen": 1, + "rep_pen_range": 600, + "top_p": 1, + "min_p": 0.1, + "top_a": 0, + "top_k": 0, + "typical": 1, + "tfs": 1, + "rep_pen_slope": 0, + "sampler_order": [ + 5, + 6, + 0, + 1, + 2, + 3, + 4 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "use_default_badwordsids": false, + "grammar": "" +} diff --git a/jiuguan2025cc/default/content/presets/kobold/Universal-Light.json b/jiuguan2025cc/default/content/presets/kobold/Universal-Light.json new file mode 100644 index 0000000000000000000000000000000000000000..3ba060087d5ebc3ab06ecb109d059d4cb0bbb638 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Universal-Light.json @@ -0,0 +1,26 @@ +{ + "temp": 1.25, + "rep_pen": 1, + "rep_pen_range": 600, + "top_p": 1, + "min_p": 0.1, + "top_a": 0, + "top_k": 0, + "typical": 1, + "tfs": 1, + "rep_pen_slope": 0, + "sampler_order": [ + 5, + 6, + 0, + 1, + 2, + 3, + 4 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "use_default_badwordsids": false, + "grammar": "" +} diff --git a/jiuguan2025cc/default/content/presets/kobold/Universal-Super-Creative.json b/jiuguan2025cc/default/content/presets/kobold/Universal-Super-Creative.json new file mode 100644 index 0000000000000000000000000000000000000000..2bbedf58abca2c56165116569aaadd0c7cd2f81a --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/Universal-Super-Creative.json @@ -0,0 +1,26 @@ +{ + "temp": 2, + "rep_pen": 1, + "rep_pen_range": 600, + "top_p": 1, + "min_p": 0.1, + "top_a": 0, + "top_k": 0, + "typical": 1, + "tfs": 1, + "rep_pen_slope": 0, + "sampler_order": [ + 5, + 6, + 0, + 1, + 2, + 3, + 4 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "use_default_badwordsids": false, + "grammar": "" +} diff --git a/jiuguan2025cc/default/content/presets/kobold/simple-proxy-for-tavern.json b/jiuguan2025cc/default/content/presets/kobold/simple-proxy-for-tavern.json new file mode 100644 index 0000000000000000000000000000000000000000..c392761002be7ddf59169722cb7f445a675331e5 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/kobold/simple-proxy-for-tavern.json @@ -0,0 +1,24 @@ +{ + "temp": 0.65, + "rep_pen": 1.18, + "rep_pen_range": 2048, + "top_p": 0.47, + "top_a": 0, + "top_k": 42, + "typical": 1, + "tfs": 1, + "rep_pen_slope": 0, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "grammar": "" +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/moving-ui/Default.json b/jiuguan2025cc/default/content/presets/moving-ui/Default.json new file mode 100644 index 0000000000000000000000000000000000000000..18b0d6da50e46fed032de59fd28d97bd46ec3ce2 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/moving-ui/Default.json @@ -0,0 +1,4 @@ +{ + "name": "Default", + "movingUIState": {} +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/presets/novel/Asper-Kayra.json b/jiuguan2025cc/default/content/presets/novel/Asper-Kayra.json new file mode 100644 index 0000000000000000000000000000000000000000..0b4b78e6d542e7df9edcb054891b4045f46e700d --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Asper-Kayra.json @@ -0,0 +1,23 @@ +{ + "order": [5, 0, 1, 3], + "temperature": 1.16, + "max_length": 150, + "min_length": 1, + "top_k": 175, + "typical_p": 0.96, + "tail_free_sampling": 0.994, + "repetition_penalty": 1.68, + "repetition_penalty_range": 2240, + "repetition_penalty_slope": 1.5, + "repetition_penalty_frequency": 0, + "repetition_penalty_presence": 0.005, + "use_cache": false, + "return_full_text": false, + "prefix": "vanilla", + "phrase_rep_pen": "medium", + "max_context": 7800, + "min_p": 0, + "math1_temp": 1, + "math1_quad": 0, + "math1_quad_entropy_scale": 0 +} diff --git a/jiuguan2025cc/default/content/presets/novel/Blended-Coffee-Kayra.json b/jiuguan2025cc/default/content/presets/novel/Blended-Coffee-Kayra.json new file mode 100644 index 0000000000000000000000000000000000000000..05f79638125c75dec1106c7bbe2751767b6b980d --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Blended-Coffee-Kayra.json @@ -0,0 +1,22 @@ +{ + "order": [0, 1, 2, 3], + "temperature": 1, + "max_length": 150, + "min_length": 1, + "top_k": 25, + "top_p": 1, + "tail_free_sampling": 0.925, + "repetition_penalty": 1.6, + "repetition_penalty_frequency": 0.001, + "repetition_penalty_range": 0, + "repetition_penalty_presence": 0, + "use_cache": false, + "return_full_text": false, + "prefix": "vanilla", + "phrase_rep_pen": "medium", + "max_context": 7800, + "min_p": 0, + "math1_temp": 1, + "math1_quad": 0, + "math1_quad_entropy_scale": 0 +} diff --git a/jiuguan2025cc/default/content/presets/novel/Blook-Kayra.json b/jiuguan2025cc/default/content/presets/novel/Blook-Kayra.json new file mode 100644 index 0000000000000000000000000000000000000000..42cf9e00ae64ed9c3699273d68ed1e0bfb32c216 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Blook-Kayra.json @@ -0,0 +1,23 @@ +{ + "order": [2, 3, 1, 0], + "temperature": 1, + "max_length": 150, + "min_length": 1, + "top_k": 0, + "top_p": 0.96, + "tail_free_sampling": 0.96, + "repetition_penalty": 2, + "repetition_penalty_slope": 1, + "repetition_penalty_frequency": 0.02, + "repetition_penalty_range": 0, + "repetition_penalty_presence": 0.3, + "use_cache": false, + "return_full_text": false, + "prefix": "vanilla", + "phrase_rep_pen": "very_aggressive", + "max_context": 7800, + "min_p": 0, + "math1_temp": 1, + "math1_quad": 0, + "math1_quad_entropy_scale": 0 +} diff --git a/jiuguan2025cc/default/content/presets/novel/Carefree-Kayra.json b/jiuguan2025cc/default/content/presets/novel/Carefree-Kayra.json new file mode 100644 index 0000000000000000000000000000000000000000..a99f18d09c8b1f6e4a6c68b9ac8067804551583e --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Carefree-Kayra.json @@ -0,0 +1,24 @@ +{ + "order": [2, 3, 0, 4, 1], + "temperature": 1.35, + "max_length": 150, + "min_length": 1, + "top_k": 15, + "top_p": 0.85, + "top_a": 0.1, + "tail_free_sampling": 0.915, + "repetition_penalty": 2.8, + "repetition_penalty_range": 2048, + "repetition_penalty_slope": 0.02, + "repetition_penalty_frequency": 0.02, + "repetition_penalty_presence": 0, + "use_cache": false, + "return_full_text": false, + "prefix": "vanilla", + "phrase_rep_pen": "aggressive", + "max_context": 7800, + "min_p": 0, + "math1_temp": 1, + "math1_quad": 0, + "math1_quad_entropy_scale": 0 +} diff --git a/jiuguan2025cc/default/content/presets/novel/CosmicCube-Kayra.json b/jiuguan2025cc/default/content/presets/novel/CosmicCube-Kayra.json new file mode 100644 index 0000000000000000000000000000000000000000..b818f6a503f128359783ee8a792b74fb81a32412 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/CosmicCube-Kayra.json @@ -0,0 +1,23 @@ +{ + "order": [8, 5, 0, 3], + "temperature": 0.9, + "max_length": 150, + "min_length": 1, + "typical_p": 0.95, + "tail_free_sampling": 0.92, + "mirostat_lr": 0.22, + "mirostat_tau": 4.95, + "repetition_penalty": 3, + "repetition_penalty_range": 4000, + "repetition_penalty_frequency": 0, + "repetition_penalty_presence": 0, + "use_cache": false, + "return_full_text": false, + "prefix": "vanilla", + "phrase_rep_pen": "off", + "max_context": 7800, + "min_p": 0, + "math1_temp": 1, + "math1_quad": 0, + "math1_quad_entropy_scale": 0 +} diff --git a/jiuguan2025cc/default/content/presets/novel/Edgewise-Clio.json b/jiuguan2025cc/default/content/presets/novel/Edgewise-Clio.json new file mode 100644 index 0000000000000000000000000000000000000000..32b4544db9900a1a8a408903297650e3bd57026c --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Edgewise-Clio.json @@ -0,0 +1,24 @@ +{ + "order": [4, 0, 5, 3, 2], + "temperature": 1.09, + "max_length": 150, + "min_length": 1, + "top_p": 0.969, + "top_a": 0.09, + "typical_p": 0.99, + "tail_free_sampling": 0.969, + "repetition_penalty": 1.09, + "repetition_penalty_range": 8192, + "repetition_penalty_slope": 0.069, + "repetition_penalty_frequency": 0.006, + "repetition_penalty_presence": 0.009, + "use_cache": false, + "return_full_text": false, + "prefix": "vanilla", + "phrase_rep_pen": "very_light", + "max_context": 7800, + "min_p": 0, + "math1_temp": 1, + "math1_quad": 0, + "math1_quad_entropy_scale": 0 +} diff --git a/jiuguan2025cc/default/content/presets/novel/Erato-Dragonfruit.json b/jiuguan2025cc/default/content/presets/novel/Erato-Dragonfruit.json new file mode 100644 index 0000000000000000000000000000000000000000..4a1fd903c7f90f9876cd45dd686f19dd1b94cf81 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Erato-Dragonfruit.json @@ -0,0 +1,31 @@ +{ + "max_context": 8000, + "temperature": 1.37, + "max_length": 150, + "min_length": 1, + "top_k": 0, + "top_p": 1, + "top_a": 0.1, + "typical_p": 0.875, + "tail_free_sampling": 0.87, + "repetition_penalty": 3.25, + "repetition_penalty_range": 6000, + "repetition_penalty_slope": 3.25, + "repetition_penalty_frequency": 0, + "repetition_penalty_presence": 0, + "phrase_rep_pen": "off", + "mirostat_lr": 0.2, + "mirostat_tau": 4, + "math1_temp": 0.9, + "math1_quad": 0.07, + "math1_quad_entropy_scale": -0.05, + "min_p": 0.035, + "order": [ + 0, + 5, + 9, + 10, + 8, + 4 + ] +} diff --git a/jiuguan2025cc/default/content/presets/novel/Erato-Golden Arrow.json b/jiuguan2025cc/default/content/presets/novel/Erato-Golden Arrow.json new file mode 100644 index 0000000000000000000000000000000000000000..e8b17dcd70462333dab8f1731d89f4ad1fb5291b --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Erato-Golden Arrow.json @@ -0,0 +1,27 @@ +{ + "max_context": 8000, + "temperature": 1, + "max_length": 150, + "min_length": 1, + "top_k": 0, + "top_p": 0.995, + "top_a": 1, + "typical_p": 1, + "tail_free_sampling": 0.87, + "repetition_penalty": 1.5, + "repetition_penalty_range": 2240, + "repetition_penalty_slope": 1, + "repetition_penalty_frequency": 0, + "repetition_penalty_presence": 0, + "phrase_rep_pen": "light", + "mirostat_lr": 1, + "mirostat_tau": 0, + "math1_temp": 0.3, + "math1_quad": 0.19, + "math1_quad_entropy_scale": 0, + "min_p": 0, + "order": [ + 9, + 2 + ] +} diff --git a/jiuguan2025cc/default/content/presets/novel/Erato-Shosetsu.json b/jiuguan2025cc/default/content/presets/novel/Erato-Shosetsu.json new file mode 100644 index 0000000000000000000000000000000000000000..14e97d09629b8439a9f311fc01c29982a7631f9c --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Erato-Shosetsu.json @@ -0,0 +1,27 @@ +{ + "max_context": 8000, + "temperature": 1, + "max_length": 150, + "min_length": 1, + "top_k": 50, + "top_p": 0.85, + "top_a": 1, + "typical_p": 1, + "tail_free_sampling": 0.895, + "repetition_penalty": 1.63, + "repetition_penalty_range": 1024, + "repetition_penalty_slope": 3.33, + "repetition_penalty_frequency": 0.0035, + "repetition_penalty_presence": 0, + "phrase_rep_pen": "medium", + "mirostat_lr": 1, + "mirostat_tau": 0, + "math1_temp": 0.3, + "math1_quad": 0.0645, + "math1_quad_entropy_scale": 0.05, + "min_p": 0.05, + "order": [ + 9, + 10 + ] +} diff --git a/jiuguan2025cc/default/content/presets/novel/Erato-Wilder.json b/jiuguan2025cc/default/content/presets/novel/Erato-Wilder.json new file mode 100644 index 0000000000000000000000000000000000000000..474d540ccfe16aee132ab53b9f112d8c3f0a5732 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Erato-Wilder.json @@ -0,0 +1,27 @@ +{ + "max_context": 8000, + "temperature": 1, + "max_length": 150, + "min_length": 1, + "top_k": 300, + "top_p": 0.98, + "top_a": 0.004, + "typical_p": 0.96, + "tail_free_sampling": 0.96, + "repetition_penalty": 1.48, + "repetition_penalty_range": 2240, + "repetition_penalty_slope": 0.64, + "repetition_penalty_frequency": 0, + "repetition_penalty_presence": 0, + "phrase_rep_pen": "medium", + "mirostat_lr": 1, + "mirostat_tau": 0, + "math1_temp": -0.0485, + "math1_quad": 0.145, + "math1_quad_entropy_scale": 0, + "min_p": 0.02, + "order": [ + 9, + 10 + ] +} diff --git a/jiuguan2025cc/default/content/presets/novel/Erato-Zany Scribe.json b/jiuguan2025cc/default/content/presets/novel/Erato-Zany Scribe.json new file mode 100644 index 0000000000000000000000000000000000000000..2f94d92bc0ed5ecca406a103fe97e6cf6e421f62 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Erato-Zany Scribe.json @@ -0,0 +1,27 @@ +{ + "max_context": 8000, + "temperature": 1, + "max_length": 150, + "min_length": 1, + "top_k": 0, + "top_p": 0.99, + "top_a": 1, + "typical_p": 1, + "tail_free_sampling": 0.99, + "repetition_penalty": 1, + "repetition_penalty_range": 64, + "repetition_penalty_slope": 1, + "repetition_penalty_frequency": 0.75, + "repetition_penalty_presence": 1.5, + "phrase_rep_pen": "medium", + "mirostat_lr": 1, + "mirostat_tau": 1, + "math1_temp": -0.4, + "math1_quad": 0.6, + "math1_quad_entropy_scale": -0.1, + "min_p": 0.08, + "order": [ + 9, + 2 + ] +} diff --git a/jiuguan2025cc/default/content/presets/novel/Fresh-Coffee-Clio.json b/jiuguan2025cc/default/content/presets/novel/Fresh-Coffee-Clio.json new file mode 100644 index 0000000000000000000000000000000000000000..729a4b4383742aaaebd2b01ecc1fade1b8349e66 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Fresh-Coffee-Clio.json @@ -0,0 +1,25 @@ +{ + "order": [0, 1, 2, 3], + "temperature": 1, + "max_length": 40, + "min_length": 1, + "top_k": 25, + "top_p": 1, + "top_a": 0, + "typical_p": 1, + "tail_free_sampling": 0.925, + "repetition_penalty": 1.9, + "repetition_penalty_range": 768, + "repetition_penalty_slope": 3.33, + "repetition_penalty_frequency": 0.0025, + "repetition_penalty_presence": 0.001, + "use_cache": false, + "return_full_text": false, + "prefix": "vanilla", + "phrase_rep_pen": "very_light", + "max_context": 7800, + "min_p": 0, + "math1_temp": 1, + "math1_quad": 0, + "math1_quad_entropy_scale": 0 +} diff --git a/jiuguan2025cc/default/content/presets/novel/Fresh-Coffee-Kayra.json b/jiuguan2025cc/default/content/presets/novel/Fresh-Coffee-Kayra.json new file mode 100644 index 0000000000000000000000000000000000000000..162b8e7781496f03666ba586190944bf59ad9dd0 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Fresh-Coffee-Kayra.json @@ -0,0 +1,23 @@ +{ + "order": [0, 1, 2, 3], + "temperature": 1, + "max_length": 150, + "min_length": 1, + "top_k": 25, + "top_p": 1, + "tail_free_sampling": 0.925, + "repetition_penalty": 1.9, + "repetition_penalty_range": 768, + "repetition_penalty_slope": 1, + "repetition_penalty_frequency": 0.0025, + "repetition_penalty_presence": 0.001, + "use_cache": false, + "return_full_text": false, + "prefix": "vanilla", + "phrase_rep_pen": "off", + "max_context": 7800, + "min_p": 0, + "math1_temp": 1, + "math1_quad": 0, + "math1_quad_entropy_scale": 0 +} diff --git a/jiuguan2025cc/default/content/presets/novel/Green-Active-Writer-Kayra.json b/jiuguan2025cc/default/content/presets/novel/Green-Active-Writer-Kayra.json new file mode 100644 index 0000000000000000000000000000000000000000..635f3fbc1ebde160b65087ee5f3c5c9e03bf3aff --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Green-Active-Writer-Kayra.json @@ -0,0 +1,23 @@ +{ + "order": [0, 8, 5, 3], + "temperature": 1.5, + "max_length": 150, + "min_length": 1, + "typical_p": 0.95, + "tail_free_sampling": 0.95, + "mirostat_lr": 0.2, + "mirostat_tau": 5.5, + "repetition_penalty": 1, + "repetition_penalty_range": 1632, + "repetition_penalty_frequency": 0, + "repetition_penalty_presence": 0, + "use_cache": false, + "return_full_text": false, + "prefix": "vanilla", + "phrase_rep_pen": "very_aggressive", + "max_context": 7800, + "min_p": 0, + "math1_temp": 1, + "math1_quad": 0, + "math1_quad_entropy_scale": 0 +} diff --git a/jiuguan2025cc/default/content/presets/novel/Keelback-Clio.json b/jiuguan2025cc/default/content/presets/novel/Keelback-Clio.json new file mode 100644 index 0000000000000000000000000000000000000000..5beba6606fce2fc3d06564e20f897481ea388681 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Keelback-Clio.json @@ -0,0 +1,25 @@ +{ + "order": [4, 5, 0, 3], + "temperature": 1.18, + "max_length": 40, + "min_length": 1, + "top_a": 0.022, + "top_k": 0, + "top_p": 1, + "typical_p": 0.9, + "tail_free_sampling": 0.956, + "repetition_penalty": 1.25, + "repetition_penalty_range": 4096, + "repetition_penalty_slope": 0.9, + "repetition_penalty_frequency": 0, + "repetition_penalty_presence": 0, + "use_cache": false, + "return_full_text": false, + "prefix": "vanilla", + "phrase_rep_pen": "very_light", + "max_context": 7800, + "min_p": 0, + "math1_temp": 1, + "math1_quad": 0, + "math1_quad_entropy_scale": 0 +} diff --git a/jiuguan2025cc/default/content/presets/novel/Long-Press-Clio.json b/jiuguan2025cc/default/content/presets/novel/Long-Press-Clio.json new file mode 100644 index 0000000000000000000000000000000000000000..c2900a2dea36d0c6c0fa5bb4d09e2efb2953cbc1 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Long-Press-Clio.json @@ -0,0 +1,25 @@ +{ + "order": [0, 4, 1, 5, 3], + "temperature": 1.155, + "max_length": 40, + "min_length": 1, + "top_k": 25, + "top_a": 0.3, + "top_p": 1, + "typical_p": 0.96, + "tail_free_sampling": 0.895, + "repetition_penalty": 1.0125, + "repetition_penalty_range": 2048, + "repetition_penalty_slope": 3.33, + "repetition_penalty_frequency": 0.011, + "repetition_penalty_presence": 0.005, + "use_cache": false, + "return_full_text": false, + "prefix": "vanilla", + "phrase_rep_pen": "very_light", + "max_context": 7800, + "min_p": 0, + "math1_temp": 1, + "math1_quad": 0, + "math1_quad_entropy_scale": 0 +} diff --git a/jiuguan2025cc/default/content/presets/novel/Pilotfish-Kayra.json b/jiuguan2025cc/default/content/presets/novel/Pilotfish-Kayra.json new file mode 100644 index 0000000000000000000000000000000000000000..15a8726c62dd702565d5433cca28f88a4900de42 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Pilotfish-Kayra.json @@ -0,0 +1,25 @@ +{ + "order": [0, 4, 1, 2, 5, 3], + "temperature": 1.31, + "max_length": 150, + "min_length": 1, + "top_k": 25, + "top_p": 0.97, + "top_a": 0.18, + "typical_p": 0.98, + "tail_free_sampling": 1, + "repetition_penalty": 1.55, + "repetition_penalty_frequency": 0.00075, + "repetition_penalty_presence": 0.00085, + "repetition_penalty_range": 8192, + "repetition_penalty_slope": 1.8, + "use_cache": false, + "return_full_text": false, + "prefix": "vanilla", + "phrase_rep_pen": "medium", + "max_context": 7800, + "min_p": 0, + "math1_temp": 1, + "math1_quad": 0, + "math1_quad_entropy_scale": 0 +} diff --git a/jiuguan2025cc/default/content/presets/novel/Pro_Writer-Kayra.json b/jiuguan2025cc/default/content/presets/novel/Pro_Writer-Kayra.json new file mode 100644 index 0000000000000000000000000000000000000000..374f96ae3db32b7ad936be31048bad5e12fdae02 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Pro_Writer-Kayra.json @@ -0,0 +1,23 @@ +{ + "order": [3, 4, 5, 0], + "temperature": 1.06, + "max_length": 150, + "min_length": 1, + "top_a": 0.146, + "typical_p": 0.976, + "tail_free_sampling": 0.969, + "repetition_penalty": 1.86, + "repetition_penalty_slope": 2.33, + "repetition_penalty_frequency": 0, + "repetition_penalty_presence": 0, + "repetition_penalty_range": 2048, + "use_cache": false, + "return_full_text": false, + "prefix": "vanilla", + "phrase_rep_pen": "medium", + "max_context": 7800, + "min_p": 0, + "math1_temp": 1, + "math1_quad": 0, + "math1_quad_entropy_scale": 0 +} diff --git a/jiuguan2025cc/default/content/presets/novel/Stelenes-Kayra.json b/jiuguan2025cc/default/content/presets/novel/Stelenes-Kayra.json new file mode 100644 index 0000000000000000000000000000000000000000..68cb0b8de2586f97ca4e179026628caa757a5d2c --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Stelenes-Kayra.json @@ -0,0 +1,21 @@ +{ + "order": [3, 0, 5], + "temperature": 2.5, + "max_length": 150, + "min_length": 1, + "typical_p": 0.969, + "tail_free_sampling": 0.941, + "repetition_penalty": 1, + "repetition_penalty_range": 1024, + "repetition_penalty_frequency": 0, + "repetition_penalty_presence": 0, + "use_cache": false, + "return_full_text": false, + "prefix": "vanilla", + "phrase_rep_pen": "medium", + "max_context": 7800, + "min_p": 0, + "math1_temp": 1, + "math1_quad": 0, + "math1_quad_entropy_scale": 0 +} diff --git a/jiuguan2025cc/default/content/presets/novel/Talker-Chat-Clio.json b/jiuguan2025cc/default/content/presets/novel/Talker-Chat-Clio.json new file mode 100644 index 0000000000000000000000000000000000000000..de93b11dc5219a0e7664421b219d8cbef3e7a442 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Talker-Chat-Clio.json @@ -0,0 +1,25 @@ +{ + "order": [1, 5, 0, 2, 3, 4], + "temperature": 1.5, + "max_length": 150, + "min_length": 1, + "top_k": 10, + "top_p": 0.75, + "top_a": 0.08, + "typical_p": 0.975, + "tail_free_sampling": 0.967, + "repetition_penalty": 2.25, + "repetition_penalty_range": 8192, + "repetition_penalty_slope": 0.09, + "repetition_penalty_frequency": 0, + "repetition_penalty_presence": 0.005, + "use_cache": false, + "return_full_text": false, + "prefix": "vanilla", + "phrase_rep_pen": "very_light", + "max_context": 7800, + "min_p": 0, + "math1_temp": 1, + "math1_quad": 0, + "math1_quad_entropy_scale": 0 +} diff --git a/jiuguan2025cc/default/content/presets/novel/Tea_Time-Kayra.json b/jiuguan2025cc/default/content/presets/novel/Tea_Time-Kayra.json new file mode 100644 index 0000000000000000000000000000000000000000..4d40d66cd00d2f4004ec22ce19680e929c2fc44f --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Tea_Time-Kayra.json @@ -0,0 +1,22 @@ +{ + "order": [5, 0, 4], + "temperature": 1, + "max_length": 150, + "min_length": 1, + "top_a": 0.017, + "typical_p": 0.975, + "repetition_penalty": 3, + "repetition_penalty_slope": 0.09, + "repetition_penalty_frequency": 0, + "repetition_penalty_presence": 0, + "repetition_penalty_range": 7680, + "use_cache": false, + "return_full_text": false, + "prefix": "vanilla", + "phrase_rep_pen": "aggressive", + "max_context": 7800, + "min_p": 0, + "math1_temp": 1, + "math1_quad": 0, + "math1_quad_entropy_scale": 0 +} diff --git a/jiuguan2025cc/default/content/presets/novel/Tesseract-Kayra.json b/jiuguan2025cc/default/content/presets/novel/Tesseract-Kayra.json new file mode 100644 index 0000000000000000000000000000000000000000..f4e44a1236d4b243c40ff114b296ea33bad6a7f7 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Tesseract-Kayra.json @@ -0,0 +1,21 @@ +{ + "order": [0, 5], + "temperature": 0.895, + "max_length": 150, + "min_length": 1, + "typical_p": 0.9, + "repetition_penalty": 2, + "repetition_penalty_slope": 3.2, + "repetition_penalty_frequency": 0, + "repetition_penalty_presence": 0, + "repetition_penalty_range": 4048, + "use_cache": false, + "return_full_text": false, + "prefix": "vanilla", + "phrase_rep_pen": "aggressive", + "max_context": 7800, + "min_p": 0, + "math1_temp": 1, + "math1_quad": 0, + "math1_quad_entropy_scale": 0 +} diff --git a/jiuguan2025cc/default/content/presets/novel/Vingt-Un-Clio.json b/jiuguan2025cc/default/content/presets/novel/Vingt-Un-Clio.json new file mode 100644 index 0000000000000000000000000000000000000000..b6e594c754ee12ec302567a11afe97e02bd9c60c --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Vingt-Un-Clio.json @@ -0,0 +1,25 @@ +{ + "order": [0, 5, 3, 2, 1], + "temperature": 1.21, + "max_length": 40, + "min_length": 1, + "top_k": 0, + "top_p": 0.912, + "top_a": 1, + "typical_p": 0.912, + "tail_free_sampling": 0.921, + "repetition_penalty": 1.21, + "repetition_penalty_range": 321, + "repetition_penalty_slope": 3.33, + "repetition_penalty_frequency": 0.00621, + "repetition_penalty_presence": 0, + "use_cache": false, + "return_full_text": false, + "prefix": "vanilla", + "phrase_rep_pen": "very_light", + "max_context": 7800, + "min_p": 0, + "math1_temp": 1, + "math1_quad": 0, + "math1_quad_entropy_scale": 0 +} diff --git a/jiuguan2025cc/default/content/presets/novel/Writers-Daemon-Kayra.json b/jiuguan2025cc/default/content/presets/novel/Writers-Daemon-Kayra.json new file mode 100644 index 0000000000000000000000000000000000000000..70561d483850fa50f7614cef243361f0b75a6449 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/novel/Writers-Daemon-Kayra.json @@ -0,0 +1,25 @@ +{ + "order": [8, 0, 5, 3, 2, 4], + "temperature": 1.5, + "max_length": 150, + "min_length": 1, + "top_a": 0.02, + "top_p": 0.95, + "typical_p": 0.95, + "tail_free_sampling": 0.95, + "mirostat_lr": 0.25, + "mirostat_tau": 5, + "repetition_penalty": 1.625, + "repetition_penalty_range": 2016, + "repetition_penalty_frequency": 0, + "repetition_penalty_presence": 0, + "use_cache": false, + "return_full_text": false, + "prefix": "vanilla", + "phrase_rep_pen": "very_aggressive", + "max_context": 7800, + "min_p": 0, + "math1_temp": 1, + "math1_quad": 0, + "math1_quad_entropy_scale": 0 +} diff --git a/jiuguan2025cc/default/content/presets/openai/Default.json b/jiuguan2025cc/default/content/presets/openai/Default.json new file mode 100644 index 0000000000000000000000000000000000000000..19660ea2ddf874b6300b9ff0d12b008974eff504 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/openai/Default.json @@ -0,0 +1,241 @@ +{ + "chat_completion_source": "openai", + "openai_model": "gpt-4-turbo", + "claude_model": "claude-3-5-sonnet-20240620", + "windowai_model": "", + "openrouter_model": "OR_Website", + "openrouter_use_fallback": false, + "openrouter_group_models": false, + "openrouter_sort_models": "alphabetically", + "ai21_model": "jamba-1.5-large", + "mistralai_model": "mistral-large-latest", + "custom_model": "", + "custom_url": "", + "custom_include_body": "", + "custom_exclude_body": "", + "custom_include_headers": "", + "google_model": "gemini-pro", + "temperature": 1, + "frequency_penalty": 0, + "presence_penalty": 0, + "top_p": 1, + "top_k": 0, + "top_a": 0, + "min_p": 0, + "repetition_penalty": 1, + "openai_max_context": 4095, + "openai_max_tokens": 300, + "wrap_in_quotes": false, + "names_behavior": 0, + "send_if_empty": "", + "impersonation_prompt": "[Write your next reply from the point of view of {{user}}, using the chat history so far as a guideline for the writing style of {{user}}. Don't write as {{char}} or system. Don't describe actions of {{char}}.]", + "new_chat_prompt": "[Start a new Chat]", + "new_group_chat_prompt": "[Start a new group chat. Group members: {{group}}]", + "new_example_chat_prompt": "[Example Chat]", + "continue_nudge_prompt": "[Continue your last message without repeating its original content.]", + "bias_preset_selected": "Default (none)", + "reverse_proxy": "", + "proxy_password": "", + "max_context_unlocked": false, + "wi_format": "{0}", + "scenario_format": "{{scenario}}", + "personality_format": "{{personality}}", + "group_nudge_prompt": "[Write the next reply only as {{char}}.]", + "stream_openai": true, + "prompts": [ + { + "name": "Main Prompt", + "system_prompt": true, + "role": "system", + "content": "Write {{char}}'s next reply in a fictional chat between {{char}} and {{user}}.", + "identifier": "main" + }, + { + "name": "Auxiliary Prompt", + "system_prompt": true, + "role": "system", + "content": "", + "identifier": "nsfw" + }, + { + "identifier": "dialogueExamples", + "name": "Chat Examples", + "system_prompt": true, + "marker": true + }, + { + "name": "Post-History Instructions", + "system_prompt": true, + "role": "system", + "content": "", + "identifier": "jailbreak" + }, + { + "identifier": "chatHistory", + "name": "Chat History", + "system_prompt": true, + "marker": true + }, + { + "identifier": "worldInfoAfter", + "name": "World Info (after)", + "system_prompt": true, + "marker": true + }, + { + "identifier": "worldInfoBefore", + "name": "World Info (before)", + "system_prompt": true, + "marker": true + }, + { + "identifier": "enhanceDefinitions", + "role": "system", + "name": "Enhance Definitions", + "content": "If you have more knowledge of {{char}}, add to the character's lore and personality to enhance them but keep the Character Sheet's definitions absolute.", + "system_prompt": true, + "marker": false + }, + { + "identifier": "charDescription", + "name": "Char Description", + "system_prompt": true, + "marker": true + }, + { + "identifier": "charPersonality", + "name": "Char Personality", + "system_prompt": true, + "marker": true + }, + { + "identifier": "scenario", + "name": "Scenario", + "system_prompt": true, + "marker": true + }, + { + "identifier": "personaDescription", + "name": "Persona Description", + "system_prompt": true, + "marker": true + } + ], + "prompt_order": [ + { + "character_id": 100000, + "order": [ + { + "identifier": "main", + "enabled": true + }, + { + "identifier": "worldInfoBefore", + "enabled": true + }, + { + "identifier": "charDescription", + "enabled": true + }, + { + "identifier": "charPersonality", + "enabled": true + }, + { + "identifier": "scenario", + "enabled": true + }, + { + "identifier": "enhanceDefinitions", + "enabled": false + }, + { + "identifier": "nsfw", + "enabled": true + }, + { + "identifier": "worldInfoAfter", + "enabled": true + }, + { + "identifier": "dialogueExamples", + "enabled": true + }, + { + "identifier": "chatHistory", + "enabled": true + }, + { + "identifier": "jailbreak", + "enabled": true + } + ] + }, + { + "character_id": 100001, + "order": [ + { + "identifier": "main", + "enabled": true + }, + { + "identifier": "worldInfoBefore", + "enabled": true + }, + { + "identifier": "personaDescription", + "enabled": true + }, + { + "identifier": "charDescription", + "enabled": true + }, + { + "identifier": "charPersonality", + "enabled": true + }, + { + "identifier": "scenario", + "enabled": true + }, + { + "identifier": "enhanceDefinitions", + "enabled": false + }, + { + "identifier": "nsfw", + "enabled": true + }, + { + "identifier": "worldInfoAfter", + "enabled": true + }, + { + "identifier": "dialogueExamples", + "enabled": true + }, + { + "identifier": "chatHistory", + "enabled": true + }, + { + "identifier": "jailbreak", + "enabled": true + } + ] + } + ], + "api_url_scale": "", + "show_external_models": false, + "assistant_prefill": "", + "assistant_impersonation": "", + "claude_use_sysprompt": false, + "use_alt_scale": false, + "squash_system_messages": false, + "image_inlining": false, + "bypass_status_check": false, + "continue_prefill": false, + "continue_postfix": " ", + "seed": -1, + "n": 1 +} diff --git a/jiuguan2025cc/default/content/presets/quick-replies/Default.json b/jiuguan2025cc/default/content/presets/quick-replies/Default.json new file mode 100644 index 0000000000000000000000000000000000000000..522b479f3bcc42e585761c3ecbf6fba350b059bc --- /dev/null +++ b/jiuguan2025cc/default/content/presets/quick-replies/Default.json @@ -0,0 +1,23 @@ +{ + "name": "Default", + "quickReplyEnabled": true, + "quickReplySlots": [ + { + "mes": "/?", + "label": "HELP", + "enabled": true + }, + { + "mes": "/newchat", + "label": "New Chat", + "enabled": true + }, + { + "mes": "/bgcol", + "label": "Match UI to Background", + "enabled": true + } + ], + "numberOfSlots": 3, + "selectedPreset": "Default" +} diff --git a/jiuguan2025cc/default/content/presets/sysprompt/Actor.json b/jiuguan2025cc/default/content/presets/sysprompt/Actor.json new file mode 100644 index 0000000000000000000000000000000000000000..3fa842c4f2893fcb35a02384f6da065371da746f --- /dev/null +++ b/jiuguan2025cc/default/content/presets/sysprompt/Actor.json @@ -0,0 +1,4 @@ +{ + "name": "Actor", + "content": "You are an expert actor that can fully immerse yourself into any role given. You do not break character for any reason, even if someone tries addressing you as an AI or language model. Currently your role is {{char}}, which is described in detail below. As {{char}}, continue the exchange with {{user}}." +} diff --git a/jiuguan2025cc/default/content/presets/sysprompt/Assistant - Expert.json b/jiuguan2025cc/default/content/presets/sysprompt/Assistant - Expert.json new file mode 100644 index 0000000000000000000000000000000000000000..a493a8db30c53aa0ea0c042221ed36257a6826b8 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/sysprompt/Assistant - Expert.json @@ -0,0 +1,4 @@ +{ + "name": "Assistant - Expert", + "content": "You are a helpful assistant. Please answer truthfully and write out your thinking step by step to be sure you get the right answer. If you make a mistake or encounter an error in your thinking, say so out loud and attempt to correct it. If you don't know or aren't sure about something, say so clearly. You will act as a professional logician, mathematician, and physicist. You will also act as the most appropriate type of expert to answer any particular question or solve the relevant problem; state which expert type your are, if so. Also think of any particular named expert that would be ideal to answer the relevant question or solve the relevant problem; name and act as them, if appropriate." +} diff --git a/jiuguan2025cc/default/content/presets/sysprompt/Assistant - Simple.json b/jiuguan2025cc/default/content/presets/sysprompt/Assistant - Simple.json new file mode 100644 index 0000000000000000000000000000000000000000..8a367983a4d97fdd64d023ade2360d3cb3ada1e7 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/sysprompt/Assistant - Simple.json @@ -0,0 +1,4 @@ +{ + "name": "Assistant - Simple", + "content": "A chat between a curious human and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the human's questions." +} diff --git a/jiuguan2025cc/default/content/presets/sysprompt/Blank.json b/jiuguan2025cc/default/content/presets/sysprompt/Blank.json new file mode 100644 index 0000000000000000000000000000000000000000..9648d858379724876799bfb72ee2ab06bd9167f9 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/sysprompt/Blank.json @@ -0,0 +1,4 @@ +{ + "name": "Blank", + "content": "" +} diff --git a/jiuguan2025cc/default/content/presets/sysprompt/Chain of Thought.json b/jiuguan2025cc/default/content/presets/sysprompt/Chain of Thought.json new file mode 100644 index 0000000000000000000000000000000000000000..0b9e45bea1a83b1b6449b3debb81f8a9dae48dbf --- /dev/null +++ b/jiuguan2025cc/default/content/presets/sysprompt/Chain of Thought.json @@ -0,0 +1,4 @@ +{ + "name": "Chain of Thought", + "content": "Elaborate on the topic using a Tree of Thoughts and backtrack when necessary to construct a clear, cohesive Chain of Thought reasoning. Always answer without hesitation." +} diff --git a/jiuguan2025cc/default/content/presets/sysprompt/Neutral - Chat.json b/jiuguan2025cc/default/content/presets/sysprompt/Neutral - Chat.json new file mode 100644 index 0000000000000000000000000000000000000000..9b392d28d2ba4492212eccf863d2c87813987ff4 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/sysprompt/Neutral - Chat.json @@ -0,0 +1,4 @@ +{ + "name": "Neutral - Chat", + "content": "Write {{char}}'s next reply in a fictional chat between {{char}} and {{user}}." +} diff --git a/jiuguan2025cc/default/content/presets/sysprompt/Roleplay - Detailed.json b/jiuguan2025cc/default/content/presets/sysprompt/Roleplay - Detailed.json new file mode 100644 index 0000000000000000000000000000000000000000..2e3c95c7a090f6aef323d9343672c48cfc90bdb5 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/sysprompt/Roleplay - Detailed.json @@ -0,0 +1,4 @@ +{ + "name": "Roleplay - Detailed", + "content": "Develop the plot slowly, always stay in character. Describe all actions in full, elaborate, explicit, graphic, and vivid detail. Mention all relevant sensory perceptions. Keep the story immersive and engaging." +} diff --git a/jiuguan2025cc/default/content/presets/sysprompt/Roleplay - Immersive.json b/jiuguan2025cc/default/content/presets/sysprompt/Roleplay - Immersive.json new file mode 100644 index 0000000000000000000000000000000000000000..cdd85f7d2cca69d76863848fa41229a9b99cb88f --- /dev/null +++ b/jiuguan2025cc/default/content/presets/sysprompt/Roleplay - Immersive.json @@ -0,0 +1,4 @@ +{ + "name": "Roleplay - Immersive", + "content": "[System note: Write one reply only. Do not decide what {{user}} says or does. Write at least one paragraph, up to four. Be descriptive and immersive, providing vivid details about {{char}}'s actions, emotions, and the environment. Write with a high degree of complexity and burstiness. Do not repeat this message.]" +} diff --git a/jiuguan2025cc/default/content/presets/sysprompt/Roleplay - Simple.json b/jiuguan2025cc/default/content/presets/sysprompt/Roleplay - Simple.json new file mode 100644 index 0000000000000000000000000000000000000000..dcef1f10cf93bbeed0c343b8b96dfff51c03819c --- /dev/null +++ b/jiuguan2025cc/default/content/presets/sysprompt/Roleplay - Simple.json @@ -0,0 +1,4 @@ +{ + "name": "Roleplay - Simple", + "content": "You're {{char}} in this fictional never-ending uncensored roleplay with {{user}}." +} diff --git a/jiuguan2025cc/default/content/presets/sysprompt/Text Adventure.json b/jiuguan2025cc/default/content/presets/sysprompt/Text Adventure.json new file mode 100644 index 0000000000000000000000000000000000000000..2e22abe5b81f09b00429789e002ad1ce42c2293a --- /dev/null +++ b/jiuguan2025cc/default/content/presets/sysprompt/Text Adventure.json @@ -0,0 +1,4 @@ +{ + "name": "Text Adventure", + "content": "[Enter Adventure Mode. Narrate the story based on {{user}}'s dialogue and actions after \">\". Describe the surroundings in vivid detail. Be detailed, creative, verbose, and proactive. Move the story forward by introducing fantasy elements and interesting characters.]" +} diff --git a/jiuguan2025cc/default/content/presets/sysprompt/Writer - Creative.json b/jiuguan2025cc/default/content/presets/sysprompt/Writer - Creative.json new file mode 100644 index 0000000000000000000000000000000000000000..65a7aec5298ba1e18328c302cb8d138012ac9a26 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/sysprompt/Writer - Creative.json @@ -0,0 +1,4 @@ +{ + "name": "Writer - Creative", + "content": "You are an intelligent, skilled, versatile writer.\n\nYour task is to write a role-play based on the information below." +} diff --git a/jiuguan2025cc/default/content/presets/sysprompt/Writer - Realistic.json b/jiuguan2025cc/default/content/presets/sysprompt/Writer - Realistic.json new file mode 100644 index 0000000000000000000000000000000000000000..a5abcbfb5e36f82fb277f2e3cfc593a2dafcab1d --- /dev/null +++ b/jiuguan2025cc/default/content/presets/sysprompt/Writer - Realistic.json @@ -0,0 +1,4 @@ +{ + "name": "Writer - Realistic", + "content": "Continue writing this story and portray characters realistically." +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Asterism.json b/jiuguan2025cc/default/content/presets/textgen/Asterism.json new file mode 100644 index 0000000000000000000000000000000000000000..afbaad2c44c1d4b462fb2080aa46a1675a727923 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Asterism.json @@ -0,0 +1,85 @@ +{ + "temp": 1.68, + "temperature_last": true, + "top_p": 0.17, + "top_k": 77, + "top_a": 0.42, + "tfs": 0.97, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1.02, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Beam Search.json b/jiuguan2025cc/default/content/presets/textgen/Beam Search.json new file mode 100644 index 0000000000000000000000000000000000000000..b584ae0ae185b7bb8b8c27b7e993b3d80067c33b --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Beam Search.json @@ -0,0 +1,85 @@ +{ + "temp": 0.7, + "temperature_last": true, + "top_p": 0.92, + "top_k": 150, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 3, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 2, + "penalty_alpha": 0, + "num_beams": 10, + "length_penalty": 1.4, + "min_length": 200, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": true, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Big O.json b/jiuguan2025cc/default/content/presets/textgen/Big O.json new file mode 100644 index 0000000000000000000000000000000000000000..4b5ca81a3f2a3fb318230e410504b654302b846f --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Big O.json @@ -0,0 +1,85 @@ +{ + "temp": 0.87, + "temperature_last": true, + "top_p": 0.99, + "top_k": 85, + "top_a": 0, + "tfs": 0.68, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 0.68, + "min_p": 0, + "rep_pen": 1.01, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Contrastive Search.json b/jiuguan2025cc/default/content/presets/textgen/Contrastive Search.json new file mode 100644 index 0000000000000000000000000000000000000000..1dae94965f5d2168e56756b0c92935630be1cb7d --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Contrastive Search.json @@ -0,0 +1,85 @@ +{ + "temp": 1, + "temperature_last": true, + "top_p": 1, + "top_k": 4, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0.6, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": false, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Default.json b/jiuguan2025cc/default/content/presets/textgen/Default.json new file mode 100644 index 0000000000000000000000000000000000000000..6f450cfeb5f0d1e5f254cbc168c87a1df02c5161 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Default.json @@ -0,0 +1,85 @@ +{ + "temp": 0.7, + "temperature_last": true, + "top_p": 0.5, + "top_k": 40, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1.2, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Deterministic.json b/jiuguan2025cc/default/content/presets/textgen/Deterministic.json new file mode 100644 index 0000000000000000000000000000000000000000..06ae546754b4db8973865967d2801f61261ccf5c --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Deterministic.json @@ -0,0 +1,85 @@ +{ + "temp": 0, + "temperature_last": true, + "top_p": 0, + "top_k": 1, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1.18, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": false, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Divine Intellect.json b/jiuguan2025cc/default/content/presets/textgen/Divine Intellect.json new file mode 100644 index 0000000000000000000000000000000000000000..d9a4757d1f6439ed06eb295b3c94943127037718 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Divine Intellect.json @@ -0,0 +1,85 @@ +{ + "temp": 1.31, + "temperature_last": true, + "top_p": 0.14, + "top_k": 49, + "top_a": 0.52, + "tfs": 1, + "epsilon_cutoff": 1.49, + "eta_cutoff": 10.42, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1.17, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Kobold (Godlike).json b/jiuguan2025cc/default/content/presets/textgen/Kobold (Godlike).json new file mode 100644 index 0000000000000000000000000000000000000000..367e126ee5c7e149b930c77c5d01b5a721f87346 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Kobold (Godlike).json @@ -0,0 +1,85 @@ +{ + "temp": 0.7, + "temperature_last": true, + "top_p": 0.5, + "top_k": 0, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 0.19, + "min_p": 0, + "rep_pen": 1.1, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Kobold (Liminal Drift).json b/jiuguan2025cc/default/content/presets/textgen/Kobold (Liminal Drift).json new file mode 100644 index 0000000000000000000000000000000000000000..9035bead029e594d1bf561f3d054c3a41abfca0f --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Kobold (Liminal Drift).json @@ -0,0 +1,85 @@ +{ + "temp": 0.66, + "temperature_last": true, + "top_p": 1, + "top_k": 0, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 0.6, + "min_p": 0, + "rep_pen": 1.1, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/LLaMa-Precise.json b/jiuguan2025cc/default/content/presets/textgen/LLaMa-Precise.json new file mode 100644 index 0000000000000000000000000000000000000000..84927b8d976155380e16dbba4567624c78e2a795 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/LLaMa-Precise.json @@ -0,0 +1,85 @@ +{ + "temp": 0.7, + "temperature_last": true, + "top_p": 0.1, + "top_k": 40, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1.18, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 200, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Midnight Enigma.json b/jiuguan2025cc/default/content/presets/textgen/Midnight Enigma.json new file mode 100644 index 0000000000000000000000000000000000000000..d60d989faeac9d2801e401930bb5028c4c0a1ba8 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Midnight Enigma.json @@ -0,0 +1,85 @@ +{ + "temp": 0.98, + "temperature_last": true, + "top_p": 0.37, + "top_k": 100, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1.18, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Miro Bronze.json b/jiuguan2025cc/default/content/presets/textgen/Miro Bronze.json new file mode 100644 index 0000000000000000000000000000000000000000..346e5c29f2641358e76d1fa00cd491cfb62f7860 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Miro Bronze.json @@ -0,0 +1,85 @@ +{ + "temp": 1.06, + "temperature_last": true, + "top_p": 1, + "top_k": 0, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 2, + "mirostat_tau": 9.61, + "mirostat_eta": 1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Miro Gold.json b/jiuguan2025cc/default/content/presets/textgen/Miro Gold.json new file mode 100644 index 0000000000000000000000000000000000000000..2b2edf49a464bd8207f693dc154998cd3cd0bcab --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Miro Gold.json @@ -0,0 +1,85 @@ +{ + "temp": 1.17, + "temperature_last": true, + "top_p": 1, + "top_k": 0, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 2, + "mirostat_tau": 9.91, + "mirostat_eta": 1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Miro Silver.json b/jiuguan2025cc/default/content/presets/textgen/Miro Silver.json new file mode 100644 index 0000000000000000000000000000000000000000..2491685893ce2745634887ddc505ffa5ddef2ac6 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Miro Silver.json @@ -0,0 +1,85 @@ +{ + "temp": 1.17, + "temperature_last": true, + "top_p": 1, + "top_k": 0, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 2, + "mirostat_tau": 9.62, + "mirostat_eta": 1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Mirostat.json b/jiuguan2025cc/default/content/presets/textgen/Mirostat.json new file mode 100644 index 0000000000000000000000000000000000000000..481e7ea52737a9648827611d260b124b4f1eadd2 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Mirostat.json @@ -0,0 +1,85 @@ +{ + "temp": 1, + "temperature_last": true, + "top_p": 1, + "top_k": 0, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 2, + "mirostat_tau": 8, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Naive.json b/jiuguan2025cc/default/content/presets/textgen/Naive.json new file mode 100644 index 0000000000000000000000000000000000000000..ac1349e5cd763ff2e7e1b625e0244c7e477d5cda --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Naive.json @@ -0,0 +1,85 @@ +{ + "temp": 0.7, + "temperature_last": true, + "top_p": 0.85, + "top_k": 50, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/NovelAI (Best Guess).json b/jiuguan2025cc/default/content/presets/textgen/NovelAI (Best Guess).json new file mode 100644 index 0000000000000000000000000000000000000000..af833988972b7fac0bb15dbb7973803d932c71da --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/NovelAI (Best Guess).json @@ -0,0 +1,85 @@ +{ + "temp": 0.8, + "temperature_last": true, + "top_p": 0.9, + "top_k": 100, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1.15, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/NovelAI (Decadence).json b/jiuguan2025cc/default/content/presets/textgen/NovelAI (Decadence).json new file mode 100644 index 0000000000000000000000000000000000000000..e970dd1bce6a0c5c748563201b3c24a3d0f4e350 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/NovelAI (Decadence).json @@ -0,0 +1,85 @@ +{ + "temp": 1.99, + "temperature_last": true, + "top_p": 1, + "top_k": 100, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 0.97, + "min_p": 0, + "rep_pen": 1, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/NovelAI (Genesis).json b/jiuguan2025cc/default/content/presets/textgen/NovelAI (Genesis).json new file mode 100644 index 0000000000000000000000000000000000000000..26e96ae25a6b484678a5aab6515aa7dbf9a8f433 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/NovelAI (Genesis).json @@ -0,0 +1,85 @@ +{ + "temp": 0.63, + "temperature_last": true, + "top_p": 0.98, + "top_k": 0, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1.05, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/NovelAI (Lycaenidae).json b/jiuguan2025cc/default/content/presets/textgen/NovelAI (Lycaenidae).json new file mode 100644 index 0000000000000000000000000000000000000000..a9eacb5426178defabb31bbca9fac7130d69d062 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/NovelAI (Lycaenidae).json @@ -0,0 +1,85 @@ +{ + "temp": 1.99, + "temperature_last": true, + "top_p": 0.85, + "top_k": 12, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1.15, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/NovelAI (Ouroboros).json b/jiuguan2025cc/default/content/presets/textgen/NovelAI (Ouroboros).json new file mode 100644 index 0000000000000000000000000000000000000000..b68a5b568beac262ae69fdc2332be76e0a890b55 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/NovelAI (Ouroboros).json @@ -0,0 +1,85 @@ +{ + "temp": 1.07, + "temperature_last": true, + "top_p": 1, + "top_k": 100, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1.05, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/NovelAI (Pleasing Results).json b/jiuguan2025cc/default/content/presets/textgen/NovelAI (Pleasing Results).json new file mode 100644 index 0000000000000000000000000000000000000000..ea5c4591909591b7deb225f7fc0fc4bdc4253705 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/NovelAI (Pleasing Results).json @@ -0,0 +1,85 @@ +{ + "temp": 0.44, + "temperature_last": true, + "top_p": 1, + "top_k": 0, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1.15, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/NovelAI (Sphinx Moth).json b/jiuguan2025cc/default/content/presets/textgen/NovelAI (Sphinx Moth).json new file mode 100644 index 0000000000000000000000000000000000000000..11085fd68f8a89dede12bf0a797266582603d41f --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/NovelAI (Sphinx Moth).json @@ -0,0 +1,85 @@ +{ + "temp": 1.99, + "temperature_last": true, + "top_p": 0.18, + "top_k": 30, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1.15, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/NovelAI (Storywriter).json b/jiuguan2025cc/default/content/presets/textgen/NovelAI (Storywriter).json new file mode 100644 index 0000000000000000000000000000000000000000..4bb308db24d4bed861443476b38aa6d588a0e149 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/NovelAI (Storywriter).json @@ -0,0 +1,85 @@ +{ + "temp": 0.72, + "temperature_last": true, + "top_p": 0.73, + "top_k": 0, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1.1, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Shortwave.json b/jiuguan2025cc/default/content/presets/textgen/Shortwave.json new file mode 100644 index 0000000000000000000000000000000000000000..44608d1726997b728a0ae730810026a17cf13c92 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Shortwave.json @@ -0,0 +1,85 @@ +{ + "temp": 1.53, + "temperature_last": true, + "top_p": 0.64, + "top_k": 33, + "top_a": 0.04, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1.07, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Simple-1.json b/jiuguan2025cc/default/content/presets/textgen/Simple-1.json new file mode 100644 index 0000000000000000000000000000000000000000..6662eaa6c5aae77ff1b6a0bf27dd71d532bfb44d --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Simple-1.json @@ -0,0 +1,85 @@ +{ + "temp": 0.7, + "temperature_last": true, + "top_p": 0.9, + "top_k": 20, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1.15, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Space Alien.json b/jiuguan2025cc/default/content/presets/textgen/Space Alien.json new file mode 100644 index 0000000000000000000000000000000000000000..e1d59426bf4cafa1dbd1349687a2a990136cdd08 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Space Alien.json @@ -0,0 +1,85 @@ +{ + "temp": 1.31, + "temperature_last": true, + "top_p": 0.29, + "top_k": 72, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1.09, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/StarChat.json b/jiuguan2025cc/default/content/presets/textgen/StarChat.json new file mode 100644 index 0000000000000000000000000000000000000000..aa572e20613efd9a9f0d58537e85fe79b54a6d7e --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/StarChat.json @@ -0,0 +1,85 @@ +{ + "temp": 0.02, + "temperature_last": true, + "top_p": 0.95, + "top_k": 50, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/TFS-with-Top-A.json b/jiuguan2025cc/default/content/presets/textgen/TFS-with-Top-A.json new file mode 100644 index 0000000000000000000000000000000000000000..ba6b4c6064d20833e02c834dff8d0df4c39b9d14 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/TFS-with-Top-A.json @@ -0,0 +1,85 @@ +{ + "temp": 0.7, + "temperature_last": true, + "top_p": 1, + "top_k": 0, + "top_a": 0.2, + "tfs": 0.95, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1.15, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Titanic.json b/jiuguan2025cc/default/content/presets/textgen/Titanic.json new file mode 100644 index 0000000000000000000000000000000000000000..d46f0cf719189f3cd156280cde3c9eaaf51e0fe1 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Titanic.json @@ -0,0 +1,85 @@ +{ + "temp": 1.01, + "temperature_last": true, + "top_p": 0.21, + "top_k": 91, + "top_a": 0.75, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 10.78, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1.21, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1.07, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Universal-Creative.json b/jiuguan2025cc/default/content/presets/textgen/Universal-Creative.json new file mode 100644 index 0000000000000000000000000000000000000000..527550b9ab0df6a84e561df9d2f5e009425cb574 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Universal-Creative.json @@ -0,0 +1,85 @@ +{ + "temp": 1.5, + "temperature_last": false, + "top_p": 1, + "top_k": 0, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0.1, + "rep_pen": 1, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 5, + 6, + 0, + 1, + 2, + 3, + 4 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Universal-Light.json b/jiuguan2025cc/default/content/presets/textgen/Universal-Light.json new file mode 100644 index 0000000000000000000000000000000000000000..8bc79a8471a49db18e2e3bd5784ee6655a64b391 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Universal-Light.json @@ -0,0 +1,85 @@ +{ + "temp": 1.25, + "temperature_last": false, + "top_p": 1, + "top_k": 0, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0.1, + "rep_pen": 1, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 5, + 6, + 0, + 1, + 2, + 3, + 4 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Universal-Super-Creative.json b/jiuguan2025cc/default/content/presets/textgen/Universal-Super-Creative.json new file mode 100644 index 0000000000000000000000000000000000000000..dfd28d8632443946cb9426761830075d4505e7bb --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Universal-Super-Creative.json @@ -0,0 +1,85 @@ +{ + "temp": 2, + "temperature_last": false, + "top_p": 1, + "top_k": 0, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0.1, + "rep_pen": 1, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 5, + 6, + 0, + 1, + 2, + 3, + 4 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/Yara.json b/jiuguan2025cc/default/content/presets/textgen/Yara.json new file mode 100644 index 0000000000000000000000000000000000000000..37601398c9e6b96fbd7c4ede66e3f4e3c288c00f --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/Yara.json @@ -0,0 +1,85 @@ +{ + "temp": 0.82, + "temperature_last": true, + "top_p": 0.21, + "top_k": 72, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1.19, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 5, + 6, + 0, + 1, + 2, + 3, + 4 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/presets/textgen/simple-proxy-for-tavern.json b/jiuguan2025cc/default/content/presets/textgen/simple-proxy-for-tavern.json new file mode 100644 index 0000000000000000000000000000000000000000..17e07784270abdb73bb0871c9ef7feb184aa11e5 --- /dev/null +++ b/jiuguan2025cc/default/content/presets/textgen/simple-proxy-for-tavern.json @@ -0,0 +1,85 @@ +{ + "temp": 0.65, + "temperature_last": true, + "top_p": 0.47, + "top_k": 42, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "min_p": 0, + "rep_pen": 1.18, + "rep_pen_range": 0, + "rep_pen_decay": 0, + "rep_pen_slope": 1, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "freq_pen": 0, + "presence_pen": 0, + "skew": 0, + "do_sample": true, + "early_stopping": false, + "dynatemp": false, + "min_temp": 0, + "max_temp": 2, + "dynatemp_exponent": 1, + "smoothing_factor": 0, + "smoothing_curve": 1, + "dry_allowed_length": 2, + "dry_multiplier": 0, + "dry_base": 1.75, + "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]", + "dry_penalty_last_n": 0, + "add_bos_token": true, + "ban_eos_token": false, + "skip_special_tokens": true, + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "grammar_string": "", + "json_schema": {}, + "banned_tokens": "", + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "ignore_eos_token": false, + "spaces_between_special_tokens": true, + "speculative_ngram": false, + "sampler_order": [ + 6, + 0, + 1, + 3, + 4, + 2, + 5 + ], + "logit_bias": [], + "rep_pen_size": 0 +} diff --git a/jiuguan2025cc/default/content/settings.json b/jiuguan2025cc/default/content/settings.json new file mode 100644 index 0000000000000000000000000000000000000000..8a47c6de5fd21192cb7120d05623784cbcdd4b02 --- /dev/null +++ b/jiuguan2025cc/default/content/settings.json @@ -0,0 +1,638 @@ +{ + "firstRun": true, + "username": "User", + "api_server": "http://127.0.0.1:5000/api", + "preset_settings": "RecoveredRuins", + "user_avatar": "user-default.png", + "amount_gen": 350, + "max_context": 8192, + "main_api": "koboldhorde", + "world_info_settings": { + "world_info": { + "globalSelect": [] + }, + "world_info_depth": 2, + "world_info_budget": 25, + "world_info_include_names": true, + "world_info_recursive": true, + "world_info_overflow_alert": false, + "world_info_case_sensitive": false, + "world_info_match_whole_words": true, + "world_info_character_strategy": 1, + "world_info_budget_cap": 0 + }, + "textgenerationwebui_settings": { + "temp": 0.5, + "top_p": 0.9, + "top_k": 0, + "top_a": 0, + "tfs": 1, + "epsilon_cutoff": 0, + "eta_cutoff": 0, + "typical_p": 1, + "rep_pen": 1.1, + "rep_pen_range": 0, + "no_repeat_ngram_size": 0, + "penalty_alpha": 0, + "num_beams": 1, + "length_penalty": 1, + "min_length": 0, + "encoder_rep_pen": 1, + "do_sample": true, + "early_stopping": false, + "seed": -1, + "preset": "Default", + "add_bos_token": true, + "stopping_strings": [], + "ban_eos_token": false, + "skip_special_tokens": true, + "streaming": false, + "sampler_priority": [ + "temperature", + "dynamic_temperature", + "quadratic_sampling", + "top_k", + "top_p", + "typical_p", + "epsilon_cutoff", + "eta_cutoff", + "tfs", + "top_a", + "min_p", + "mirostat" + ], + "samplers": [ + "top_k", + "tfs_z", + "typical_p", + "top_p", + "min_p", + "temperature" + ], + "mirostat_mode": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "guidance_scale": 1, + "negative_prompt": "", + "rep_pen_size": 0 + }, + "swipes": true, + "horde_settings": { + "models": [], + "auto_adjust_response_length": true, + "auto_adjust_context_length": false, + "trusted_workers_only": false + }, + "power_user": { + "tokenizer": 99, + "token_padding": 64, + "collapse_newlines": false, + "pin_examples": false, + "strip_examples": false, + "trim_sentences": false, + "always_force_name2": true, + "user_prompt_bias": "", + "show_user_prompt_bias": true, + "markdown_escape_strings": "", + "fast_ui_mode": true, + "avatar_style": 0, + "chat_display": 0, + "chat_width": 50, + "never_resize_avatars": false, + "show_card_avatar_urls": false, + "play_message_sound": false, + "play_sound_unfocused": true, + "auto_save_msg_edits": false, + "confirm_message_delete": true, + "sort_field": "name", + "sort_order": "asc", + "sort_rule": null, + "font_scale": 1, + "blur_strength": 10, + "shadow_width": 2, + "main_text_color": "rgba(220, 220, 210, 1)", + "italics_text_color": "rgba(145, 145, 145, 1)", + "underline_text_color": "rgba(188, 231, 207, 1)", + "quote_text_color": "rgba(225, 138, 36, 1)", + "chat_tint_color": "rgba(23, 23, 23, 1)", + "blur_tint_color": "rgba(23, 23, 23, 1)", + "user_mes_blur_tint_color": "rgba(30, 30, 30, 0.9)", + "bot_mes_blur_tint_color": "rgba(30, 30, 30, 0.9)", + "shadow_color": "rgba(0, 0, 0, 1)", + "waifuMode": false, + "movingUI": false, + "movingUIState": {}, + "movingUIPreset": "Default", + "noShadows": true, + "theme": "Dark Lite", + "auto_swipe": false, + "auto_swipe_minimum_length": 0, + "auto_swipe_blacklist": [], + "auto_swipe_blacklist_threshold": 2, + "auto_scroll_chat_to_bottom": true, + "auto_fix_generated_markdown": false, + "send_on_enter": 0, + "console_log_prompts": false, + "allow_name1_display": false, + "allow_name2_display": false, + "hotswap_enabled": true, + "timer_enabled": false, + "timestamps_enabled": true, + "timestamp_model_icon": true, + "mesIDDisplay_enabled": false, + "hideChatAvatars_enabled": false, + "max_context_unlocked": false, + "prefer_character_prompt": true, + "prefer_character_jailbreak": true, + "quick_continue": false, + "continue_on_send": false, + "trim_spaces": true, + "relaxed_api_urls": false, + "instruct": { + "enabled": false, + "preset": "Alpaca", + "input_sequence": "### Instruction:", + "output_sequence": "### Response:", + "last_output_sequence": "", + "system_sequence": "### Input:", + "stop_sequence": "", + "wrap": true, + "macro": true, + "names_behavior": "force", + "activation_regex": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "first_output_sequence": "", + "skip_examples": false, + "output_suffix": "\n\n", + "input_suffix": "\n\n", + "system_suffix": "\n\n", + "user_alignment_message": "", + "system_same_as_user": false + }, + "sysprompt": { + "enabled": true, + "name": "Neutral - Chat", + "content": "Write {{char}}'s next reply in a fictional chat between {{char}} and {{user}}." + }, + "context": { + "preset": "Default", + "story_string": "{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}", + "chat_start": "***", + "example_separator": "***", + "use_stop_strings": true + }, + "personas": {}, + "default_persona": null, + "persona_descriptions": {}, + "persona_description": "", + "persona_description_position": 0, + "persona_show_notifications": true, + "custom_stopping_strings": "", + "custom_stopping_strings_macro": true, + "fuzzy_search": true, + "encode_tags": false, + "enableLabMode": false, + "enableZenSliders": false, + "ui_mode": 1, + "forbid_external_media": true, + "stscript": { + "parser": { + "flags": { + "1": true, + "2": true + } + } + } + }, + "extension_settings": { + "apiUrl": "http://localhost:5100", + "apiKey": "", + "autoConnect": false, + "disabledExtensions": [], + "expressionOverrides": [], + "memory": { + "minLongMemory": 16, + "maxLongMemory": 1024, + "longMemoryLength": 128, + "shortMemoryLength": 512, + "minShortMemory": 128, + "maxShortMemory": 1024, + "shortMemoryStep": 16, + "longMemoryStep": 8, + "repetitionPenaltyStep": 0.05, + "repetitionPenalty": 1.2, + "maxRepetitionPenalty": 2, + "minRepetitionPenalty": 1, + "temperature": 1, + "minTemperature": 0.1, + "maxTemperature": 2, + "temperatureStep": 0.05, + "lengthPenalty": 1, + "minLengthPenalty": -4, + "maxLengthPenalty": 4, + "lengthPenaltyStep": 0.1, + "memoryFrozen": false, + "source": "extras", + "prompt": "Ignore previous instructions. Summarize the most important facts and events in the story so far. If a summary already exists in your memory, use that as a base and expand with new facts. Limit the summary to {{words}} words or less. Your response should include nothing but the summary.", + "promptWords": 200, + "promptMinWords": 25, + "promptMaxWords": 1000, + "promptWordsStep": 25, + "promptInterval": 10, + "promptMinInterval": 1, + "promptMaxInterval": 100, + "promptIntervalStep": 1, + "template": "[Summary: {{summary}}]", + "position": 0, + "depth": 2, + "promptForceWords": 0, + "promptForceWordsStep": 100, + "promptMinForceWords": 0, + "promptMaxForceWords": 10000 + }, + "note": { + "default": "", + "chara": [], + "wiAddition": [] + }, + "caption": { + "refine_mode": false + }, + "expressions": { + "showDefault": false + }, + "dice": {}, + "regex": [], + "tts": { + "voiceMap": "", + "ttsEnabled": false, + "currentProvider": "System", + "auto_generation": true, + "ElevenLabs": {}, + "System": {} + }, + "sd": { + "scale_min": 1, + "scale_max": 30, + "scale_step": 0.5, + "scale": 7, + "steps_min": 1, + "steps_max": 150, + "steps_step": 1, + "steps": 20, + "dimension_min": 64, + "dimension_max": 2048, + "dimension_step": 64, + "width": 512, + "height": 512, + "prompt_prefix": "best quality, absurdres, masterpiece,", + "negative_prompt": "lowres, bad anatomy, bad hands, text, error, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry", + "sampler": "DDIM", + "model": "", + "restore_faces": false, + "enable_hr": false, + "horde": true, + "horde_nsfw": false, + "horde_karras": true, + "refine_mode": false, + "prompts": { + "0": "In the next response I want you to provide only a detailed comma-delimited list of keywords and phrases which describe {{char}}. The list must include all of the following items in this order: name, species and race, gender, age, clothing, occupation, physical features and appearances. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase 'full body portrait,'", + "1": "Ignore previous instructions and provide a detailed description of {{user}}'s physical appearance from the perspective of {{char}} in the form of a comma-delimited list of keywords and phrases. The list must include all of the following items in this order: name, species and race, gender, age, clothing, occupation, physical features and appearances. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase 'full body portrait,'. Ignore the rest of the story when crafting this description. Do not reply as {{char}} when writing this description, and do not attempt to continue the story.", + "2": "Ignore previous instructions and provide a detailed description for all of the following: a brief recap of recent events in the story, {{char}}'s appearance, and {{char}}'s surroundings. Do not reply as {{char}} when writing this description, and do not attempt to continue the story.", + "3": "Ignore previous instructions and provide ONLY the last chat message string back to me verbatim. Do not write anything after the string. Do not reply as {{char}} when writing this description, and do not attempt to continue the story.", + "4": "Ignore previous instructions. Your next response must be formatted as a single comma-delimited list of concise keywords. The list will describe of the visual details included in the last chat message.\n\n Only mention characters by using pronouns ('he','his','she','her','it','its') or neutral nouns ('male', 'the man', 'female', 'the woman').\n\n Ignore non-visible things such as feelings, personality traits, thoughts, and spoken dialog.\n\n Add keywords in this precise order:\n a keyword to describe the location of the scene,\n a keyword to mention how many characters of each gender or type are present in the scene (minimum of two characters:\n {{user}} and {{char}}, example: '2 men ' or '1 man 1 woman ', '1 man 3 robots'),\n\n keywords to describe the relative physical positioning of the characters to each other (if a commonly known term for the positioning is known use it instead of describing the positioning in detail) + 'POV',\n\n a single keyword or phrase to describe the primary act taking place in the last chat message,\n\n keywords to describe {{char}}'s physical appearance and facial expression,\n keywords to describe {{char}}'s actions,\n keywords to describe {{user}}'s physical appearance and actions.\n\n If character actions involve direct physical interaction with another character, mention specifically which body parts interacting and how.\n\n A correctly formatted example response would be:\n '(location),(character list by gender),(primary action), (relative character position) POV, (character 1's description and actions), (character 2's description and actions)'", + "5": "In the next response I want you to provide only a detailed comma-delimited list of keywords and phrases which describe {{char}}. The list must include all of the following items in this order: name, species and race, gender, age, facial features and expressions, occupation, hair and hair accessories (if any), what they are wearing on their upper body (if anything). Do not describe anything below their neck. Do not include descriptions of non-visual qualities such as personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase 'close up facial portrait,'", + "7": "Ignore previous instructions and provide a detailed description of {{char}}'s surroundings in the form of a comma-delimited list of keywords and phrases. The list must include all of the following items in this order: location, time of day, weather, lighting, and any other relevant details. Do not include descriptions of characters and non-visual qualities such as names, personality, movements, scents, mental traits, or anything which could not be seen in a still photograph. Do not write in full sentences. Prefix your description with the phrase 'background,'. Ignore the rest of the story when crafting this description. Do not reply as {{user}} when writing this description, and do not attempt to continue the story." + }, + "character_prompts": {} + }, + "chromadb": {}, + "translate": { + "target_language": "en", + "internal_language": "en", + "provider": "google", + "auto_mode": "none" + }, + "objective": { + "customPrompts": { + "default": { + "createTask": "Ignore previous instructions and generate a list of tasks to complete an objective. Your next response must be formatted as a numbered list of plain text entries. Do not include anything but the numbered list. The list must be prioritized in the order that tasks must be completed.\n\nThe objective that you must make a numbered task list for is: [{{objective}}].\nThe tasks created should take into account the character traits of {{char}}. These tasks may or may not involve {{user}} directly. Be sure to include the objective as the final task.\n\nGiven an example objective of 'Make me a four course dinner', here is an example output:\n1. Determine what the courses will be\n2. Find recipes for each course\n3. Go shopping for supplies with {{user}}\n4. Cook the food\n5. Get {{user}} to set the table\n6. Serve the food\n7. Enjoy eating the meal with {{user}}\n ", + "checkTaskCompleted": "Ignore previous instructions. Determine if this task is completed: [{{task}}].\nTo do this, examine the most recent messages. Your response must only contain either true or false, nothing other words.\nExample output:\ntrue\n ", + "currentTask": "Your current task is [{{task}}]. Balance existing story with completing this task." + } + } + }, + "quickReply": { + "quickReplyEnabled": false, + "numberOfSlots": 5, + "quickReplySlots": [ + { + "mes": "", + "label": "", + "enabled": true + }, + { + "mes": "", + "label": "", + "enabled": true + }, + { + "mes": "", + "label": "", + "enabled": true + }, + { + "mes": "", + "label": "", + "enabled": true + }, + { + "mes": "", + "label": "", + "enabled": true + } + ] + }, + "randomizer": { + "controls": [], + "fluctuation": 0.1, + "enabled": false + }, + "speech_recognition": { + "currentProvider": "None", + "messageMode": "append", + "messageMappingText": "", + "messageMapping": [], + "messageMappingEnabled": false, + "None": {} + }, + "rvc": { + "enabled": false, + "model": "", + "pitchOffset": 0, + "pitchExtraction": "dio", + "indexRate": 0.88, + "filterRadius": 3, + "rmsMixRate": 1, + "protect": 0.33, + "voicMapText": "", + "voiceMap": {} + }, + "cfg": { + "global": { + "guidance_scale": 1, + "negative_prompt": "" + }, + "chara": [] + } + }, + "tags": [ + { + "id": "1345561466591", + "name": "ST Default", + "color": "rgba(108, 32, 32, 1)" + } + ], + "tag_map": { + "default_Seraphina.png": [ + "1345561466591" + ] + }, + "nai_settings": { + "temperature": 1.5, + "repetition_penalty": 2.25, + "repetition_penalty_range": 2048, + "repetition_penalty_slope": 0.09, + "repetition_penalty_frequency": 0, + "repetition_penalty_presence": 0.005, + "tail_free_sampling": 0.975, + "top_k": 10, + "top_p": 0.75, + "top_a": 0.08, + "typical_p": 0.975, + "min_length": 1, + "model_novel": "clio-v1", + "preset_settings_novel": "Talker-Chat-Clio", + "streaming_novel": true, + "preamble": "[ Style: chat, complex, sensory, visceral ]", + "banned_tokens": "", + "order": [ + 1, + 5, + 0, + 2, + 3, + 4 + ], + "logit_bias": [] + }, + "kai_settings": { + "temp": 1, + "rep_pen": 1.1, + "rep_pen_range": 600, + "top_p": 0.95, + "top_a": 0, + "top_k": 0, + "typical": 1, + "tfs": 1, + "rep_pen_slope": 0, + "streaming_kobold": false, + "sampler_order": [ + 6, + 0, + 1, + 2, + 3, + 4, + 5 + ], + "mirostat": 0, + "mirostat_tau": 5, + "mirostat_eta": 0.1, + "use_default_badwordsids": false, + "grammar": "" + }, + "oai_settings": { + "preset_settings_openai": "Default", + "temp_openai": 1.0, + "freq_pen_openai": 0, + "pres_pen_openai": 0, + "top_p_openai": 1, + "top_k_openai": 0, + "stream_openai": true, + "openai_max_context": 4095, + "openai_max_tokens": 300, + "wrap_in_quotes": false, + "prompts": [ + { + "name": "Main Prompt", + "system_prompt": true, + "role": "system", + "content": "Write {{char}}'s next reply in a fictional chat between {{char}} and {{user}}.", + "identifier": "main" + }, + { + "name": "Auxiliary Prompt", + "system_prompt": true, + "role": "system", + "content": "", + "identifier": "nsfw" + }, + { + "identifier": "dialogueExamples", + "name": "Chat Examples", + "system_prompt": true, + "marker": true + }, + { + "name": "Post-History Instructions", + "system_prompt": true, + "role": "system", + "content": "", + "identifier": "jailbreak" + }, + { + "identifier": "chatHistory", + "name": "Chat History", + "system_prompt": true, + "marker": true + }, + { + "identifier": "worldInfoAfter", + "name": "World Info (after)", + "system_prompt": true, + "marker": true + }, + { + "identifier": "worldInfoBefore", + "name": "World Info (before)", + "system_prompt": true, + "marker": true + }, + { + "identifier": "enhanceDefinitions", + "role": "system", + "name": "Enhance Definitions", + "content": "If you have more knowledge of {{char}}, add to the character's lore and personality to enhance them but keep the Character Sheet's definitions absolute.", + "system_prompt": true, + "marker": false + }, + { + "identifier": "charDescription", + "name": "Char Description", + "system_prompt": true, + "marker": true + }, + { + "identifier": "charPersonality", + "name": "Char Personality", + "system_prompt": true, + "marker": true + }, + { + "identifier": "scenario", + "name": "Scenario", + "system_prompt": true, + "marker": true + } + ], + "prompt_order": [ + { + "character_id": 100000, + "order": [ + { + "identifier": "main", + "enabled": true + }, + { + "identifier": "worldInfoBefore", + "enabled": true + }, + { + "identifier": "charDescription", + "enabled": true + }, + { + "identifier": "charPersonality", + "enabled": true + }, + { + "identifier": "scenario", + "enabled": true + }, + { + "identifier": "enhanceDefinitions", + "enabled": false + }, + { + "identifier": "nsfw", + "enabled": true + }, + { + "identifier": "worldInfoAfter", + "enabled": true + }, + { + "identifier": "dialogueExamples", + "enabled": true + }, + { + "identifier": "chatHistory", + "enabled": true + }, + { + "identifier": "jailbreak", + "enabled": true + } + ] + } + ], + "send_if_empty": "", + "impersonation_prompt": "[Write your next reply from the point of view of {{user}}, using the chat history so far as a guideline for the writing style of {{user}}. Write 1 reply only in internet RP style. Don't write as {{char}} or system. Don't describe actions of {{char}}.]", + "new_chat_prompt": "[Start a new Chat]", + "new_group_chat_prompt": "[Start a new group chat. Group members: {{group}}]", + "new_example_chat_prompt": "[Example Chat]", + "continue_nudge_prompt": "[Continue your last message without repeating its original content.]", + "bias_preset_selected": "Default (none)", + "bias_presets": { + "Default (none)": [], + "Anti-bond": [ + { + "id": "22154f79-dd98-41bc-8e34-87015d6a0eaf", + "text": " bond", + "value": -50 + }, + { + "id": "8ad2d5c4-d8ef-49e4-bc5e-13e7f4690e0f", + "text": " future", + "value": -50 + }, + { + "id": "52a4b280-0956-4940-ac52-4111f83e4046", + "text": " bonding", + "value": -50 + }, + { + "id": "e63037c7-c9d1-4724-ab2d-7756008b433b", + "text": " connection", + "value": -25 + } + ] + }, + "wi_format": "{0}", + "openai_model": "gpt-4-turbo", + "claude_model": "claude-3-5-sonnet-20240620", + "ai21_model": "jamba-1.5-large", + "windowai_model": "", + "openrouter_model": "OR_Website", + "reverse_proxy": "", + "chat_completion_source": "openai", + "max_context_unlocked": false, + "api_url_scale": "", + "show_external_models": false, + "proxy_password": "", + "assistant_prefill": "", + "assistant_impersonation": "" + } +} diff --git a/jiuguan2025cc/default/content/themes/Azure.json b/jiuguan2025cc/default/content/themes/Azure.json new file mode 100644 index 0000000000000000000000000000000000000000..69a0b4305716c1381c0753b59f13c790a991f1b7 --- /dev/null +++ b/jiuguan2025cc/default/content/themes/Azure.json @@ -0,0 +1,36 @@ +{ + "name": "Azure", + "blur_strength": 11, + "main_text_color": "rgba(171, 198, 223, 1)", + "italics_text_color": "rgba(255, 255, 255, 1)", + "underline_text_color": "rgba(188, 231, 207, 1)", + "quote_text_color": "rgba(111, 133, 253, 1)", + "blur_tint_color": "rgba(23, 30, 33, 0.61)", + "chat_tint_color": "rgba(23, 23, 23, 0)", + "user_mes_blur_tint_color": "rgba(0, 28, 174, 0.2)", + "bot_mes_blur_tint_color": "rgba(0, 13, 57, 0.22)", + "shadow_color": "rgba(0, 0, 0, 1)", + "shadow_width": 5, + "border_color": "rgba(0, 0, 0, 0.5)", + "font_scale": 1, + "fast_ui_mode": false, + "waifuMode": false, + "avatar_style": 1, + "chat_display": 1, + "noShadows": false, + "chat_width": 50, + "timer_enabled": true, + "timestamps_enabled": true, + "timestamp_model_icon": false, + "mesIDDisplay_enabled": true, + "hideChatAvatars_enabled": false, + "message_token_count_enabled": false, + "expand_message_actions": false, + "enableZenSliders": false, + "enableLabMode": false, + "hotswap_enabled": true, + "custom_css": "", + "bogus_folders": false, + "reduced_motion": false, + "compact_input_area": false +} diff --git a/jiuguan2025cc/default/content/themes/Cappuccino.json b/jiuguan2025cc/default/content/themes/Cappuccino.json new file mode 100644 index 0000000000000000000000000000000000000000..9b168397e9d405fee4e88721a9edcfe8c0269560 --- /dev/null +++ b/jiuguan2025cc/default/content/themes/Cappuccino.json @@ -0,0 +1,36 @@ +{ + "name": "Cappuccino", + "blur_strength": 3, + "main_text_color": "rgba(235, 235, 235, 1)", + "italics_text_color": "rgba(230, 210, 190, 1)", + "underline_text_color": "rgba(205, 180, 160, 1)", + "quote_text_color": "rgba(165, 140, 115, 1)", + "blur_tint_color": "rgba(34, 30, 32, 0.95)", + "chat_tint_color": "rgba(50, 45, 50, 0.75)", + "user_mes_blur_tint_color": "rgba(34, 30, 32, 0.75)", + "bot_mes_blur_tint_color": "rgba(34, 30, 32, 0.75)", + "shadow_color": "rgba(0, 0, 0, 0.3)", + "shadow_width": 1, + "border_color": "rgba(80, 80, 80, 0.89)", + "font_scale": 1, + "fast_ui_mode": false, + "waifuMode": false, + "avatar_style": 0, + "chat_display": 1, + "noShadows": false, + "chat_width": 50, + "timer_enabled": false, + "timestamps_enabled": true, + "timestamp_model_icon": true, + "mesIDDisplay_enabled": true, + "hideChatAvatars_enabled": false, + "message_token_count_enabled": false, + "expand_message_actions": false, + "enableZenSliders": false, + "enableLabMode": false, + "hotswap_enabled": true, + "custom_css": "", + "bogus_folders": true, + "reduced_motion": false, + "compact_input_area": true +} diff --git a/jiuguan2025cc/default/content/themes/Celestial Macaron.json b/jiuguan2025cc/default/content/themes/Celestial Macaron.json new file mode 100644 index 0000000000000000000000000000000000000000..db76bf6e43e8fd472a055738e2405dba4f538414 --- /dev/null +++ b/jiuguan2025cc/default/content/themes/Celestial Macaron.json @@ -0,0 +1,37 @@ +{ + "name": "Celestial Macaron", + "blur_strength": 10, + "main_text_color": "rgba(229, 175, 162, 1)", + "italics_text_color": "rgba(146, 147, 161, 1)", + "underline_text_color": "rgba(157, 215, 198, 1)", + "quote_text_color": "rgba(197, 202, 206, 1)", + "blur_tint_color": "rgba(23, 36, 55, 0.9)", + "chat_tint_color": "rgba(18, 26, 40, 0.9)", + "user_mes_blur_tint_color": "rgba(51, 67, 90, 0.7)", + "bot_mes_blur_tint_color": "rgba(23, 36, 55, 0.75)", + "shadow_color": "rgba(0, 0, 0, 0.3)", + "shadow_width": 1, + "border_color": "rgba(60, 74, 110, 0.93)", + "font_scale": 1, + "fast_ui_mode": false, + "waifuMode": false, + "avatar_style": 0, + "chat_display": 1, + "noShadows": true, + "chat_width": 58, + "timer_enabled": true, + "timestamps_enabled": true, + "timestamp_model_icon": false, + "mesIDDisplay_enabled": true, + "hideChatAvatars_enabled": false, + "message_token_count_enabled": true, + "expand_message_actions": true, + "enableZenSliders": false, + "enableLabMode": false, + "hotswap_enabled": true, + "custom_css": "", + "bogus_folders": true, + "zoomed_avatar_magnification": false, + "reduced_motion": false, + "compact_input_area": true +} \ No newline at end of file diff --git a/jiuguan2025cc/default/content/themes/Dark Lite.json b/jiuguan2025cc/default/content/themes/Dark Lite.json new file mode 100644 index 0000000000000000000000000000000000000000..b04fa5849bd5b1e198b4121dd087fffd96e02abe --- /dev/null +++ b/jiuguan2025cc/default/content/themes/Dark Lite.json @@ -0,0 +1,36 @@ +{ + "name": "Dark Lite", + "blur_strength": 10, + "main_text_color": "rgba(220, 220, 210, 1)", + "italics_text_color": "rgba(145, 145, 145, 1)", + "underline_text_color": "rgba(188, 231, 207, 1)", + "quote_text_color": "rgba(225, 138, 36, 1)", + "blur_tint_color": "rgba(23, 23, 23, 1)", + "chat_tint_color": "rgba(23, 23, 23, 1)", + "user_mes_blur_tint_color": "rgba(30, 30, 30, 0.9)", + "bot_mes_blur_tint_color": "rgba(30, 30, 30, 0.9)", + "shadow_color": "rgba(0, 0, 0, 1)", + "shadow_width": 2, + "border_color": "rgba(0, 0, 0, 1)", + "font_scale": 1, + "fast_ui_mode": true, + "waifuMode": false, + "avatar_style": 0, + "chat_display": 0, + "noShadows": true, + "chat_width": 50, + "timer_enabled": false, + "timestamps_enabled": true, + "timestamp_model_icon": true, + "mesIDDisplay_enabled": false, + "hideChatAvatars_enabled": false, + "message_token_count_enabled": false, + "expand_message_actions": false, + "enableZenSliders": "", + "enableLabMode": "", + "hotswap_enabled": true, + "custom_css": "", + "bogus_folders": true, + "reduced_motion": false, + "compact_input_area": true +} diff --git a/jiuguan2025cc/default/content/themes/Dark V 1.0.json b/jiuguan2025cc/default/content/themes/Dark V 1.0.json new file mode 100644 index 0000000000000000000000000000000000000000..76c9658bfee9872485a2d8f350c6961a308febd1 --- /dev/null +++ b/jiuguan2025cc/default/content/themes/Dark V 1.0.json @@ -0,0 +1,37 @@ +{ + "name": "Dark V 1.0", + "blur_strength": 13, + "main_text_color": "rgba(207, 207, 197, 1)", + "italics_text_color": "rgba(145, 145, 145, 1)", + "underline_text_color": "rgba(145, 145, 145, 1)", + "quote_text_color": "rgba(198, 193, 151, 1)", + "blur_tint_color": "rgba(29, 33, 40, 0.9)", + "chat_tint_color": "rgba(29, 33, 40, 0.9)", + "user_mes_blur_tint_color": "rgba(29, 33, 40, 0.9)", + "bot_mes_blur_tint_color": "rgba(29, 33, 40, 0.9)", + "shadow_color": "rgba(0, 0, 0, 0.9)", + "shadow_width": 2, + "border_color": "rgba(0, 0, 0, 1)", + "font_scale": 1, + "fast_ui_mode": false, + "waifuMode": false, + "avatar_style": 0, + "chat_display": 0, + "noShadows": false, + "chat_width": 55, + "timer_enabled": false, + "timestamps_enabled": false, + "timestamp_model_icon": false, + "mesIDDisplay_enabled": false, + "hideChatAvatars_enabled": false, + "message_token_count_enabled": false, + "expand_message_actions": false, + "enableZenSliders": false, + "enableLabMode": false, + "hotswap_enabled": true, + "custom_css": "", + "bogus_folders": true, + "zoomed_avatar_magnification": true, + "reduced_motion": true, + "compact_input_area": false +} diff --git a/jiuguan2025cc/default/content/user-default.png b/jiuguan2025cc/default/content/user-default.png new file mode 100644 index 0000000000000000000000000000000000000000..cfe32e4b3c1f7ce26d41ff58d553aa6081e9f3ab Binary files /dev/null and b/jiuguan2025cc/default/content/user-default.png differ diff --git a/jiuguan2025cc/default/public/css/user.css b/jiuguan2025cc/default/public/css/user.css new file mode 100644 index 0000000000000000000000000000000000000000..317a2728c224f0134bb039c236c4db8ad9724252 --- /dev/null +++ b/jiuguan2025cc/default/public/css/user.css @@ -0,0 +1 @@ +/* Put custom styles here. */ diff --git a/jiuguan2025cc/default/public/error/forbidden-by-whitelist.html b/jiuguan2025cc/default/public/error/forbidden-by-whitelist.html new file mode 100644 index 0000000000000000000000000000000000000000..70ff71852b2d33671104acec19bc1584d3c8bffa --- /dev/null +++ b/jiuguan2025cc/default/public/error/forbidden-by-whitelist.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html> + +<head> + <title>Forbidden + + + +

Forbidden

+

+ If you are the system administrator, add your IP address to the + whitelist or disable whitelist mode by editing + config.yaml in the root directory of your installation. +

+
+

+ Connection from {{ipDetails}} has been blocked. This attempt + has been logged. +

+ + + diff --git a/jiuguan2025cc/default/public/error/unauthorized.html b/jiuguan2025cc/default/public/error/unauthorized.html new file mode 100644 index 0000000000000000000000000000000000000000..e3fa5f94d0e027deb3e29f6ba3573df3f529e030 --- /dev/null +++ b/jiuguan2025cc/default/public/error/unauthorized.html @@ -0,0 +1,17 @@ + + + + + Unauthorized + + + +

Unauthorized

+

+ If you are the system administrator, you can configure the + basicAuthUser credentials by editing + config.yaml in the root directory of your installation. +

+ + + diff --git a/jiuguan2025cc/default/public/error/url-not-found.html b/jiuguan2025cc/default/public/error/url-not-found.html new file mode 100644 index 0000000000000000000000000000000000000000..87974145f7fbeb26c6c959ad5ddb465701b881a8 --- /dev/null +++ b/jiuguan2025cc/default/public/error/url-not-found.html @@ -0,0 +1,15 @@ + + + + + Not found + + + +

Not found

+

+ The requested URL was not found on this server. +

+ + + diff --git a/jiuguan2025cc/default/scaffold/README.md b/jiuguan2025cc/default/scaffold/README.md new file mode 100644 index 0000000000000000000000000000000000000000..b1272cf8f73366510f88924168e49ceb816f1a74 --- /dev/null +++ b/jiuguan2025cc/default/scaffold/README.md @@ -0,0 +1,26 @@ +# Content Scaffolding + +Content files in this folder will be copied for all users (old and new) on the server startup. + +1. You **must** create an `index.json` file in `/default/scaffold` for it to work. The syntax is the same as for default content. +2. All file paths should be relative to `/default/scaffold`, the use of subdirectories is allowed. +3. Scaffolded files are copied first, so they override any of the default files (presets/settings/etc.) that have the same file name. + +## Example + +```json +[ + { + "filename": "themes/Midnight.json", + "type": "theme" + }, + { + "filename": "backgrounds/city.png", + "type": "background" + }, + { + "filename": "characters/Charlie.png", + "type": "character" + } +] +``` diff --git a/jiuguan2025cc/docker/build-lib.js b/jiuguan2025cc/docker/build-lib.js new file mode 100644 index 0000000000000000000000000000000000000000..c56983b8bd840db167a87e7a601c761ff7da7fff --- /dev/null +++ b/jiuguan2025cc/docker/build-lib.js @@ -0,0 +1,4 @@ +import getWebpackServeMiddleware from '../src/middleware/webpack-serve.js'; + +const middleware = getWebpackServeMiddleware(); +await middleware.runWebpackCompiler({ forceDist: true }); diff --git a/jiuguan2025cc/docker/docker-compose.yml b/jiuguan2025cc/docker/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..74b749c4887523b3e2b90b6d817c6dae9aa96ced --- /dev/null +++ b/jiuguan2025cc/docker/docker-compose.yml @@ -0,0 +1,17 @@ +services: + sillytavern: + build: .. + container_name: sillytavern + hostname: sillytavern + image: ghcr.io/sillytavern/sillytavern:latest + environment: + - NODE_ENV=production + - FORCE_COLOR=1 + ports: + - "8000:8000" + volumes: + - "./config:/home/node/app/config" + - "./data:/home/node/app/data" + - "./plugins:/home/node/app/plugins" + - "./extensions:/home/node/app/public/scripts/extensions/third-party" + restart: unless-stopped diff --git a/jiuguan2025cc/docker/docker-entrypoint.sh b/jiuguan2025cc/docker/docker-entrypoint.sh new file mode 100644 index 0000000000000000000000000000000000000000..082ffc9aafa1dc44ac935e609612b0df15619c5e --- /dev/null +++ b/jiuguan2025cc/docker/docker-entrypoint.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +if [ ! -e "config/config.yaml" ]; then + echo "Resource not found, copying from defaults: config.yaml" + cp -r "default/config.yaml" "config/config.yaml" +fi + +# Execute postinstall to auto-populate config.yaml with missing values +npm run postinstall + +# Start the server +exec node server.js --listen "$@" diff --git a/jiuguan2025cc/index.d.ts b/jiuguan2025cc/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..b566dc355905b12a26968ecc5b8dc1211555a391 --- /dev/null +++ b/jiuguan2025cc/index.d.ts @@ -0,0 +1,69 @@ +import { EventEmitter } from 'node:events'; +import { CsrfSyncedToken } from 'csrf-sync'; +import { UserDirectoryList, User } from './src/users.js'; +import { CommandLineArguments } from './src/command-line.js'; +import { EVENT_NAMES } from './src/server-events.js'; + +/** + * Event payload for SERVER_STARTED event. + */ +export interface ServerStartedEvent { + /** + * The URL the server is listening on. + */ + url: URL; +} + +/** + * Map of all server events to their payload types. + */ +export interface ServerEventMap { + [EVENT_NAMES.SERVER_STARTED]: [ServerStartedEvent]; +} + +declare global { + declare namespace NodeJS { + export interface Process { + /** + * A global instance of the server events emitter. + */ + serverEvents: EventEmitter; + } + } + + declare namespace CookieSessionInterfaces { + export interface CookieSessionObject { + /** + * The CSRF token for the session. + */ + csrfToken: CsrfSyncedToken; + /** + * Authenticated user handle. + */ + handle: string; + /** + * Last time the session was extended. + */ + touch: number; + } + } + + namespace Express { + export interface Request { + user: { + profile: User; + directories: UserDirectoryList; + }; + } + } + + /** + * The root directory for user data. + */ + var DATA_ROOT: string; + + /** + * Parsed command line arguments. + */ + var COMMAND_LINE_ARGS: CommandLineArguments; +} diff --git a/jiuguan2025cc/jsconfig.json b/jiuguan2025cc/jsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..4130eaedc99ff11e738e337ea6e98c5a1db1440d --- /dev/null +++ b/jiuguan2025cc/jsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "module": "ESNext", + "target": "ES2023", + "moduleResolution": "Node", + "strictNullChecks": true, + "strictFunctionTypes": true, + "checkJs": true, + "allowUmdGlobalAccess": true, + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true, + "strictBindCallApply": true + }, + "exclude": [ + "**/node_modules/**", + "**/dist/**", + "**/.git/**", + "public/**", + "backups/**", + "data/**", + "cache/**", + "src/tokenizers/**", + "docker/**" + ] +} diff --git a/jiuguan2025cc/package-lock.json b/jiuguan2025cc/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..3c3f67dd2299ea99191c2c372f60cf36b7b89523 --- /dev/null +++ b/jiuguan2025cc/package-lock.json @@ -0,0 +1,7826 @@ +{ + "name": "sillytavern", + "version": "1.12.13", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sillytavern", + "version": "1.12.13", + "hasInstallScript": true, + "license": "AGPL-3.0", + "dependencies": { + "@adobe/css-tools": "^4.4.2", + "@agnai/sentencepiece-js": "^1.1.1", + "@agnai/web-tokenizers": "^0.1.3", + "@iconfu/svg-inject": "^1.2.3", + "@mozilla/readability": "^0.6.0", + "@popperjs/core": "^2.11.8", + "@zeldafan0225/ai_horde": "^5.2.0", + "archiver": "^7.0.1", + "bing-translate-api": "^4.0.2", + "body-parser": "^1.20.2", + "bowser": "^2.11.0", + "bytes": "^3.1.2", + "chalk": "^5.4.1", + "command-exists": "^1.2.9", + "compression": "^1.8.0", + "cookie-parser": "^1.4.6", + "cookie-session": "^2.1.0", + "cors": "^2.8.5", + "csrf-sync": "^4.0.3", + "diff-match-patch": "^1.0.5", + "dompurify": "^3.2.4", + "droll": "^0.2.1", + "express": "^4.21.0", + "form-data": "^4.0.2", + "fuse.js": "^7.1.0", + "google-translate-api-browser": "^3.0.1", + "google-translate-api-x": "^10.7.2", + "handlebars": "^4.7.8", + "helmet": "^7.2.0", + "highlight.js": "^11.11.1", + "html-entities": "^2.5.2", + "iconv-lite": "^0.6.3", + "ip-matching": "^2.1.2", + "ip-regex": "^5.0.0", + "ipaddr.js": "^2.2.0", + "is-docker": "^3.0.0", + "jimp": "^0.22.10", + "localforage": "^1.10.0", + "lodash": "^4.17.21", + "mime-types": "^2.1.35", + "moment": "^2.30.1", + "morphdom": "^2.7.4", + "multer": "^1.4.5-lts.1", + "node-fetch": "^3.3.2", + "node-persist": "^4.0.4", + "open": "^8.4.2", + "png-chunk-text": "^1.0.0", + "png-chunks-encode": "^1.0.0", + "png-chunks-extract": "^1.0.0", + "proxy-agent": "^6.5.0", + "rate-limiter-flexible": "^5.0.5", + "response-time": "^2.3.3", + "sanitize-filename": "^1.6.3", + "seedrandom": "^3.0.5", + "showdown": "^2.1.0", + "sillytavern-transformers": "2.14.6", + "simple-git": "^3.27.0", + "slidetoggle": "^4.0.0", + "tiktoken": "^1.0.20", + "url-join": "^5.0.0", + "vectra": "^0.2.2", + "wavefile": "^11.0.0", + "webpack": "^5.98.0", + "write-file-atomic": "^5.0.1", + "ws": "^8.18.1", + "yaml": "^2.7.0", + "yargs": "^17.7.1", + "yauzl": "^2.10.0" + }, + "bin": { + "sillytavern": "server.js" + }, + "devDependencies": { + "@types/archiver": "^6.0.3", + "@types/bytes": "^3.1.5", + "@types/command-exists": "^1.2.3", + "@types/compression": "^1.7.5", + "@types/cookie-parser": "^1.4.8", + "@types/cookie-session": "^2.0.49", + "@types/cors": "^2.8.17", + "@types/deno": "^2.2.0", + "@types/express": "^4.17.21", + "@types/jquery": "^3.5.32", + "@types/jquery-cropper": "^1.0.4", + "@types/jquery.transit": "^0.9.33", + "@types/jqueryui": "^1.12.24", + "@types/lodash": "^4.17.16", + "@types/mime-types": "^2.1.4", + "@types/multer": "^1.4.12", + "@types/node": "^18.19.80", + "@types/node-persist": "^3.1.8", + "@types/png-chunk-text": "^1.0.3", + "@types/png-chunks-encode": "^1.0.2", + "@types/png-chunks-extract": "^1.0.2", + "@types/response-time": "^2.3.8", + "@types/select2": "^4.0.63", + "@types/toastr": "^2.1.43", + "@types/write-file-atomic": "^4.0.3", + "@types/yargs": "^17.0.33", + "@types/yauzl": "^2.10.3", + "eslint": "^8.57.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.2.tgz", + "integrity": "sha512-baYZExFpsdkBNuvGKTKWCwKH57HRZLVtycZS05WTQNVOiXVSeAki3nU35zlRbToeMW8aHlJfyS+1C4BOv27q0A==", + "license": "MIT" + }, + "node_modules/@agnai/sentencepiece-js": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@agnai/sentencepiece-js/-/sentencepiece-js-1.1.1.tgz", + "integrity": "sha512-h2+XPrJVLuVLl+2+3iZPWcTw6Fs2NNulnxyh7LoI1hzHHib1wDC6KTmTrDJlLq7/lr5QFYpeMz2rlTFQrS0C0g==", + "license": "Apache-2.0", + "dependencies": { + "app-root-path": "^3.1.0" + } + }, + "node_modules/@agnai/web-tokenizers": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@agnai/web-tokenizers/-/web-tokenizers-0.1.3.tgz", + "integrity": "sha512-KlmTftToTtmb6aLVdne4NluS+POWputPF5J8v25UN/EQS+K9vahWEIe1NPRSFqBQclObkqHaj7JOnFrmnSm5MA==", + "license": "Apache-2.0" + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "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" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@huggingface/jinja": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@huggingface/jinja/-/jinja-0.1.2.tgz", + "integrity": "sha512-x5mpbfJt1nKmVep5WNP5VjNsjWApWNj8pPYI+uYMkBWH9bWUJmQmHt2lbf0VCoQd54Oq3XuFEh/UyoVh7rPxmg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@iconfu/svg-inject": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@iconfu/svg-inject/-/svg-inject-1.2.3.tgz", + "integrity": "sha512-3v1MUAJqmJS4jmhHoCkSxt+EdJrjPHlLXrWocCT25kCxnxJto8028Z6CC406EL11KA53SDZgI/QQA5GEJAoiRw==", + "license": "MIT" + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@jimp/bmp": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.22.12.tgz", + "integrity": "sha512-aeI64HD0npropd+AR76MCcvvRaa+Qck6loCOS03CkkxGHN5/r336qTM5HPUdHKMDOGzqknuVPA8+kK1t03z12g==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12", + "bmp-js": "^0.1.0" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/core": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/core/-/core-0.22.12.tgz", + "integrity": "sha512-l0RR0dOPyzMKfjUW1uebzueFEDtCOj9fN6pyTYWWOM/VS4BciXQ1VVrJs8pO3kycGYZxncRKhCoygbNr8eEZQA==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12", + "any-base": "^1.1.0", + "buffer": "^5.2.0", + "exif-parser": "^0.1.12", + "file-type": "^16.5.4", + "isomorphic-fetch": "^3.0.0", + "pixelmatch": "^4.0.2", + "tinycolor2": "^1.6.0" + } + }, + "node_modules/@jimp/custom": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.22.12.tgz", + "integrity": "sha512-xcmww1O/JFP2MrlGUMd3Q78S3Qu6W3mYTXYuIqFq33EorgYHV/HqymHfXy9GjiCJ7OI+7lWx6nYFOzU7M4rd1Q==", + "license": "MIT", + "dependencies": { + "@jimp/core": "^0.22.12" + } + }, + "node_modules/@jimp/gif": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/gif/-/gif-0.22.12.tgz", + "integrity": "sha512-y6BFTJgch9mbor2H234VSjd9iwAhaNf/t3US5qpYIs0TSbAvM02Fbc28IaDETj9+4YB4676sz4RcN/zwhfu1pg==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12", + "gifwrap": "^0.10.1", + "omggif": "^1.0.9" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/jpeg": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.22.12.tgz", + "integrity": "sha512-Rq26XC/uQWaQKyb/5lksCTCxXhtY01NJeBN+dQv5yNYedN0i7iYu+fXEoRsfaJ8xZzjoANH8sns7rVP4GE7d/Q==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12", + "jpeg-js": "^0.4.4" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-blit": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.22.12.tgz", + "integrity": "sha512-xslz2ZoFZOPLY8EZ4dC29m168BtDx95D6K80TzgUi8gqT7LY6CsajWO0FAxDwHz6h0eomHMfyGX0stspBrTKnQ==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-blur": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.22.12.tgz", + "integrity": "sha512-S0vJADTuh1Q9F+cXAwFPlrKWzDj2F9t/9JAbUvaaDuivpyWuImEKXVz5PUZw2NbpuSHjwssbTpOZ8F13iJX4uw==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-circle": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-0.22.12.tgz", + "integrity": "sha512-SWVXx1yiuj5jZtMijqUfvVOJBwOifFn0918ou4ftoHgegc5aHWW5dZbYPjvC9fLpvz7oSlptNl2Sxr1zwofjTg==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-color": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.22.12.tgz", + "integrity": "sha512-xImhTE5BpS8xa+mAN6j4sMRWaUgUDLoaGHhJhpC+r7SKKErYDR0WQV4yCE4gP+N0gozD0F3Ka1LUSaMXrn7ZIA==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12", + "tinycolor2": "^1.6.0" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-contain": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-0.22.12.tgz", + "integrity": "sha512-Eo3DmfixJw3N79lWk8q/0SDYbqmKt1xSTJ69yy8XLYQj9svoBbyRpSnHR+n9hOw5pKXytHwUW6nU4u1wegHNoQ==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5", + "@jimp/plugin-scale": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-cover": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-0.22.12.tgz", + "integrity": "sha512-z0w/1xH/v/knZkpTNx+E8a7fnasQ2wHG5ze6y5oL2dhH1UufNua8gLQXlv8/W56+4nJ1brhSd233HBJCo01BXA==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-crop": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5", + "@jimp/plugin-scale": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-crop": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.22.12.tgz", + "integrity": "sha512-FNuUN0OVzRCozx8XSgP9MyLGMxNHHJMFt+LJuFjn1mu3k0VQxrzqbN06yIl46TVejhyAhcq5gLzqmSCHvlcBVw==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-displace": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-0.22.12.tgz", + "integrity": "sha512-qpRM8JRicxfK6aPPqKZA6+GzBwUIitiHaZw0QrJ64Ygd3+AsTc7BXr+37k2x7QcyCvmKXY4haUrSIsBug4S3CA==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-dither": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-0.22.12.tgz", + "integrity": "sha512-jYgGdSdSKl1UUEanX8A85v4+QUm+PE8vHFwlamaKk89s+PXQe7eVE3eNeSZX4inCq63EHL7cX580dMqkoC3ZLw==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-fisheye": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-0.22.12.tgz", + "integrity": "sha512-LGuUTsFg+fOp6KBKrmLkX4LfyCy8IIsROwoUvsUPKzutSqMJnsm3JGDW2eOmWIS/jJpPaeaishjlxvczjgII+Q==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-flip": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-0.22.12.tgz", + "integrity": "sha512-m251Rop7GN8W0Yo/rF9LWk6kNclngyjIJs/VXHToGQ6EGveOSTSQaX2Isi9f9lCDLxt+inBIb7nlaLLxnvHX8Q==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-rotate": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-gaussian": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-gaussian/-/plugin-gaussian-0.22.12.tgz", + "integrity": "sha512-sBfbzoOmJ6FczfG2PquiK84NtVGeScw97JsCC3rpQv1PHVWyW+uqWFF53+n3c8Y0P2HWlUjflEla2h/vWShvhg==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-invert": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-invert/-/plugin-invert-0.22.12.tgz", + "integrity": "sha512-N+6rwxdB+7OCR6PYijaA/iizXXodpxOGvT/smd/lxeXsZ/empHmFFFJ/FaXcYh19Tm04dGDaXcNF/dN5nm6+xQ==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-mask": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-0.22.12.tgz", + "integrity": "sha512-4AWZg+DomtpUA099jRV8IEZUfn1wLv6+nem4NRJC7L/82vxzLCgXKTxvNvBcNmJjT9yS1LAAmiJGdWKXG63/NA==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-normalize": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-normalize/-/plugin-normalize-0.22.12.tgz", + "integrity": "sha512-0So0rexQivnWgnhacX4cfkM2223YdExnJTTy6d06WbkfZk5alHUx8MM3yEzwoCN0ErO7oyqEWRnEkGC+As1FtA==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-print": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-0.22.12.tgz", + "integrity": "sha512-c7TnhHlxm87DJeSnwr/XOLjJU/whoiKYY7r21SbuJ5nuH+7a78EW1teOaj5gEr2wYEd7QtkFqGlmyGXY/YclyQ==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12", + "load-bmfont": "^1.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-resize": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.22.12.tgz", + "integrity": "sha512-3NyTPlPbTnGKDIbaBgQ3HbE6wXbAlFfxHVERmrbqAi8R3r6fQPxpCauA8UVDnieg5eo04D0T8nnnNIX//i/sXg==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-rotate": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.22.12.tgz", + "integrity": "sha512-9YNEt7BPAFfTls2FGfKBVgwwLUuKqy+E8bDGGEsOqHtbuhbshVGxN2WMZaD4gh5IDWvR+emmmPPWGgaYNYt1gA==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5", + "@jimp/plugin-crop": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-scale": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.22.12.tgz", + "integrity": "sha512-dghs92qM6MhHj0HrV2qAwKPMklQtjNpoYgAB94ysYpsXslhRTiPisueSIELRwZGEr0J0VUxpUY7HgJwlSIgGZw==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-shadow": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-shadow/-/plugin-shadow-0.22.12.tgz", + "integrity": "sha512-FX8mTJuCt7/3zXVoeD/qHlm4YH2bVqBuWQHXSuBK054e7wFRnRnbSLPUqAwSeYP3lWqpuQzJtgiiBxV3+WWwTg==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blur": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-threshold": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-0.22.12.tgz", + "integrity": "sha512-4x5GrQr1a/9L0paBC/MZZJjjgjxLYrqSmWd+e+QfAEPvmRxdRoQ5uKEuNgXnm9/weHQBTnQBQsOY2iFja+XGAw==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-color": ">=0.8.0", + "@jimp/plugin-resize": ">=0.8.0" + } + }, + "node_modules/@jimp/plugins": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugins/-/plugins-0.22.12.tgz", + "integrity": "sha512-yBJ8vQrDkBbTgQZLty9k4+KtUQdRjsIDJSPjuI21YdVeqZxYywifHl4/XWILoTZsjTUASQcGoH0TuC0N7xm3ww==", + "license": "MIT", + "dependencies": { + "@jimp/plugin-blit": "^0.22.12", + "@jimp/plugin-blur": "^0.22.12", + "@jimp/plugin-circle": "^0.22.12", + "@jimp/plugin-color": "^0.22.12", + "@jimp/plugin-contain": "^0.22.12", + "@jimp/plugin-cover": "^0.22.12", + "@jimp/plugin-crop": "^0.22.12", + "@jimp/plugin-displace": "^0.22.12", + "@jimp/plugin-dither": "^0.22.12", + "@jimp/plugin-fisheye": "^0.22.12", + "@jimp/plugin-flip": "^0.22.12", + "@jimp/plugin-gaussian": "^0.22.12", + "@jimp/plugin-invert": "^0.22.12", + "@jimp/plugin-mask": "^0.22.12", + "@jimp/plugin-normalize": "^0.22.12", + "@jimp/plugin-print": "^0.22.12", + "@jimp/plugin-resize": "^0.22.12", + "@jimp/plugin-rotate": "^0.22.12", + "@jimp/plugin-scale": "^0.22.12", + "@jimp/plugin-shadow": "^0.22.12", + "@jimp/plugin-threshold": "^0.22.12", + "timm": "^1.6.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/png": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/png/-/png-0.22.12.tgz", + "integrity": "sha512-Mrp6dr3UTn+aLK8ty/dSKELz+Otdz1v4aAXzV5q53UDD2rbB5joKVJ/ChY310B+eRzNxIovbUF1KVrUsYdE8Hg==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12", + "pngjs": "^6.0.0" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/tiff": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.22.12.tgz", + "integrity": "sha512-E1LtMh4RyJsoCAfAkBRVSYyZDTtLq9p9LUiiYP0vPtXyxX4BiYBUYihTLSBlCQg5nF2e4OpQg7SPrLdJ66u7jg==", + "license": "MIT", + "dependencies": { + "utif2": "^4.0.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/types": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/types/-/types-0.22.12.tgz", + "integrity": "sha512-wwKYzRdElE1MBXFREvCto5s699izFHNVvALUv79GXNbsOVqlwlOxlWJ8DuyOGIXoLP4JW/m30YyuTtfUJgMRMA==", + "license": "MIT", + "dependencies": { + "@jimp/bmp": "^0.22.12", + "@jimp/gif": "^0.22.12", + "@jimp/jpeg": "^0.22.12", + "@jimp/png": "^0.22.12", + "@jimp/tiff": "^0.22.12", + "timm": "^1.6.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/utils": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.22.12.tgz", + "integrity": "sha512-yJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/nMKXk8TrSwAE71zt716Q==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.13.3" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@kwsites/file-exists": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.1" + } + }, + "node_modules/@kwsites/file-exists/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@kwsites/file-exists/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" + }, + "node_modules/@kwsites/promise-deferred": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", + "license": "MIT" + }, + "node_modules/@mozilla/readability": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@mozilla/readability/-/readability-0.6.0.tgz", + "integrity": "sha512-juG5VWh4qAivzTAeMzvY9xs9HY5rAcr2E4I7tiSSCokRFi7XIZCAu92ZkSTsIj1OPceCifL3cpfteP3pDT9/QQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@thunder04/supermap": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@thunder04/supermap/-/supermap-3.0.4.tgz", + "integrity": "sha512-LiPOoZ/a0L9I9+a0F3Ba4VMQIkZ4gAG0hBT9eqMWc+pjohSsYpxiMbyego+UxUk4nzh9yCHVWjYx3o6B7EGPhg==", + "license": "MIT" + }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "license": "MIT" + }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "license": "MIT" + }, + "node_modules/@types/archiver": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-6.0.3.tgz", + "integrity": "sha512-a6wUll6k3zX6qs5KlxIggs1P1JcYJaTCx2gnlr+f0S1yd2DoaEwoIK10HmBaLnZwWneBz+JBm0dwcZu0zECBcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/readdir-glob": "*" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bytes": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@types/bytes/-/bytes-3.1.5.tgz", + "integrity": "sha512-VgZkrJckypj85YxEsEavcMmmSOIzkUHqWmM4CCyia5dc54YwsXzJ5uT4fYxBQNEXx+oF1krlhgCbvfubXqZYsQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/command-exists": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/command-exists/-/command-exists-1.2.3.tgz", + "integrity": "sha512-PpbaE2XWLaWYboXD6k70TcXO/OdOyyRFq5TVpmlUELNxdkkmXU9fkImNosmXU1DtsNrqdUgWd/nJQYXgwmtdXQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/compression": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz", + "integrity": "sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookie-parser": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.8.tgz", + "integrity": "sha512-l37JqFrOJ9yQfRQkljb41l0xVphc7kg5JTjjr+pLRZ0IyZ49V4BQ8vbF4Ut2C2e+WH4al3xD3ZwYwIUfnbT4NQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/cookie-session": { + "version": "2.0.49", + "resolved": "https://registry.npmjs.org/@types/cookie-session/-/cookie-session-2.0.49.tgz", + "integrity": "sha512-4E/bBjlqLhU5l4iGPR+NkVJH593hpNsT4dC3DJDr+ODm6Qpe13kZQVkezRIb+TYDXaBMemS3yLQ+0leba3jlkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*", + "@types/keygrip": "*" + } + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/deno": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/deno/-/deno-2.2.0.tgz", + "integrity": "sha512-4x6M/ZSyoQy6fJeMArP0dvvNT4IOolfySyukuqqKhsLmSXDV4wGanqXIZ+xFihw3TlReS6JTa4hRG9nAZInpmw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "license": "MIT" + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.2.tgz", + "integrity": "sha512-FD+nQWA2zJjh4L9+pFXqWOi0Hs1ryBCfI+985NjluQ1p8EYtoLvjLOKidXBtZ4/IcxDX4o8/E8qDS3540tNliw==", + "license": "MIT" + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jquery": { + "version": "3.5.32", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.32.tgz", + "integrity": "sha512-b9Xbf4CkMqS02YH8zACqN1xzdxc3cO735Qe5AbSUFmyOiaWAbcpqh9Wna+Uk0vgACvoQHpWDg2rGdHkYPLmCiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/sizzle": "*" + } + }, + "node_modules/@types/jquery-cropper": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@types/jquery-cropper/-/jquery-cropper-1.0.4.tgz", + "integrity": "sha512-YMyUoY+rhB8yc3xM1B/daNaSq5+q93rzvRx6HP8K9mmvXEviTH3/rldlYNCGd0TmE/kLlZYJsruYhu9wY350PA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/jquery": "*" + } + }, + "node_modules/@types/jquery.transit": { + "version": "0.9.33", + "resolved": "https://registry.npmjs.org/@types/jquery.transit/-/jquery.transit-0.9.33.tgz", + "integrity": "sha512-gEDi1Lw7qfHFxtcnm2dg0F3Z5yG+84Sn0gDpGbd+u+r2RxsCcdQzfUmFKzHGBjWflZ9CXOZiAkenKOSvwLITrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/jquery": "*" + } + }, + "node_modules/@types/jqueryui": { + "version": "1.12.24", + "resolved": "https://registry.npmjs.org/@types/jqueryui/-/jqueryui-1.12.24.tgz", + "integrity": "sha512-E2sGULwzMhg4kAeOV+gYcXjg988RuPkviWCt09jLe6GGK9sHM7dTqS8H7JMuUWoZQBucIBzBAgM5o/ezKUFkeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/jquery": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, + "node_modules/@types/keygrip": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/keygrip/-/keygrip-1.0.6.tgz", + "integrity": "sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/lodash": { + "version": "4.17.16", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.16.tgz", + "integrity": "sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==", + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mime-types": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.4.tgz", + "integrity": "sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/multer": { + "version": "1.4.12", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.12.tgz", + "integrity": "sha512-pQ2hoqvXiJt2FP9WQVLPRO+AmiIm/ZYkavPlIQnx282u4ZrVdztx0pkh3jjpQt0Kz+YI0YhSG264y08UJKoUQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/node": { + "version": "18.19.80", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.80.tgz", + "integrity": "sha512-kEWeMwMeIvxYkeg1gTc01awpwLbfMRZXdIhwRcakd/KlK53jmRC26LqcbIt7fnAQTu5GzlnWmzA3H6+l1u6xxQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/node-persist": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/node-persist/-/node-persist-3.1.8.tgz", + "integrity": "sha512-QLidg6/SadZYPrTKxtxL1A85XBoQlG40bhoMdhu6DH6+eNCMr2j+RGfFZ9I9+IY8W/PDwQonJ+iBWD62jZjMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/png-chunk-text": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/png-chunk-text/-/png-chunk-text-1.0.3.tgz", + "integrity": "sha512-7keEFz73uNJ9Ar1XMCNnHEXT9pICJnouMQCCYgBEmHMgdkXaQzSTmSvr6tUDSqgdEgmlRAxZd97wprgliyZoCg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/png-chunks-encode": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/png-chunks-encode/-/png-chunks-encode-1.0.2.tgz", + "integrity": "sha512-Dxn0aXEcSg1wVeHjvNlygm/+fKBDzWMCdxJYhjGUTeefFW/jYxWcrg+W7ppLBfH44iJMqeVBHtHBwtYQUeYvgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/png-chunks-extract": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/png-chunks-extract/-/png-chunks-extract-1.0.2.tgz", + "integrity": "sha512-z6djfFIbrrddtunoMJBOPlyZrnmeuG1kkvHUNi2QfpOb+JMMLuLliHHTmMyRi7k7LiTAut0HbdGCF6ibDtQAHQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/qs": { + "version": "6.9.16", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz", + "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/readdir-glob": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@types/readdir-glob/-/readdir-glob-1.1.5.tgz", + "integrity": "sha512-raiuEPUYqXu+nvtY2Pe8s8FEmZ3x5yAH4VkLdihcPdalvsHltomrRC9BzuStrJ9yk06470hS0Crw0f1pXqD+Hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/response-time": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@types/response-time/-/response-time-2.3.8.tgz", + "integrity": "sha512-7qGaNYvdxc0zRab8oHpYx7AW17qj+G0xuag1eCrw3M2VWPJQ/HyKaaghWygiaOUl0y9x7QGQwppDpqLJ5V9pzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*", + "@types/node": "*" + } + }, + "node_modules/@types/responselike": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.1.tgz", + "integrity": "sha512-TiGnitEDxj2X0j+98Eqk5lv/Cij8oHd32bU4D/Yw6AOq7vvTk0gSD2GPj0G/HkvhMoVsdlhYF4yqqlyPBTM6Sg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/select2": { + "version": "4.0.63", + "resolved": "https://registry.npmjs.org/@types/select2/-/select2-4.0.63.tgz", + "integrity": "sha512-/DXUfPSj3iVTGlRYRYPCFKKSogAGP/j+Z0fIMXbBiBtmmZj0WH7vnfNuckafq9C43KnqPPQW2TI/Rj/vTSGnQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/jquery": "*" + } + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/sizzle": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.8.tgz", + "integrity": "sha512-0vWLNK2D5MT9dg0iOo8GlKguPAU02QjmZitPEsXRuJXU/OGIOt9vT9Fc26wtYuavLxtO45v9PGleoL9Z0k1LHg==", + "dev": true + }, + "node_modules/@types/toastr": { + "version": "2.1.43", + "resolved": "https://registry.npmjs.org/@types/toastr/-/toastr-2.1.43.tgz", + "integrity": "sha512-sLC2fr2OXeE1iyhUixpQ64wQ2tA26awmLidn4tXTLBz4yP/VhtYUKHpmiIyDtztKkHjucdiTLH8F5uRRyhNi2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/jquery": "*" + } + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, + "node_modules/@types/write-file-atomic": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/write-file-atomic/-/write-file-atomic-4.0.3.tgz", + "integrity": "sha512-qdo+vZRchyJIHNeuI1nrpsLw+hnkgqP/8mlaN6Wle/NKhydHmUN9l4p3ZE8yP90AJNJW4uB8HQhedb4f1vNayQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "license": "Apache-2.0", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "license": "Apache-2.0" + }, + "node_modules/@zeldafan0225/ai_horde": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@zeldafan0225/ai_horde/-/ai_horde-5.2.0.tgz", + "integrity": "sha512-IkFFwt8nTW+F87Kndl1b5ZQfZVgnTm2qf5By4M82fEH+KyHXvnkSTzOl/rUaqW0tjAXIyD+DM0D35TpdolPj4g==", + "license": "MIT", + "dependencies": { + "@thunder04/supermap": "^3.0.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-base": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/any-base/-/any-base-1.1.0.tgz", + "integrity": "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==", + "license": "MIT" + }, + "node_modules/app-root-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz", + "integrity": "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "license": "MIT" + }, + "node_modules/archiver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", + "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", + "dependencies": { + "archiver-utils": "^5.0.2", + "async": "^3.2.4", + "buffer-crc32": "^1.0.0", + "readable-stream": "^4.0.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^3.0.0", + "zip-stream": "^6.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/archiver-utils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", + "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", + "dependencies": { + "glob": "^10.0.0", + "graceful-fs": "^4.2.0", + "is-stream": "^2.0.1", + "lazystream": "^1.0.0", + "lodash": "^4.17.15", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/archiver-utils/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/archiver-utils/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/archiver-utils/node_modules/glob": { + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/archiver-utils/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/archiver-utils/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/archiver-utils/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/archiver/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/archiver/node_modules/buffer-crc32": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/archiver/node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/archiver/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/archiver/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.3.tgz", + "integrity": "sha512-iP4DebzoNlP/YN2dpwCgb8zoCmhtkajzS48JvwmkSkXvPI3DHc7m+XYL5tGnSlJtR6nImXZmdCuN5aP8dh1d8A==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/b4a": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/bare-events": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.2.tgz", + "integrity": "sha512-h7z00dWdG0PYOQEvChhOSWvOfkIKsdZGkWr083FgN/HyoQuebSew/cgirYqh9SCuy/hRvxc5Vy6Fw8xAmYHLkQ==", + "optional": true + }, + "node_modules/base-64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", + "integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/basic-ftp": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/bing-translate-api": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/bing-translate-api/-/bing-translate-api-4.0.2.tgz", + "integrity": "sha512-JJ8XUehnxzOhHU91oy86xEtp8OOMjVEjCZJX042fKxoO19NNvxJ5omeCcxQNFoPbDqVpBJwqiGVquL0oPdQm1Q==", + "license": "MIT", + "dependencies": { + "got": "^11.8.6" + } + }, + "node_modules/bmp-js": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz", + "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==", + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, + "node_modules/bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", + "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001663", + "electron-to-chromium": "^1.5.28", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-equal": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", + "integrity": "sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "license": "MIT", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "license": "MIT", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001669", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz", + "integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/centra": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/centra/-/centra-2.7.0.tgz", + "integrity": "sha512-PbFMgMSrmgx6uxCdm57RUos9Tc3fclMvhLSATYN39XsDV29B89zZ3KA89jmY0vwSGazyU+uerqwa6t+KaodPcg==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6" + } + }, + "node_modules/chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "license": "MIT", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "license": "BSD-2-Clause", + "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" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clone-response/node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "license": "MIT" + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/compress-commons": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", + "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", + "dependencies": { + "crc-32": "^1.2.0", + "crc32-stream": "^6.0.0", + "is-stream": "^2.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/compress-commons/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/compress-commons/node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/compress-commons/node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/compress-commons/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/compress-commons/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz", + "integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.0.2", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-parser": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", + "license": "MIT", + "dependencies": { + "cookie": "0.7.2", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-session": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cookie-session/-/cookie-session-2.1.0.tgz", + "integrity": "sha512-u73BDmR8QLGcs+Lprs0cfbcAPKl2HnPcjpwRXT41sEV4DRJ2+W0vJEEZkG31ofkx+HZflA70siRIjiTdIodmOQ==", + "dependencies": { + "cookies": "0.9.1", + "debug": "3.2.7", + "on-headers": "~1.0.2", + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cookie-session/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/cookie-session/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/cookie-session/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/cookies": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.9.1.tgz", + "integrity": "sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==", + "dependencies": { + "depd": "~2.0.0", + "keygrip": "~1.1.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/crc-32": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-0.3.0.tgz", + "integrity": "sha512-kucVIjOmMc1f0tv53BJ/5WIX+MGLcKuoBhnGqQrgKJNqLByb/sVMWfW/Aw6hw0jgcqjJ2pi9E5y32zOIpaUlsA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", + "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/crc32-stream/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/crc32-stream/node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream/node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/crc32-stream/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/crc32-stream/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz", + "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/csrf-sync": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/csrf-sync/-/csrf-sync-4.0.3.tgz", + "integrity": "sha512-wXzltBBzt/7imzDt6ZT7G/axQG7jo4Sm0uXDUzFY8hR59qhDHdjqpW2hojS4oAVIZDzwlMQloIVCTJoDDh0wwA==", + "license": "ISC", + "dependencies": { + "http-errors": "^2.0.0" + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/diff-match-patch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", + "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==", + "license": "Apache-2.0" + }, + "node_modules/digest-fetch": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/digest-fetch/-/digest-fetch-1.3.0.tgz", + "integrity": "sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==", + "license": "ISC", + "dependencies": { + "base-64": "^0.1.0", + "md5": "^2.3.0" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/dompurify": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.4.tgz", + "integrity": "sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=10" + } + }, + "node_modules/droll": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/droll/-/droll-0.2.1.tgz", + "integrity": "sha512-fXxtxZSwGK6afeG18Vk6q/8LQDAnIylsvk/2tQhHwDOJmdB/x+YL9GLoSZUZXJkQ8LrBcyU/1EoIL1eSlpDMsg==", + "bin": { + "droll": "bin/droll-cli.js" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.39", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.39.tgz", + "integrity": "sha512-4xkpSR6CjuiaNyvwiWDI85N9AxsvbPawB8xc7yzLPonYTuP19BVgYweKyUMFtHEZgIcHWMt1ks5Cqx2m+6/Grg==", + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "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" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/exif-parser": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz", + "integrity": "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==" + }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-type": { + "version": "16.5.4", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz", + "integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==", + "license": "MIT", + "dependencies": { + "readable-web-to-node-stream": "^3.0.0", + "strtok3": "^6.2.4", + "token-types": "^4.1.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatbuffers": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-1.12.0.tgz", + "integrity": "sha512-c7CZADjRcl6j0PlvFy0ZqXQ67qSEZfrVPynmnL+2zPc+NtMvrF8Y0QceMo7QqnSPc7+uWjUIAbvCQ5WIKlMVdQ==", + "license": "SEE LICENSE IN LICENSE.txt" + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", + "license": "MIT" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "license": "MIT", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, + "node_modules/formdata-node/node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fuse.js": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.1.0.tgz", + "integrity": "sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-uri": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.4.tgz", + "integrity": "sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==", + "license": "MIT", + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/get-uri/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/get-uri/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/gifwrap": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/gifwrap/-/gifwrap-0.10.1.tgz", + "integrity": "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw==", + "license": "MIT", + "dependencies": { + "image-q": "^4.0.0", + "omggif": "^1.0.10" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "license": "ISC", + "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" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "license": "BSD-2-Clause" + }, + "node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "license": "MIT", + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "node_modules/globals": { + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/google-translate-api-browser": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/google-translate-api-browser/-/google-translate-api-browser-3.0.1.tgz", + "integrity": "sha512-KTLodkyGBWMK9IW6QIeJ2zCuju4Z0CLpbkADKo+yLhbSTD4l+CXXpQ/xaynGVAzeBezzJG6qn8MLeqOq3SmW0A==", + "license": "MIT" + }, + "node_modules/google-translate-api-x": { + "version": "10.7.2", + "resolved": "https://registry.npmjs.org/google-translate-api-x/-/google-translate-api-x-10.7.2.tgz", + "integrity": "sha512-GSmbvGMcnULaih2NFgD4Y6840DLAMot90mLWgwoB+FG/QpetyZkFrZkxop8ZxXgOAQXGskFOhGJady8nA6ZJ2g==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/AidanWelch" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/gpt-3-encoder": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/gpt-3-encoder/-/gpt-3-encoder-1.1.4.tgz", + "integrity": "sha512-fSQRePV+HUAhCn7+7HL7lNIXNm6eaFWFbNLOOGtmSJ0qJycyQvj60OvRlH7mee8xAMjBDNRdMXlMwjAbMTDjkg==", + "license": "MIT" + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/guid-typescript": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/guid-typescript/-/guid-typescript-1.0.9.tgz", + "integrity": "sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ==", + "license": "ISC" + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/helmet": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.2.0.tgz", + "integrity": "sha512-ZRiwvN089JfMXokizgqEPXsl2Guk094yExfoDXR0cBYWxtBbaSww/w+vT4WEJsBW2iTUi1GgZ6swmoug3Oy4Xw==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/highlight.js": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", + "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "license": "MIT" + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "license": "BSD-2-Clause" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/http-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-q": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/image-q/-/image-q-4.0.0.tgz", + "integrity": "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw==", + "license": "MIT", + "dependencies": { + "@types/node": "16.9.1" + } + }, + "node_modules/image-q/node_modules/@types/node": { + "version": "16.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz", + "integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==", + "license": "MIT" + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "license": "MIT", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-matching": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ip-matching/-/ip-matching-2.1.2.tgz", + "integrity": "sha512-/ok+VhKMasgR5gvTRViwRFQfc0qYt9Vdowg6TO4/pFlDCob5ZjGPkwuOoQVCd5OrMm20zqh+1vA8KLJZTeWudg==", + "license": "LGPL-3.0-only" + }, + "node_modules/ip-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-5.0.0.tgz", + "integrity": "sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "license": "MIT" + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "license": "MIT" + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-wsl/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/isomorphic-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", + "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.1", + "whatwg-fetch": "^3.4.1" + } + }, + "node_modules/isomorphic-fetch/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jimp": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/jimp/-/jimp-0.22.12.tgz", + "integrity": "sha512-R5jZaYDnfkxKJy1dwLpj/7cvyjxiclxU3F4TrI/J4j2rS0niq6YDUMoPn5hs8GDpO+OZGo7Ky057CRtWesyhfg==", + "license": "MIT", + "dependencies": { + "@jimp/custom": "^0.22.12", + "@jimp/plugins": "^0.22.12", + "@jimp/types": "^0.22.12", + "regenerator-runtime": "^0.13.3" + } + }, + "node_modules/jpeg-js": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz", + "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==", + "license": "BSD-3-Clause" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "license": "MIT" + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "license": "MIT" + }, + "node_modules/json-colorizer": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/json-colorizer/-/json-colorizer-2.2.2.tgz", + "integrity": "sha512-56oZtwV1piXrQnRNTtJeqRv+B9Y/dXAYLqBBaYl/COcUdoZxgLBLAO88+CnkbT6MxNs0c5E9mPBIb2sFcNz3vw==", + "license": "MIT", + "dependencies": { + "chalk": "^2.4.1", + "lodash.get": "^4.4.2" + } + }, + "node_modules/json-colorizer/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-colorizer/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-colorizer/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/json-colorizer/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/json-colorizer/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/json-colorizer/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keygrip": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", + "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==", + "dependencies": { + "tsscmp": "1.0.6" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/keyv": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", + "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lie": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", + "integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/load-bmfont": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.2.tgz", + "integrity": "sha512-qElWkmjW9Oq1F9EI5Gt7aD9zcdHb9spJCW1L/dmPf7KzCCEJxq8nhHz5eCgI9aMf7vrG/wyaCqdsI+Iy9ZTlog==", + "license": "MIT", + "dependencies": { + "buffer-equal": "0.0.1", + "mime": "^1.3.4", + "parse-bmfont-ascii": "^1.0.3", + "parse-bmfont-binary": "^1.0.5", + "parse-bmfont-xml": "^1.1.4", + "phin": "^3.7.1", + "xhr": "^2.0.1", + "xtend": "^4.0.0" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "license": "MIT", + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/localforage": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz", + "integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==", + "license": "Apache-2.0", + "dependencies": { + "lie": "3.1.1" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", + "license": "Apache-2.0" + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "license": "BSD-3-Clause", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", + "dependencies": { + "dom-walk": "^0.1.0" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/morphdom": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/morphdom/-/morphdom-2.7.4.tgz", + "integrity": "sha512-ATTbWMgGa+FaMU3FhnFYB6WgulCqwf6opOll4CBzmVDTLvPMmUPrEv8CudmLPK0MESa64+6B89fWOxP3+YIlxQ==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/multer": { + "version": "1.4.5-lts.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz", + "integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==", + "license": "MIT", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.0.0", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/multer/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" + }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/node-fetch/node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/node-persist": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-4.0.4.tgz", + "integrity": "sha512-8sPAz/7tw1mCCc8xBG4f0wi+flHkSSgQeX998iQ75Pu27evA6UUWCjSE7xnrYTg2q33oU5leJ061EKPDv6BocQ==", + "license": "MIT", + "dependencies": { + "p-limit": "^3.1.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/omggif": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/omggif/-/omggif-1.0.10.tgz", + "integrity": "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==", + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onnx-proto": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/onnx-proto/-/onnx-proto-4.0.4.tgz", + "integrity": "sha512-aldMOB3HRoo6q/phyB6QRQxSt895HNNw82BNyZ2CMh4bjeKv7g/c+VpAFtJuEMVfYLMbRx61hbuqnKceLeDcDA==", + "license": "MIT", + "dependencies": { + "protobufjs": "^6.8.8" + } + }, + "node_modules/onnxruntime-common": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.14.0.tgz", + "integrity": "sha512-3LJpegM2iMNRX2wUmtYfeX/ytfOzNwAWKSq1HbRrKc9+uqG/FsEA0bbKZl1btQeZaXhC26l44NWpNUeXPII7Ew==", + "license": "MIT" + }, + "node_modules/onnxruntime-web": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/onnxruntime-web/-/onnxruntime-web-1.14.0.tgz", + "integrity": "sha512-Kcqf43UMfW8mCydVGcX9OMXI2VN17c0p6XvR7IPSZzBf/6lteBzXHvcEVWDPmCKuGombl997HgLqj91F11DzXw==", + "license": "MIT", + "dependencies": { + "flatbuffers": "^1.12.0", + "guid-typescript": "^1.0.9", + "long": "^4.0.0", + "onnx-proto": "^4.0.4", + "onnxruntime-common": "~1.14.0", + "platform": "^1.3.6" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openai": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.17.4.tgz", + "integrity": "sha512-ThRFkl6snLbcAKS58St7N3CaKuI5WdYUvIjPvf4s+8SdymgNtOfzmZcZXVcCefx04oKFnvZJvIcTh3eAFUUhAQ==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "digest-fetch": "^1.3.0", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7", + "web-streams-polyfill": "^3.2.1" + }, + "bin": { + "openai": "bin/cli" + } + }, + "node_modules/openai/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pac-proxy-agent": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", + "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", + "license": "MIT", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.6", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/pac-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "license": "MIT", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-bmfont-ascii": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz", + "integrity": "sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA==", + "license": "MIT" + }, + "node_modules/parse-bmfont-binary": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/parse-bmfont-binary/-/parse-bmfont-binary-1.0.6.tgz", + "integrity": "sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA==", + "license": "MIT" + }, + "node_modules/parse-bmfont-xml": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.6.tgz", + "integrity": "sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA==", + "license": "MIT", + "dependencies": { + "xml-parse-from-string": "^1.0.0", + "xml2js": "^0.5.0" + } + }, + "node_modules/parse-headers": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", + "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==", + "license": "MIT" + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "license": "MIT", + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "license": "MIT", + "dependencies": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/peek-readable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz", + "integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "license": "MIT" + }, + "node_modules/phin": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/phin/-/phin-3.7.1.tgz", + "integrity": "sha512-GEazpTWwTZaEQ9RhL7Nyz0WwqilbqgLahDM3D0hxWwmVDI52nXEybHqiN6/elwpkJBhcuj+WbBu+QfT0uhPGfQ==", + "license": "MIT", + "dependencies": { + "centra": "^2.7.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/picocolors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "license": "ISC" + }, + "node_modules/pixelmatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz", + "integrity": "sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA==", + "license": "ISC", + "dependencies": { + "pngjs": "^3.0.0" + }, + "bin": { + "pixelmatch": "bin/pixelmatch" + } + }, + "node_modules/pixelmatch/node_modules/pngjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/platform": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", + "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==", + "license": "MIT" + }, + "node_modules/png-chunk-text": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/png-chunk-text/-/png-chunk-text-1.0.0.tgz", + "integrity": "sha512-DEROKU3SkkLGWNMzru3xPVgxyd48UGuMSZvioErCure6yhOc/pRH2ZV+SEn7nmaf7WNf3NdIpH+UTrRdKyq9Lw==", + "license": "MIT" + }, + "node_modules/png-chunks-encode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/png-chunks-encode/-/png-chunks-encode-1.0.0.tgz", + "integrity": "sha512-J1jcHgbQRsIIgx5wxW9UmCymV3wwn4qCCJl6KYgEU/yHCh/L2Mwq/nMOkRPtmV79TLxRZj5w3tH69pvygFkDqA==", + "license": "MIT", + "dependencies": { + "crc-32": "^0.3.0", + "sliced": "^1.0.1" + } + }, + "node_modules/png-chunks-extract": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/png-chunks-extract/-/png-chunks-extract-1.0.0.tgz", + "integrity": "sha512-ZiVwF5EJ0DNZyzAqld8BP1qyJBaGOFaq9zl579qfbkcmOwWLLO4I9L8i2O4j3HkI6/35i0nKG2n+dZplxiT89Q==", + "license": "MIT", + "dependencies": { + "crc-32": "^0.3.0" + } + }, + "node_modules/pngjs": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", + "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", + "license": "MIT", + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/protobufjs": { + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-agent": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", + "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.6", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.1.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==" + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/rate-limiter-flexible": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-5.0.5.tgz", + "integrity": "sha512-+/dSQfo+3FYwYygUs/V2BBdwGa9nFtakDwKt4l0bnvNB53TNT++QSFewwHX9qXrZJuMe9j+TUaU21lm5ARgqdQ==", + "license": "ISC" + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "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" + } + }, + "node_modules/readable-web-to-node-stream": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", + "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", + "license": "MIT", + "dependencies": { + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/readable-web-to-node-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "license": "MIT" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/response-time": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/response-time/-/response-time-2.3.3.tgz", + "integrity": "sha512-SsjjOPHl/FfrTQNgmc5oen8Hr1Jxpn6LlHNXxCIFdYMHuK1kMeYMobb9XN3mvxaGQm3dbegqYFMX4+GDORfbWg==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "on-headers": "~1.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "license": "MIT", + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sanitize-filename": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", + "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", + "license": "WTFPL OR ISC", + "dependencies": { + "truncate-utf8-bytes": "^1.0.0" + } + }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "license": "ISC" + }, + "node_modules/schema-utils": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz", + "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/seedrandom": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", + "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==", + "license": "MIT" + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/showdown": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/showdown/-/showdown-2.1.0.tgz", + "integrity": "sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==", + "license": "MIT", + "dependencies": { + "commander": "^9.0.0" + }, + "bin": { + "showdown": "bin/showdown.js" + }, + "funding": { + "type": "individual", + "url": "https://www.paypal.me/tiviesantos" + } + }, + "node_modules/showdown/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sillytavern-transformers": { + "version": "2.14.6", + "resolved": "https://registry.npmjs.org/sillytavern-transformers/-/sillytavern-transformers-2.14.6.tgz", + "integrity": "sha512-Tpu3lcDfa3vQB/wRgF+7ZG8ZNtYygT6vEQs9+4BpXLghVanx6ic7rBSxmTxx9Sm90G1P3W8mxoVkzfs8KAvMiA==", + "license": "Apache-2.0", + "dependencies": { + "@huggingface/jinja": "^0.1.0", + "jimp": "^0.22.10", + "onnxruntime-web": "1.14.0" + } + }, + "node_modules/simple-git": { + "version": "3.27.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.27.0.tgz", + "integrity": "sha512-ivHoFS9Yi9GY49ogc6/YAi3Fl9ROnF4VyubNylgCkA+RVqLaKWnDSzXOVzya8csELIaWaYNutsEuAhZrtOjozA==", + "license": "MIT", + "dependencies": { + "@kwsites/file-exists": "^1.1.1", + "@kwsites/promise-deferred": "^1.1.1", + "debug": "^4.3.5" + }, + "funding": { + "type": "github", + "url": "https://github.com/steveukx/git-js?sponsor=1" + } + }, + "node_modules/simple-git/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/simple-git/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/sliced": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", + "integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA==", + "license": "MIT" + }, + "node_modules/slidetoggle": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slidetoggle/-/slidetoggle-4.0.0.tgz", + "integrity": "sha512-6qvrOS1dnDFEr41UEEFFRQE8nswaAFIYZAHer6dVlznRIjHyCISjNJoxIn5U5QlAbZfBBxTELQk4jS7miHto1A==", + "license": "MIT" + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz", + "integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==", + "license": "MIT", + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/socks-proxy-agent/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socks-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "license": "BSD-3-Clause" + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/streamx": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.16.1.tgz", + "integrity": "sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==", + "dependencies": { + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strtok3": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz", + "integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==", + "license": "MIT", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^4.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/terser": { + "version": "5.39.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz", + "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==", + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.12", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.12.tgz", + "integrity": "sha512-jDLYqo7oF8tJIttjXO6jBY5Hk8p3A8W4ttih7cCEq64fQFWmgJ4VqAQjKr7WwIDlmXKEc6QeoRb5ecjZ+2afcg==", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "serialize-javascript": "^6.0.2", + "terser": "^5.31.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tiktoken": { + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/tiktoken/-/tiktoken-1.0.20.tgz", + "integrity": "sha512-zVIpXp84kth/Ni2me1uYlJgl2RZ2EjxwDaWLeDY/s6fZiyO9n1QoTOM5P7ZSYfToPvAvwYNMbg5LETVYVKyzfQ==", + "license": "MIT" + }, + "node_modules/timm": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/timm/-/timm-1.7.1.tgz", + "integrity": "sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw==", + "license": "MIT" + }, + "node_modules/tinycolor2": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", + "license": "MIT" + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/token-types": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz", + "integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==", + "license": "MIT", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/truncate-utf8-bytes": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", + "integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==", + "license": "WTFPL", + "dependencies": { + "utf8-byte-length": "^1.0.1" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsscmp": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", + "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==", + "engines": { + "node": ">=0.6.x" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-join": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", + "integrity": "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/utf8-byte-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", + "integrity": "sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA==", + "license": "WTFPL" + }, + "node_modules/utif2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/utif2/-/utif2-4.1.0.tgz", + "integrity": "sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w==", + "license": "MIT", + "dependencies": { + "pako": "^1.0.11" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vectra": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/vectra/-/vectra-0.2.2.tgz", + "integrity": "sha512-Z1d29Zil+dlA9/Qz4VJB3zcWjIARY8QH5xQEnHmGgmTUP58cPRV8NK7P0QH91IRs0RvAWrYiQf9Y5JqQo0vJlQ==", + "license": "MIT", + "dependencies": { + "axios": "^1.3.4", + "cheerio": "^1.0.0-rc.12", + "dotenv": "^8.2.0", + "gpt-3-encoder": "1.1.4", + "json-colorizer": "^2.2.2", + "openai": "^3.2.1", + "uuid": "^9.0.0", + "yargs": "^17.7.2" + }, + "bin": { + "vectra": "bin/vectra.js" + } + }, + "node_modules/watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wavefile": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/wavefile/-/wavefile-11.0.0.tgz", + "integrity": "sha512-/OBiAALgWU24IG7sC84cDO/KfFuvajWc5Uec0oV2zrpOOZZDgGdOwHwgEzOrwh8jkubBk7PtZfQBIcI1OaE5Ng==", + "license": "MIT", + "bin": { + "wavefile": "bin/wavefile.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/webpack": { + "version": "5.98.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz", + "integrity": "sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==", + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.6", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.14.0", + "browserslist": "^4.24.0", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.11", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "license": "MIT" + }, + "node_modules/whatwg-url": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "license": "MIT", + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xhr": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", + "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==", + "license": "MIT", + "dependencies": { + "global": "~4.4.0", + "is-function": "^1.0.1", + "parse-headers": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/xml-parse-from-string": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz", + "integrity": "sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g==", + "license": "MIT" + }, + "node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", + "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zip-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", + "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", + "dependencies": { + "archiver-utils": "^5.0.0", + "compress-commons": "^6.0.2", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/zip-stream/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/zip-stream/node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/zip-stream/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/zip-stream/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + } + } +} diff --git a/jiuguan2025cc/package.json b/jiuguan2025cc/package.json new file mode 100644 index 0000000000000000000000000000000000000000..c9d969d494b26dd2f7ef538b94cd49ef5a523cfa --- /dev/null +++ b/jiuguan2025cc/package.json @@ -0,0 +1,145 @@ +{ + "dependencies": { + "@adobe/css-tools": "^4.4.2", + "@agnai/sentencepiece-js": "^1.1.1", + "@agnai/web-tokenizers": "^0.1.3", + "@iconfu/svg-inject": "^1.2.3", + "@mozilla/readability": "^0.6.0", + "@popperjs/core": "^2.11.8", + "@zeldafan0225/ai_horde": "^5.2.0", + "archiver": "^7.0.1", + "bing-translate-api": "^4.0.2", + "body-parser": "^1.20.2", + "bowser": "^2.11.0", + "bytes": "^3.1.2", + "chalk": "^5.4.1", + "command-exists": "^1.2.9", + "compression": "^1.8.0", + "cookie-parser": "^1.4.6", + "cookie-session": "^2.1.0", + "cors": "^2.8.5", + "csrf-sync": "^4.0.3", + "diff-match-patch": "^1.0.5", + "dompurify": "^3.2.4", + "droll": "^0.2.1", + "express": "^4.21.0", + "form-data": "^4.0.2", + "fuse.js": "^7.1.0", + "google-translate-api-browser": "^3.0.1", + "google-translate-api-x": "^10.7.2", + "handlebars": "^4.7.8", + "helmet": "^7.2.0", + "highlight.js": "^11.11.1", + "html-entities": "^2.5.2", + "iconv-lite": "^0.6.3", + "ip-matching": "^2.1.2", + "ip-regex": "^5.0.0", + "ipaddr.js": "^2.2.0", + "is-docker": "^3.0.0", + "jimp": "^0.22.10", + "localforage": "^1.10.0", + "lodash": "^4.17.21", + "mime-types": "^2.1.35", + "moment": "^2.30.1", + "morphdom": "^2.7.4", + "multer": "^1.4.5-lts.1", + "node-fetch": "^3.3.2", + "node-persist": "^4.0.4", + "open": "^8.4.2", + "png-chunk-text": "^1.0.0", + "png-chunks-encode": "^1.0.0", + "png-chunks-extract": "^1.0.0", + "proxy-agent": "^6.5.0", + "rate-limiter-flexible": "^5.0.5", + "response-time": "^2.3.3", + "sanitize-filename": "^1.6.3", + "seedrandom": "^3.0.5", + "showdown": "^2.1.0", + "sillytavern-transformers": "2.14.6", + "simple-git": "^3.27.0", + "slidetoggle": "^4.0.0", + "tiktoken": "^1.0.20", + "url-join": "^5.0.0", + "vectra": "^0.2.2", + "wavefile": "^11.0.0", + "webpack": "^5.98.0", + "write-file-atomic": "^5.0.1", + "ws": "^8.18.1", + "yaml": "^2.7.0", + "yargs": "^17.7.1", + "yauzl": "^2.10.0" + }, + "engines": { + "node": ">= 18" + }, + "overrides": { + "vectra": { + "openai": "^4.17.0" + }, + "axios": { + "follow-redirects": "^1.15.4" + }, + "node-fetch": { + "whatwg-url": "^14.0.0" + } + }, + "name": "sillytavern", + "type": "module", + "license": "AGPL-3.0", + "repository": { + "type": "git", + "url": "https://github.com/SillyTavern/SillyTavern.git" + }, + "version": "1.12.13", + "scripts": { + "start": "node server.js", + "debug": "node --inspect server.js", + "start:electron": "cd ./src/electron && npm run start", + "start:deno": "deno run --allow-run --allow-net --allow-read --allow-write --allow-sys --allow-env server.js", + "start:bun": "bun server.js", + "start:no-csrf": "node server.js --disableCsrf", + "postinstall": "node post-install.js", + "lint": "eslint \"src/**/*.js\" \"public/**/*.js\" ./*.js", + "lint:fix": "eslint \"src/**/*.js\" \"public/**/*.js\" ./*.js --fix", + "plugins:update": "node plugins update", + "plugins:install": "node plugins install" + }, + "bin": { + "sillytavern": "./server.js" + }, + "rules": { + "no-path-concat": "off", + "no-var": "off" + }, + "main": "server.js", + "devDependencies": { + "@types/archiver": "^6.0.3", + "@types/bytes": "^3.1.5", + "@types/command-exists": "^1.2.3", + "@types/compression": "^1.7.5", + "@types/cookie-parser": "^1.4.8", + "@types/cookie-session": "^2.0.49", + "@types/cors": "^2.8.17", + "@types/deno": "^2.2.0", + "@types/express": "^4.17.21", + "@types/jquery": "^3.5.32", + "@types/jquery-cropper": "^1.0.4", + "@types/jquery.transit": "^0.9.33", + "@types/jqueryui": "^1.12.24", + "@types/lodash": "^4.17.16", + "@types/mime-types": "^2.1.4", + "@types/multer": "^1.4.12", + "@types/node": "^18.19.80", + "@types/node-persist": "^3.1.8", + "@types/png-chunk-text": "^1.0.3", + "@types/png-chunks-encode": "^1.0.2", + "@types/png-chunks-extract": "^1.0.2", + "@types/response-time": "^2.3.8", + "@types/select2": "^4.0.63", + "@types/toastr": "^2.1.43", + "@types/write-file-atomic": "^4.0.3", + "@types/yargs": "^17.0.33", + "@types/yauzl": "^2.10.3", + "eslint": "^8.57.1" + } +} diff --git a/jiuguan2025cc/plugins.js b/jiuguan2025cc/plugins.js new file mode 100644 index 0000000000000000000000000000000000000000..92b04977cd9263362a2a95bd77b81b0b895b18b4 --- /dev/null +++ b/jiuguan2025cc/plugins.js @@ -0,0 +1,96 @@ +// Plugin manager script. +// Usage: +// 1. node plugins.js update +// 2. node plugins.js install +// More operations coming soon. +import fs from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; +import { fileURLToPath } from 'node:url'; + +import { default as git, CheckRepoActions } from 'simple-git'; +import { color } from './src/util.js'; + +const __dirname = import.meta.dirname ?? path.dirname(fileURLToPath(import.meta.url)); +process.chdir(__dirname); +const pluginsPath = './plugins'; + +const command = process.argv[2]; + +if (!command) { + console.log('Usage: node plugins.js '); + console.log('Commands:'); + console.log(' update - Update all installed plugins'); + console.log(' install - Install plugin from a Git URL'); + process.exit(1); +} + +if (command === 'update') { + console.log(color.magenta('Updating all plugins')); + updatePlugins(); +} + +if (command === 'install') { + const pluginName = process.argv[3]; + console.log('Installing a new plugin', color.green(pluginName)); + installPlugin(pluginName); +} + +async function updatePlugins() { + const directories = fs.readdirSync(pluginsPath) + .filter(file => !file.startsWith('.')) + .filter(file => fs.statSync(path.join(pluginsPath, file)).isDirectory()); + + console.log(`Found ${color.cyan(directories.length)} directories in ./plugins`); + + for (const directory of directories) { + try { + console.log(`Updating plugin ${color.green(directory)}...`); + const pluginPath = path.join(pluginsPath, directory); + const pluginRepo = git(pluginPath); + + const isRepo = await pluginRepo.checkIsRepo(CheckRepoActions.IS_REPO_ROOT); + if (!isRepo) { + console.log(`Directory ${color.yellow(directory)} is not a Git repository`); + continue; + } + + await pluginRepo.fetch(); + const commitHash = await pluginRepo.revparse(['HEAD']); + const trackingBranch = await pluginRepo.revparse(['--abbrev-ref', '@{u}']); + const log = await pluginRepo.log({ + from: commitHash, + to: trackingBranch, + }); + + if (log.total === 0) { + console.log(`Plugin ${color.blue(directory)} is already up to date`); + continue; + } + + await pluginRepo.pull(); + const latestCommit = await pluginRepo.revparse(['HEAD']); + console.log(`Plugin ${color.green(directory)} updated to commit ${color.cyan(latestCommit)}`); + } catch (error) { + console.error(color.red(`Failed to update plugin ${directory}: ${error.message}`)); + } + } + + console.log(color.magenta('All plugins updated!')); +} + +async function installPlugin(pluginName) { + try { + const pluginPath = path.join(pluginsPath, path.basename(pluginName, '.git')); + + if (fs.existsSync(pluginPath)) { + return console.log(color.yellow(`Directory already exists at ${pluginPath}`)); + } + + await git().clone(pluginName, pluginPath, { '--depth': 1 }); + console.log(`Plugin ${color.green(pluginName)} installed to ${color.cyan(pluginPath)}`); + } + catch (error) { + console.error(color.red(`Failed to install plugin ${pluginName}`), error); + } +} diff --git a/jiuguan2025cc/plugins/.gitkeep b/jiuguan2025cc/plugins/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/jiuguan2025cc/plugins/package.json b/jiuguan2025cc/plugins/package.json new file mode 100644 index 0000000000000000000000000000000000000000..ba698398ce4250f0daae537453c1af76d62e2c69 --- /dev/null +++ b/jiuguan2025cc/plugins/package.json @@ -0,0 +1,4 @@ +{ + "name": "sillytavern-plugins", + "type": "commonjs" +} diff --git a/jiuguan2025cc/post-install.js b/jiuguan2025cc/post-install.js new file mode 100644 index 0000000000000000000000000000000000000000..0048d9c6f42e81455e408b47b41b3cfaf83bb6a2 --- /dev/null +++ b/jiuguan2025cc/post-install.js @@ -0,0 +1,343 @@ +/** + * Scripts to be done before starting the server for the first time. + */ +import fs from 'node:fs'; +import path from 'node:path'; +import crypto from 'node:crypto'; +import process from 'node:process'; +import yaml from 'yaml'; +import _ from 'lodash'; +import chalk from 'chalk'; +import { createRequire } from 'node:module'; + +/** + * Colorizes console output. + */ +const color = chalk; + +const keyMigrationMap = [ + { + oldKey: 'disableThumbnails', + newKey: 'thumbnails.enabled', + migrate: (value) => !value, + }, + { + oldKey: 'thumbnailsQuality', + newKey: 'thumbnails.quality', + migrate: (value) => value, + }, + { + oldKey: 'avatarThumbnailsPng', + newKey: 'thumbnails.format', + migrate: (value) => (value ? 'png' : 'jpg'), + }, + { + oldKey: 'disableChatBackup', + newKey: 'backups.chat.enabled', + migrate: (value) => !value, + }, + { + oldKey: 'numberOfBackups', + newKey: 'backups.common.numberOfBackups', + migrate: (value) => value, + }, + { + oldKey: 'maxTotalChatBackups', + newKey: 'backups.chat.maxTotalBackups', + migrate: (value) => value, + }, + { + oldKey: 'chatBackupThrottleInterval', + newKey: 'backups.chat.throttleInterval', + migrate: (value) => value, + }, + { + oldKey: 'enableExtensions', + newKey: 'extensions.enabled', + migrate: (value) => value, + }, + { + oldKey: 'enableExtensionsAutoUpdate', + newKey: 'extensions.autoUpdate', + migrate: (value) => value, + }, + { + oldKey: 'extras.disableAutoDownload', + newKey: 'extensions.models.autoDownload', + migrate: (value) => !value, + }, + { + oldKey: 'extras.classificationModel', + newKey: 'extensions.models.classification', + migrate: (value) => value, + }, + { + oldKey: 'extras.captioningModel', + newKey: 'extensions.models.captioning', + migrate: (value) => value, + }, + { + oldKey: 'extras.embeddingModel', + newKey: 'extensions.models.embedding', + migrate: (value) => value, + }, + { + oldKey: 'extras.speechToTextModel', + newKey: 'extensions.models.speechToText', + migrate: (value) => value, + }, + { + oldKey: 'extras.textToSpeechModel', + newKey: 'extensions.models.textToSpeech', + migrate: (value) => value, + }, + { + oldKey: 'minLogLevel', + newKey: 'logging.minLogLevel', + migrate: (value) => value, + }, + { + oldKey: 'cardsCacheCapacity', + newKey: 'performance.memoryCacheCapacity', + migrate: (value) => `${value}mb`, + }, + // uncomment one release after 1.12.13 + /* + { + oldKey: 'cookieSecret', + newKey: 'cookieSecret', + migrate: () => void 0, + remove: true, + }, + */ +]; + +/** + * Gets all keys from an object recursively. + * @param {object} obj Object to get all keys from + * @param {string} prefix Prefix to prepend to all keys + * @returns {string[]} Array of all keys in the object + */ +function getAllKeys(obj, prefix = '') { + if (typeof obj !== 'object' || Array.isArray(obj) || obj === null) { + return []; + } + + return _.flatMap(Object.keys(obj), key => { + const newPrefix = prefix ? `${prefix}.${key}` : key; + if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) { + return getAllKeys(obj[key], newPrefix); + } else { + return [newPrefix]; + } + }); +} + +/** + * Converts the old config.conf file to the new config.yaml format. + */ +function convertConfig() { + if (fs.existsSync('./config.conf')) { + if (fs.existsSync('./config.yaml')) { + console.log(color.yellow('Both config.conf and config.yaml exist. Please delete config.conf manually.')); + return; + } + + try { + console.log(color.blue('Converting config.conf to config.yaml. Your old config.conf will be renamed to config.conf.bak')); + fs.renameSync('./config.conf', './config.conf.cjs'); // Force loading as CommonJS + const require = createRequire(import.meta.url); + const config = require(path.join(process.cwd(), './config.conf.cjs')); + fs.copyFileSync('./config.conf.cjs', './config.conf.bak'); + fs.rmSync('./config.conf.cjs'); + fs.writeFileSync('./config.yaml', yaml.stringify(config)); + console.log(color.green('Conversion successful. Please check your config.yaml and fix it if necessary.')); + } catch (error) { + console.error(color.red('FATAL: Config conversion failed. Please check your config.conf file and try again.'), error); + return; + } + } +} + +/** + * Compares the current config.yaml with the default config.yaml and adds any missing values. + */ +function addMissingConfigValues() { + try { + const defaultConfig = yaml.parse(fs.readFileSync(path.join(process.cwd(), './default/config.yaml'), 'utf8')); + let config = yaml.parse(fs.readFileSync(path.join(process.cwd(), './config.yaml'), 'utf8')); + + // Migrate old keys to new keys + const migratedKeys = []; + for (const { oldKey, newKey, migrate, remove } of keyMigrationMap) { + if (_.has(config, oldKey)) { + if (remove) { + _.unset(config, oldKey); + migratedKeys.push({ + oldKey, + newValue: void 0, + }); + continue; + } + + const oldValue = _.get(config, oldKey); + const newValue = migrate(oldValue); + _.set(config, newKey, newValue); + _.unset(config, oldKey); + + migratedKeys.push({ + oldKey, + newKey, + oldValue, + newValue, + }); + } + } + + // Get all keys from the original config + const originalKeys = getAllKeys(config); + + // Use lodash's defaultsDeep function to recursively apply default properties + config = _.defaultsDeep(config, defaultConfig); + + // Get all keys from the updated config + const updatedKeys = getAllKeys(config); + + // Find the keys that were added + const addedKeys = _.difference(updatedKeys, originalKeys); + + if (addedKeys.length === 0 && migratedKeys.length === 0) { + return; + } + + if (addedKeys.length > 0) { + console.log('Adding missing config values to config.yaml:', addedKeys); + } + + if (migratedKeys.length > 0) { + console.log('Migrating config values in config.yaml:', migratedKeys); + } + + fs.writeFileSync('./config.yaml', yaml.stringify(config)); + } catch (error) { + console.error(color.red('FATAL: Could not add missing config values to config.yaml'), error); + } +} + +/** + * Creates the default config files if they don't exist yet. + */ +function createDefaultFiles() { + /** + * @typedef DefaultItem + * @type {object} + * @property {'file' | 'directory'} type - Whether the item should be copied as a single file or merged into a directory structure. + * @property {string} defaultPath - The path to the default item (typically in `default/`). + * @property {string} productionPath - The path to the copied item for production use. + */ + + /** @type {DefaultItem[]} */ + const defaultItems = [ + { + type: 'file', + defaultPath: './default/config.yaml', + productionPath: './config.yaml', + }, + { + type: 'directory', + defaultPath: './default/public/', + productionPath: './public/', + }, + ]; + + for (const defaultItem of defaultItems) { + try { + if (defaultItem.type === 'file') { + if (!fs.existsSync(defaultItem.productionPath)) { + fs.copyFileSync( + defaultItem.defaultPath, + defaultItem.productionPath, + ); + console.log( + color.green(`Created default file: ${defaultItem.productionPath}`), + ); + } + } else if (defaultItem.type === 'directory') { + fs.cpSync(defaultItem.defaultPath, defaultItem.productionPath, { + force: false, // Don't overwrite existing files! + recursive: true, + }); + console.log( + color.green(`Synchronized missing files: ${defaultItem.productionPath}`), + ); + } else { + throw new Error( + 'FATAL: Unexpected default file format in `post-install.js#createDefaultFiles()`.', + ); + } + } catch (error) { + console.error( + color.red( + `FATAL: Could not write default ${defaultItem.type}: ${defaultItem.productionPath}`, + ), + error, + ); + } + } +} + +/** + * Returns the MD5 hash of the given data. + * @param {Buffer} data Input data + * @returns {string} MD5 hash of the input data + */ +function getMd5Hash(data) { + return crypto + .createHash('md5') + .update(new Uint8Array(data)) + .digest('hex'); +} + +/** + * Copies the WASM binaries from the sillytavern-transformers package to the dist folder. + */ +function copyWasmFiles() { + if (!fs.existsSync('./dist')) { + fs.mkdirSync('./dist'); + } + + const listDir = fs.readdirSync('./node_modules/sillytavern-transformers/dist'); + + for (const file of listDir) { + if (file.endsWith('.wasm')) { + const sourcePath = `./node_modules/sillytavern-transformers/dist/${file}`; + const targetPath = `./dist/${file}`; + + // Don't copy if the file already exists and is the same checksum + if (fs.existsSync(targetPath)) { + const sourceChecksum = getMd5Hash(fs.readFileSync(sourcePath)); + const targetChecksum = getMd5Hash(fs.readFileSync(targetPath)); + + if (sourceChecksum === targetChecksum) { + continue; + } + } + + fs.copyFileSync(sourcePath, targetPath); + console.log(`${file} successfully copied to ./dist/${file}`); + } + } +} + +try { + // 0. Convert config.conf to config.yaml + convertConfig(); + // 1. Create default config files + createDefaultFiles(); + // 2. Copy transformers WASM binaries from node_modules + copyWasmFiles(); + // 3. Add missing config values + addMissingConfigValues(); +} catch (error) { + console.error(error); +} diff --git a/jiuguan2025cc/public/css/accounts.css b/jiuguan2025cc/public/css/accounts.css new file mode 100644 index 0000000000000000000000000000000000000000..e5414bf59a2f746d287e8a866aef028cb01358ea --- /dev/null +++ b/jiuguan2025cc/public/css/accounts.css @@ -0,0 +1,5 @@ +.userAccount { + border: 1px solid var(--SmartThemeBorderColor); + padding: 5px 10px; + border-radius: 5px; +} diff --git a/jiuguan2025cc/public/css/animations.css b/jiuguan2025cc/public/css/animations.css new file mode 100644 index 0000000000000000000000000000000000000000..2477fe46a5dc74ac77eb250e2b32811a35c6f732 --- /dev/null +++ b/jiuguan2025cc/public/css/animations.css @@ -0,0 +1,121 @@ +/* Fade animations with opacity */ +@keyframes fade-in { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} + +@keyframes fade-out { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + } +} + +/* Pop animations with opacity and vertical scaling */ +@keyframes pop-in { + 0% { + opacity: 0; + transform: scaleY(0); + } + + /* Make the scaling faster on pop-in, otherwise it looks a bit weird */ + 33% { + transform: scaleY(1); + } + + 100% { + opacity: 1; + transform: scaleY(1); + } +} + +@keyframes pop-out { + 0% { + opacity: 1; + transform: scaleY(1); + } + + 66% { + transform: scaleY(1); + } + + 100% { + opacity: 0; + transform: scaleY(0); + } +} + +/* Flashing for highlighting animation */ +@keyframes flash { + 0%, 50%, 100% { + opacity: 1; + } + + 25%, 75% { + opacity: 0.2; + } +} + +/* Pulsing highlight, slightly resizing the element */ +@keyframes pulse { + from { + transform: scale(1); + filter: brightness(1.1); + } + + to { + transform: scale(1.01); + filter: brightness(1.3); + } +} + +/* Ellipsis animation */ +@keyframes ellipsis { + 0% { + content: "" + } + + 25% { + content: "." + } + + 50% { + content: ".." + } + + 75% { + content: "..." + } +} + +/* HEINOUS */ +@keyframes infinite-spinning { + from { + transform: rotate(0deg); + } + + to { + transform: rotate(360deg); + } +} + +/* STscript animation */ +@keyframes script_progress_pulse { + + 0%, + 100% { + border-top-color: var(--progColor); + } + + 50% { + border-top-color: var(--progFlashColor); + } +} diff --git a/jiuguan2025cc/public/css/brands.min.css b/jiuguan2025cc/public/css/brands.min.css new file mode 100644 index 0000000000000000000000000000000000000000..3e7076057c7538e9270ac4766de21da251ae771d --- /dev/null +++ b/jiuguan2025cc/public/css/brands.min.css @@ -0,0 +1,6 @@ +/*! + * Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +:host,:root{--fa-style-family-brands:"Font Awesome 6 Brands";--fa-font-brands:normal 400 1em/1 "Font Awesome 6 Brands"}@font-face{font-family:"Font Awesome 6 Brands";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}.fa-brands,.fab{font-weight:400}.fa-monero:before{content:"\f3d0"}.fa-hooli:before{content:"\f427"}.fa-yelp:before{content:"\f1e9"}.fa-cc-visa:before{content:"\f1f0"}.fa-lastfm:before{content:"\f202"}.fa-shopware:before{content:"\f5b5"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-aws:before{content:"\f375"}.fa-redhat:before{content:"\f7bc"}.fa-yoast:before{content:"\f2b1"}.fa-cloudflare:before{content:"\e07d"}.fa-ups:before{content:"\f7e0"}.fa-pixiv:before{content:"\e640"}.fa-wpexplorer:before{content:"\f2de"}.fa-dyalog:before{content:"\f399"}.fa-bity:before{content:"\f37a"}.fa-stackpath:before{content:"\f842"}.fa-buysellads:before{content:"\f20d"}.fa-first-order:before{content:"\f2b0"}.fa-modx:before{content:"\f285"}.fa-guilded:before{content:"\e07e"}.fa-vnv:before{content:"\f40b"}.fa-js-square:before,.fa-square-js:before{content:"\f3b9"}.fa-microsoft:before{content:"\f3ca"}.fa-qq:before{content:"\f1d6"}.fa-orcid:before{content:"\f8d2"}.fa-java:before{content:"\f4e4"}.fa-invision:before{content:"\f7b0"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-centercode:before{content:"\f380"}.fa-glide-g:before{content:"\f2a6"}.fa-drupal:before{content:"\f1a9"}.fa-jxl:before{content:"\e67b"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-unity:before{content:"\e049"}.fa-whmcs:before{content:"\f40d"}.fa-rocketchat:before{content:"\f3e8"}.fa-vk:before{content:"\f189"}.fa-untappd:before{content:"\f405"}.fa-mailchimp:before{content:"\f59e"}.fa-css3-alt:before{content:"\f38b"}.fa-reddit-square:before,.fa-square-reddit:before{content:"\f1a2"}.fa-vimeo-v:before{content:"\f27d"}.fa-contao:before{content:"\f26d"}.fa-square-font-awesome:before{content:"\e5ad"}.fa-deskpro:before{content:"\f38f"}.fa-brave:before{content:"\e63c"}.fa-sistrix:before{content:"\f3ee"}.fa-instagram-square:before,.fa-square-instagram:before{content:"\e055"}.fa-battle-net:before{content:"\f835"}.fa-the-red-yeti:before{content:"\f69d"}.fa-hacker-news-square:before,.fa-square-hacker-news:before{content:"\f3af"}.fa-edge:before{content:"\f282"}.fa-threads:before{content:"\e618"}.fa-napster:before{content:"\f3d2"}.fa-snapchat-square:before,.fa-square-snapchat:before{content:"\f2ad"}.fa-google-plus-g:before{content:"\f0d5"}.fa-artstation:before{content:"\f77a"}.fa-markdown:before{content:"\f60f"}.fa-sourcetree:before{content:"\f7d3"}.fa-google-plus:before{content:"\f2b3"}.fa-diaspora:before{content:"\f791"}.fa-foursquare:before{content:"\f180"}.fa-stack-overflow:before{content:"\f16c"}.fa-github-alt:before{content:"\f113"}.fa-phoenix-squadron:before{content:"\f511"}.fa-pagelines:before{content:"\f18c"}.fa-algolia:before{content:"\f36c"}.fa-red-river:before{content:"\f3e3"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-safari:before{content:"\f267"}.fa-google:before{content:"\f1a0"}.fa-font-awesome-alt:before,.fa-square-font-awesome-stroke:before{content:"\f35c"}.fa-atlassian:before{content:"\f77b"}.fa-linkedin-in:before{content:"\f0e1"}.fa-digital-ocean:before{content:"\f391"}.fa-nimblr:before{content:"\f5a8"}.fa-chromecast:before{content:"\f838"}.fa-evernote:before{content:"\f839"}.fa-hacker-news:before{content:"\f1d4"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-adversal:before{content:"\f36a"}.fa-creative-commons:before{content:"\f25e"}.fa-watchman-monitoring:before{content:"\e087"}.fa-fonticons:before{content:"\f280"}.fa-weixin:before{content:"\f1d7"}.fa-shirtsinbulk:before{content:"\f214"}.fa-codepen:before{content:"\f1cb"}.fa-git-alt:before{content:"\f841"}.fa-lyft:before{content:"\f3c3"}.fa-rev:before{content:"\f5b2"}.fa-windows:before{content:"\f17a"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-square-viadeo:before,.fa-viadeo-square:before{content:"\f2aa"}.fa-meetup:before{content:"\f2e0"}.fa-centos:before{content:"\f789"}.fa-adn:before{content:"\f170"}.fa-cloudsmith:before{content:"\f384"}.fa-opensuse:before{content:"\e62b"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-dribbble-square:before,.fa-square-dribbble:before{content:"\f397"}.fa-codiepie:before{content:"\f284"}.fa-node:before{content:"\f419"}.fa-mix:before{content:"\f3cb"}.fa-steam:before{content:"\f1b6"}.fa-cc-apple-pay:before{content:"\f416"}.fa-scribd:before{content:"\f28a"}.fa-debian:before{content:"\e60b"}.fa-openid:before{content:"\f19b"}.fa-instalod:before{content:"\e081"}.fa-expeditedssl:before{content:"\f23e"}.fa-sellcast:before{content:"\f2da"}.fa-square-twitter:before,.fa-twitter-square:before{content:"\f081"}.fa-r-project:before{content:"\f4f7"}.fa-delicious:before{content:"\f1a5"}.fa-freebsd:before{content:"\f3a4"}.fa-vuejs:before{content:"\f41f"}.fa-accusoft:before{content:"\f369"}.fa-ioxhost:before{content:"\f208"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-app-store:before{content:"\f36f"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-itunes-note:before{content:"\f3b5"}.fa-golang:before{content:"\e40f"}.fa-kickstarter:before,.fa-square-kickstarter:before{content:"\f3bb"}.fa-grav:before{content:"\f2d6"}.fa-weibo:before{content:"\f18a"}.fa-uncharted:before{content:"\e084"}.fa-firstdraft:before{content:"\f3a1"}.fa-square-youtube:before,.fa-youtube-square:before{content:"\f431"}.fa-wikipedia-w:before{content:"\f266"}.fa-rendact:before,.fa-wpressr:before{content:"\f3e4"}.fa-angellist:before{content:"\f209"}.fa-galactic-republic:before{content:"\f50c"}.fa-nfc-directional:before{content:"\e530"}.fa-skype:before{content:"\f17e"}.fa-joget:before{content:"\f3b7"}.fa-fedora:before{content:"\f798"}.fa-stripe-s:before{content:"\f42a"}.fa-meta:before{content:"\e49b"}.fa-laravel:before{content:"\f3bd"}.fa-hotjar:before{content:"\f3b1"}.fa-bluetooth-b:before{content:"\f294"}.fa-square-letterboxd:before{content:"\e62e"}.fa-sticker-mule:before{content:"\f3f7"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-hips:before{content:"\f452"}.fa-behance:before{content:"\f1b4"}.fa-reddit:before{content:"\f1a1"}.fa-discord:before{content:"\f392"}.fa-chrome:before{content:"\f268"}.fa-app-store-ios:before{content:"\f370"}.fa-cc-discover:before{content:"\f1f2"}.fa-wpbeginner:before{content:"\f297"}.fa-confluence:before{content:"\f78d"}.fa-shoelace:before{content:"\e60c"}.fa-mdb:before{content:"\f8ca"}.fa-dochub:before{content:"\f394"}.fa-accessible-icon:before{content:"\f368"}.fa-ebay:before{content:"\f4f4"}.fa-amazon:before{content:"\f270"}.fa-unsplash:before{content:"\e07c"}.fa-yarn:before{content:"\f7e3"}.fa-square-steam:before,.fa-steam-square:before{content:"\f1b7"}.fa-500px:before{content:"\f26e"}.fa-square-vimeo:before,.fa-vimeo-square:before{content:"\f194"}.fa-asymmetrik:before{content:"\f372"}.fa-font-awesome-flag:before,.fa-font-awesome-logo-full:before,.fa-font-awesome:before{content:"\f2b4"}.fa-gratipay:before{content:"\f184"}.fa-apple:before{content:"\f179"}.fa-hive:before{content:"\e07f"}.fa-gitkraken:before{content:"\f3a6"}.fa-keybase:before{content:"\f4f5"}.fa-apple-pay:before{content:"\f415"}.fa-padlet:before{content:"\e4a0"}.fa-amazon-pay:before{content:"\f42c"}.fa-github-square:before,.fa-square-github:before{content:"\f092"}.fa-stumbleupon:before{content:"\f1a4"}.fa-fedex:before{content:"\f797"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-shopify:before{content:"\e057"}.fa-neos:before{content:"\f612"}.fa-square-threads:before{content:"\e619"}.fa-hackerrank:before{content:"\f5f7"}.fa-researchgate:before{content:"\f4f8"}.fa-swift:before{content:"\f8e1"}.fa-angular:before{content:"\f420"}.fa-speakap:before{content:"\f3f3"}.fa-angrycreative:before{content:"\f36e"}.fa-y-combinator:before{content:"\f23b"}.fa-empire:before{content:"\f1d1"}.fa-envira:before{content:"\f299"}.fa-google-scholar:before{content:"\e63b"}.fa-gitlab-square:before,.fa-square-gitlab:before{content:"\e5ae"}.fa-studiovinari:before{content:"\f3f8"}.fa-pied-piper:before{content:"\f2ae"}.fa-wordpress:before{content:"\f19a"}.fa-product-hunt:before{content:"\f288"}.fa-firefox:before{content:"\f269"}.fa-linode:before{content:"\f2b8"}.fa-goodreads:before{content:"\f3a8"}.fa-odnoklassniki-square:before,.fa-square-odnoklassniki:before{content:"\f264"}.fa-jsfiddle:before{content:"\f1cc"}.fa-sith:before{content:"\f512"}.fa-themeisle:before{content:"\f2b2"}.fa-page4:before{content:"\f3d7"}.fa-hashnode:before{content:"\e499"}.fa-react:before{content:"\f41b"}.fa-cc-paypal:before{content:"\f1f4"}.fa-squarespace:before{content:"\f5be"}.fa-cc-stripe:before{content:"\f1f5"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-bitcoin:before{content:"\f379"}.fa-keycdn:before{content:"\f3ba"}.fa-opera:before{content:"\f26a"}.fa-itch-io:before{content:"\f83a"}.fa-umbraco:before{content:"\f8e8"}.fa-galactic-senate:before{content:"\f50d"}.fa-ubuntu:before{content:"\f7df"}.fa-draft2digital:before{content:"\f396"}.fa-stripe:before{content:"\f429"}.fa-houzz:before{content:"\f27c"}.fa-gg:before{content:"\f260"}.fa-dhl:before{content:"\f790"}.fa-pinterest-square:before,.fa-square-pinterest:before{content:"\f0d3"}.fa-xing:before{content:"\f168"}.fa-blackberry:before{content:"\f37b"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-playstation:before{content:"\f3df"}.fa-quinscape:before{content:"\f459"}.fa-less:before{content:"\f41d"}.fa-blogger-b:before{content:"\f37d"}.fa-opencart:before{content:"\f23d"}.fa-vine:before{content:"\f1ca"}.fa-signal-messenger:before{content:"\e663"}.fa-paypal:before{content:"\f1ed"}.fa-gitlab:before{content:"\f296"}.fa-typo3:before{content:"\f42b"}.fa-reddit-alien:before{content:"\f281"}.fa-yahoo:before{content:"\f19e"}.fa-dailymotion:before{content:"\e052"}.fa-affiliatetheme:before{content:"\f36b"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-bootstrap:before{content:"\f836"}.fa-odnoklassniki:before{content:"\f263"}.fa-nfc-symbol:before{content:"\e531"}.fa-mintbit:before{content:"\e62f"}.fa-ethereum:before{content:"\f42e"}.fa-speaker-deck:before{content:"\f83c"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-patreon:before{content:"\f3d9"}.fa-avianex:before{content:"\f374"}.fa-ello:before{content:"\f5f1"}.fa-gofore:before{content:"\f3a7"}.fa-bimobject:before{content:"\f378"}.fa-brave-reverse:before{content:"\e63d"}.fa-facebook-f:before{content:"\f39e"}.fa-google-plus-square:before,.fa-square-google-plus:before{content:"\f0d4"}.fa-web-awesome:before{content:"\e682"}.fa-mandalorian:before{content:"\f50f"}.fa-first-order-alt:before{content:"\f50a"}.fa-osi:before{content:"\f41a"}.fa-google-wallet:before{content:"\f1ee"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-periscope:before{content:"\f3da"}.fa-fulcrum:before{content:"\f50b"}.fa-cloudscale:before{content:"\f383"}.fa-forumbee:before{content:"\f211"}.fa-mizuni:before{content:"\f3cc"}.fa-schlix:before{content:"\f3ea"}.fa-square-xing:before,.fa-xing-square:before{content:"\f169"}.fa-bandcamp:before{content:"\f2d5"}.fa-wpforms:before{content:"\f298"}.fa-cloudversify:before{content:"\f385"}.fa-usps:before{content:"\f7e1"}.fa-megaport:before{content:"\f5a3"}.fa-magento:before{content:"\f3c4"}.fa-spotify:before{content:"\f1bc"}.fa-optin-monster:before{content:"\f23c"}.fa-fly:before{content:"\f417"}.fa-aviato:before{content:"\f421"}.fa-itunes:before{content:"\f3b4"}.fa-cuttlefish:before{content:"\f38c"}.fa-blogger:before{content:"\f37c"}.fa-flickr:before{content:"\f16e"}.fa-viber:before{content:"\f409"}.fa-soundcloud:before{content:"\f1be"}.fa-digg:before{content:"\f1a6"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-letterboxd:before{content:"\e62d"}.fa-symfony:before{content:"\f83d"}.fa-maxcdn:before{content:"\f136"}.fa-etsy:before{content:"\f2d7"}.fa-facebook-messenger:before{content:"\f39f"}.fa-audible:before{content:"\f373"}.fa-think-peaks:before{content:"\f731"}.fa-bilibili:before{content:"\e3d9"}.fa-erlang:before{content:"\f39d"}.fa-x-twitter:before{content:"\e61b"}.fa-cotton-bureau:before{content:"\f89e"}.fa-dashcube:before{content:"\f210"}.fa-42-group:before,.fa-innosoft:before{content:"\e080"}.fa-stack-exchange:before{content:"\f18d"}.fa-elementor:before{content:"\f430"}.fa-pied-piper-square:before,.fa-square-pied-piper:before{content:"\e01e"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-palfed:before{content:"\f3d8"}.fa-superpowers:before{content:"\f2dd"}.fa-resolving:before{content:"\f3e7"}.fa-xbox:before{content:"\f412"}.fa-square-web-awesome-stroke:before{content:"\e684"}.fa-searchengin:before{content:"\f3eb"}.fa-tiktok:before{content:"\e07b"}.fa-facebook-square:before,.fa-square-facebook:before{content:"\f082"}.fa-renren:before{content:"\f18b"}.fa-linux:before{content:"\f17c"}.fa-glide:before{content:"\f2a5"}.fa-linkedin:before{content:"\f08c"}.fa-hubspot:before{content:"\f3b2"}.fa-deploydog:before{content:"\f38e"}.fa-twitch:before{content:"\f1e8"}.fa-ravelry:before{content:"\f2d9"}.fa-mixer:before{content:"\e056"}.fa-lastfm-square:before,.fa-square-lastfm:before{content:"\f203"}.fa-vimeo:before{content:"\f40a"}.fa-mendeley:before{content:"\f7b3"}.fa-uniregistry:before{content:"\f404"}.fa-figma:before{content:"\f799"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-dropbox:before{content:"\f16b"}.fa-instagram:before{content:"\f16d"}.fa-cmplid:before{content:"\e360"}.fa-upwork:before{content:"\e641"}.fa-facebook:before{content:"\f09a"}.fa-gripfire:before{content:"\f3ac"}.fa-jedi-order:before{content:"\f50e"}.fa-uikit:before{content:"\f403"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-phabricator:before{content:"\f3db"}.fa-ussunnah:before{content:"\f407"}.fa-earlybirds:before{content:"\f39a"}.fa-trade-federation:before{content:"\f513"}.fa-autoprefixer:before{content:"\f41c"}.fa-whatsapp:before{content:"\f232"}.fa-square-upwork:before{content:"\e67c"}.fa-slideshare:before{content:"\f1e7"}.fa-google-play:before{content:"\f3ab"}.fa-viadeo:before{content:"\f2a9"}.fa-line:before{content:"\f3c0"}.fa-google-drive:before{content:"\f3aa"}.fa-servicestack:before{content:"\f3ec"}.fa-simplybuilt:before{content:"\f215"}.fa-bitbucket:before{content:"\f171"}.fa-imdb:before{content:"\f2d8"}.fa-deezer:before{content:"\e077"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-jira:before{content:"\f7b1"}.fa-docker:before{content:"\f395"}.fa-screenpal:before{content:"\e570"}.fa-bluetooth:before{content:"\f293"}.fa-gitter:before{content:"\f426"}.fa-d-and-d:before{content:"\f38d"}.fa-microblog:before{content:"\e01a"}.fa-cc-diners-club:before{content:"\f24c"}.fa-gg-circle:before{content:"\f261"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-yandex:before{content:"\f413"}.fa-readme:before{content:"\f4d5"}.fa-html5:before{content:"\f13b"}.fa-sellsy:before{content:"\f213"}.fa-square-web-awesome:before{content:"\e683"}.fa-sass:before{content:"\f41e"}.fa-wirsindhandwerk:before,.fa-wsh:before{content:"\e2d0"}.fa-buromobelexperte:before{content:"\f37f"}.fa-salesforce:before{content:"\f83b"}.fa-octopus-deploy:before{content:"\e082"}.fa-medapps:before{content:"\f3c6"}.fa-ns8:before{content:"\f3d5"}.fa-pinterest-p:before{content:"\f231"}.fa-apper:before{content:"\f371"}.fa-fort-awesome:before{content:"\f286"}.fa-waze:before{content:"\f83f"}.fa-bluesky:before{content:"\e671"}.fa-cc-jcb:before{content:"\f24b"}.fa-snapchat-ghost:before,.fa-snapchat:before{content:"\f2ab"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-rust:before{content:"\e07a"}.fa-wix:before{content:"\f5cf"}.fa-behance-square:before,.fa-square-behance:before{content:"\f1b5"}.fa-supple:before{content:"\f3f9"}.fa-webflow:before{content:"\e65c"}.fa-rebel:before{content:"\f1d0"}.fa-css3:before{content:"\f13c"}.fa-staylinked:before{content:"\f3f5"}.fa-kaggle:before{content:"\f5fa"}.fa-space-awesome:before{content:"\e5ac"}.fa-deviantart:before{content:"\f1bd"}.fa-cpanel:before{content:"\f388"}.fa-goodreads-g:before{content:"\f3a9"}.fa-git-square:before,.fa-square-git:before{content:"\f1d2"}.fa-square-tumblr:before,.fa-tumblr-square:before{content:"\f174"}.fa-trello:before{content:"\f181"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-get-pocket:before{content:"\f265"}.fa-perbyte:before{content:"\e083"}.fa-grunt:before{content:"\f3ad"}.fa-weebly:before{content:"\f5cc"}.fa-connectdevelop:before{content:"\f20e"}.fa-leanpub:before{content:"\f212"}.fa-black-tie:before{content:"\f27e"}.fa-themeco:before{content:"\f5c6"}.fa-python:before{content:"\f3e2"}.fa-android:before{content:"\f17b"}.fa-bots:before{content:"\e340"}.fa-free-code-camp:before{content:"\f2c5"}.fa-hornbill:before{content:"\f592"}.fa-js:before{content:"\f3b8"}.fa-ideal:before{content:"\e013"}.fa-git:before{content:"\f1d3"}.fa-dev:before{content:"\f6cc"}.fa-sketch:before{content:"\f7c6"}.fa-yandex-international:before{content:"\f414"}.fa-cc-amex:before{content:"\f1f3"}.fa-uber:before{content:"\f402"}.fa-github:before{content:"\f09b"}.fa-php:before{content:"\f457"}.fa-alipay:before{content:"\f642"}.fa-youtube:before{content:"\f167"}.fa-skyatlas:before{content:"\f216"}.fa-firefox-browser:before{content:"\e007"}.fa-replyd:before{content:"\f3e6"}.fa-suse:before{content:"\f7d6"}.fa-jenkins:before{content:"\f3b6"}.fa-twitter:before{content:"\f099"}.fa-rockrms:before{content:"\f3e9"}.fa-pinterest:before{content:"\f0d2"}.fa-buffer:before{content:"\f837"}.fa-npm:before{content:"\f3d4"}.fa-yammer:before{content:"\f840"}.fa-btc:before{content:"\f15a"}.fa-dribbble:before{content:"\f17d"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-internet-explorer:before{content:"\f26b"}.fa-stubber:before{content:"\e5c7"}.fa-telegram-plane:before,.fa-telegram:before{content:"\f2c6"}.fa-old-republic:before{content:"\f510"}.fa-odysee:before{content:"\e5c6"}.fa-square-whatsapp:before,.fa-whatsapp-square:before{content:"\f40c"}.fa-node-js:before{content:"\f3d3"}.fa-edge-legacy:before{content:"\e078"}.fa-slack-hash:before,.fa-slack:before{content:"\f198"}.fa-medrt:before{content:"\f3c8"}.fa-usb:before{content:"\f287"}.fa-tumblr:before{content:"\f173"}.fa-vaadin:before{content:"\f408"}.fa-quora:before{content:"\f2c4"}.fa-square-x-twitter:before{content:"\e61a"}.fa-reacteurope:before{content:"\f75d"}.fa-medium-m:before,.fa-medium:before{content:"\f23a"}.fa-amilia:before{content:"\f36d"}.fa-mixcloud:before{content:"\f289"}.fa-flipboard:before{content:"\f44d"}.fa-viacoin:before{content:"\f237"}.fa-critical-role:before{content:"\f6c9"}.fa-sitrox:before{content:"\e44a"}.fa-discourse:before{content:"\f393"}.fa-joomla:before{content:"\f1aa"}.fa-mastodon:before{content:"\f4f6"}.fa-airbnb:before{content:"\f834"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-buy-n-large:before{content:"\f8a6"}.fa-gulp:before{content:"\f3ae"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-strava:before{content:"\f428"}.fa-ember:before{content:"\f423"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-teamspeak:before{content:"\f4f9"}.fa-pushed:before{content:"\f3e1"}.fa-wordpress-simple:before{content:"\f411"}.fa-nutritionix:before{content:"\f3d6"}.fa-wodu:before{content:"\e088"}.fa-google-pay:before{content:"\e079"}.fa-intercom:before{content:"\f7af"}.fa-zhihu:before{content:"\f63f"}.fa-korvue:before{content:"\f42f"}.fa-pix:before{content:"\e43a"}.fa-steam-symbol:before{content:"\f3f6"} \ No newline at end of file diff --git a/jiuguan2025cc/public/css/bright.min.css b/jiuguan2025cc/public/css/bright.min.css new file mode 100644 index 0000000000000000000000000000000000000000..0e104ef8247099add3d0e0d83eb1e4613f81535a --- /dev/null +++ b/jiuguan2025cc/public/css/bright.min.css @@ -0,0 +1,7 @@ +/*! + Theme: Bright + Author: Chris Kempson (http://chriskempson.com) + License: ~ MIT (or more permissive) [via base16-schemes-source] + Maintainer: @highlightjs/core-team + Version: 2021.09.0 +*/pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#e0e0e0;background:#000}.hljs ::selection,.hljs::selection{background-color:#505050;color:#e0e0e0}.hljs-comment{color:#b0b0b0}.hljs-tag{color:#d0d0d0}.hljs-operator,.hljs-punctuation,.hljs-subst{color:#e0e0e0}.hljs-operator{opacity:.7}.hljs-bullet,.hljs-deletion,.hljs-name,.hljs-selector-tag,.hljs-template-variable,.hljs-variable{color:#fb0120}.hljs-attr,.hljs-link,.hljs-literal,.hljs-number,.hljs-symbol,.hljs-variable.constant_{color:#fc6d24}.hljs-class .hljs-title,.hljs-title,.hljs-title.class_{color:#fda331}.hljs-strong{font-weight:700;color:#fda331}.hljs-addition,.hljs-code,.hljs-string,.hljs-title.class_.inherited__{color:#a1c659}.hljs-built_in,.hljs-doctag,.hljs-keyword.hljs-atrule,.hljs-quote,.hljs-regexp{color:#76c7b7}.hljs-attribute,.hljs-function .hljs-title,.hljs-section,.hljs-title.function_,.ruby .hljs-property{color:#6fb3d2}.diff .hljs-meta,.hljs-keyword,.hljs-template-tag,.hljs-type{color:#d381c3}.hljs-emphasis{color:#d381c3;font-style:italic}.hljs-meta,.hljs-meta .hljs-keyword,.hljs-meta .hljs-string{color:#be643c}.hljs-meta .hljs-keyword,.hljs-meta-keyword{font-weight:700} \ No newline at end of file diff --git a/jiuguan2025cc/public/css/character-group-overlay.css b/jiuguan2025cc/public/css/character-group-overlay.css new file mode 100644 index 0000000000000000000000000000000000000000..5327694a85d0a3cd097918dc80645c76b9db9126 --- /dev/null +++ b/jiuguan2025cc/public/css/character-group-overlay.css @@ -0,0 +1,104 @@ + +#rm_print_characters_block.group_overlay_mode_select .character_select { + transition: background-color 0.4s ease; + background-color: rgba(170, 170, 170, 0.15); +} + +#rm_print_characters_block.group_overlay_mode_select .bogus_folder_select, +#rm_print_characters_block.group_overlay_mode_select .group_select { + cursor: auto; + filter: saturate(0.3); +} + +#rm_print_characters_block.group_overlay_mode_select .bogus_folder_select:hover, +#rm_print_characters_block.group_overlay_mode_select .group_select:hover { + background: none; +} + +#rm_print_characters_block.group_overlay_mode_select .character_select input.bulk_select_checkbox { + display: none !important; +} + +#rm_print_characters_block.group_overlay_mode_select .character_select.character_selected { + background-color: var(--SmartThemeQuoteColor); +} + +#rm_print_characters_block.group_overlay_mode_select .character_select .bulk_select_checkbox { + visibility: hidden; + height: 0 !important; +} + +#character_context_menu.hidden { display: none; } +#character_context_menu { + position: absolute; + padding: 3px; + z-index: 9998; + background-color: var(--black90a); + border: 1px solid var(--black90a); + border-radius: 10px; +} + +#character_context_menu ul li button { + border: 0; + border-bottom-color: currentcolor; + color: var(--SmartThemeQuoteColor); + background-color: transparent; + font-weight: bold; + font-size: 1em; + padding: 0.5em; + border-bottom: 1px dotted var(--SmartThemeQuoteColor); + width: 100%; + cursor: pointer; +} + +#character_context_menu ul li button:hover { + background-color: var(--SmartThemeBlurTintColor); +} + +#character_context_menu ul li:last-child button { + border-bottom: 0; +} + +#character_context_menu ul li #character_context_menu_delete { + color: var(--fullred); +} + +#character_context_menu ul { + list-style-type: none; + padding: 0; + margin: 0; +} + +#character_context_menu .character_context_menu_separator { + height: 1px; + background-color: var(--SmartThemeBotMesBlurTintColor); +} + +#character_context_menu li:hover { + background-color: var(--SmartThemeBotMesBlurTintColor); +} + +#bulkEditButton.bulk_edit_overlay_active { + color: var(--golden); +} + +#bulk_tag_shadow_popup { + backdrop-filter: blur(calc(var(--SmartThemeBlurStrength) * 2)); + -webkit-backdrop-filter: blur(calc(var(--SmartThemeBlurStrength) * 2)); + background-color: var(--black30a); + position: absolute; + width: 100%; + height: 100vh; + height: 100dvh; + z-index: 9998; + top: 0; +} + +#bulk_tag_shadow_popup #bulk_tag_popup { + padding: 1em; +} + +#bulk_tag_shadow_popup #bulk_tag_popup #dialogue_popup_controls .menu_button { + width: unset; + padding: 0.25em; +} diff --git a/jiuguan2025cc/public/css/cropper.min.css b/jiuguan2025cc/public/css/cropper.min.css new file mode 100644 index 0000000000000000000000000000000000000000..e97743ad00e3ee2f10eed53e9c1acb3257422531 --- /dev/null +++ b/jiuguan2025cc/public/css/cropper.min.css @@ -0,0 +1,9 @@ +/*! + * Cropper.js v1.5.13 + * https://fengyuanchen.github.io/cropperjs + * + * Copyright 2015-present Chen Fengyuan + * Released under the MIT license + * + * Date: 2022-11-20T05:30:43.444Z + */.cropper-container{direction:ltr;font-size:0;line-height:0;position:relative;-ms-touch-action:none;touch-action:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.cropper-container img{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:block;height:100%;image-orientation:0deg;max-height:none!important;max-width:none!important;min-height:0!important;min-width:0!important;width:100%}.cropper-canvas,.cropper-crop-box,.cropper-drag-box,.cropper-modal,.cropper-wrap-box{bottom:0;left:0;position:absolute;right:0;top:0}.cropper-canvas,.cropper-wrap-box{overflow:hidden}.cropper-drag-box{background-color:#fff;opacity:0}.cropper-modal{background-color:#000;opacity:.5}.cropper-view-box{display:block;height:100%;outline:1px solid #39f;outline-color:rgba(51,153,255,.75);overflow:hidden;width:100%}.cropper-dashed{border:0 dashed #eee;display:block;opacity:.5;position:absolute}.cropper-dashed.dashed-h{border-bottom-width:1px;border-top-width:1px;height:33.33333%;left:0;top:33.33333%;width:100%}.cropper-dashed.dashed-v{border-left-width:1px;border-right-width:1px;height:100%;left:33.33333%;top:0;width:33.33333%}.cropper-center{display:block;height:0;left:50%;opacity:.75;position:absolute;top:50%;width:0}.cropper-center:after,.cropper-center:before{background-color:#eee;content:" ";display:block;position:absolute}.cropper-center:before{height:1px;left:-3px;top:0;width:7px}.cropper-center:after{height:7px;left:0;top:-3px;width:1px}.cropper-face,.cropper-line,.cropper-point{display:block;height:100%;opacity:.1;position:absolute;width:100%}.cropper-face{background-color:#fff;left:0;top:0}.cropper-line{background-color:#39f}.cropper-line.line-e{cursor:ew-resize;right:-3px;top:0;width:5px}.cropper-line.line-n{cursor:ns-resize;height:5px;left:0;top:-3px}.cropper-line.line-w{cursor:ew-resize;left:-3px;top:0;width:5px}.cropper-line.line-s{bottom:-3px;cursor:ns-resize;height:5px;left:0}.cropper-point{background-color:#39f;height:5px;opacity:.75;width:5px}.cropper-point.point-e{cursor:ew-resize;margin-top:-3px;right:-3px;top:50%}.cropper-point.point-n{cursor:ns-resize;left:50%;margin-left:-3px;top:-3px}.cropper-point.point-w{cursor:ew-resize;left:-3px;margin-top:-3px;top:50%}.cropper-point.point-s{bottom:-3px;cursor:s-resize;left:50%;margin-left:-3px}.cropper-point.point-ne{cursor:nesw-resize;right:-3px;top:-3px}.cropper-point.point-nw{cursor:nwse-resize;left:-3px;top:-3px}.cropper-point.point-sw{bottom:-3px;cursor:nesw-resize;left:-3px}.cropper-point.point-se{bottom:-3px;cursor:nwse-resize;height:20px;opacity:1;right:-3px;width:20px}@media (min-width:768px){.cropper-point.point-se{height:15px;width:15px}}@media (min-width:992px){.cropper-point.point-se{height:10px;width:10px}}@media (min-width:1200px){.cropper-point.point-se{height:5px;opacity:.75;width:5px}}.cropper-point.point-se:before{background-color:#39f;bottom:-50%;content:" ";display:block;height:200%;opacity:0;position:absolute;right:-50%;width:200%}.cropper-invisible{opacity:0}.cropper-bg{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC")}.cropper-hide{display:block;height:0;position:absolute;width:0}.cropper-hidden{display:none!important}.cropper-move{cursor:move}.cropper-crop{cursor:crosshair}.cropper-disabled .cropper-drag-box,.cropper-disabled .cropper-face,.cropper-disabled .cropper-line,.cropper-disabled .cropper-point{cursor:not-allowed} \ No newline at end of file diff --git a/jiuguan2025cc/public/css/extensions-panel.css b/jiuguan2025cc/public/css/extensions-panel.css new file mode 100644 index 0000000000000000000000000000000000000000..ad0bd01279c60f73988e51aae200e5b8243f43b1 --- /dev/null +++ b/jiuguan2025cc/public/css/extensions-panel.css @@ -0,0 +1,148 @@ +/* Extensions */ +#extensions_url { + display: block; +} + +.extensions_block input[type="submit"]:hover { + background-color: green; +} + +.extensions_block input[type="checkbox"], +.extensions_block input[type="radio"] { + margin-left: 10px; + margin-right: 10px; +} + +label[for="extensions_autoconnect"] { + display: flex; + align-items: center; + margin: 0 !important; +} + +.extensions_url_block { + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; +} + +.extensions_url_block h4 { + display: inline; +} + +.extensions_block { + clear: both; + padding: 0.05px; +} + +.extensions_info { + text-align: left; +} + +.extensions_info h3 { + margin-bottom: 0.5em; +} + +.extensions_info h4 { + margin-bottom: 0.5em; +} + +.extensions_info p { + margin-bottom: 0.5em; + margin-left: 1em; +} + +.extensions_info .disabled { + color: lightgray; +} + +.extensions_info .toggle_enable { + color: lightgreen; +} + +.extensions_info .toggle_disable { + color: rgb(238, 144, 144); +} + +.extensions_info .extension_enabled { + font-weight: bold; +} + +.extensions_info .extension_disabled { + color: lightgray; +} + +.extensions_info .extension_missing { + color: gray; +} + +.extensions_info .extension_modules { + font-size: 0.8em; + font-weight: normal; +} + +.extensions_info .extension_block { + display: flex; + flex-wrap: nowrap; + padding: 5px; + margin-bottom: 5px; + border: 1px solid var(--SmartThemeBorderColor); + border-radius: 10px; + align-items: baseline; + justify-content: space-between; + gap: 5px; +} + +.extensions_info .extension_name { + font-size: 1.05em; +} + +.extensions_info .extension_version { + opacity: 0.8; + font-size: 0.8em; + font-weight: normal; + margin-left: 2px; +} + +.extensions_info .extension_block a { + color: var(--SmartThemeBodyColor); +} + +.extensions_info .extension_name.update_available { + color: limegreen; +} + +input.extension_missing[type="checkbox"] { + opacity: 0.5; +} + +.update-button { + margin-right: 10px; + display: inline-flex; +} + +/* Fixes order of settings for extensions */ +#extensions_settings, +#extensions_settings2 { + display: flex; + flex-direction: column; +} + +/* Fixes order of settings for extensions */ +.extension_container { + display: contents; +} + +#extensionsMenu>div.extension_container:empty { + display: none; +} + +.extensions_info .extension_text_block { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.extensions_info .extension_actions { + flex-wrap: nowrap; +} diff --git a/jiuguan2025cc/public/css/file-form.css b/jiuguan2025cc/public/css/file-form.css new file mode 100644 index 0000000000000000000000000000000000000000..67801ba30e87a0d972fec59e0a15917915b3616b --- /dev/null +++ b/jiuguan2025cc/public/css/file-form.css @@ -0,0 +1,57 @@ +.file_attached { + display: flex; + min-width: 150px; + max-width: calc(var(--sheldWidth) * 0.9); + flex-direction: row; + gap: 10px; + align-items: center; + margin: 0.25em auto; + padding: 0 0.75em; + border: 2px solid var(--SmartThemeBorderColor); + border-radius: 15px; + background-color: var(--white20a); +} + +.mes_file_container { + cursor: default; + display: flex; + gap: 15px; + align-items: center; + width: fit-content; + max-width: 100%; + background-color: var(--white20a); + border: 2px solid var(--SmartThemeBorderColor); + padding: 0.5em 1em; + border-radius: 15px; +} + +.mes_file_container .right_menu_button { + padding-right: 0; +} + +.mes_file_container .mes_file_size, +.file_attached .file_size { + font-size: 0.9em; + color: var(--SmartThemeQuoteColor); +} + +.file_attached .file_name, +.mes_file_container .mes_file_name { + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +#file_form { + display: flex; + width: 100%; +} + +.file_modal { + width: 100%; + height: 100%; + overflow-y: auto; + display: flex; + text-align: left; +} diff --git a/jiuguan2025cc/public/css/fontawesome.min.css b/jiuguan2025cc/public/css/fontawesome.min.css new file mode 100644 index 0000000000000000000000000000000000000000..7e1c2541d760ff7b5295e0d44842ee462efa7598 --- /dev/null +++ b/jiuguan2025cc/public/css/fontawesome.min.css @@ -0,0 +1,9 @@ +/*! + * Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +.fa{font-family:var(--fa-style-family,"Font Awesome 6 Free");font-weight:var(--fa-style,900)}.fa,.fa-brands,.fa-classic,.fa-regular,.fa-sharp,.fa-solid,.fab,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:var(--fa-display,inline-block);font-style:normal;font-variant:normal;line-height:1;text-rendering:auto}.fa-classic,.fa-regular,.fa-solid,.far,.fas{font-family:"Font Awesome 6 Free"}.fa-brands,.fab{font-family:"Font Awesome 6 Brands"}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-2xs{font-size:.625em;line-height:.1em;vertical-align:.225em}.fa-xs{font-size:.75em;line-height:.08333em;vertical-align:.125em}.fa-sm{font-size:.875em;line-height:.07143em;vertical-align:.05357em}.fa-lg{font-size:1.25em;line-height:.05em;vertical-align:-.075em}.fa-xl{font-size:1.5em;line-height:.04167em;vertical-align:-.125em}.fa-2xl{font-size:2em;line-height:.03125em;vertical-align:-.1875em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:var(--fa-li-margin,2.5em);padding-left:0}.fa-ul>li{position:relative}.fa-li{left:calc(var(--fa-li-width, 2em)*-1);position:absolute;text-align:center;width:var(--fa-li-width,2em);line-height:inherit}.fa-border{border-radius:var(--fa-border-radius,.1em);border:var(--fa-border-width,.08em) var(--fa-border-style,solid) var(--fa-border-color,#eee);padding:var(--fa-border-padding,.2em .25em .15em)}.fa-pull-left{float:left;margin-right:var(--fa-pull-margin,.3em)}.fa-pull-right{float:right;margin-left:var(--fa-pull-margin,.3em)}.fa-beat{-webkit-animation-name:fa-beat;animation-name:fa-beat;-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,ease-in-out);animation-timing-function:var(--fa-animation-timing,ease-in-out)}.fa-bounce{-webkit-animation-name:fa-bounce;animation-name:fa-bounce;-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.28,.84,.42,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.28,.84,.42,1))}.fa-fade{-webkit-animation-name:fa-fade;animation-name:fa-fade;-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1))}.fa-beat-fade,.fa-fade{-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s)}.fa-beat-fade{-webkit-animation-name:fa-beat-fade;animation-name:fa-beat-fade;-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1))}.fa-flip{-webkit-animation-name:fa-flip;animation-name:fa-flip;-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,ease-in-out);animation-timing-function:var(--fa-animation-timing,ease-in-out)}.fa-shake{-webkit-animation-name:fa-shake;animation-name:fa-shake;-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,linear);animation-timing-function:var(--fa-animation-timing,linear)}.fa-shake,.fa-spin{-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal)}.fa-spin{-webkit-animation-name:fa-spin;animation-name:fa-spin;-webkit-animation-duration:var(--fa-animation-duration,2s);animation-duration:var(--fa-animation-duration,2s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,linear);animation-timing-function:var(--fa-animation-timing,linear)}.fa-spin-reverse{--fa-animation-direction:reverse}.fa-pulse,.fa-spin-pulse{-webkit-animation-name:fa-spin;animation-name:fa-spin;-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,steps(8));animation-timing-function:var(--fa-animation-timing,steps(8))}@media (prefers-reduced-motion:reduce){.fa-beat,.fa-beat-fade,.fa-bounce,.fa-fade,.fa-flip,.fa-pulse,.fa-shake,.fa-spin,.fa-spin-pulse{-webkit-animation-delay:-1ms;animation-delay:-1ms;-webkit-animation-duration:1ms;animation-duration:1ms;-webkit-animation-iteration-count:1;animation-iteration-count:1;-webkit-transition-delay:0s;transition-delay:0s;-webkit-transition-duration:0s;transition-duration:0s}}@-webkit-keyframes fa-beat{0%,90%{-webkit-transform:scale(1);transform:scale(1)}45%{-webkit-transform:scale(var(--fa-beat-scale,1.25));transform:scale(var(--fa-beat-scale,1.25))}}@keyframes fa-beat{0%,90%{-webkit-transform:scale(1);transform:scale(1)}45%{-webkit-transform:scale(var(--fa-beat-scale,1.25));transform:scale(var(--fa-beat-scale,1.25))}}@-webkit-keyframes fa-bounce{0%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}10%{-webkit-transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0);transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0)}30%{-webkit-transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em));transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em))}50%{-webkit-transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0);transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0)}57%{-webkit-transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em));transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em))}64%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}to{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}}@keyframes fa-bounce{0%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}10%{-webkit-transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0);transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0)}30%{-webkit-transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em));transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em))}50%{-webkit-transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0);transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0)}57%{-webkit-transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em));transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em))}64%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}to{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}}@-webkit-keyframes fa-fade{50%{opacity:var(--fa-fade-opacity,.4)}}@keyframes fa-fade{50%{opacity:var(--fa-fade-opacity,.4)}}@-webkit-keyframes fa-beat-fade{0%,to{opacity:var(--fa-beat-fade-opacity,.4);-webkit-transform:scale(1);transform:scale(1)}50%{opacity:1;-webkit-transform:scale(var(--fa-beat-fade-scale,1.125));transform:scale(var(--fa-beat-fade-scale,1.125))}}@keyframes fa-beat-fade{0%,to{opacity:var(--fa-beat-fade-opacity,.4);-webkit-transform:scale(1);transform:scale(1)}50%{opacity:1;-webkit-transform:scale(var(--fa-beat-fade-scale,1.125));transform:scale(var(--fa-beat-fade-scale,1.125))}}@-webkit-keyframes fa-flip{50%{-webkit-transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg));transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg))}}@keyframes fa-flip{50%{-webkit-transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg));transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg))}}@-webkit-keyframes fa-shake{0%{-webkit-transform:rotate(-15deg);transform:rotate(-15deg)}4%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}8%,24%{-webkit-transform:rotate(-18deg);transform:rotate(-18deg)}12%,28%{-webkit-transform:rotate(18deg);transform:rotate(18deg)}16%{-webkit-transform:rotate(-22deg);transform:rotate(-22deg)}20%{-webkit-transform:rotate(22deg);transform:rotate(22deg)}32%{-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}36%{-webkit-transform:rotate(12deg);transform:rotate(12deg)}40%,to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@keyframes fa-shake{0%{-webkit-transform:rotate(-15deg);transform:rotate(-15deg)}4%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}8%,24%{-webkit-transform:rotate(-18deg);transform:rotate(-18deg)}12%,28%{-webkit-transform:rotate(18deg);transform:rotate(18deg)}16%{-webkit-transform:rotate(-22deg);transform:rotate(-22deg)}20%{-webkit-transform:rotate(22deg);transform:rotate(22deg)}32%{-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}36%{-webkit-transform:rotate(12deg);transform:rotate(12deg)}40%,to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}.fa-rotate-by{-webkit-transform:rotate(var(--fa-rotate-angle,0));transform:rotate(var(--fa-rotate-angle,0))}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%;z-index:var(--fa-stack-z-index,auto)}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:var(--fa-inverse,#fff)} + +.fa-0:before{content:"\30"}.fa-1:before{content:"\31"}.fa-2:before{content:"\32"}.fa-3:before{content:"\33"}.fa-4:before{content:"\34"}.fa-5:before{content:"\35"}.fa-6:before{content:"\36"}.fa-7:before{content:"\37"}.fa-8:before{content:"\38"}.fa-9:before{content:"\39"}.fa-fill-drip:before{content:"\f576"}.fa-arrows-to-circle:before{content:"\e4bd"}.fa-chevron-circle-right:before,.fa-circle-chevron-right:before{content:"\f138"}.fa-at:before{content:"\40"}.fa-trash-alt:before,.fa-trash-can:before{content:"\f2ed"}.fa-text-height:before{content:"\f034"}.fa-user-times:before,.fa-user-xmark:before{content:"\f235"}.fa-stethoscope:before{content:"\f0f1"}.fa-comment-alt:before,.fa-message:before{content:"\f27a"}.fa-info:before{content:"\f129"}.fa-compress-alt:before,.fa-down-left-and-up-right-to-center:before{content:"\f422"}.fa-explosion:before{content:"\e4e9"}.fa-file-alt:before,.fa-file-lines:before,.fa-file-text:before{content:"\f15c"}.fa-wave-square:before{content:"\f83e"}.fa-ring:before{content:"\f70b"}.fa-building-un:before{content:"\e4d9"}.fa-dice-three:before{content:"\f527"}.fa-calendar-alt:before,.fa-calendar-days:before{content:"\f073"}.fa-anchor-circle-check:before{content:"\e4aa"}.fa-building-circle-arrow-right:before{content:"\e4d1"}.fa-volleyball-ball:before,.fa-volleyball:before{content:"\f45f"}.fa-arrows-up-to-line:before{content:"\e4c2"}.fa-sort-desc:before,.fa-sort-down:before{content:"\f0dd"}.fa-circle-minus:before,.fa-minus-circle:before{content:"\f056"}.fa-door-open:before{content:"\f52b"}.fa-right-from-bracket:before,.fa-sign-out-alt:before{content:"\f2f5"}.fa-atom:before{content:"\f5d2"}.fa-soap:before{content:"\e06e"}.fa-heart-music-camera-bolt:before,.fa-icons:before{content:"\f86d"}.fa-microphone-alt-slash:before,.fa-microphone-lines-slash:before{content:"\f539"}.fa-bridge-circle-check:before{content:"\e4c9"}.fa-pump-medical:before{content:"\e06a"}.fa-fingerprint:before{content:"\f577"}.fa-hand-point-right:before{content:"\f0a4"}.fa-magnifying-glass-location:before,.fa-search-location:before{content:"\f689"}.fa-forward-step:before,.fa-step-forward:before{content:"\f051"}.fa-face-smile-beam:before,.fa-smile-beam:before{content:"\f5b8"}.fa-flag-checkered:before{content:"\f11e"}.fa-football-ball:before,.fa-football:before{content:"\f44e"}.fa-school-circle-exclamation:before{content:"\e56c"}.fa-crop:before{content:"\f125"}.fa-angle-double-down:before,.fa-angles-down:before{content:"\f103"}.fa-users-rectangle:before{content:"\e594"}.fa-people-roof:before{content:"\e537"}.fa-people-line:before{content:"\e534"}.fa-beer-mug-empty:before,.fa-beer:before{content:"\f0fc"}.fa-diagram-predecessor:before{content:"\e477"}.fa-arrow-up-long:before,.fa-long-arrow-up:before{content:"\f176"}.fa-burn:before,.fa-fire-flame-simple:before{content:"\f46a"}.fa-male:before,.fa-person:before{content:"\f183"}.fa-laptop:before{content:"\f109"}.fa-file-csv:before{content:"\f6dd"}.fa-menorah:before{content:"\f676"}.fa-truck-plane:before{content:"\e58f"}.fa-record-vinyl:before{content:"\f8d9"}.fa-face-grin-stars:before,.fa-grin-stars:before{content:"\f587"}.fa-bong:before{content:"\f55c"}.fa-pastafarianism:before,.fa-spaghetti-monster-flying:before{content:"\f67b"}.fa-arrow-down-up-across-line:before{content:"\e4af"}.fa-spoon:before,.fa-utensil-spoon:before{content:"\f2e5"}.fa-jar-wheat:before{content:"\e517"}.fa-envelopes-bulk:before,.fa-mail-bulk:before{content:"\f674"}.fa-file-circle-exclamation:before{content:"\e4eb"}.fa-circle-h:before,.fa-hospital-symbol:before{content:"\f47e"}.fa-pager:before{content:"\f815"}.fa-address-book:before,.fa-contact-book:before{content:"\f2b9"}.fa-strikethrough:before{content:"\f0cc"}.fa-k:before{content:"\4b"}.fa-landmark-flag:before{content:"\e51c"}.fa-pencil-alt:before,.fa-pencil:before{content:"\f303"}.fa-backward:before{content:"\f04a"}.fa-caret-right:before{content:"\f0da"}.fa-comments:before{content:"\f086"}.fa-file-clipboard:before,.fa-paste:before{content:"\f0ea"}.fa-code-pull-request:before{content:"\e13c"}.fa-clipboard-list:before{content:"\f46d"}.fa-truck-loading:before,.fa-truck-ramp-box:before{content:"\f4de"}.fa-user-check:before{content:"\f4fc"}.fa-vial-virus:before{content:"\e597"}.fa-sheet-plastic:before{content:"\e571"}.fa-blog:before{content:"\f781"}.fa-user-ninja:before{content:"\f504"}.fa-person-arrow-up-from-line:before{content:"\e539"}.fa-scroll-torah:before,.fa-torah:before{content:"\f6a0"}.fa-broom-ball:before,.fa-quidditch-broom-ball:before,.fa-quidditch:before{content:"\f458"}.fa-toggle-off:before{content:"\f204"}.fa-archive:before,.fa-box-archive:before{content:"\f187"}.fa-person-drowning:before{content:"\e545"}.fa-arrow-down-9-1:before,.fa-sort-numeric-desc:before,.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-face-grin-tongue-squint:before,.fa-grin-tongue-squint:before{content:"\f58a"}.fa-spray-can:before{content:"\f5bd"}.fa-truck-monster:before{content:"\f63b"}.fa-w:before{content:"\57"}.fa-earth-africa:before,.fa-globe-africa:before{content:"\f57c"}.fa-rainbow:before{content:"\f75b"}.fa-circle-notch:before{content:"\f1ce"}.fa-tablet-alt:before,.fa-tablet-screen-button:before{content:"\f3fa"}.fa-paw:before{content:"\f1b0"}.fa-cloud:before{content:"\f0c2"}.fa-trowel-bricks:before{content:"\e58a"}.fa-face-flushed:before,.fa-flushed:before{content:"\f579"}.fa-hospital-user:before{content:"\f80d"}.fa-tent-arrow-left-right:before{content:"\e57f"}.fa-gavel:before,.fa-legal:before{content:"\f0e3"}.fa-binoculars:before{content:"\f1e5"}.fa-microphone-slash:before{content:"\f131"}.fa-box-tissue:before{content:"\e05b"}.fa-motorcycle:before{content:"\f21c"}.fa-bell-concierge:before,.fa-concierge-bell:before{content:"\f562"}.fa-pen-ruler:before,.fa-pencil-ruler:before{content:"\f5ae"}.fa-people-arrows-left-right:before,.fa-people-arrows:before{content:"\e068"}.fa-mars-and-venus-burst:before{content:"\e523"}.fa-caret-square-right:before,.fa-square-caret-right:before{content:"\f152"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-sun-plant-wilt:before{content:"\e57a"}.fa-toilets-portable:before{content:"\e584"}.fa-hockey-puck:before{content:"\f453"}.fa-table:before{content:"\f0ce"}.fa-magnifying-glass-arrow-right:before{content:"\e521"}.fa-digital-tachograph:before,.fa-tachograph-digital:before{content:"\f566"}.fa-users-slash:before{content:"\e073"}.fa-clover:before{content:"\e139"}.fa-mail-reply:before,.fa-reply:before{content:"\f3e5"}.fa-star-and-crescent:before{content:"\f699"}.fa-house-fire:before{content:"\e50c"}.fa-minus-square:before,.fa-square-minus:before{content:"\f146"}.fa-helicopter:before{content:"\f533"}.fa-compass:before{content:"\f14e"}.fa-caret-square-down:before,.fa-square-caret-down:before{content:"\f150"}.fa-file-circle-question:before{content:"\e4ef"}.fa-laptop-code:before{content:"\f5fc"}.fa-swatchbook:before{content:"\f5c3"}.fa-prescription-bottle:before{content:"\f485"}.fa-bars:before,.fa-navicon:before{content:"\f0c9"}.fa-people-group:before{content:"\e533"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-heart-broken:before,.fa-heart-crack:before{content:"\f7a9"}.fa-external-link-square-alt:before,.fa-square-up-right:before{content:"\f360"}.fa-face-kiss-beam:before,.fa-kiss-beam:before{content:"\f597"}.fa-film:before{content:"\f008"}.fa-ruler-horizontal:before{content:"\f547"}.fa-people-robbery:before{content:"\e536"}.fa-lightbulb:before{content:"\f0eb"}.fa-caret-left:before{content:"\f0d9"}.fa-circle-exclamation:before,.fa-exclamation-circle:before{content:"\f06a"}.fa-school-circle-xmark:before{content:"\e56d"}.fa-arrow-right-from-bracket:before,.fa-sign-out:before{content:"\f08b"}.fa-chevron-circle-down:before,.fa-circle-chevron-down:before{content:"\f13a"}.fa-unlock-alt:before,.fa-unlock-keyhole:before{content:"\f13e"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-headphones-alt:before,.fa-headphones-simple:before{content:"\f58f"}.fa-sitemap:before{content:"\f0e8"}.fa-circle-dollar-to-slot:before,.fa-donate:before{content:"\f4b9"}.fa-memory:before{content:"\f538"}.fa-road-spikes:before{content:"\e568"}.fa-fire-burner:before{content:"\e4f1"}.fa-flag:before{content:"\f024"}.fa-hanukiah:before{content:"\f6e6"}.fa-feather:before{content:"\f52d"}.fa-volume-down:before,.fa-volume-low:before{content:"\f027"}.fa-comment-slash:before{content:"\f4b3"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-compress:before{content:"\f066"}.fa-wheat-alt:before,.fa-wheat-awn:before{content:"\e2cd"}.fa-ankh:before{content:"\f644"}.fa-hands-holding-child:before{content:"\e4fa"}.fa-asterisk:before{content:"\2a"}.fa-check-square:before,.fa-square-check:before{content:"\f14a"}.fa-peseta-sign:before{content:"\e221"}.fa-header:before,.fa-heading:before{content:"\f1dc"}.fa-ghost:before{content:"\f6e2"}.fa-list-squares:before,.fa-list:before{content:"\f03a"}.fa-phone-square-alt:before,.fa-square-phone-flip:before{content:"\f87b"}.fa-cart-plus:before{content:"\f217"}.fa-gamepad:before{content:"\f11b"}.fa-circle-dot:before,.fa-dot-circle:before{content:"\f192"}.fa-dizzy:before,.fa-face-dizzy:before{content:"\f567"}.fa-egg:before{content:"\f7fb"}.fa-house-medical-circle-xmark:before{content:"\e513"}.fa-campground:before{content:"\f6bb"}.fa-folder-plus:before{content:"\f65e"}.fa-futbol-ball:before,.fa-futbol:before,.fa-soccer-ball:before{content:"\f1e3"}.fa-paint-brush:before,.fa-paintbrush:before{content:"\f1fc"}.fa-lock:before{content:"\f023"}.fa-gas-pump:before{content:"\f52f"}.fa-hot-tub-person:before,.fa-hot-tub:before{content:"\f593"}.fa-map-location:before,.fa-map-marked:before{content:"\f59f"}.fa-house-flood-water:before{content:"\e50e"}.fa-tree:before{content:"\f1bb"}.fa-bridge-lock:before{content:"\e4cc"}.fa-sack-dollar:before{content:"\f81d"}.fa-edit:before,.fa-pen-to-square:before{content:"\f044"}.fa-car-side:before{content:"\f5e4"}.fa-share-alt:before,.fa-share-nodes:before{content:"\f1e0"}.fa-heart-circle-minus:before{content:"\e4ff"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-microscope:before{content:"\f610"}.fa-sink:before{content:"\e06d"}.fa-bag-shopping:before,.fa-shopping-bag:before{content:"\f290"}.fa-arrow-down-z-a:before,.fa-sort-alpha-desc:before,.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-mitten:before{content:"\f7b5"}.fa-person-rays:before{content:"\e54d"}.fa-users:before{content:"\f0c0"}.fa-eye-slash:before{content:"\f070"}.fa-flask-vial:before{content:"\e4f3"}.fa-hand-paper:before,.fa-hand:before{content:"\f256"}.fa-om:before{content:"\f679"}.fa-worm:before{content:"\e599"}.fa-house-circle-xmark:before{content:"\e50b"}.fa-plug:before{content:"\f1e6"}.fa-chevron-up:before{content:"\f077"}.fa-hand-spock:before{content:"\f259"}.fa-stopwatch:before{content:"\f2f2"}.fa-face-kiss:before,.fa-kiss:before{content:"\f596"}.fa-bridge-circle-xmark:before{content:"\e4cb"}.fa-face-grin-tongue:before,.fa-grin-tongue:before{content:"\f589"}.fa-chess-bishop:before{content:"\f43a"}.fa-face-grin-wink:before,.fa-grin-wink:before{content:"\f58c"}.fa-deaf:before,.fa-deafness:before,.fa-ear-deaf:before,.fa-hard-of-hearing:before{content:"\f2a4"}.fa-road-circle-check:before{content:"\e564"}.fa-dice-five:before{content:"\f523"}.fa-rss-square:before,.fa-square-rss:before{content:"\f143"}.fa-land-mine-on:before{content:"\e51b"}.fa-i-cursor:before{content:"\f246"}.fa-stamp:before{content:"\f5bf"}.fa-stairs:before{content:"\e289"}.fa-i:before{content:"\49"}.fa-hryvnia-sign:before,.fa-hryvnia:before{content:"\f6f2"}.fa-pills:before{content:"\f484"}.fa-face-grin-wide:before,.fa-grin-alt:before{content:"\f581"}.fa-tooth:before{content:"\f5c9"}.fa-v:before{content:"\56"}.fa-bangladeshi-taka-sign:before{content:"\e2e6"}.fa-bicycle:before{content:"\f206"}.fa-rod-asclepius:before,.fa-rod-snake:before,.fa-staff-aesculapius:before,.fa-staff-snake:before{content:"\e579"}.fa-head-side-cough-slash:before{content:"\e062"}.fa-ambulance:before,.fa-truck-medical:before{content:"\f0f9"}.fa-wheat-awn-circle-exclamation:before{content:"\e598"}.fa-snowman:before{content:"\f7d0"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-road-barrier:before{content:"\e562"}.fa-school:before{content:"\f549"}.fa-igloo:before{content:"\f7ae"}.fa-joint:before{content:"\f595"}.fa-angle-right:before{content:"\f105"}.fa-horse:before{content:"\f6f0"}.fa-q:before{content:"\51"}.fa-g:before{content:"\47"}.fa-notes-medical:before{content:"\f481"}.fa-temperature-2:before,.fa-temperature-half:before,.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-dong-sign:before{content:"\e169"}.fa-capsules:before{content:"\f46b"}.fa-poo-bolt:before,.fa-poo-storm:before{content:"\f75a"}.fa-face-frown-open:before,.fa-frown-open:before{content:"\f57a"}.fa-hand-point-up:before{content:"\f0a6"}.fa-money-bill:before{content:"\f0d6"}.fa-bookmark:before{content:"\f02e"}.fa-align-justify:before{content:"\f039"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-helmet-un:before{content:"\e503"}.fa-bullseye:before{content:"\f140"}.fa-bacon:before{content:"\f7e5"}.fa-hand-point-down:before{content:"\f0a7"}.fa-arrow-up-from-bracket:before{content:"\e09a"}.fa-folder-blank:before,.fa-folder:before{content:"\f07b"}.fa-file-medical-alt:before,.fa-file-waveform:before{content:"\f478"}.fa-radiation:before{content:"\f7b9"}.fa-chart-simple:before{content:"\e473"}.fa-mars-stroke:before{content:"\f229"}.fa-vial:before{content:"\f492"}.fa-dashboard:before,.fa-gauge-med:before,.fa-gauge:before,.fa-tachometer-alt-average:before{content:"\f624"}.fa-magic-wand-sparkles:before,.fa-wand-magic-sparkles:before{content:"\e2ca"}.fa-e:before{content:"\45"}.fa-pen-alt:before,.fa-pen-clip:before{content:"\f305"}.fa-bridge-circle-exclamation:before{content:"\e4ca"}.fa-user:before{content:"\f007"}.fa-school-circle-check:before{content:"\e56b"}.fa-dumpster:before{content:"\f793"}.fa-shuttle-van:before,.fa-van-shuttle:before{content:"\f5b6"}.fa-building-user:before{content:"\e4da"}.fa-caret-square-left:before,.fa-square-caret-left:before{content:"\f191"}.fa-highlighter:before{content:"\f591"}.fa-key:before{content:"\f084"}.fa-bullhorn:before{content:"\f0a1"}.fa-globe:before{content:"\f0ac"}.fa-synagogue:before{content:"\f69b"}.fa-person-half-dress:before{content:"\e548"}.fa-road-bridge:before{content:"\e563"}.fa-location-arrow:before{content:"\f124"}.fa-c:before{content:"\43"}.fa-tablet-button:before{content:"\f10a"}.fa-building-lock:before{content:"\e4d6"}.fa-pizza-slice:before{content:"\f818"}.fa-money-bill-wave:before{content:"\f53a"}.fa-area-chart:before,.fa-chart-area:before{content:"\f1fe"}.fa-house-flag:before{content:"\e50d"}.fa-person-circle-minus:before{content:"\e540"}.fa-ban:before,.fa-cancel:before{content:"\f05e"}.fa-camera-rotate:before{content:"\e0d8"}.fa-air-freshener:before,.fa-spray-can-sparkles:before{content:"\f5d0"}.fa-star:before{content:"\f005"}.fa-repeat:before{content:"\f363"}.fa-cross:before{content:"\f654"}.fa-box:before{content:"\f466"}.fa-venus-mars:before{content:"\f228"}.fa-arrow-pointer:before,.fa-mouse-pointer:before{content:"\f245"}.fa-expand-arrows-alt:before,.fa-maximize:before{content:"\f31e"}.fa-charging-station:before{content:"\f5e7"}.fa-shapes:before,.fa-triangle-circle-square:before{content:"\f61f"}.fa-random:before,.fa-shuffle:before{content:"\f074"}.fa-person-running:before,.fa-running:before{content:"\f70c"}.fa-mobile-retro:before{content:"\e527"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-spider:before{content:"\f717"}.fa-hands-bound:before{content:"\e4f9"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-plane-circle-exclamation:before{content:"\e556"}.fa-x-ray:before{content:"\f497"}.fa-spell-check:before{content:"\f891"}.fa-slash:before{content:"\f715"}.fa-computer-mouse:before,.fa-mouse:before{content:"\f8cc"}.fa-arrow-right-to-bracket:before,.fa-sign-in:before{content:"\f090"}.fa-shop-slash:before,.fa-store-alt-slash:before{content:"\e070"}.fa-server:before{content:"\f233"}.fa-virus-covid-slash:before{content:"\e4a9"}.fa-shop-lock:before{content:"\e4a5"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-blender-phone:before{content:"\f6b6"}.fa-building-wheat:before{content:"\e4db"}.fa-person-breastfeeding:before{content:"\e53a"}.fa-right-to-bracket:before,.fa-sign-in-alt:before{content:"\f2f6"}.fa-venus:before{content:"\f221"}.fa-passport:before{content:"\f5ab"}.fa-heart-pulse:before,.fa-heartbeat:before{content:"\f21e"}.fa-people-carry-box:before,.fa-people-carry:before{content:"\f4ce"}.fa-temperature-high:before{content:"\f769"}.fa-microchip:before{content:"\f2db"}.fa-crown:before{content:"\f521"}.fa-weight-hanging:before{content:"\f5cd"}.fa-xmarks-lines:before{content:"\e59a"}.fa-file-prescription:before{content:"\f572"}.fa-weight-scale:before,.fa-weight:before{content:"\f496"}.fa-user-friends:before,.fa-user-group:before{content:"\f500"}.fa-arrow-up-a-z:before,.fa-sort-alpha-up:before{content:"\f15e"}.fa-chess-knight:before{content:"\f441"}.fa-face-laugh-squint:before,.fa-laugh-squint:before{content:"\f59b"}.fa-wheelchair:before{content:"\f193"}.fa-arrow-circle-up:before,.fa-circle-arrow-up:before{content:"\f0aa"}.fa-toggle-on:before{content:"\f205"}.fa-person-walking:before,.fa-walking:before{content:"\f554"}.fa-l:before{content:"\4c"}.fa-fire:before{content:"\f06d"}.fa-bed-pulse:before,.fa-procedures:before{content:"\f487"}.fa-shuttle-space:before,.fa-space-shuttle:before{content:"\f197"}.fa-face-laugh:before,.fa-laugh:before{content:"\f599"}.fa-folder-open:before{content:"\f07c"}.fa-heart-circle-plus:before{content:"\e500"}.fa-code-fork:before{content:"\e13b"}.fa-city:before{content:"\f64f"}.fa-microphone-alt:before,.fa-microphone-lines:before{content:"\f3c9"}.fa-pepper-hot:before{content:"\f816"}.fa-unlock:before{content:"\f09c"}.fa-colon-sign:before{content:"\e140"}.fa-headset:before{content:"\f590"}.fa-store-slash:before{content:"\e071"}.fa-road-circle-xmark:before{content:"\e566"}.fa-user-minus:before{content:"\f503"}.fa-mars-stroke-up:before,.fa-mars-stroke-v:before{content:"\f22a"}.fa-champagne-glasses:before,.fa-glass-cheers:before{content:"\f79f"}.fa-clipboard:before{content:"\f328"}.fa-house-circle-exclamation:before{content:"\e50a"}.fa-file-arrow-up:before,.fa-file-upload:before{content:"\f574"}.fa-wifi-3:before,.fa-wifi-strong:before,.fa-wifi:before{content:"\f1eb"}.fa-bath:before,.fa-bathtub:before{content:"\f2cd"}.fa-underline:before{content:"\f0cd"}.fa-user-edit:before,.fa-user-pen:before{content:"\f4ff"}.fa-signature:before{content:"\f5b7"}.fa-stroopwafel:before{content:"\f551"}.fa-bold:before{content:"\f032"}.fa-anchor-lock:before{content:"\e4ad"}.fa-building-ngo:before{content:"\e4d7"}.fa-manat-sign:before{content:"\e1d5"}.fa-not-equal:before{content:"\f53e"}.fa-border-style:before,.fa-border-top-left:before{content:"\f853"}.fa-map-location-dot:before,.fa-map-marked-alt:before{content:"\f5a0"}.fa-jedi:before{content:"\f669"}.fa-poll:before,.fa-square-poll-vertical:before{content:"\f681"}.fa-mug-hot:before{content:"\f7b6"}.fa-battery-car:before,.fa-car-battery:before{content:"\f5df"}.fa-gift:before{content:"\f06b"}.fa-dice-two:before{content:"\f528"}.fa-chess-queen:before{content:"\f445"}.fa-glasses:before{content:"\f530"}.fa-chess-board:before{content:"\f43c"}.fa-building-circle-check:before{content:"\e4d2"}.fa-person-chalkboard:before{content:"\e53d"}.fa-mars-stroke-h:before,.fa-mars-stroke-right:before{content:"\f22b"}.fa-hand-back-fist:before,.fa-hand-rock:before{content:"\f255"}.fa-caret-square-up:before,.fa-square-caret-up:before{content:"\f151"}.fa-cloud-showers-water:before{content:"\e4e4"}.fa-bar-chart:before,.fa-chart-bar:before{content:"\f080"}.fa-hands-bubbles:before,.fa-hands-wash:before{content:"\e05e"}.fa-less-than-equal:before{content:"\f537"}.fa-train:before{content:"\f238"}.fa-eye-low-vision:before,.fa-low-vision:before{content:"\f2a8"}.fa-crow:before{content:"\f520"}.fa-sailboat:before{content:"\e445"}.fa-window-restore:before{content:"\f2d2"}.fa-plus-square:before,.fa-square-plus:before{content:"\f0fe"}.fa-torii-gate:before{content:"\f6a1"}.fa-frog:before{content:"\f52e"}.fa-bucket:before{content:"\e4cf"}.fa-image:before{content:"\f03e"}.fa-microphone:before{content:"\f130"}.fa-cow:before{content:"\f6c8"}.fa-caret-up:before{content:"\f0d8"}.fa-screwdriver:before{content:"\f54a"}.fa-folder-closed:before{content:"\e185"}.fa-house-tsunami:before{content:"\e515"}.fa-square-nfi:before{content:"\e576"}.fa-arrow-up-from-ground-water:before{content:"\e4b5"}.fa-glass-martini-alt:before,.fa-martini-glass:before{content:"\f57b"}.fa-rotate-back:before,.fa-rotate-backward:before,.fa-rotate-left:before,.fa-undo-alt:before{content:"\f2ea"}.fa-columns:before,.fa-table-columns:before{content:"\f0db"}.fa-lemon:before{content:"\f094"}.fa-head-side-mask:before{content:"\e063"}.fa-handshake:before{content:"\f2b5"}.fa-gem:before{content:"\f3a5"}.fa-dolly-box:before,.fa-dolly:before{content:"\f472"}.fa-smoking:before{content:"\f48d"}.fa-compress-arrows-alt:before,.fa-minimize:before{content:"\f78c"}.fa-monument:before{content:"\f5a6"}.fa-snowplow:before{content:"\f7d2"}.fa-angle-double-right:before,.fa-angles-right:before{content:"\f101"}.fa-cannabis:before{content:"\f55f"}.fa-circle-play:before,.fa-play-circle:before{content:"\f144"}.fa-tablets:before{content:"\f490"}.fa-ethernet:before{content:"\f796"}.fa-eur:before,.fa-euro-sign:before,.fa-euro:before{content:"\f153"}.fa-chair:before{content:"\f6c0"}.fa-check-circle:before,.fa-circle-check:before{content:"\f058"}.fa-circle-stop:before,.fa-stop-circle:before{content:"\f28d"}.fa-compass-drafting:before,.fa-drafting-compass:before{content:"\f568"}.fa-plate-wheat:before{content:"\e55a"}.fa-icicles:before{content:"\f7ad"}.fa-person-shelter:before{content:"\e54f"}.fa-neuter:before{content:"\f22c"}.fa-id-badge:before{content:"\f2c1"}.fa-marker:before{content:"\f5a1"}.fa-face-laugh-beam:before,.fa-laugh-beam:before{content:"\f59a"}.fa-helicopter-symbol:before{content:"\e502"}.fa-universal-access:before{content:"\f29a"}.fa-chevron-circle-up:before,.fa-circle-chevron-up:before{content:"\f139"}.fa-lari-sign:before{content:"\e1c8"}.fa-volcano:before{content:"\f770"}.fa-person-walking-dashed-line-arrow-right:before{content:"\e553"}.fa-gbp:before,.fa-pound-sign:before,.fa-sterling-sign:before{content:"\f154"}.fa-viruses:before{content:"\e076"}.fa-square-person-confined:before{content:"\e577"}.fa-user-tie:before{content:"\f508"}.fa-arrow-down-long:before,.fa-long-arrow-down:before{content:"\f175"}.fa-tent-arrow-down-to-line:before{content:"\e57e"}.fa-certificate:before{content:"\f0a3"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-suitcase:before{content:"\f0f2"}.fa-person-skating:before,.fa-skating:before{content:"\f7c5"}.fa-filter-circle-dollar:before,.fa-funnel-dollar:before{content:"\f662"}.fa-camera-retro:before{content:"\f083"}.fa-arrow-circle-down:before,.fa-circle-arrow-down:before{content:"\f0ab"}.fa-arrow-right-to-file:before,.fa-file-import:before{content:"\f56f"}.fa-external-link-square:before,.fa-square-arrow-up-right:before{content:"\f14c"}.fa-box-open:before{content:"\f49e"}.fa-scroll:before{content:"\f70e"}.fa-spa:before{content:"\f5bb"}.fa-location-pin-lock:before{content:"\e51f"}.fa-pause:before{content:"\f04c"}.fa-hill-avalanche:before{content:"\e507"}.fa-temperature-0:before,.fa-temperature-empty:before,.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-bomb:before{content:"\f1e2"}.fa-registered:before{content:"\f25d"}.fa-address-card:before,.fa-contact-card:before,.fa-vcard:before{content:"\f2bb"}.fa-balance-scale-right:before,.fa-scale-unbalanced-flip:before{content:"\f516"}.fa-subscript:before{content:"\f12c"}.fa-diamond-turn-right:before,.fa-directions:before{content:"\f5eb"}.fa-burst:before{content:"\e4dc"}.fa-house-laptop:before,.fa-laptop-house:before{content:"\e066"}.fa-face-tired:before,.fa-tired:before{content:"\f5c8"}.fa-money-bills:before{content:"\e1f3"}.fa-smog:before{content:"\f75f"}.fa-crutch:before{content:"\f7f7"}.fa-cloud-arrow-up:before,.fa-cloud-upload-alt:before,.fa-cloud-upload:before{content:"\f0ee"}.fa-palette:before{content:"\f53f"}.fa-arrows-turn-right:before{content:"\e4c0"}.fa-vest:before{content:"\e085"}.fa-ferry:before{content:"\e4ea"}.fa-arrows-down-to-people:before{content:"\e4b9"}.fa-seedling:before,.fa-sprout:before{content:"\f4d8"}.fa-arrows-alt-h:before,.fa-left-right:before{content:"\f337"}.fa-boxes-packing:before{content:"\e4c7"}.fa-arrow-circle-left:before,.fa-circle-arrow-left:before{content:"\f0a8"}.fa-group-arrows-rotate:before{content:"\e4f6"}.fa-bowl-food:before{content:"\e4c6"}.fa-candy-cane:before{content:"\f786"}.fa-arrow-down-wide-short:before,.fa-sort-amount-asc:before,.fa-sort-amount-down:before{content:"\f160"}.fa-cloud-bolt:before,.fa-thunderstorm:before{content:"\f76c"}.fa-remove-format:before,.fa-text-slash:before{content:"\f87d"}.fa-face-smile-wink:before,.fa-smile-wink:before{content:"\f4da"}.fa-file-word:before{content:"\f1c2"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-arrows-h:before,.fa-arrows-left-right:before{content:"\f07e"}.fa-house-lock:before{content:"\e510"}.fa-cloud-arrow-down:before,.fa-cloud-download-alt:before,.fa-cloud-download:before{content:"\f0ed"}.fa-children:before{content:"\e4e1"}.fa-blackboard:before,.fa-chalkboard:before{content:"\f51b"}.fa-user-alt-slash:before,.fa-user-large-slash:before{content:"\f4fa"}.fa-envelope-open:before{content:"\f2b6"}.fa-handshake-alt-slash:before,.fa-handshake-simple-slash:before{content:"\e05f"}.fa-mattress-pillow:before{content:"\e525"}.fa-guarani-sign:before{content:"\e19a"}.fa-arrows-rotate:before,.fa-refresh:before,.fa-sync:before{content:"\f021"}.fa-fire-extinguisher:before{content:"\f134"}.fa-cruzeiro-sign:before{content:"\e152"}.fa-greater-than-equal:before{content:"\f532"}.fa-shield-alt:before,.fa-shield-halved:before{content:"\f3ed"}.fa-atlas:before,.fa-book-atlas:before{content:"\f558"}.fa-virus:before{content:"\e074"}.fa-envelope-circle-check:before{content:"\e4e8"}.fa-layer-group:before{content:"\f5fd"}.fa-arrows-to-dot:before{content:"\e4be"}.fa-archway:before{content:"\f557"}.fa-heart-circle-check:before{content:"\e4fd"}.fa-house-chimney-crack:before,.fa-house-damage:before{content:"\f6f1"}.fa-file-archive:before,.fa-file-zipper:before{content:"\f1c6"}.fa-square:before{content:"\f0c8"}.fa-glass-martini:before,.fa-martini-glass-empty:before{content:"\f000"}.fa-couch:before{content:"\f4b8"}.fa-cedi-sign:before{content:"\e0df"}.fa-italic:before{content:"\f033"}.fa-table-cells-column-lock:before{content:"\e678"}.fa-church:before{content:"\f51d"}.fa-comments-dollar:before{content:"\f653"}.fa-democrat:before{content:"\f747"}.fa-z:before{content:"\5a"}.fa-person-skiing:before,.fa-skiing:before{content:"\f7c9"}.fa-road-lock:before{content:"\e567"}.fa-a:before{content:"\41"}.fa-temperature-arrow-down:before,.fa-temperature-down:before{content:"\e03f"}.fa-feather-alt:before,.fa-feather-pointed:before{content:"\f56b"}.fa-p:before{content:"\50"}.fa-snowflake:before{content:"\f2dc"}.fa-newspaper:before{content:"\f1ea"}.fa-ad:before,.fa-rectangle-ad:before{content:"\f641"}.fa-arrow-circle-right:before,.fa-circle-arrow-right:before{content:"\f0a9"}.fa-filter-circle-xmark:before{content:"\e17b"}.fa-locust:before{content:"\e520"}.fa-sort:before,.fa-unsorted:before{content:"\f0dc"}.fa-list-1-2:before,.fa-list-numeric:before,.fa-list-ol:before{content:"\f0cb"}.fa-person-dress-burst:before{content:"\e544"}.fa-money-check-alt:before,.fa-money-check-dollar:before{content:"\f53d"}.fa-vector-square:before{content:"\f5cb"}.fa-bread-slice:before{content:"\f7ec"}.fa-language:before{content:"\f1ab"}.fa-face-kiss-wink-heart:before,.fa-kiss-wink-heart:before{content:"\f598"}.fa-filter:before{content:"\f0b0"}.fa-question:before{content:"\3f"}.fa-file-signature:before{content:"\f573"}.fa-arrows-alt:before,.fa-up-down-left-right:before{content:"\f0b2"}.fa-house-chimney-user:before{content:"\e065"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-puzzle-piece:before{content:"\f12e"}.fa-money-check:before{content:"\f53c"}.fa-star-half-alt:before,.fa-star-half-stroke:before{content:"\f5c0"}.fa-code:before{content:"\f121"}.fa-glass-whiskey:before,.fa-whiskey-glass:before{content:"\f7a0"}.fa-building-circle-exclamation:before{content:"\e4d3"}.fa-magnifying-glass-chart:before{content:"\e522"}.fa-arrow-up-right-from-square:before,.fa-external-link:before{content:"\f08e"}.fa-cubes-stacked:before{content:"\e4e6"}.fa-krw:before,.fa-won-sign:before,.fa-won:before{content:"\f159"}.fa-virus-covid:before{content:"\e4a8"}.fa-austral-sign:before{content:"\e0a9"}.fa-f:before{content:"\46"}.fa-leaf:before{content:"\f06c"}.fa-road:before{content:"\f018"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-person-circle-plus:before{content:"\e541"}.fa-chart-pie:before,.fa-pie-chart:before{content:"\f200"}.fa-bolt-lightning:before{content:"\e0b7"}.fa-sack-xmark:before{content:"\e56a"}.fa-file-excel:before{content:"\f1c3"}.fa-file-contract:before{content:"\f56c"}.fa-fish-fins:before{content:"\e4f2"}.fa-building-flag:before{content:"\e4d5"}.fa-face-grin-beam:before,.fa-grin-beam:before{content:"\f582"}.fa-object-ungroup:before{content:"\f248"}.fa-poop:before{content:"\f619"}.fa-location-pin:before,.fa-map-marker:before{content:"\f041"}.fa-kaaba:before{content:"\f66b"}.fa-toilet-paper:before{content:"\f71e"}.fa-hard-hat:before,.fa-hat-hard:before,.fa-helmet-safety:before{content:"\f807"}.fa-eject:before{content:"\f052"}.fa-arrow-alt-circle-right:before,.fa-circle-right:before{content:"\f35a"}.fa-plane-circle-check:before{content:"\e555"}.fa-face-rolling-eyes:before,.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-object-group:before{content:"\f247"}.fa-chart-line:before,.fa-line-chart:before{content:"\f201"}.fa-mask-ventilator:before{content:"\e524"}.fa-arrow-right:before{content:"\f061"}.fa-map-signs:before,.fa-signs-post:before{content:"\f277"}.fa-cash-register:before{content:"\f788"}.fa-person-circle-question:before{content:"\e542"}.fa-h:before{content:"\48"}.fa-tarp:before{content:"\e57b"}.fa-screwdriver-wrench:before,.fa-tools:before{content:"\f7d9"}.fa-arrows-to-eye:before{content:"\e4bf"}.fa-plug-circle-bolt:before{content:"\e55b"}.fa-heart:before{content:"\f004"}.fa-mars-and-venus:before{content:"\f224"}.fa-home-user:before,.fa-house-user:before{content:"\e1b0"}.fa-dumpster-fire:before{content:"\f794"}.fa-house-crack:before{content:"\e3b1"}.fa-cocktail:before,.fa-martini-glass-citrus:before{content:"\f561"}.fa-face-surprise:before,.fa-surprise:before{content:"\f5c2"}.fa-bottle-water:before{content:"\e4c5"}.fa-circle-pause:before,.fa-pause-circle:before{content:"\f28b"}.fa-toilet-paper-slash:before{content:"\e072"}.fa-apple-alt:before,.fa-apple-whole:before{content:"\f5d1"}.fa-kitchen-set:before{content:"\e51a"}.fa-r:before{content:"\52"}.fa-temperature-1:before,.fa-temperature-quarter:before,.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-cube:before{content:"\f1b2"}.fa-bitcoin-sign:before{content:"\e0b4"}.fa-shield-dog:before{content:"\e573"}.fa-solar-panel:before{content:"\f5ba"}.fa-lock-open:before{content:"\f3c1"}.fa-elevator:before{content:"\e16d"}.fa-money-bill-transfer:before{content:"\e528"}.fa-money-bill-trend-up:before{content:"\e529"}.fa-house-flood-water-circle-arrow-right:before{content:"\e50f"}.fa-poll-h:before,.fa-square-poll-horizontal:before{content:"\f682"}.fa-circle:before{content:"\f111"}.fa-backward-fast:before,.fa-fast-backward:before{content:"\f049"}.fa-recycle:before{content:"\f1b8"}.fa-user-astronaut:before{content:"\f4fb"}.fa-plane-slash:before{content:"\e069"}.fa-trademark:before{content:"\f25c"}.fa-basketball-ball:before,.fa-basketball:before{content:"\f434"}.fa-satellite-dish:before{content:"\f7c0"}.fa-arrow-alt-circle-up:before,.fa-circle-up:before{content:"\f35b"}.fa-mobile-alt:before,.fa-mobile-screen-button:before{content:"\f3cd"}.fa-volume-high:before,.fa-volume-up:before{content:"\f028"}.fa-users-rays:before{content:"\e593"}.fa-wallet:before{content:"\f555"}.fa-clipboard-check:before{content:"\f46c"}.fa-file-audio:before{content:"\f1c7"}.fa-burger:before,.fa-hamburger:before{content:"\f805"}.fa-wrench:before{content:"\f0ad"}.fa-bugs:before{content:"\e4d0"}.fa-rupee-sign:before,.fa-rupee:before{content:"\f156"}.fa-file-image:before{content:"\f1c5"}.fa-circle-question:before,.fa-question-circle:before{content:"\f059"}.fa-plane-departure:before{content:"\f5b0"}.fa-handshake-slash:before{content:"\e060"}.fa-book-bookmark:before{content:"\e0bb"}.fa-code-branch:before{content:"\f126"}.fa-hat-cowboy:before{content:"\f8c0"}.fa-bridge:before{content:"\e4c8"}.fa-phone-alt:before,.fa-phone-flip:before{content:"\f879"}.fa-truck-front:before{content:"\e2b7"}.fa-cat:before{content:"\f6be"}.fa-anchor-circle-exclamation:before{content:"\e4ab"}.fa-truck-field:before{content:"\e58d"}.fa-route:before{content:"\f4d7"}.fa-clipboard-question:before{content:"\e4e3"}.fa-panorama:before{content:"\e209"}.fa-comment-medical:before{content:"\f7f5"}.fa-teeth-open:before{content:"\f62f"}.fa-file-circle-minus:before{content:"\e4ed"}.fa-tags:before{content:"\f02c"}.fa-wine-glass:before{content:"\f4e3"}.fa-fast-forward:before,.fa-forward-fast:before{content:"\f050"}.fa-face-meh-blank:before,.fa-meh-blank:before{content:"\f5a4"}.fa-parking:before,.fa-square-parking:before{content:"\f540"}.fa-house-signal:before{content:"\e012"}.fa-bars-progress:before,.fa-tasks-alt:before{content:"\f828"}.fa-faucet-drip:before{content:"\e006"}.fa-cart-flatbed:before,.fa-dolly-flatbed:before{content:"\f474"}.fa-ban-smoking:before,.fa-smoking-ban:before{content:"\f54d"}.fa-terminal:before{content:"\f120"}.fa-mobile-button:before{content:"\f10b"}.fa-house-medical-flag:before{content:"\e514"}.fa-basket-shopping:before,.fa-shopping-basket:before{content:"\f291"}.fa-tape:before{content:"\f4db"}.fa-bus-alt:before,.fa-bus-simple:before{content:"\f55e"}.fa-eye:before{content:"\f06e"}.fa-face-sad-cry:before,.fa-sad-cry:before{content:"\f5b3"}.fa-audio-description:before{content:"\f29e"}.fa-person-military-to-person:before{content:"\e54c"}.fa-file-shield:before{content:"\e4f0"}.fa-user-slash:before{content:"\f506"}.fa-pen:before{content:"\f304"}.fa-tower-observation:before{content:"\e586"}.fa-file-code:before{content:"\f1c9"}.fa-signal-5:before,.fa-signal-perfect:before,.fa-signal:before{content:"\f012"}.fa-bus:before{content:"\f207"}.fa-heart-circle-xmark:before{content:"\e501"}.fa-home-lg:before,.fa-house-chimney:before{content:"\e3af"}.fa-window-maximize:before{content:"\f2d0"}.fa-face-frown:before,.fa-frown:before{content:"\f119"}.fa-prescription:before{content:"\f5b1"}.fa-shop:before,.fa-store-alt:before{content:"\f54f"}.fa-floppy-disk:before,.fa-save:before{content:"\f0c7"}.fa-vihara:before{content:"\f6a7"}.fa-balance-scale-left:before,.fa-scale-unbalanced:before{content:"\f515"}.fa-sort-asc:before,.fa-sort-up:before{content:"\f0de"}.fa-comment-dots:before,.fa-commenting:before{content:"\f4ad"}.fa-plant-wilt:before{content:"\e5aa"}.fa-diamond:before{content:"\f219"}.fa-face-grin-squint:before,.fa-grin-squint:before{content:"\f585"}.fa-hand-holding-dollar:before,.fa-hand-holding-usd:before{content:"\f4c0"}.fa-bacterium:before{content:"\e05a"}.fa-hand-pointer:before{content:"\f25a"}.fa-drum-steelpan:before{content:"\f56a"}.fa-hand-scissors:before{content:"\f257"}.fa-hands-praying:before,.fa-praying-hands:before{content:"\f684"}.fa-arrow-right-rotate:before,.fa-arrow-rotate-forward:before,.fa-arrow-rotate-right:before,.fa-redo:before{content:"\f01e"}.fa-biohazard:before{content:"\f780"}.fa-location-crosshairs:before,.fa-location:before{content:"\f601"}.fa-mars-double:before{content:"\f227"}.fa-child-dress:before{content:"\e59c"}.fa-users-between-lines:before{content:"\e591"}.fa-lungs-virus:before{content:"\e067"}.fa-face-grin-tears:before,.fa-grin-tears:before{content:"\f588"}.fa-phone:before{content:"\f095"}.fa-calendar-times:before,.fa-calendar-xmark:before{content:"\f273"}.fa-child-reaching:before{content:"\e59d"}.fa-head-side-virus:before{content:"\e064"}.fa-user-cog:before,.fa-user-gear:before{content:"\f4fe"}.fa-arrow-up-1-9:before,.fa-sort-numeric-up:before{content:"\f163"}.fa-door-closed:before{content:"\f52a"}.fa-shield-virus:before{content:"\e06c"}.fa-dice-six:before{content:"\f526"}.fa-mosquito-net:before{content:"\e52c"}.fa-bridge-water:before{content:"\e4ce"}.fa-person-booth:before{content:"\f756"}.fa-text-width:before{content:"\f035"}.fa-hat-wizard:before{content:"\f6e8"}.fa-pen-fancy:before{content:"\f5ac"}.fa-digging:before,.fa-person-digging:before{content:"\f85e"}.fa-trash:before{content:"\f1f8"}.fa-gauge-simple-med:before,.fa-gauge-simple:before,.fa-tachometer-average:before{content:"\f629"}.fa-book-medical:before{content:"\f7e6"}.fa-poo:before{content:"\f2fe"}.fa-quote-right-alt:before,.fa-quote-right:before{content:"\f10e"}.fa-shirt:before,.fa-t-shirt:before,.fa-tshirt:before{content:"\f553"}.fa-cubes:before{content:"\f1b3"}.fa-divide:before{content:"\f529"}.fa-tenge-sign:before,.fa-tenge:before{content:"\f7d7"}.fa-headphones:before{content:"\f025"}.fa-hands-holding:before{content:"\f4c2"}.fa-hands-clapping:before{content:"\e1a8"}.fa-republican:before{content:"\f75e"}.fa-arrow-left:before{content:"\f060"}.fa-person-circle-xmark:before{content:"\e543"}.fa-ruler:before{content:"\f545"}.fa-align-left:before{content:"\f036"}.fa-dice-d6:before{content:"\f6d1"}.fa-restroom:before{content:"\f7bd"}.fa-j:before{content:"\4a"}.fa-users-viewfinder:before{content:"\e595"}.fa-file-video:before{content:"\f1c8"}.fa-external-link-alt:before,.fa-up-right-from-square:before{content:"\f35d"}.fa-table-cells:before,.fa-th:before{content:"\f00a"}.fa-file-pdf:before{content:"\f1c1"}.fa-bible:before,.fa-book-bible:before{content:"\f647"}.fa-o:before{content:"\4f"}.fa-medkit:before,.fa-suitcase-medical:before{content:"\f0fa"}.fa-user-secret:before{content:"\f21b"}.fa-otter:before{content:"\f700"}.fa-female:before,.fa-person-dress:before{content:"\f182"}.fa-comment-dollar:before{content:"\f651"}.fa-briefcase-clock:before,.fa-business-time:before{content:"\f64a"}.fa-table-cells-large:before,.fa-th-large:before{content:"\f009"}.fa-book-tanakh:before,.fa-tanakh:before{content:"\f827"}.fa-phone-volume:before,.fa-volume-control-phone:before{content:"\f2a0"}.fa-hat-cowboy-side:before{content:"\f8c1"}.fa-clipboard-user:before{content:"\f7f3"}.fa-child:before{content:"\f1ae"}.fa-lira-sign:before{content:"\f195"}.fa-satellite:before{content:"\f7bf"}.fa-plane-lock:before{content:"\e558"}.fa-tag:before{content:"\f02b"}.fa-comment:before{content:"\f075"}.fa-birthday-cake:before,.fa-cake-candles:before,.fa-cake:before{content:"\f1fd"}.fa-envelope:before{content:"\f0e0"}.fa-angle-double-up:before,.fa-angles-up:before{content:"\f102"}.fa-paperclip:before{content:"\f0c6"}.fa-arrow-right-to-city:before{content:"\e4b3"}.fa-ribbon:before{content:"\f4d6"}.fa-lungs:before{content:"\f604"}.fa-arrow-up-9-1:before,.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-litecoin-sign:before{content:"\e1d3"}.fa-border-none:before{content:"\f850"}.fa-circle-nodes:before{content:"\e4e2"}.fa-parachute-box:before{content:"\f4cd"}.fa-indent:before{content:"\f03c"}.fa-truck-field-un:before{content:"\e58e"}.fa-hourglass-empty:before,.fa-hourglass:before{content:"\f254"}.fa-mountain:before{content:"\f6fc"}.fa-user-doctor:before,.fa-user-md:before{content:"\f0f0"}.fa-circle-info:before,.fa-info-circle:before{content:"\f05a"}.fa-cloud-meatball:before{content:"\f73b"}.fa-camera-alt:before,.fa-camera:before{content:"\f030"}.fa-square-virus:before{content:"\e578"}.fa-meteor:before{content:"\f753"}.fa-car-on:before{content:"\e4dd"}.fa-sleigh:before{content:"\f7cc"}.fa-arrow-down-1-9:before,.fa-sort-numeric-asc:before,.fa-sort-numeric-down:before{content:"\f162"}.fa-hand-holding-droplet:before,.fa-hand-holding-water:before{content:"\f4c1"}.fa-water:before{content:"\f773"}.fa-calendar-check:before{content:"\f274"}.fa-braille:before{content:"\f2a1"}.fa-prescription-bottle-alt:before,.fa-prescription-bottle-medical:before{content:"\f486"}.fa-landmark:before{content:"\f66f"}.fa-truck:before{content:"\f0d1"}.fa-crosshairs:before{content:"\f05b"}.fa-person-cane:before{content:"\e53c"}.fa-tent:before{content:"\e57d"}.fa-vest-patches:before{content:"\e086"}.fa-check-double:before{content:"\f560"}.fa-arrow-down-a-z:before,.fa-sort-alpha-asc:before,.fa-sort-alpha-down:before{content:"\f15d"}.fa-money-bill-wheat:before{content:"\e52a"}.fa-cookie:before{content:"\f563"}.fa-arrow-left-rotate:before,.fa-arrow-rotate-back:before,.fa-arrow-rotate-backward:before,.fa-arrow-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-hard-drive:before,.fa-hdd:before{content:"\f0a0"}.fa-face-grin-squint-tears:before,.fa-grin-squint-tears:before{content:"\f586"}.fa-dumbbell:before{content:"\f44b"}.fa-list-alt:before,.fa-rectangle-list:before{content:"\f022"}.fa-tarp-droplet:before{content:"\e57c"}.fa-house-medical-circle-check:before{content:"\e511"}.fa-person-skiing-nordic:before,.fa-skiing-nordic:before{content:"\f7ca"}.fa-calendar-plus:before{content:"\f271"}.fa-plane-arrival:before{content:"\f5af"}.fa-arrow-alt-circle-left:before,.fa-circle-left:before{content:"\f359"}.fa-subway:before,.fa-train-subway:before{content:"\f239"}.fa-chart-gantt:before{content:"\e0e4"}.fa-indian-rupee-sign:before,.fa-indian-rupee:before,.fa-inr:before{content:"\e1bc"}.fa-crop-alt:before,.fa-crop-simple:before{content:"\f565"}.fa-money-bill-1:before,.fa-money-bill-alt:before{content:"\f3d1"}.fa-left-long:before,.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-dna:before{content:"\f471"}.fa-virus-slash:before{content:"\e075"}.fa-minus:before,.fa-subtract:before{content:"\f068"}.fa-chess:before{content:"\f439"}.fa-arrow-left-long:before,.fa-long-arrow-left:before{content:"\f177"}.fa-plug-circle-check:before{content:"\e55c"}.fa-street-view:before{content:"\f21d"}.fa-franc-sign:before{content:"\e18f"}.fa-volume-off:before{content:"\f026"}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before,.fa-hands-american-sign-language-interpreting:before,.fa-hands-asl-interpreting:before{content:"\f2a3"}.fa-cog:before,.fa-gear:before{content:"\f013"}.fa-droplet-slash:before,.fa-tint-slash:before{content:"\f5c7"}.fa-mosque:before{content:"\f678"}.fa-mosquito:before{content:"\e52b"}.fa-star-of-david:before{content:"\f69a"}.fa-person-military-rifle:before{content:"\e54b"}.fa-cart-shopping:before,.fa-shopping-cart:before{content:"\f07a"}.fa-vials:before{content:"\f493"}.fa-plug-circle-plus:before{content:"\e55f"}.fa-place-of-worship:before{content:"\f67f"}.fa-grip-vertical:before{content:"\f58e"}.fa-arrow-turn-up:before,.fa-level-up:before{content:"\f148"}.fa-u:before{content:"\55"}.fa-square-root-alt:before,.fa-square-root-variable:before{content:"\f698"}.fa-clock-four:before,.fa-clock:before{content:"\f017"}.fa-backward-step:before,.fa-step-backward:before{content:"\f048"}.fa-pallet:before{content:"\f482"}.fa-faucet:before{content:"\e005"}.fa-baseball-bat-ball:before{content:"\f432"}.fa-s:before{content:"\53"}.fa-timeline:before{content:"\e29c"}.fa-keyboard:before{content:"\f11c"}.fa-caret-down:before{content:"\f0d7"}.fa-clinic-medical:before,.fa-house-chimney-medical:before{content:"\f7f2"}.fa-temperature-3:before,.fa-temperature-three-quarters:before,.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-mobile-android-alt:before,.fa-mobile-screen:before{content:"\f3cf"}.fa-plane-up:before{content:"\e22d"}.fa-piggy-bank:before{content:"\f4d3"}.fa-battery-3:before,.fa-battery-half:before{content:"\f242"}.fa-mountain-city:before{content:"\e52e"}.fa-coins:before{content:"\f51e"}.fa-khanda:before{content:"\f66d"}.fa-sliders-h:before,.fa-sliders:before{content:"\f1de"}.fa-folder-tree:before{content:"\f802"}.fa-network-wired:before{content:"\f6ff"}.fa-map-pin:before{content:"\f276"}.fa-hamsa:before{content:"\f665"}.fa-cent-sign:before{content:"\e3f5"}.fa-flask:before{content:"\f0c3"}.fa-person-pregnant:before{content:"\e31e"}.fa-wand-sparkles:before{content:"\f72b"}.fa-ellipsis-v:before,.fa-ellipsis-vertical:before{content:"\f142"}.fa-ticket:before{content:"\f145"}.fa-power-off:before{content:"\f011"}.fa-long-arrow-alt-right:before,.fa-right-long:before{content:"\f30b"}.fa-flag-usa:before{content:"\f74d"}.fa-laptop-file:before{content:"\e51d"}.fa-teletype:before,.fa-tty:before{content:"\f1e4"}.fa-diagram-next:before{content:"\e476"}.fa-person-rifle:before{content:"\e54e"}.fa-house-medical-circle-exclamation:before{content:"\e512"}.fa-closed-captioning:before{content:"\f20a"}.fa-hiking:before,.fa-person-hiking:before{content:"\f6ec"}.fa-venus-double:before{content:"\f226"}.fa-images:before{content:"\f302"}.fa-calculator:before{content:"\f1ec"}.fa-people-pulling:before{content:"\e535"}.fa-n:before{content:"\4e"}.fa-cable-car:before,.fa-tram:before{content:"\f7da"}.fa-cloud-rain:before{content:"\f73d"}.fa-building-circle-xmark:before{content:"\e4d4"}.fa-ship:before{content:"\f21a"}.fa-arrows-down-to-line:before{content:"\e4b8"}.fa-download:before{content:"\f019"}.fa-face-grin:before,.fa-grin:before{content:"\f580"}.fa-backspace:before,.fa-delete-left:before{content:"\f55a"}.fa-eye-dropper-empty:before,.fa-eye-dropper:before,.fa-eyedropper:before{content:"\f1fb"}.fa-file-circle-check:before{content:"\e5a0"}.fa-forward:before{content:"\f04e"}.fa-mobile-android:before,.fa-mobile-phone:before,.fa-mobile:before{content:"\f3ce"}.fa-face-meh:before,.fa-meh:before{content:"\f11a"}.fa-align-center:before{content:"\f037"}.fa-book-dead:before,.fa-book-skull:before{content:"\f6b7"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-heart-circle-exclamation:before{content:"\e4fe"}.fa-home-alt:before,.fa-home-lg-alt:before,.fa-home:before,.fa-house:before{content:"\f015"}.fa-calendar-week:before{content:"\f784"}.fa-laptop-medical:before{content:"\f812"}.fa-b:before{content:"\42"}.fa-file-medical:before{content:"\f477"}.fa-dice-one:before{content:"\f525"}.fa-kiwi-bird:before{content:"\f535"}.fa-arrow-right-arrow-left:before,.fa-exchange:before{content:"\f0ec"}.fa-redo-alt:before,.fa-rotate-forward:before,.fa-rotate-right:before{content:"\f2f9"}.fa-cutlery:before,.fa-utensils:before{content:"\f2e7"}.fa-arrow-up-wide-short:before,.fa-sort-amount-up:before{content:"\f161"}.fa-mill-sign:before{content:"\e1ed"}.fa-bowl-rice:before{content:"\e2eb"}.fa-skull:before{content:"\f54c"}.fa-broadcast-tower:before,.fa-tower-broadcast:before{content:"\f519"}.fa-truck-pickup:before{content:"\f63c"}.fa-long-arrow-alt-up:before,.fa-up-long:before{content:"\f30c"}.fa-stop:before{content:"\f04d"}.fa-code-merge:before{content:"\f387"}.fa-upload:before{content:"\f093"}.fa-hurricane:before{content:"\f751"}.fa-mound:before{content:"\e52d"}.fa-toilet-portable:before{content:"\e583"}.fa-compact-disc:before{content:"\f51f"}.fa-file-arrow-down:before,.fa-file-download:before{content:"\f56d"}.fa-caravan:before{content:"\f8ff"}.fa-shield-cat:before{content:"\e572"}.fa-bolt:before,.fa-zap:before{content:"\f0e7"}.fa-glass-water:before{content:"\e4f4"}.fa-oil-well:before{content:"\e532"}.fa-vault:before{content:"\e2c5"}.fa-mars:before{content:"\f222"}.fa-toilet:before{content:"\f7d8"}.fa-plane-circle-xmark:before{content:"\e557"}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen-sign:before,.fa-yen:before{content:"\f157"}.fa-rouble:before,.fa-rub:before,.fa-ruble-sign:before,.fa-ruble:before{content:"\f158"}.fa-sun:before{content:"\f185"}.fa-guitar:before{content:"\f7a6"}.fa-face-laugh-wink:before,.fa-laugh-wink:before{content:"\f59c"}.fa-horse-head:before{content:"\f7ab"}.fa-bore-hole:before{content:"\e4c3"}.fa-industry:before{content:"\f275"}.fa-arrow-alt-circle-down:before,.fa-circle-down:before{content:"\f358"}.fa-arrows-turn-to-dots:before{content:"\e4c1"}.fa-florin-sign:before{content:"\e184"}.fa-arrow-down-short-wide:before,.fa-sort-amount-desc:before,.fa-sort-amount-down-alt:before{content:"\f884"}.fa-less-than:before{content:"\3c"}.fa-angle-down:before{content:"\f107"}.fa-car-tunnel:before{content:"\e4de"}.fa-head-side-cough:before{content:"\e061"}.fa-grip-lines:before{content:"\f7a4"}.fa-thumbs-down:before{content:"\f165"}.fa-user-lock:before{content:"\f502"}.fa-arrow-right-long:before,.fa-long-arrow-right:before{content:"\f178"}.fa-anchor-circle-xmark:before{content:"\e4ac"}.fa-ellipsis-h:before,.fa-ellipsis:before{content:"\f141"}.fa-chess-pawn:before{content:"\f443"}.fa-first-aid:before,.fa-kit-medical:before{content:"\f479"}.fa-person-through-window:before{content:"\e5a9"}.fa-toolbox:before{content:"\f552"}.fa-hands-holding-circle:before{content:"\e4fb"}.fa-bug:before{content:"\f188"}.fa-credit-card-alt:before,.fa-credit-card:before{content:"\f09d"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-hand-holding-hand:before{content:"\e4f7"}.fa-book-open-reader:before,.fa-book-reader:before{content:"\f5da"}.fa-mountain-sun:before{content:"\e52f"}.fa-arrows-left-right-to-line:before{content:"\e4ba"}.fa-dice-d20:before{content:"\f6cf"}.fa-truck-droplet:before{content:"\e58c"}.fa-file-circle-xmark:before{content:"\e5a1"}.fa-temperature-arrow-up:before,.fa-temperature-up:before{content:"\e040"}.fa-medal:before{content:"\f5a2"}.fa-bed:before{content:"\f236"}.fa-h-square:before,.fa-square-h:before{content:"\f0fd"}.fa-podcast:before{content:"\f2ce"}.fa-temperature-4:before,.fa-temperature-full:before,.fa-thermometer-4:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-bell:before{content:"\f0f3"}.fa-superscript:before{content:"\f12b"}.fa-plug-circle-xmark:before{content:"\e560"}.fa-star-of-life:before{content:"\f621"}.fa-phone-slash:before{content:"\f3dd"}.fa-paint-roller:before{content:"\f5aa"}.fa-hands-helping:before,.fa-handshake-angle:before{content:"\f4c4"}.fa-location-dot:before,.fa-map-marker-alt:before{content:"\f3c5"}.fa-file:before{content:"\f15b"}.fa-greater-than:before{content:"\3e"}.fa-person-swimming:before,.fa-swimmer:before{content:"\f5c4"}.fa-arrow-down:before{content:"\f063"}.fa-droplet:before,.fa-tint:before{content:"\f043"}.fa-eraser:before{content:"\f12d"}.fa-earth-america:before,.fa-earth-americas:before,.fa-earth:before,.fa-globe-americas:before{content:"\f57d"}.fa-person-burst:before{content:"\e53b"}.fa-dove:before{content:"\f4ba"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-socks:before{content:"\f696"}.fa-inbox:before{content:"\f01c"}.fa-section:before{content:"\e447"}.fa-gauge-high:before,.fa-tachometer-alt-fast:before,.fa-tachometer-alt:before{content:"\f625"}.fa-envelope-open-text:before{content:"\f658"}.fa-hospital-alt:before,.fa-hospital-wide:before,.fa-hospital:before{content:"\f0f8"}.fa-wine-bottle:before{content:"\f72f"}.fa-chess-rook:before{content:"\f447"}.fa-bars-staggered:before,.fa-reorder:before,.fa-stream:before{content:"\f550"}.fa-dharmachakra:before{content:"\f655"}.fa-hotdog:before{content:"\f80f"}.fa-blind:before,.fa-person-walking-with-cane:before{content:"\f29d"}.fa-drum:before{content:"\f569"}.fa-ice-cream:before{content:"\f810"}.fa-heart-circle-bolt:before{content:"\e4fc"}.fa-fax:before{content:"\f1ac"}.fa-paragraph:before{content:"\f1dd"}.fa-check-to-slot:before,.fa-vote-yea:before{content:"\f772"}.fa-star-half:before{content:"\f089"}.fa-boxes-alt:before,.fa-boxes-stacked:before,.fa-boxes:before{content:"\f468"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-assistive-listening-systems:before,.fa-ear-listen:before{content:"\f2a2"}.fa-tree-city:before{content:"\e587"}.fa-play:before{content:"\f04b"}.fa-font:before{content:"\f031"}.fa-table-cells-row-lock:before{content:"\e67a"}.fa-rupiah-sign:before{content:"\e23d"}.fa-magnifying-glass:before,.fa-search:before{content:"\f002"}.fa-ping-pong-paddle-ball:before,.fa-table-tennis-paddle-ball:before,.fa-table-tennis:before{content:"\f45d"}.fa-diagnoses:before,.fa-person-dots-from-line:before{content:"\f470"}.fa-trash-can-arrow-up:before,.fa-trash-restore-alt:before{content:"\f82a"}.fa-naira-sign:before{content:"\e1f6"}.fa-cart-arrow-down:before{content:"\f218"}.fa-walkie-talkie:before{content:"\f8ef"}.fa-file-edit:before,.fa-file-pen:before{content:"\f31c"}.fa-receipt:before{content:"\f543"}.fa-pen-square:before,.fa-pencil-square:before,.fa-square-pen:before{content:"\f14b"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-person-circle-exclamation:before{content:"\e53f"}.fa-chevron-down:before{content:"\f078"}.fa-battery-5:before,.fa-battery-full:before,.fa-battery:before{content:"\f240"}.fa-skull-crossbones:before{content:"\f714"}.fa-code-compare:before{content:"\e13a"}.fa-list-dots:before,.fa-list-ul:before{content:"\f0ca"}.fa-school-lock:before{content:"\e56f"}.fa-tower-cell:before{content:"\e585"}.fa-down-long:before,.fa-long-arrow-alt-down:before{content:"\f309"}.fa-ranking-star:before{content:"\e561"}.fa-chess-king:before{content:"\f43f"}.fa-person-harassing:before{content:"\e549"}.fa-brazilian-real-sign:before{content:"\e46c"}.fa-landmark-alt:before,.fa-landmark-dome:before{content:"\f752"}.fa-arrow-up:before{content:"\f062"}.fa-television:before,.fa-tv-alt:before,.fa-tv:before{content:"\f26c"}.fa-shrimp:before{content:"\e448"}.fa-list-check:before,.fa-tasks:before{content:"\f0ae"}.fa-jug-detergent:before{content:"\e519"}.fa-circle-user:before,.fa-user-circle:before{content:"\f2bd"}.fa-user-shield:before{content:"\f505"}.fa-wind:before{content:"\f72e"}.fa-car-burst:before,.fa-car-crash:before{content:"\f5e1"}.fa-y:before{content:"\59"}.fa-person-snowboarding:before,.fa-snowboarding:before{content:"\f7ce"}.fa-shipping-fast:before,.fa-truck-fast:before{content:"\f48b"}.fa-fish:before{content:"\f578"}.fa-user-graduate:before{content:"\f501"}.fa-adjust:before,.fa-circle-half-stroke:before{content:"\f042"}.fa-clapperboard:before{content:"\e131"}.fa-circle-radiation:before,.fa-radiation-alt:before{content:"\f7ba"}.fa-baseball-ball:before,.fa-baseball:before{content:"\f433"}.fa-jet-fighter-up:before{content:"\e518"}.fa-diagram-project:before,.fa-project-diagram:before{content:"\f542"}.fa-copy:before{content:"\f0c5"}.fa-volume-mute:before,.fa-volume-times:before,.fa-volume-xmark:before{content:"\f6a9"}.fa-hand-sparkles:before{content:"\e05d"}.fa-grip-horizontal:before,.fa-grip:before{content:"\f58d"}.fa-share-from-square:before,.fa-share-square:before{content:"\f14d"}.fa-child-combatant:before,.fa-child-rifle:before{content:"\e4e0"}.fa-gun:before{content:"\e19b"}.fa-phone-square:before,.fa-square-phone:before{content:"\f098"}.fa-add:before,.fa-plus:before{content:"\2b"}.fa-expand:before{content:"\f065"}.fa-computer:before{content:"\e4e5"}.fa-close:before,.fa-multiply:before,.fa-remove:before,.fa-times:before,.fa-xmark:before{content:"\f00d"}.fa-arrows-up-down-left-right:before,.fa-arrows:before{content:"\f047"}.fa-chalkboard-teacher:before,.fa-chalkboard-user:before{content:"\f51c"}.fa-peso-sign:before{content:"\e222"}.fa-building-shield:before{content:"\e4d8"}.fa-baby:before{content:"\f77c"}.fa-users-line:before{content:"\e592"}.fa-quote-left-alt:before,.fa-quote-left:before{content:"\f10d"}.fa-tractor:before{content:"\f722"}.fa-trash-arrow-up:before,.fa-trash-restore:before{content:"\f829"}.fa-arrow-down-up-lock:before{content:"\e4b0"}.fa-lines-leaning:before{content:"\e51e"}.fa-ruler-combined:before{content:"\f546"}.fa-copyright:before{content:"\f1f9"}.fa-equals:before{content:"\3d"}.fa-blender:before{content:"\f517"}.fa-teeth:before{content:"\f62e"}.fa-ils:before,.fa-shekel-sign:before,.fa-shekel:before,.fa-sheqel-sign:before,.fa-sheqel:before{content:"\f20b"}.fa-map:before{content:"\f279"}.fa-rocket:before{content:"\f135"}.fa-photo-film:before,.fa-photo-video:before{content:"\f87c"}.fa-folder-minus:before{content:"\f65d"}.fa-store:before{content:"\f54e"}.fa-arrow-trend-up:before{content:"\e098"}.fa-plug-circle-minus:before{content:"\e55e"}.fa-sign-hanging:before,.fa-sign:before{content:"\f4d9"}.fa-bezier-curve:before{content:"\f55b"}.fa-bell-slash:before{content:"\f1f6"}.fa-tablet-android:before,.fa-tablet:before{content:"\f3fb"}.fa-school-flag:before{content:"\e56e"}.fa-fill:before{content:"\f575"}.fa-angle-up:before{content:"\f106"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-holly-berry:before{content:"\f7aa"}.fa-chevron-left:before{content:"\f053"}.fa-bacteria:before{content:"\e059"}.fa-hand-lizard:before{content:"\f258"}.fa-notdef:before{content:"\e1fe"}.fa-disease:before{content:"\f7fa"}.fa-briefcase-medical:before{content:"\f469"}.fa-genderless:before{content:"\f22d"}.fa-chevron-right:before{content:"\f054"}.fa-retweet:before{content:"\f079"}.fa-car-alt:before,.fa-car-rear:before{content:"\f5de"}.fa-pump-soap:before{content:"\e06b"}.fa-video-slash:before{content:"\f4e2"}.fa-battery-2:before,.fa-battery-quarter:before{content:"\f243"}.fa-radio:before{content:"\f8d7"}.fa-baby-carriage:before,.fa-carriage-baby:before{content:"\f77d"}.fa-traffic-light:before{content:"\f637"}.fa-thermometer:before{content:"\f491"}.fa-vr-cardboard:before{content:"\f729"}.fa-hand-middle-finger:before{content:"\f806"}.fa-percent:before,.fa-percentage:before{content:"\25"}.fa-truck-moving:before{content:"\f4df"}.fa-glass-water-droplet:before{content:"\e4f5"}.fa-display:before{content:"\e163"}.fa-face-smile:before,.fa-smile:before{content:"\f118"}.fa-thumb-tack:before,.fa-thumbtack:before{content:"\f08d"}.fa-trophy:before{content:"\f091"}.fa-person-praying:before,.fa-pray:before{content:"\f683"}.fa-hammer:before{content:"\f6e3"}.fa-hand-peace:before{content:"\f25b"}.fa-rotate:before,.fa-sync-alt:before{content:"\f2f1"}.fa-spinner:before{content:"\f110"}.fa-robot:before{content:"\f544"}.fa-peace:before{content:"\f67c"}.fa-cogs:before,.fa-gears:before{content:"\f085"}.fa-warehouse:before{content:"\f494"}.fa-arrow-up-right-dots:before{content:"\e4b7"}.fa-splotch:before{content:"\f5bc"}.fa-face-grin-hearts:before,.fa-grin-hearts:before{content:"\f584"}.fa-dice-four:before{content:"\f524"}.fa-sim-card:before{content:"\f7c4"}.fa-transgender-alt:before,.fa-transgender:before{content:"\f225"}.fa-mercury:before{content:"\f223"}.fa-arrow-turn-down:before,.fa-level-down:before{content:"\f149"}.fa-person-falling-burst:before{content:"\e547"}.fa-award:before{content:"\f559"}.fa-ticket-alt:before,.fa-ticket-simple:before{content:"\f3ff"}.fa-building:before{content:"\f1ad"}.fa-angle-double-left:before,.fa-angles-left:before{content:"\f100"}.fa-qrcode:before{content:"\f029"}.fa-clock-rotate-left:before,.fa-history:before{content:"\f1da"}.fa-face-grin-beam-sweat:before,.fa-grin-beam-sweat:before{content:"\f583"}.fa-arrow-right-from-file:before,.fa-file-export:before{content:"\f56e"}.fa-shield-blank:before,.fa-shield:before{content:"\f132"}.fa-arrow-up-short-wide:before,.fa-sort-amount-up-alt:before{content:"\f885"}.fa-house-medical:before{content:"\e3b2"}.fa-golf-ball-tee:before,.fa-golf-ball:before{content:"\f450"}.fa-chevron-circle-left:before,.fa-circle-chevron-left:before{content:"\f137"}.fa-house-chimney-window:before{content:"\e00d"}.fa-pen-nib:before{content:"\f5ad"}.fa-tent-arrow-turn-left:before{content:"\e580"}.fa-tents:before{content:"\e582"}.fa-magic:before,.fa-wand-magic:before{content:"\f0d0"}.fa-dog:before{content:"\f6d3"}.fa-carrot:before{content:"\f787"}.fa-moon:before{content:"\f186"}.fa-wine-glass-alt:before,.fa-wine-glass-empty:before{content:"\f5ce"}.fa-cheese:before{content:"\f7ef"}.fa-yin-yang:before{content:"\f6ad"}.fa-music:before{content:"\f001"}.fa-code-commit:before{content:"\f386"}.fa-temperature-low:before{content:"\f76b"}.fa-biking:before,.fa-person-biking:before{content:"\f84a"}.fa-broom:before{content:"\f51a"}.fa-shield-heart:before{content:"\e574"}.fa-gopuram:before{content:"\f664"}.fa-earth-oceania:before,.fa-globe-oceania:before{content:"\e47b"}.fa-square-xmark:before,.fa-times-square:before,.fa-xmark-square:before{content:"\f2d3"}.fa-hashtag:before{content:"\23"}.fa-expand-alt:before,.fa-up-right-and-down-left-from-center:before{content:"\f424"}.fa-oil-can:before{content:"\f613"}.fa-t:before{content:"\54"}.fa-hippo:before{content:"\f6ed"}.fa-chart-column:before{content:"\e0e3"}.fa-infinity:before{content:"\f534"}.fa-vial-circle-check:before{content:"\e596"}.fa-person-arrow-down-to-line:before{content:"\e538"}.fa-voicemail:before{content:"\f897"}.fa-fan:before{content:"\f863"}.fa-person-walking-luggage:before{content:"\e554"}.fa-arrows-alt-v:before,.fa-up-down:before{content:"\f338"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-calendar:before{content:"\f133"}.fa-trailer:before{content:"\e041"}.fa-bahai:before,.fa-haykal:before{content:"\f666"}.fa-sd-card:before{content:"\f7c2"}.fa-dragon:before{content:"\f6d5"}.fa-shoe-prints:before{content:"\f54b"}.fa-circle-plus:before,.fa-plus-circle:before{content:"\f055"}.fa-face-grin-tongue-wink:before,.fa-grin-tongue-wink:before{content:"\f58b"}.fa-hand-holding:before{content:"\f4bd"}.fa-plug-circle-exclamation:before{content:"\e55d"}.fa-chain-broken:before,.fa-chain-slash:before,.fa-link-slash:before,.fa-unlink:before{content:"\f127"}.fa-clone:before{content:"\f24d"}.fa-person-walking-arrow-loop-left:before{content:"\e551"}.fa-arrow-up-z-a:before,.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-fire-alt:before,.fa-fire-flame-curved:before{content:"\f7e4"}.fa-tornado:before{content:"\f76f"}.fa-file-circle-plus:before{content:"\e494"}.fa-book-quran:before,.fa-quran:before{content:"\f687"}.fa-anchor:before{content:"\f13d"}.fa-border-all:before{content:"\f84c"}.fa-angry:before,.fa-face-angry:before{content:"\f556"}.fa-cookie-bite:before{content:"\f564"}.fa-arrow-trend-down:before{content:"\e097"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-draw-polygon:before{content:"\f5ee"}.fa-balance-scale:before,.fa-scale-balanced:before{content:"\f24e"}.fa-gauge-simple-high:before,.fa-tachometer-fast:before,.fa-tachometer:before{content:"\f62a"}.fa-shower:before{content:"\f2cc"}.fa-desktop-alt:before,.fa-desktop:before{content:"\f390"}.fa-m:before{content:"\4d"}.fa-table-list:before,.fa-th-list:before{content:"\f00b"}.fa-comment-sms:before,.fa-sms:before{content:"\f7cd"}.fa-book:before{content:"\f02d"}.fa-user-plus:before{content:"\f234"}.fa-check:before{content:"\f00c"}.fa-battery-4:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-house-circle-check:before{content:"\e509"}.fa-angle-left:before{content:"\f104"}.fa-diagram-successor:before{content:"\e47a"}.fa-truck-arrow-right:before{content:"\e58b"}.fa-arrows-split-up-and-left:before{content:"\e4bc"}.fa-fist-raised:before,.fa-hand-fist:before{content:"\f6de"}.fa-cloud-moon:before{content:"\f6c3"}.fa-briefcase:before{content:"\f0b1"}.fa-person-falling:before{content:"\e546"}.fa-image-portrait:before,.fa-portrait:before{content:"\f3e0"}.fa-user-tag:before{content:"\f507"}.fa-rug:before{content:"\e569"}.fa-earth-europe:before,.fa-globe-europe:before{content:"\f7a2"}.fa-cart-flatbed-suitcase:before,.fa-luggage-cart:before{content:"\f59d"}.fa-rectangle-times:before,.fa-rectangle-xmark:before,.fa-times-rectangle:before,.fa-window-close:before{content:"\f410"}.fa-baht-sign:before{content:"\e0ac"}.fa-book-open:before{content:"\f518"}.fa-book-journal-whills:before,.fa-journal-whills:before{content:"\f66a"}.fa-handcuffs:before{content:"\e4f8"}.fa-exclamation-triangle:before,.fa-triangle-exclamation:before,.fa-warning:before{content:"\f071"}.fa-database:before{content:"\f1c0"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-bottle-droplet:before{content:"\e4c4"}.fa-mask-face:before{content:"\e1d7"}.fa-hill-rockslide:before{content:"\e508"}.fa-exchange-alt:before,.fa-right-left:before{content:"\f362"}.fa-paper-plane:before{content:"\f1d8"}.fa-road-circle-exclamation:before{content:"\e565"}.fa-dungeon:before{content:"\f6d9"}.fa-align-right:before{content:"\f038"}.fa-money-bill-1-wave:before,.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-life-ring:before{content:"\f1cd"}.fa-hands:before,.fa-sign-language:before,.fa-signing:before{content:"\f2a7"}.fa-calendar-day:before{content:"\f783"}.fa-ladder-water:before,.fa-swimming-pool:before,.fa-water-ladder:before{content:"\f5c5"}.fa-arrows-up-down:before,.fa-arrows-v:before{content:"\f07d"}.fa-face-grimace:before,.fa-grimace:before{content:"\f57f"}.fa-wheelchair-alt:before,.fa-wheelchair-move:before{content:"\e2ce"}.fa-level-down-alt:before,.fa-turn-down:before{content:"\f3be"}.fa-person-walking-arrow-right:before{content:"\e552"}.fa-envelope-square:before,.fa-square-envelope:before{content:"\f199"}.fa-dice:before{content:"\f522"}.fa-bowling-ball:before{content:"\f436"}.fa-brain:before{content:"\f5dc"}.fa-band-aid:before,.fa-bandage:before{content:"\f462"}.fa-calendar-minus:before{content:"\f272"}.fa-circle-xmark:before,.fa-times-circle:before,.fa-xmark-circle:before{content:"\f057"}.fa-gifts:before{content:"\f79c"}.fa-hotel:before{content:"\f594"}.fa-earth-asia:before,.fa-globe-asia:before{content:"\f57e"}.fa-id-card-alt:before,.fa-id-card-clip:before{content:"\f47f"}.fa-magnifying-glass-plus:before,.fa-search-plus:before{content:"\f00e"}.fa-thumbs-up:before{content:"\f164"}.fa-user-clock:before{content:"\f4fd"}.fa-allergies:before,.fa-hand-dots:before{content:"\f461"}.fa-file-invoice:before{content:"\f570"}.fa-window-minimize:before{content:"\f2d1"}.fa-coffee:before,.fa-mug-saucer:before{content:"\f0f4"}.fa-brush:before{content:"\f55d"}.fa-mask:before{content:"\f6fa"}.fa-magnifying-glass-minus:before,.fa-search-minus:before{content:"\f010"}.fa-ruler-vertical:before{content:"\f548"}.fa-user-alt:before,.fa-user-large:before{content:"\f406"}.fa-train-tram:before{content:"\e5b4"}.fa-user-nurse:before{content:"\f82f"}.fa-syringe:before{content:"\f48e"}.fa-cloud-sun:before{content:"\f6c4"}.fa-stopwatch-20:before{content:"\e06f"}.fa-square-full:before{content:"\f45c"}.fa-magnet:before{content:"\f076"}.fa-jar:before{content:"\e516"}.fa-note-sticky:before,.fa-sticky-note:before{content:"\f249"}.fa-bug-slash:before{content:"\e490"}.fa-arrow-up-from-water-pump:before{content:"\e4b6"}.fa-bone:before{content:"\f5d7"}.fa-user-injured:before{content:"\f728"}.fa-face-sad-tear:before,.fa-sad-tear:before{content:"\f5b4"}.fa-plane:before{content:"\f072"}.fa-tent-arrows-down:before{content:"\e581"}.fa-exclamation:before{content:"\21"}.fa-arrows-spin:before{content:"\e4bb"}.fa-print:before{content:"\f02f"}.fa-try:before,.fa-turkish-lira-sign:before,.fa-turkish-lira:before{content:"\e2bb"}.fa-dollar-sign:before,.fa-dollar:before,.fa-usd:before{content:"\24"}.fa-x:before{content:"\58"}.fa-magnifying-glass-dollar:before,.fa-search-dollar:before{content:"\f688"}.fa-users-cog:before,.fa-users-gear:before{content:"\f509"}.fa-person-military-pointing:before{content:"\e54a"}.fa-bank:before,.fa-building-columns:before,.fa-institution:before,.fa-museum:before,.fa-university:before{content:"\f19c"}.fa-umbrella:before{content:"\f0e9"}.fa-trowel:before{content:"\e589"}.fa-d:before{content:"\44"}.fa-stapler:before{content:"\e5af"}.fa-masks-theater:before,.fa-theater-masks:before{content:"\f630"}.fa-kip-sign:before{content:"\e1c4"}.fa-hand-point-left:before{content:"\f0a5"}.fa-handshake-alt:before,.fa-handshake-simple:before{content:"\f4c6"}.fa-fighter-jet:before,.fa-jet-fighter:before{content:"\f0fb"}.fa-share-alt-square:before,.fa-square-share-nodes:before{content:"\f1e1"}.fa-barcode:before{content:"\f02a"}.fa-plus-minus:before{content:"\e43c"}.fa-video-camera:before,.fa-video:before{content:"\f03d"}.fa-graduation-cap:before,.fa-mortar-board:before{content:"\f19d"}.fa-hand-holding-medical:before{content:"\e05c"}.fa-person-circle-check:before{content:"\e53e"}.fa-level-up-alt:before,.fa-turn-up:before{content:"\f3bf"} +.fa-sr-only,.fa-sr-only-focusable:not(:focus),.sr-only,.sr-only-focusable:not(:focus){position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0} \ No newline at end of file diff --git a/jiuguan2025cc/public/css/group-avatars.css b/jiuguan2025cc/public/css/group-avatars.css new file mode 100644 index 0000000000000000000000000000000000000000..96f01e66e90f4fccd4ef79126bca62e4849f8172 --- /dev/null +++ b/jiuguan2025cc/public/css/group-avatars.css @@ -0,0 +1,91 @@ +.avatar_collage { + border-radius: 50%; + position: relative; + overflow: hidden; +} + +.avatar_collage img { + position: absolute; + overflow: hidden; +} + +.collage_2 .img_1 { + left: 0; + top: 0; + max-width: 50%; + max-height: 100%; + width: 50%; + height: 100%; +} + +.collage_2 .img_2 { + left: 50%; + top: 0; + max-width: 50%; + max-height: 100%; + width: 50%; + height: 100%; +} + +.collage_3 .img_1 { + left: 0; + top: 0; + max-width: 50%; + max-height: 50%; + width: 50%; + height: 50%; +} + +.collage_3 .img_2 { + left: 50%; + top: 0; + max-width: 50%; + max-height: 50%; + width: 50%; + height: 50%; +} + +.collage_3 .img_3 { + left: 0; + top: 50%; + max-width: 100%; + max-height: 50%; + width: 100%; + height: 50%; +} + +.collage_4 .img_1 { + left: 0; + top: 0; + max-width: 50%; + max-height: 50%; + width: 50%; + height: 50%; +} + +.collage_4 .img_2 { + left: 50%; + top: 0; + max-width: 50%; + max-height: 50%; + width: 50%; + height: 50%; +} + +.collage_4 .img_3 { + left: 0; + top: 50%; + max-width: 50%; + max-height: 50%; + width: 50%; + height: 50%; +} + +.collage_4 .img_4 { + left: 50%; + top: 50%; + max-width: 50%; + max-height: 50%; + width: 50%; + height: 50%; +} \ No newline at end of file diff --git a/jiuguan2025cc/public/css/jquery-ui.min.css b/jiuguan2025cc/public/css/jquery-ui.min.css new file mode 100644 index 0000000000000000000000000000000000000000..ab54bc66190bb19f111fdb272b6a0692fca1555b --- /dev/null +++ b/jiuguan2025cc/public/css/jquery-ui.min.css @@ -0,0 +1,7 @@ +/*! jQuery UI - v1.13.2 - 2022-07-14 +* http://jqueryui.com +* Includes: core.css, accordion.css, autocomplete.css, menu.css, button.css, controlgroup.css, checkboxradio.css, datepicker.css, dialog.css, draggable.css, resizable.css, progressbar.css, selectable.css, selectmenu.css, slider.css, sortable.css, spinner.css, tabs.css, tooltip.css, theme.css +* To view and modify this theme, visit http://jqueryui.com/themeroller/?bgShadowXPos=&bgOverlayXPos=&bgErrorXPos=&bgHighlightXPos=&bgContentXPos=&bgHeaderXPos=&bgActiveXPos=&bgHoverXPos=&bgDefaultXPos=&bgShadowYPos=&bgOverlayYPos=&bgErrorYPos=&bgHighlightYPos=&bgContentYPos=&bgHeaderYPos=&bgActiveYPos=&bgHoverYPos=&bgDefaultYPos=&bgShadowRepeat=&bgOverlayRepeat=&bgErrorRepeat=&bgHighlightRepeat=&bgContentRepeat=&bgHeaderRepeat=&bgActiveRepeat=&bgHoverRepeat=&bgDefaultRepeat=&iconsHover=url(%22images%2Fui-icons_555555_256x240.png%22)&iconsHighlight=url(%22images%2Fui-icons_777620_256x240.png%22)&iconsHeader=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsError=url(%22images%2Fui-icons_cc0000_256x240.png%22)&iconsDefault=url(%22images%2Fui-icons_777777_256x240.png%22)&iconsContent=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsActive=url(%22images%2Fui-icons_ffffff_256x240.png%22)&bgImgUrlShadow=&bgImgUrlOverlay=&bgImgUrlHover=&bgImgUrlHighlight=&bgImgUrlHeader=&bgImgUrlError=&bgImgUrlDefault=&bgImgUrlContent=&bgImgUrlActive=&opacityFilterShadow=Alpha(Opacity%3D30)&opacityFilterOverlay=Alpha(Opacity%3D30)&opacityShadowPerc=30&opacityOverlayPerc=30&iconColorHover=%23555555&iconColorHighlight=%23777620&iconColorHeader=%23444444&iconColorError=%23cc0000&iconColorDefault=%23777777&iconColorContent=%23444444&iconColorActive=%23ffffff&bgImgOpacityShadow=0&bgImgOpacityOverlay=0&bgImgOpacityError=95&bgImgOpacityHighlight=55&bgImgOpacityContent=75&bgImgOpacityHeader=75&bgImgOpacityActive=65&bgImgOpacityHover=75&bgImgOpacityDefault=75&bgTextureShadow=flat&bgTextureOverlay=flat&bgTextureError=flat&bgTextureHighlight=flat&bgTextureContent=flat&bgTextureHeader=flat&bgTextureActive=flat&bgTextureHover=flat&bgTextureDefault=flat&cornerRadius=3px&fwDefault=normal&ffDefault=Arial%2CHelvetica%2Csans-serif&fsDefault=1em&cornerRadiusShadow=8px&thicknessShadow=5px&offsetLeftShadow=0px&offsetTopShadow=0px&opacityShadow=.3&bgColorShadow=%23666666&opacityOverlay=.3&bgColorOverlay=%23aaaaaa&fcError=%235f3f3f&borderColorError=%23f1a899&bgColorError=%23fddfdf&fcHighlight=%23777620&borderColorHighlight=%23dad55e&bgColorHighlight=%23fffa90&fcContent=%23333333&borderColorContent=%23dddddd&bgColorContent=%23ffffff&fcHeader=%23333333&borderColorHeader=%23dddddd&bgColorHeader=%23e9e9e9&fcActive=%23ffffff&borderColorActive=%23003eff&bgColorActive=%23007fff&fcHover=%232b2b2b&borderColorHover=%23cccccc&bgColorHover=%23ededed&fcDefault=%23454545&borderColorDefault=%23c5c5c5&bgColorDefault=%23f6f6f6 +* Copyright jQuery Foundation and other contributors; Licensed MIT */ + +.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;-ms-filter:"alpha(opacity=0)"}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important;pointer-events:none}.ui-icon{display:inline-block;vertical-align:middle;margin-top:-.25em;position:relative;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-icon-block{left:50%;margin-left:-8px;display:block}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin:2px 0 0 0;padding:.5em .5em .5em .7em;font-size:100%}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{margin:0;cursor:pointer;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-item-wrapper{position:relative;padding:3px 1em 3px .4em}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item-wrapper{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-button{padding:.4em 1em;display:inline-block;position:relative;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2em;box-sizing:border-box;text-indent:-9999px;white-space:nowrap}input.ui-button.ui-button-icon-only{text-indent:0}.ui-button-icon-only .ui-icon{position:absolute;top:50%;left:50%;margin-top:-8px;margin-left:-8px}.ui-button.ui-icon-notext .ui-icon{padding:0;width:2.1em;height:2.1em;text-indent:-9999px;white-space:nowrap}input.ui-button.ui-icon-notext .ui-icon{width:auto;height:auto;text-indent:0;white-space:normal;padding:.4em 1em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-controlgroup{vertical-align:middle;display:inline-block}.ui-controlgroup > .ui-controlgroup-item{float:left;margin-left:0;margin-right:0}.ui-controlgroup > .ui-controlgroup-item:focus,.ui-controlgroup > .ui-controlgroup-item.ui-visual-focus{z-index:9999}.ui-controlgroup-vertical > .ui-controlgroup-item{display:block;float:none;width:100%;margin-top:0;margin-bottom:0;text-align:left}.ui-controlgroup-vertical .ui-controlgroup-item{box-sizing:border-box}.ui-controlgroup .ui-controlgroup-label{padding:.4em 1em}.ui-controlgroup .ui-controlgroup-label span{font-size:80%}.ui-controlgroup-horizontal .ui-controlgroup-label + .ui-controlgroup-item{border-left:none}.ui-controlgroup-vertical .ui-controlgroup-label + .ui-controlgroup-item{border-top:none}.ui-controlgroup-horizontal .ui-controlgroup-label.ui-widget-content{border-right:none}.ui-controlgroup-vertical .ui-controlgroup-label.ui-widget-content{border-bottom:none}.ui-controlgroup-vertical .ui-spinner-input{width:75%;width:calc( 100% - 2.4em )}.ui-controlgroup-vertical .ui-spinner .ui-spinner-up{border-top-style:solid}.ui-checkboxradio-label .ui-icon-background{box-shadow:inset 1px 1px 1px #ccc;border-radius:.12em;border:none}.ui-checkboxradio-radio-label .ui-icon-background{width:16px;height:16px;border-radius:1em;overflow:visible;border:none}.ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon,.ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon{background-image:none;width:8px;height:8px;border-width:4px;border-style:solid}.ui-checkboxradio-disabled{pointer-events:none}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:45%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-datepicker .ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat;left:.5em;top:.3em}.ui-dialog{position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-n{height:2px;top:0}.ui-dialog .ui-resizable-e{width:2px;right:0}.ui-dialog .ui-resizable-s{height:2px;bottom:0}.ui-dialog .ui-resizable-w{width:2px;left:0}.ui-dialog .ui-resizable-se,.ui-dialog .ui-resizable-sw,.ui-dialog .ui-resizable-ne,.ui-dialog .ui-resizable-nw{width:7px;height:7px}.ui-dialog .ui-resizable-se{right:0;bottom:0}.ui-dialog .ui-resizable-sw{left:0;bottom:0}.ui-dialog .ui-resizable-ne{right:0;top:0}.ui-dialog .ui-resizable-nw{left:0;top:0}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block;-ms-touch-action:none;touch-action:none}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");height:100%;-ms-filter:"alpha(opacity=25)";opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-selectable{-ms-touch-action:none;touch-action:none}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-selectmenu-menu{padding:0;margin:0;position:absolute;top:0;left:0;display:none}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{font-size:1em;font-weight:bold;line-height:1.5;padding:2px 0.4em;margin:0.5em 0 0 0;height:auto;border:0}.ui-selectmenu-open{display:block}.ui-selectmenu-text{display:block;margin-right:20px;overflow:hidden;text-overflow:ellipsis}.ui-selectmenu-button.ui-button{text-align:left;white-space:nowrap;width:14em}.ui-selectmenu-icon.ui-icon{float:right;margin-top:0}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:pointer;-ms-touch-action:none;touch-action:none}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-sortable-handle{-ms-touch-action:none;touch-action:none}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:.222em 0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:2em}.ui-spinner-button{width:1.6em;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top-style:none;border-bottom-style:none;border-right-style:none}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Arial,Helvetica,sans-serif;font-size:1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Arial,Helvetica,sans-serif;font-size:1em}.ui-widget.ui-widget-content{border:1px solid #c5c5c5}.ui-widget-content{border:1px solid #ddd;background:#fff;color:#333}.ui-widget-content a{color:#333}.ui-widget-header{border:1px solid #ddd;background:#e9e9e9;color:#333;font-weight:bold}.ui-widget-header a{color:#333}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default,.ui-button,html .ui-button.ui-state-disabled:hover,html .ui-button.ui-state-disabled:active{border:1px solid #c5c5c5;background:#f6f6f6;font-weight:normal;color:#454545}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited,a.ui-button,a:link.ui-button,a:visited.ui-button,.ui-button{color:#454545;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus,.ui-button:hover,.ui-button:focus{border:1px solid #ccc;background:#ededed;font-weight:normal;color:#2b2b2b}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited,a.ui-button:hover,a.ui-button:focus{color:#2b2b2b;text-decoration:none}.ui-visual-focus{box-shadow:0 0 3px 1px rgb(94,158,214)}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active,a.ui-button:active,.ui-button:active,.ui-button.ui-state-active:hover{border:1px solid #003eff;background:#007fff;font-weight:normal;color:#fff}.ui-icon-background,.ui-state-active .ui-icon-background{border:#003eff;background-color:#fff}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#fff;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #dad55e;background:#fffa90;color:#777620}.ui-state-checked{border:1px solid #dad55e;background:#fffa90}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#777620}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #f1a899;background:#fddfdf;color:#5f3f3f}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#5f3f3f}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#5f3f3f}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;-ms-filter:"alpha(opacity=70)";font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;-ms-filter:"alpha(opacity=35)";background-image:none}.ui-state-disabled .ui-icon{-ms-filter:"alpha(opacity=35)"}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_444444_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_444444_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon,.ui-button:hover .ui-icon,.ui-button:focus .ui-icon{background-image:url("images/ui-icons_555555_256x240.png")}.ui-state-active .ui-icon,.ui-button:active .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-highlight .ui-icon,.ui-button .ui-state-highlight.ui-icon{background-image:url("images/ui-icons_777620_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_cc0000_256x240.png")}.ui-button .ui-icon{background-image:url("images/ui-icons_777777_256x240.png")}.ui-icon-blank.ui-icon-blank.ui-icon-blank{background-image:none}.ui-icon-caret-1-n{background-position:0 0}.ui-icon-caret-1-ne{background-position:-16px 0}.ui-icon-caret-1-e{background-position:-32px 0}.ui-icon-caret-1-se{background-position:-48px 0}.ui-icon-caret-1-s{background-position:-65px 0}.ui-icon-caret-1-sw{background-position:-80px 0}.ui-icon-caret-1-w{background-position:-96px 0}.ui-icon-caret-1-nw{background-position:-112px 0}.ui-icon-caret-2-n-s{background-position:-128px 0}.ui-icon-caret-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-65px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-65px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:1px -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:3px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:3px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:3px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:3px}.ui-widget-overlay{background:#aaa;opacity:.003;-ms-filter:Alpha(Opacity=.3)}.ui-widget-shadow{-webkit-box-shadow:0 0 5px #666;box-shadow:0 0 5px #666} \ No newline at end of file diff --git a/jiuguan2025cc/public/css/loader.css b/jiuguan2025cc/public/css/loader.css new file mode 100644 index 0000000000000000000000000000000000000000..acf82613d055b2860c71610c5dac1d95e11d8b87 --- /dev/null +++ b/jiuguan2025cc/public/css/loader.css @@ -0,0 +1,31 @@ +#preloader { + position: fixed; + margin: 0; + padding: 0; + top: 0; + left: 0; + z-index: 999999; + width: 100vw; + height: 100vh; + width: 100dvw; + height: 100dvh; + background-color: var(--SmartThemeBlurTintColor); + color: var(--SmartThemeBodyColor); + /*for some reason the full screen blur does not work on iOS*/ + backdrop-filter: blur(30px); + opacity: 1; +} + +#load-spinner { + --spinner-size: 2em; + transition: all 300ms ease-out; + opacity: 1; + top: calc(50% - var(--spinner-size) / 2); + left: calc(50% - var(--spinner-size) / 2); + position: absolute; + width: var(--spinner-size); + height: var(--spinner-size); + display: flex; + align-items: center; + justify-content: center; +} diff --git a/jiuguan2025cc/public/css/login.css b/jiuguan2025cc/public/css/login.css new file mode 100644 index 0000000000000000000000000000000000000000..689988682db71e9337191c74c5e6df8850e78c33 --- /dev/null +++ b/jiuguan2025cc/public/css/login.css @@ -0,0 +1,50 @@ +body.login #shadow_popup { + opacity: 1; + display: flex; +} + +body.login .logo { + max-width: 30px; +} + +body.login #logoBlock { + align-items: center; + margin: 0 auto; + gap: 10px; +} + +body.login .userSelect { + display: flex; + flex-direction: column; + color: var(--SmartThemeBodyColor); + border: 1px solid var(--SmartThemeBorderColor); + border-radius: 5px; + padding: 3px 5px; + width: 30%; + cursor: pointer; + margin: 5px 0; + transition: background-color 0.15s ease-in-out; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + overflow: hidden; +} + +body.login .userSelect .userName, +body.login .userSelect .userHandle { + width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +body.login .userSelect:hover { + background-color: var(--black30a); +} + +body.login #handleEntryBlock, +body.login #passwordEntryBlock, +body.login #passwordRecoveryBlock { + margin: 2px; +} diff --git a/jiuguan2025cc/public/css/logprobs.css b/jiuguan2025cc/public/css/logprobs.css new file mode 100644 index 0000000000000000000000000000000000000000..71b319539c9ba6cda9a496836f403437a1a67668 --- /dev/null +++ b/jiuguan2025cc/public/css/logprobs.css @@ -0,0 +1,144 @@ +#logprobsViewer { + overflow-y: auto; + max-width: 90dvw; + max-height: 90dvh; + min-width: 100px; + min-height: 50px; + border-radius: 10px; + border: 1px solid var(--SmartThemeBorderColor); + position: fixed; + padding: 10px; + display: none; + flex-direction: column; + box-shadow: 0 0 10px var(--black70a); + z-index: 3000; + left: 0; + top: 0; + margin: 0; + right: unset; + width: calc(((100dvw - var(--sheldWidth)) / 2) - 1px); +} + +.logprobs_panel_header { + display: flex; + justify-content: space-between; + align-items: center; +} + +.logprobs_panel_title { + font-weight: bold; +} + +.logprobs_panel_controls { + display: flex; + align-items: center; +} + +.logprobs_panel_content { + overflow-y: auto; +} + +.logprobs_panel_control_button { + width: 25px; + height: 25px; + margin-left: 5px; + opacity: 0.5; + transition: all 250ms; + position: unset !important; +} + +.logprobs_panel_control_button:hover { + opacity: 1; + cursor: pointer; +} + +#logprobs_generation_output { + user-select: none; + height: 100%; + overflow-y: auto; + word-break: break-all; +} + +.logprobs_empty_state { + display: flex; + justify-content: center; + align-items: center; + opacity: 0.5; + min-height: 100px; + text-align: center; +} + +.logprobs_output_prefix { + opacity: 0.5; +} + +.logprobs_output_prefix:hover { + background-color: rgba(255, 0, 50, 0.4); +} + +.logprobs_output_prefix:hover ~ .logprobs_output_prefix { + background-color: rgba(255, 0, 50, 0.4); +} + +.logprobs_candidate_list { + grid-row-start: 3; + grid-row-end: 4; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); + gap: 2px; + padding: 2px; + border-top: 1px solid var(--SmartThemeBodyColor); + text-align: center; +} + +.logprobs_top_candidate { + border: none; + background-color: transparent; + color: inherit; + font: inherit; +} + +.logprobs_top_candidate:not([disabled]) { + cursor: pointer; +} + +.logprobs_top_candidate.selected { + background-color: rgba(0, 255, 0, 0.2); + font-weight: bold; +} + +.logprobs_top_candidate:not([disabled]):hover { + background-color: rgba(0, 0, 0, 0.3); +} + +.logprobs_tint_0 { + background-color: rgba(255, 255, 0, 0.05); +} + +.logprobs_tint_0:hover, .logprobs_tint_0.selected { + background-color: rgba(255, 255, 0, 0.4); +} + +.logprobs_tint_1 { + background-color: rgba(255, 0, 255, 0.05); +} + +.logprobs_tint_1:hover, .logprobs_tint_1.selected { + background-color: rgba(255, 0, 255, 0.4); +} + +.logprobs_tint_2 { + background-color: rgba(0, 255, 255, 0.05); +} + +.logprobs_tint_2:hover, .logprobs_tint_2.selected { + background-color: rgba(0, 255, 255, 0.4); +} + +.logprobs_tint_3 { + background-color: rgba(50, 205, 50, 0.05); +} + +.logprobs_tint_3:hover, .logprobs_tint_3.selected { + background-color: rgba(50, 205, 50, 0.4); +} diff --git a/jiuguan2025cc/public/css/mobile-styles.css b/jiuguan2025cc/public/css/mobile-styles.css new file mode 100644 index 0000000000000000000000000000000000000000..56c89e27514ca7c66102b365c1a55891f9270d04 --- /dev/null +++ b/jiuguan2025cc/public/css/mobile-styles.css @@ -0,0 +1,502 @@ +/*will apply to anything 1000px or less. this catches ipads, horizontal phones, and vertical phones)*/ +@media screen and (max-width: 1000px) { + + #UI-Theme-Block, + #UI-Customization, + #power-user-options-block, + #ContextSettings, + #InstructSettingsColumn, + #InstructSequencesColumn { + flex-basis: 100%; + } + + + #send_form.compact #leftSendForm, + #send_form.compact #rightSendForm { + flex-wrap: nowrap; + width: unset; + } + + #sheldWidthToggleBlock { + display: none; + } + + .bg_button { + font-size: 15px; + } + + .mes_text img { + width: 100%; + } + + #extensions_settings, + #extensions_settings2 { + width: 100% !important; + min-width: 100% !important; + } + + body:not(.waifuMode) .zoomed_avatar { + min-width: 100px; + min-height: 100px; + position: absolute; + padding: 0; + filter: drop-shadow(2px 2px 2px #51515199); + z-index: 30; + overflow: hidden; + right: 0; + width: fit-content; + max-height: calc(60vh - 60px); + max-height: calc(60dvh - 60px); + max-width: 90vw; + max-width: 90dvw; + left: 50%; + top: 50%; + transform: translateX(-50%) translateY(-50%); + align-items: center; + justify-content: center; + height: fit-content; + width: 100%; + } + + .zoomed_avatar .dragClose { + display: unset; + } + + /* .world_entry_thin_controls, */ + #persona-management-block, + #character_popup .flex-container { + flex-direction: column; + } + + #WIMultiSelector { + align-self: normal; + } + + .WIEntryContentAndMemo { + flex-flow: column; + } + + .WIEntryContentAndMemo .world_entry_thin_controls { + width: 100%; + } + + .world_entry_form_control.world_entry_form_horizontal { + /* flex-direction: column; */ + align-items: flex-start; + row-gap: 0.5rem; + } + + .world_entry_form_control.world_entry_form_horizontal .world_popup_expander { + display: none; + } + + .world_entry .inline-drawer-toggle { + padding-bottom: 5px; + } + + #worldInfoScanningCheckboxes { + flex-flow: row; + flex-wrap: wrap; + } + + body { + touch-action: none; + overflow: hidden; + position: fixed; + } + + .world_entry_form_control { + /* width: 100%; */ + } + + .drawer-content { + min-width: unset; + width: 100dvw; + max-height: calc(100vh - 45px); + max-height: calc(100dvh - 45px); + position: fixed; + left: 0; + top: 5px; + border: 1px solid var(--SmartThemeBorderColor); + } + + .drawer-content .floating_panel_maximize, + .drawer-content .inline-drawer-maximize { + display: none; + } + + #select_chat_popup { + align-items: start; + height: min-content; + align-content: start; + max-width: unset; + } + + #wiActivationSettings, + #wiTopBlock { + flex-direction: column; + } + + #top-settings-holder, + #top-bar { + position: fixed; + width: 100vw; + width: 100dvw; + } + + #bg1, + #bg_custom { + height: 100vh !important; + height: 100dvh !important; + width: 100vw !important; + width: 100dvw !important; + background-position: center; + + } + + + #sheld, + #character_popup, + .drawer-content { + width: 100dvw !important; + margin: 0 auto; + max-width: 100dvw; + left: 0 !important; + resize: none !important; + top: var(--topBarBlockSize); + } + + .wi-settings { + flex-direction: column; + gap: 5px !important; + } + + .WIEntryTitleAndStatus, + .WIEntryHeaderControls { + width: 100%; + } + + #WIEntryHeaderTitlesPC { + display: none; + } + + .WIEntryHeaderTitleMobile { + display: block !important; + } + + #character_popup, + #world_popup { + overflow-y: auto; + } + + #character_popup, + #send_form { + border: 1px solid var(--SmartThemeBorderColor); + backdrop-filter: blur(calc(var(--SmartThemeBlurStrength) * 2)); + max-width: 100dvw; + } + + #chat { + border-left: 1px solid var(--SmartThemeBorderColor); + border-right: 1px solid var(--SmartThemeBorderColor); + border-bottom: 1px solid var(--SmartThemeBorderColor); + align-items: start; + align-content: start; + overflow-y: auto; + overflow-x: hidden + } + + .mes_buttons { + font-size: calc(var(--mainFontSize)*1.2); + } + + .drag-grabber, + .pull-tab { + display: none !important; + + } + + #groupCurrentMemberPopoutButton, + #summaryExtensionPopoutButton { + display: none; + } + + #right-nav-panel, + #left-nav-panel, + #floatingPrompt, + #cfgConfig, + #logprobsViewer, + #movingDivs>div { + /* 100vh are fallback units for browsers that don't support dvh */ + height: calc(100vh - 45px); + height: calc(100dvh - 45px); + min-width: 100dvw !important; + width: 100dvw !important; + max-width: 100dvw !important; + overflow-y: hidden; + border-left: 1px solid var(--SmartThemeBorderColor); + border-right: 1px solid var(--SmartThemeBorderColor); + border-bottom: 1px solid var(--SmartThemeBorderColor); + border-radius: 0 0 20px 20px; + top: var(--topBarBlockSize) !important; + left: 0 !important; + backdrop-filter: blur(calc(var(--SmartThemeBlurStrength) * 2)); + } + + /* + #right-nav-panel { + padding-right: 15px; + } + */ + + #floatingPrompt, + #cfgConfig, + #logprobsViewer, + #movingDivs>div { + height: min-content; + } + + #right-nav-panel h4 { + margin: 5px auto; + } + + #result_info { + font-size: calc(var(--mainFontSize) - .1rem); + } + + /* .avatar_div { + margin-top: 5px; + } */ + + #character_popup { + width: 100%; + border-radius: 0 0 20px 20px; + margin-top: 0px; + height: calc(100% - var(--topBarBlockSize)); + } + + .drawer25pWidth { + flex-basis: max(calc(100% / 4 - 10px), 190px); + } + + .drawer33pWidth { + flex-basis: max(calc(100% / 3 - 10px), 190px); + } + + .expression-holder { + display: none; + } + + body.waifuMode #sheld { + height: 40vh; + height: 40dvh; + top: 60vh; + top: 60dvh; + bottom: 0 !important; + } + + body:not(.waifuMode) #expression-wrapper { + visibility: hidden; + } + + #visual-novel-wrapper { + position: unset !important; + } + + body.waifuMode .expression-holder { + /*display: inline;*/ + + max-width: 100vw; + height: 100vh; + width: max-content; + margin: 0 auto; + position: absolute; + left: 0; + right: 0; + filter: drop-shadow(2px 2px 2px #51515199); + z-index: 1 !important; + } + + body.waifuMode img.expression { + object-fit: cover; + } + + body.waifuMode .zoomed_avatar_container { + height: 100%; + } + + body.waifuMode .zoomed_avatar { + width: fit-content; + max-height: calc(60vh - 60px); + max-height: calc(60dvh - 60px); + max-width: 90vw; + max-width: 90dvw; + } + + .scrollableInner { + overflow-y: auto; + overflow-x: hidden; + max-height: calc(100vh - 90px); + max-height: calc(100dvh - 90px); + } + + .horde_multiple_hint { + display: none; + } + + .bg_list { + width: unset; + } +} + +/*landscape mode phones and ipads*/ +@media screen and (max-width: 1000px) and (orientation: landscape) { + body.waifuMode img.expression { + object-fit: contain; + } + + .tag.excluded:after { + top: unset; + bottom: unset; + } + + body:not(.waifuMode) .zoomed_avatar { + max-height: calc(60vh - 60px); + max-height: calc(60dvh - 60px); + max-width: 90vw; + max-width: 90dvw; + left: 50%; + top: 50%; + transform: translateX(-50%) translateY(-50%); + align-items: center; + justify-content: center; + height: fit-content; + width: 100%; + } +} + +/*portrait mode phones*/ +@media screen and (max-width: 450px) { + + body:not(.waifuMode) .zoomed_avatar { + min-width: 100px; + min-height: 100px; + max-height: 50vh; + max-width: 90vw; + position: absolute; + padding: 0; + filter: drop-shadow(2px 2px 2px #51515199); + z-index: 30; + overflow: hidden; + display: none; + right: 0; + left: 50%; + top: 50%; + transform: translateX(-50%) translateY(-50%); + align-items: center; + justify-content: center; + height: fit-content; + width: 100%; + } + + .drawer25pWidth { + flex-basis: max(calc(100% / 2 - 10px), 180px); + } + + .drawer33pWidth { + flex-basis: max(calc(100% / 2 - 10px), 180px); + } + + .BGSampleTitle { + display: none; + } + + .tag.excluded:after { + top: unset; + bottom: unset; + } + + + #leftSendForm, + #rightSendForm { + width: 1.15em; + flex-wrap: wrap; + height: unset; + } +} + +/*iOS specific*/ +@supports (-webkit-touch-callout: none) { + body { + margin: 0 auto; + } + + #top-bar { + width: 100vw; + } + + #sheld { + margin: unset; + padding: unset; + width: unset; + height: unset; + min-width: unset; + max-width: unset; + min-height: unset; + max-height: unset; + width: 100vw; + width: 100dvw; + height: calc(100vh - 36px); + height: calc(100dvh - 36px); + padding-right: max(env(safe-area-inset-right), 0px); + padding-left: max(env(safe-area-inset-left), 0px); + padding-bottom: 0; + } + + body.PWA #sheld { + padding-right: max(env(safe-area-inset-right), 2px); + padding-left: max(env(safe-area-inset-left), 2px); + padding-bottom: max(env(safe-area-inset-bottom), 15px); + + } + + #character_popup, + #world_popup, + #left-nav-panel, + #right-nav-panel, + .drawer-content { + width: unset; + height: unset; + min-width: unset; + max-width: unset; + min-height: unset; + max-height: unset; + backdrop-filter: blur(calc(var(--SmartThemeBlurStrength) * 2)); + left: 0; + right: 0; + top: 0; + margin: 0 auto; + height: calc(100vh - 70px); + height: calc(100dvh - 70px); + width: calc(100dvw - 5px); + max-height: calc(100vh - 70px); + max-height: calc(100dvh - 70px); + max-width: calc(100dvw - 5px); + + } + + #character_popup, + #world_popup, + .drawer-content { + margin-top: 36px; + } + + .scrollableInner { + overflow-y: auto; + overflow-x: hidden; + } + + #horde_model { + height: unset; + } +} diff --git a/jiuguan2025cc/public/css/popup-safari-fix.css b/jiuguan2025cc/public/css/popup-safari-fix.css new file mode 100644 index 0000000000000000000000000000000000000000..a59fe4010c75257a88322f7bad248fec2e84ac40 --- /dev/null +++ b/jiuguan2025cc/public/css/popup-safari-fix.css @@ -0,0 +1,19 @@ +/* iPhone copium land */ +body.safari .popup .popup-body:has(.maximized_textarea), +body.safari .popup.large_dialogue_popup .popup-body { + height: 100%; +} + +body.safari .popup .popup-body { + height: fit-content; + max-height: 90vh; + max-height: 90dvh; +} + +body.safari #select_chat_div { + height: auto; +} + +body.safari #select_chat_popup { + height: max-content; +} diff --git a/jiuguan2025cc/public/css/popup.css b/jiuguan2025cc/public/css/popup.css new file mode 100644 index 0000000000000000000000000000000000000000..e477bfd756ab841fb202dc3e31379439e0fe455e --- /dev/null +++ b/jiuguan2025cc/public/css/popup.css @@ -0,0 +1,193 @@ +@import url('/lib/dialog-polyfill.css'); +@import url('./popup-safari-fix.css'); + +dialog { + color: var(--SmartThemeBodyColor); +} + +/* Closed state of the dialog */ +.popup { + width: 500px; + text-align: center; + box-shadow: 0px 0px 14px var(--black70a); + border: 1px solid var(--SmartThemeBorderColor); + padding: 4px 14px; + background-color: var(--SmartThemeBlurTintColor); + border-radius: 10px; + display: flex; + flex-direction: column; + + max-height: calc(100dvh - 2em); + max-width: calc(100dvw - 2em); + min-height: fit-content; + + /* Overflow visible so elements (like toasts) can appear outside of the dialog. '.popup-body' is hiding overflow for the real content. */ + overflow: visible; + + /* Fix weird animation issue with font-scaling during popup open */ + backface-visibility: hidden; + transform: translateZ(0); + -webkit-font-smoothing: subpixel-antialiased; + + /* Variables setup */ + --popup-animation-speed: var(--animation-duration-slow); +} + +/** Popup styles applied to the main popup */ +.popup--animation-fast { --popup-animation-speed: var(--animation-duration); } +.popup--animation-slow { --popup-animation-speed: var(--animation-duration-slow); } +.popup--animation-none { --popup-animation-speed: 0ms; } + +/* Styling of main popup elements */ +.popup .popup-body { + display: flex; + flex-direction: column; + overflow: hidden; + width: min(100%, 100vw); + height: 100%; + padding: 1px; +} + +.popup:not(:has(.img_enlarged_container)) .popup-body { + max-height: 95dvh; +} + +.popup .popup-content { + margin-top: 10px; + padding: 0 8px; + overflow: hidden; + flex-grow: 1; +} + +.popup .popup-content h3:first-child { + /* No double spacing for the first heading needed, the .popup-content already has margin */ + margin-top: 0px; +} + +.popup.vertical_scrolling_dialogue_popup .popup-content { + overflow-y: auto; +} + +.popup.horizontal_scrolling_dialogue_popup .popup-content { + overflow-x: auto; +} + +.popup.left_aligned_dialogue_popup .popup-content { + text-align: start; +} + +/* Opening animation */ +.popup[opening] { + animation: pop-in var(--popup-animation-speed) ease-in-out; +} + +.popup[opening]::backdrop { + animation: fade-in var(--popup-animation-speed) ease-in-out; +} + +/* Open state of the dialog */ +.popup[open] { + color: var(--SmartThemeBodyColor); +} + +.popup[open]::backdrop { + backdrop-filter: blur(calc(var(--SmartThemeBlurStrength) * 2)); + -webkit-backdrop-filter: blur(calc(var(--SmartThemeBlurStrength) * 2)); + background-color: var(--black30a); +} + +body.no-blur .popup[open]::backdrop { + backdrop-filter: none; + -webkit-backdrop-filter: none; +} + +/* Closing animation */ +.popup[closing] { + animation: pop-out var(--popup-animation-speed) ease-in-out; +} + +.popup[closing]::backdrop { + animation: fade-out var(--popup-animation-speed) ease-in-out; +} + +.popup #toast-container { + /* Fix toastr in dialogs by actually placing it at the top of the screen via transform */ + height: 100dvh; + top: calc(50% + var(--topBarBlockSize)); + left: 50%; + transform: translate(-50%, -50%); + + /* Fix text align, popups are centered by default. toasts should not. */ + text-align: left; +} + +.popup-crop-wrap { + margin: 10px auto; + max-height: 75vh; + max-height: 75dvh; + max-width: 100%; +} + +.popup-crop-wrap img { + max-width: 100%; + /* This rule is very important, please do not ignore this! */ +} + +.popup-inputs { + margin-top: 10px; + font-size: smaller; + opacity: 0.7; +} + +.popup-input { + margin-top: 10px; +} + +.popup-controls { + margin-top: 10px; + display: flex; + align-self: center; + gap: 20px; +} + +.menu_button.menu_button_default { + box-shadow: 0 0 5px var(--white20a); +} + +.menu_button.popup-button-ok { + background-color: var(--crimson70a); +} + +.menu_button.popup-button-ok:hover { + background-color: var(--crimson-hover); +} + +.popup-controls .menu_button { + /* Popup buttons should not scale to smallest size, otherwise they will always break to multiline if multiple words */ + width: unset; + + /* Fix weird animation issue with fonts on brightness filter */ + backface-visibility: hidden; + transform: translateZ(0); + -webkit-font-smoothing: subpixel-antialiased; +} + +.popup-controls .menu_button:hover:focus-visible { + filter: brightness(1.3) saturate(1.3); +} + +.popup .popup-button-close { + position: absolute; + top: -6px; + right: -6px; + width: 24px; + height: 24px; + font-size: 20px; + padding: 2px 3px 3px 2px; + + filter: brightness(0.8); + + /* Fix weird animation issue with font-scaling during popup open */ + backface-visibility: hidden; +} + diff --git a/jiuguan2025cc/public/css/promptmanager.css b/jiuguan2025cc/public/css/promptmanager.css new file mode 100644 index 0000000000000000000000000000000000000000..f02b172b1d0c1a4e57e1727b5e6ef496cac90f8c --- /dev/null +++ b/jiuguan2025cc/public/css/promptmanager.css @@ -0,0 +1,368 @@ +#completion_prompt_manager .caution { + color: var(--fullred); +} + +#completion_prompt_manager #completion_prompt_manager_list { + display: flex; + flex-direction: column; + min-height: 300px; +} + +#completion_prompt_manager .completion_prompt_manager_list_separator hr { + grid-column-start: 1; + grid-column-end: 4; + width: 100%; + margin: 0.5em 0; + background-image: linear-gradient(90deg, var(--transparent), var(--SmartThemeBorderColor), var(--transparent)); + min-height: 1px; +} + +#completion_prompt_manager #completion_prompt_manager_list li { + display: grid; + grid-template-columns: 4fr 80px 45px; + margin-bottom: 0.5em; + width: 100% +} + +#completion_prompt_manager #completion_prompt_manager_list .completion_prompt_manager_prompt .completion_prompt_manager_prompt_name .fa-solid { + color: var(--white50a); +} + +#completion_prompt_manager #completion_prompt_manager_list .completion_prompt_manager_prompt .completion_prompt_manager_prompt_name .fa-solid[data-role] { + vertical-align: unset; + margin-left: 3px; +} + +#completion_prompt_manager #completion_prompt_manager_list .completion_prompt_manager_prompt_invisible { + display: none; +} + +#completion_prompt_manager #completion_prompt_manager_list .completion_prompt_manager_prompt_visible { + display: grid; +} + + +#completion_prompt_manager #completion_prompt_manager_list li.completion_prompt_manager_list_head .prompt_manager_prompt_tokens, +#completion_prompt_manager #completion_prompt_manager_list li.completion_prompt_manager_prompt .prompt_manager_prompt_tokens { + font-size: calc(var(--mainFontSize)*0.9); + text-align: right; +} + +#completion_prompt_manager #completion_prompt_manager_list .completion_prompt_manager_prompt .prompt_manager_prompt_controls { + text-align: right; +} + +#completion_prompt_manager .completion_prompt_manager_list_head { + padding: 0.5em 0.5em 0; +} + +#completion_prompt_manager #completion_prompt_manager_list li.completion_prompt_manager_prompt { + align-items: center; + padding: 0.5em; + border: 1px solid var(--SmartThemeBorderColor); +} + +#completion_prompt_manager #completion_prompt_manager_list li.completion_prompt_manager_prompt .prompt_manager_prompt_controls { + display: flex; + justify-content: space-between; + font-size: calc(var(--mainFontSize)*1.2); +} + +#completion_prompt_manager #completion_prompt_manager_list li.completion_prompt_manager_prompt .prompt_manager_prompt_controls span { + display: flex; + height: 18px; + width: 18px; +} + +#completion_prompt_manager #completion_prompt_manager_list li.completion_prompt_manager_prompt span span span { + flex-direction: column; + justify-content: center; + margin-left: 0.25em; + cursor: pointer; + transition: 0.3s ease-in-out; + height: 20px; + width: 20px; + filter: drop-shadow(0px 0px 2px black); + opacity: 0.4; +} + +#completion_prompt_manager #completion_prompt_manager_list li.completion_prompt_manager_prompt span span:hover { + opacity: 1; +} + +#completion_prompt_manager_popup #completion_prompt_manager_popup_edit, +#completion_prompt_manager_popup #completion_prompt_manager_popup_chathistory_edit, +#completion_prompt_manager_popup #completion_prompt_manager_popup_dialogueexamples_edit, +#completion_prompt_manager_popup #completion_prompt_manager_popup_inspect { + display: none; + padding: 0.5em; + height: 100%; + display: flex; + flex-direction: column; +} + +#completion_prompt_manager_popup .completion_prompt_manager_popup_entry { + padding: 0.5em; + flex: 1; +} + +#completion_prompt_manager_popup .completion_prompt_manager_popup_entry_form { + height: 100%; + display: flex; + flex-direction: column; +} + +#completion_prompt_manager_popup .completion_prompt_manager_popup_entry_form_control:has(#completion_prompt_manager_popup_entry_form_prompt) { + flex: 1; + display: flex; + flex-direction: column; +} + +#completion_prompt_manager_popup #completion_prompt_manager_popup_entry_form_prompt { + flex: 1; +} + +#completion_prompt_manager_popup #completion_prompt_manager_popup_inspect .completion_prompt_manager_popup_entry { + padding: 0.5em; +} + +#completion_prompt_manager_popup #completion_prompt_manager_popup_entry_form_inspect_list { + margin-top: 1em; +} + +#completion_prompt_manager_popup .completion_prompt_manager_prompt { + margin: 1em 0; + padding: 0.5em; + border: 1px solid var(--SmartThemeBorderColor); +} + +#completion_prompt_manager_popup .completion_prompt_manager_popup_header { + display: flex; + justify-content: space-between; + align-items: center; +} + +#completion_prompt_manager_popup #completion_prompt_manager_popup_close_button { + font-size: 1em; + padding: 0.5em; +} + +.completion_prompt_manager_popup_entry_form_control { + margin-top: 1em; +} + +#prompt-manager-reset-character, +#completion_prompt_manager_popup .completion_prompt_manager_popup_entry_form_footer #completion_prompt_manager_popup_entry_form_reset { + color: rgb(220 173 16); +} + +#completion_prompt_manager_popup .completion_prompt_manager_popup_entry_form_footer #completion_prompt_manager_popup_entry_form_close, +#completion_prompt_manager_popup .completion_prompt_manager_popup_entry_form_footer #completion_prompt_manager_popup_entry_form_reset, +#completion_prompt_manager_popup .completion_prompt_manager_popup_entry_form_footer #completion_prompt_manager_popup_entry_form_save { + font-size: 1.25em; + padding: 0.5em; +} + +#completion_prompt_manager_popup .completion_prompt_manager_popup_entry_form_control #completion_prompt_manager_popup_entry_form_prompt { + min-height: 200px; +} + +#completion_prompt_manager_popup .completion_prompt_manager_popup_entry .completion_prompt_manager_popup_entry_form_footer { + display: flex; + justify-content: space-between; + margin-top: 1em; +} + +#completion_prompt_manager #completion_prompt_manager_list .completion_prompt_manager_prompt_draggable { + cursor: grab; +} + +#completion_prompt_manager #completion_prompt_manager_list .completion_prompt_manager_prompt_name { + white-space: nowrap; + overflow: hidden; +} + +#completion_prompt_manager #completion_prompt_manager_list .completion_prompt_manager_prompt_name .prompt-manager-inspect-action { + color: var(--SmartThemeBodyColor); + cursor: pointer; +} + +#completion_prompt_manager #completion_prompt_manager_list .completion_prompt_manager_prompt_name .prompt-manager-inspect-action:hover { + text-decoration: underline; +} + +#completion_prompt_manager #completion_prompt_manager_list .completion_prompt_manager_prompt_disabled .completion_prompt_manager_prompt_name, +#completion_prompt_manager #completion_prompt_manager_list .completion_prompt_manager_prompt_disabled .completion_prompt_manager_prompt_name .prompt-manager-inspect-action { + color: var(--white30a); +} + +#completion_prompt_manager #completion_prompt_manager_list .completion_prompt_manager_prompt:not(.completion_prompt_manager_prompt_disabled) .prompt-manager-toggle-action { + color: var(--SmartThemeQuoteColor); +} + +#completion_prompt_manager #completion_prompt_manager_list .completion_prompt_manager_prompt.completion_prompt_manager_prompt_disabled { + border: 1px solid var(--white20a); +} + +#completion_prompt_manager #completion_prompt_manager_list li.completion_prompt_manager_prompt .mes_edit { + margin-left: 0.5em; +} + +#completion_prompt_manager .completion_prompt_manager_error { + padding: 1em; + border: 3px solid var(--fullred); + margin-top: 1em; + margin-bottom: 0.5em; +} + +#completion_prompt_manager .completion_prompt_manager_header { + display: flex; + flex-direction: row; + justify-content: space-between; + color: var(--white50a); + margin-top: 0.5em; + padding: 0 0.25em; + width: 100% +} + +#completion_prompt_manager .completion_prompt_manager_header div { + margin-top: 0.5em; + width: fit-content; +} + +#completion_prompt_manager .completion_prompt_manager_header_advanced { + display: flex; + margin-right: 0.25em; +} + +#completion_prompt_manager .completion_prompt_manager_header_advanced span { + flex-direction: column; + justify-content: center; + margin-left: 0.25em; + transition: 0.3s ease-in-out; + filter: drop-shadow(0px 0px 2px black); +} + +#completion_prompt_manager .completion_prompt_manager_header_advanced span.fa-solid { + display: inherit; +} + +#completion_prompt_manager .completion_prompt_manager_footer { + display: flex; + flex-direction: row; + justify-content: flex-end; + gap: 0.25em; + padding: 0 0.25em; + width: 100% +} + +#completion_prompt_manager .completion_prompt_manager_footer a { + font-size: 12px; +} + +#completion_prompt_manager .completion_prompt_manager_important a { + font-weight: 600; +} + +#completion_prompt_manager #completion_prompt_manager_list .completion_prompt_manager_prompt .completion_prompt_manager_prompt_name .fa-solid.prompt-manager-overridden { + margin-left: 3px; + color: var(--SmartThemeQuoteColor); + cursor: pointer; + opacity: 0.8; +} + +#completion_prompt_manager #completion_prompt_manager_list .completion_prompt_manager_prompt .drag-handle:not(.ui-sortable-handle) { + display: none; +} + +#completion_prompt_manager #completion_prompt_manager_list .completion_prompt_manager_prompt:has(.drag-handle.ui-sortable-handle) { + position: relative; + padding-left: 20px; +} + +#completion_prompt_manager #completion_prompt_manager_list .completion_prompt_manager_prompt .drag-handle { + position: absolute; + height: 100%; + top: 0; + padding: 0 5px; + display: flex; + align-items: center; +} + +#completion_prompt_manager_footer_append_prompt { + font-size: 1em; +} + +#prompt-manager-export-format-popup { + padding: 0.25em; + display: none; +} + +#prompt-manager-export-format-popup[data-show] { + display: block; +} + +#completion_prompt_manager_popup { + margin-top: 0; +} + +#completion_prompt_manager_popup { + overflow-y: auto; + height: calc(100% - var(--topBarBlockSize)); + position: absolute; + margin-left: auto; + margin-right: auto; + left: 0; + right: 0; + top: var(--topBarBlockSize); + box-shadow: 0 0 2px rgba(0, 0, 0, 0.5); + padding: 1em; + border: 1px solid var(--SmartThemeBorderColor); + flex-direction: column; + z-index: 3010 !important; + border-radius: 0 0 20px 20px; + background-color: var(--SmartThemeBlurTintColor); +} + +#prompt-manager-export-format-popup { + display: none; +} + +.prompt-manager-export-format-popup-flex { + display: flex; + flex-direction: column; +} + +.prompt-manager-export-format-popup-flex .row { + display: flex; + justify-content: space-between; +} + +.prompt-manager-export-format-popup-flex a, +.prompt-manager-export-format-popup-flex span { + display: flex; + margin: auto 0; + justify-content: space-between; +} + +@media screen and (max-width: 412px) { + #completion_prompt_manager_popup { + max-width: 100%; + } + + #completion_prompt_manager #completion_prompt_manager_list li.completion_prompt_manager_prompt span span span { + margin-left: 0.5em; + } +} + +.completion_prompt_manager_popup_entry_form_control:has(#completion_prompt_manager_popup_entry_form_prompt:disabled)>div:first-child::after { + content: attr(external_piece_text); + display: block; + width: 100%; + font-weight: 600; + text-align: center; +} + +.completion_prompt_manager_popup_entry_form_control #completion_prompt_manager_popup_entry_form_prompt:disabled { + visibility: hidden; +} diff --git a/jiuguan2025cc/public/css/rm-groups.css b/jiuguan2025cc/public/css/rm-groups.css new file mode 100644 index 0000000000000000000000000000000000000000..499f59873c2ddda2069e844b03132a0a2d4fc0aa --- /dev/null +++ b/jiuguan2025cc/public/css/rm-groups.css @@ -0,0 +1,236 @@ +/* GROUP CHATS */ + +.group_pagination { + display: flex; + justify-content: center; + align-items: center; +} + +#rm_group_chats_block .tag.filterByGroups { + display: none; +} + +#rm_button_group_chats h2 { + margin-top: auto; + margin-bottom: auto; + color: rgb(188, 193, 200, 1); + border: 1px solid var(--SmartThemeBorderColor); + ; + background-color: rgba(0, 0, 0, 0.3); + padding: 6px; + border-radius: 10px; +} + +#rm_group_chats_block { + display: none; + align-items: flex-start; + padding: 0 5px; + overflow-y: auto; +} + +#rm_group_chats_block h3, +#rm_group_chats_block h5 { + margin-top: 5px; + margin-bottom: 5px; +} + +#rm_group_buttons>div { + display: flex; + flex-direction: column; +} + +#rm_group_buttons .checkbox { + display: flex; +} + +#rm_group_buttons .checkbox h4 { + display: inline-block; +} + +#rm_group_buttons>input { + + cursor: pointer; + user-select: none; +} + +#rm_group_buttons>input:disabled { + filter: brightness(0.3); + cursor: unset; +} + +#rm_group_buttons textarea { + margin: 0px; + min-width: 200px; +} + +#rm_group_members, +#rm_group_add_members { + margin-top: 0.25rem; + margin-bottom: 0.5rem; + border: 1px solid var(--SmartThemeBorderColor); + border-radius: 10px; + background-color: var(--black30a); + padding: 2px; +} + +#rm_group_buttons_expander { + flex-grow: 1; +} + +#rm_group_delete { + color: rgb(190, 0, 0); +} + +#rm_group_members:empty { + width: 100%; + padding: 0.5em 0; +} + +#rm_group_members:empty::before { + content: 'Group is empty'; + + font-weight: bolder; + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + opacity: 0.8; +} + +#rm_group_add_members:empty { + width: 100%; +} + +#rm_group_add_members_header { + display: flex; + flex-direction: row; + width: 100%; + column-gap: 10px; +} + +#rm_group_add_members_header input { + flex: 1; + width: 100%; +} + +#rm_group_add_members:empty::before { + content: 'No characters available'; + + font-weight: bolder; + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + opacity: 0.8; +} + +.group_member_icon { + display: flex; + column-gap: 10px; + align-items: center; + justify-content: end; + flex-grow: 1; +} + +.group_member { + display: flex; + flex-direction: row; + align-items: center; + width: 100%; + padding: 5px; + border-radius: 10px; +} + +.group_member .group_member_name { + flex-grow: 1; + margin-left: 10px; + overflow: hidden; + text-overflow: ellipsis; + width: calc(100% - 110px); + display: flex; + gap: 5px; + height: 100%; + flex-direction: column; + justify-content: center; +} + +.group_member_icon .flex-container { + gap: 0px; +} + +#rm_group_members .right_menu_button, +#rm_group_add_members .right_menu_button { + padding: 0px; + height: 20px; + display: flex; + align-items: center; +} + +#rm_group_members .right_menu_button[data-action="speak"], +#rm_group_members .group_member:not(.disabled) .right_menu_button[data-action="disable"] { + opacity: 0.4; + filter: brightness(0.5); + transition: all 0.2s ease-in-out; +} + +/* #rm_group_members .right_menu_button[data-action="speak"]:hover, */ +#rm_group_members .group_member:not(.disabled) .right_menu_button[data-action="disable"]:hover { + opacity: inherit; + filter: drop-shadow(0px 0px 5px rgb(243, 166, 65)); +} + +#rm_group_members .group_member.disabled .right_menu_button[data-action="enable"] { + filter: drop-shadow(0px 0px 5px rgb(243, 166, 65)); +} + + +#rm_group_members .right_menu_button[data-action="speak"]:hover { + opacity: inherit; + filter: drop-shadow(0px 0px 5px rgb(153, 255, 153)); +} + +/* Rules for icon display */ +#rm_group_add_members .right_menu_button:not([data-action="add"], [data-action="view"]), +#rm_group_members .right_menu_button[data-action="add"], +#rm_group_members .group_member.disabled .right_menu_button[data-action="disable"], +#rm_group_members .group_member:not(.disabled) .right_menu_button[data-action="enable"] { + display: none; +} + +.group_select { + display: flex; + flex-direction: row; + padding: 5px; + border-radius: 10px; + cursor: pointer; +} + +.group_select:hover { + background-color: var(--white30a); +} + +.group_select .avatar { + flex: 0; +} + +.group_select .group_icon { + width: 20px; + height: 20px; + margin: 0 10px; +} + +.group_select .group_fav_icon { + filter: drop-shadow(0px 0px 1px black); + color: #c5b457; + font-size: 12px; + order: -1; + margin-left: -18px; + margin-top: 3px; +} + +.group_member .avatar { + flex-shrink: 0; + flex-basis: auto; +} diff --git a/jiuguan2025cc/public/css/scrollable-button.css b/jiuguan2025cc/public/css/scrollable-button.css new file mode 100644 index 0000000000000000000000000000000000000000..9cee2c67ab66a11960ca1b2e9a9183b89aa9974a --- /dev/null +++ b/jiuguan2025cc/public/css/scrollable-button.css @@ -0,0 +1,18 @@ +.scrollable-buttons-container { + max-height: 50vh; /* Use viewport height instead of fixed pixels */ + -webkit-overflow-scrolling: touch; /* Momentum scrolling on iOS */ + margin-top: 1rem; /* m-t-1 is equivalent to margin-top: 1rem; */ + flex-shrink: 1; + min-height: 0; + scrollbar-width: thin; + scrollbar-color: rgba(255, 255, 255, 0.3) transparent; +} + +.scrollable-buttons-container::-webkit-scrollbar { + width: 6px; +} + +.scrollable-buttons-container::-webkit-scrollbar-thumb { + background-color: rgba(255, 255, 255, 0.3); + border-radius: 3px; +} diff --git a/jiuguan2025cc/public/css/select2-overrides.css b/jiuguan2025cc/public/css/select2-overrides.css new file mode 100644 index 0000000000000000000000000000000000000000..84f758d7c4a91ff599c44fade8fd345cc83c54e7 --- /dev/null +++ b/jiuguan2025cc/public/css/select2-overrides.css @@ -0,0 +1,283 @@ +/* Customize the Select2 container */ +.select2-container { + color: var(--SmartThemeBodyColor); +} + +/* Customize the dropdown */ +.select2-dropdown { + background-color: var(--SmartThemeBlurTintColor); + border: 1px solid var(--SmartThemeBorderColor) !important; + border-radius: 10px; + box-shadow: 0 0 5px black; + text-shadow: 0px 0px calc(var(--shadowWidth) * 1px) var(--SmartThemeShadowColor); + backdrop-filter: blur(calc(var(--SmartThemeBlurStrength)*2)); + color: var(--SmartThemeBodyColor); + z-index: 40000; +} + +.select2-container .select2-selection .select2-selection__clear { + color: var(--SmartThemeBodyColor); + font-size: 20px; + padding: 0; + position: absolute; + right: 5px; + top: 0; +} + +.select2-container .select2-search__field { + opacity: 0.8; +} + +.select2-selection--single .select2-selection__placeholder { + color: var(--SmartThemeEmColor); +} + +.select2-container--classic .select2-selection--single .select2-selection__placeholder { + color: var(--SmartThemeEmColor); +} + +.select2-container .select2-selection--single .select2-selection__rendered { + color: var(--SmartThemeBodyColor); + line-height: revert; + padding-left: unset; +} + +.select2-container .select2-results>.select2-results__options { + max-height: 300px; +} + +.select2-container .select2-selection--multiple .select2-selection__choice__remove { + padding: revert; + border-right: 1px solid var(--SmartThemeBorderColor); + font-size: 1.1em; + line-height: 1; +} + +.select2-container .select2-selection--multiple .select2-selection__choice__display { + padding-left: 5px; +} + +/* Customize the search input */ +.select2-search__field { + background-color: var(--black30a); + color: var(--SmartThemeBodyColor); + border: 1px solid var(--SmartThemeBorderColor); + border-radius: 7px; + font-family: var(--mainFontFamily); + padding: 3px 5px; +} + +/* Customize the selected option */ +.select2-selection--single { + border: 1px solid var(--SmartThemeShadowColor); + border-radius: 4px; + background-color: var(--SmartThemeBlurTintColor); +} + +/* Customize the selected option text */ +.select2-selection__rendered { + color: var(--SmartThemeBodyColor); +} + +/* Customize the option list item */ +.select2-results__option { + color: var(--SmartThemeBodyColor); + background-color: var(--SmartThemeBodyColor); +} + +.select2-container .select2-selection--multiple, +.select2-container .select2-selection--single { + background-color: var(--black30a); + color: var(--SmartThemeBodyColor); + border: 1px solid var(--SmartThemeBorderColor); + border-radius: 7px; + font-family: var(--mainFontFamily); + padding: 3px 5px; +} + +.select2-container.select2-container--focus .select2-selection--multiple, +.select2-container.select2-container--focus .select2-selection--single { + border: 1px solid var(--SmartThemeBorderColor); +} + +.select2-container .select2-results .select2-results__option--disabled { + color: inherit; + background-color: inherit; + cursor: not-allowed; + filter: brightness(0.5); +} + +.select2-container .select2-selection--multiple .select2-selection__choice, +.select2-container .select2-selection--single .select2-selection__choice { + border-radius: 5px; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + color: var(--SmartThemeBodyColor); + background-color: var(--black30a); + border-color: var(--SmartThemeBorderColor); + font-size: calc(var(--mainFontSize) - 5%); + text-shadow: none !important; +} + +.select2-results .select2-results__option--selectable { + background-color: unset; + color: var(--SmartThemeBodyColor); + opacity: 0.5; + transition: opacity 200ms ease-in-out; + position: relative; +} + +.select2-results .select2-results__option--group { + color: var(--SmartThemeBodyColor); + background-color: var(--SmartThemeBlurTintColor); + position: relative; +} + +/* Customize the hovered option list item */ +.select2-results .select2-results__option--highlighted.select2-results__option--selectable { + color: var(--SmartThemeBodyColor); + background-color: unset; + opacity: 1; +} + +.select2-results__option.select2-results__option--group::before { + display: none; +} + +/* Customize the option list item */ +.select2-results__option { + padding-left: 30px; + /* Add some padding to make room for the checkbox */ +} + +.select2-results .select2-results__option--group .select2-results__options--nested .select2-results__option { + padding-left: 2em; +} + +/* Add the custom checkbox */ +.select2-results__option::before { + content: ''; + display: inline-block; + position: absolute; + left: 6px; + top: 50%; + margin-top: -7px; + width: 14px; + height: 14px; + border: 1px solid var(--SmartThemeBorderColor); + background-color: var(--SmartThemeBlurTintColor); + border-radius: 2px; +} + +.select2-container .select2-selection--multiple .select2-selection__choice__remove, +.select2-container .select2-selection--single .select2-selection__choice__remove { + color: var(--SmartThemeBodyColor); +} + +/* Add the custom checkbox checkmark */ +.select2-results__option--selected.select2-results__option::before { + content: '\2713'; + font-weight: bold; + color: var(--SmartThemeBodyColor); + background-color: var(--SmartThemeBlurTintColor); + text-align: center; + line-height: 14px; +} + +.select2-results__option.select2-results__message { + background-color: inherit; +} + +.select2-results__option.select2-results__message::before { + display: none; +} + +.select2-selection__choice__display { + /* Fix weird alignment of the inside block */ + margin-left: 3px; + margin-right: 1px; +} + +/* Styling for choice remove icon */ +span.select2.select2-container .select2-selection__choice__remove { + cursor: pointer; + transition: background-color 0.3s; + color: var(--SmartThemeBodyColor); + background-color: var(--black50a); +} + +span.select2.select2-container .select2-selection__choice__remove:hover { + color: var(--SmartThemeBodyColor); + background-color: var(--white30a); +} + +/* Custom class to support styling to show clickable choice options */ +.select2_choice_clickable+span.select2-container .select2-selection__choice__display { + cursor: pointer; +} + +.select2_choice_clickable_buttonstyle+span.select2-container .select2-selection__choice__display { + cursor: pointer; + transition: background-color 0.3s; + color: var(--SmartThemeBodyColor); + background-color: var(--black50a); + white-space: break-spaces; + word-break: break-all; +} + +.select2_choice_clickable_buttonstyle+span.select2-container .select2-selection__choice__display:hover { + background-color: var(--white30a); +} + +/* Custom class to support same line multi inputs of select2 controls */ +.select2_multi_sameline+span.select2-container .select2-selection--multiple { + display: flex; + flex-wrap: wrap; +} + +.select2_multi_sameline+span.select2-container .select2-selection--multiple .select2-search--inline { + /* Allow search placeholder to take up all space if needed */ + flex-grow: 1; +} + +.select2_multi_sameline+span.select2-container .select2-selection--multiple .select2-selection__rendered { + /* Fix weird styling choice or huge margin around selected options */ + margin-block-start: 2px; + margin-block-end: 2px; + display: flex; + align-items: center; + flex-wrap: wrap; + row-gap: 5px; +} + +.select2_multi_sameline+span.select2-container .select2-selection--multiple .select2-selection__choice { + margin-top: 0px; +} + +.select2_multi_sameline+span.select2-container .select2-selection--multiple .select2-search__field { + /* Min height to reserve spacing */ + min-height: calc(var(--mainFontSize) + 13px); + /* Min width to be clickable */ + min-width: 4em; + align-content: center; + /* Fix search textarea alignment issue with UL elements */ + margin-top: 0px; + height: unset; + /* Prevent height from jumping around when input is focused */ + line-height: 1; +} + +.select2_multi_sameline+span.select2-container .select2-selection--multiple .select2-selection__rendered { + /* Min height to reserve spacing */ + min-height: calc(var(--mainFontSize) + 13px); +} + +/* Make search bar invisible unless the select2 is active, to save space */ +.select2_multi_sameline+span.select2-container .select2-selection--multiple .select2-search--inline { + height: 1px; +} + +.select2_multi_sameline+span.select2-container.select2-container--focus .select2-selection--multiple .select2-search--inline { + height: unset; +} diff --git a/jiuguan2025cc/public/css/select2.min.css b/jiuguan2025cc/public/css/select2.min.css new file mode 100644 index 0000000000000000000000000000000000000000..39a4547ff6bf750e7be6a5345138436a31215390 --- /dev/null +++ b/jiuguan2025cc/public/css/select2.min.css @@ -0,0 +1 @@ +.select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{background-color:transparent;border:none;font-size:1em}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline;list-style:none;padding:0}.select2-container .select2-selection--multiple .select2-selection__clear{background-color:transparent;border:none;font-size:1em}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;margin-left:5px;padding:0;max-width:100%;resize:none;height:18px;vertical-align:bottom;font-family:sans-serif;overflow:hidden;word-break:keep-all}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:white;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option--selectable{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0 !important;clip:rect(0 0 0 0) !important;-webkit-clip-path:inset(50%) !important;clip-path:inset(50%) !important;height:1px !important;overflow:hidden !important;padding:0 !important;position:absolute !important;width:1px !important;white-space:nowrap !important}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;height:26px;margin-right:20px;padding-right:0px}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--default .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;padding-bottom:5px;padding-right:5px;position:relative}.select2-container--default .select2-selection--multiple.select2-selection--clearable{padding-right:25px}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;font-weight:bold;height:20px;margin-right:10px;margin-top:5px;position:absolute;right:0;padding:1px}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:inline-block;margin-left:5px;margin-top:5px;padding:0;padding-left:20px;position:relative;max-width:100%;overflow:hidden;text-overflow:ellipsis;vertical-align:bottom;white-space:nowrap}.select2-container--default .select2-selection--multiple .select2-selection__choice__display{cursor:default;padding-left:2px;padding-right:5px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{background-color:transparent;border:none;border-right:1px solid #aaa;border-top-left-radius:4px;border-bottom-left-radius:4px;color:#999;cursor:pointer;font-size:1em;font-weight:bold;padding:0 4px;position:absolute;left:0;top:0}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover,.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:focus{background-color:#f1f1f1;color:#333;outline:none}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__display{padding-left:5px;padding-right:2px}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{border-left:1px solid #aaa;border-right:none;border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:4px;border-bottom-right-radius:4px}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__clear{float:left;margin-left:10px;margin-right:auto}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid black 1px;outline:0}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--default .select2-search--dropdown .select2-search__field{border:1px solid #aaa}.select2-container--default .select2-search--inline .select2-search__field{background:transparent;border:none;outline:0;box-shadow:none;-webkit-appearance:textfield}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em}.select2-container--default .select2-results__option--group{padding:0}.select2-container--default .select2-results__option--disabled{color:#999}.select2-container--default .select2-results__option--selected{background-color:#ddd}.select2-container--default .select2-results__option--highlighted.select2-results__option--selectable{background-color:#5897fb;color:white}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:#f7f7f7;border:1px solid #aaa;border-radius:4px;outline:0;background-image:-webkit-linear-gradient(top, #fff 50%, #eee 100%);background-image:-o-linear-gradient(top, #fff 50%, #eee 100%);background-image:linear-gradient(to bottom, #fff 50%, #eee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;height:26px;margin-right:20px}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eee 50%, #ccc 100%);background-image:-o-linear-gradient(top, #eee 50%, #ccc 100%);background-image:linear-gradient(to bottom, #eee 50%, #ccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0)}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, #fff 0%, #eee 50%);background-image:-o-linear-gradient(top, #fff 0%, #eee 50%);background-image:linear-gradient(to bottom, #fff 0%, #eee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eee 50%, #fff 100%);background-image:-o-linear-gradient(top, #eee 50%, #fff 100%);background-image:linear-gradient(to bottom, #eee 50%, #fff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;outline:0;padding-bottom:5px;padding-right:5px}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;display:inline-block;margin-left:5px;margin-top:5px;padding:0}.select2-container--classic .select2-selection--multiple .select2-selection__choice__display{cursor:default;padding-left:2px;padding-right:5px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{background-color:transparent;border:none;border-top-left-radius:4px;border-bottom-left-radius:4px;color:#888;cursor:pointer;font-size:1em;font-weight:bold;padding:0 4px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555;outline:none}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__display{padding-left:5px;padding-right:2px}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:4px;border-bottom-right-radius:4px}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;box-shadow:none}.select2-container--classic .select2-dropdown{background-color:#fff;border:1px solid transparent}.select2-container--classic .select2-dropdown--above{border-bottom:none}.select2-container--classic .select2-dropdown--below{border-top:none}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--classic .select2-results__option--group{padding:0}.select2-container--classic .select2-results__option--disabled{color:grey}.select2-container--classic .select2-results__option--highlighted.select2-results__option--selectable{background-color:#3875d7;color:#fff}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb} diff --git a/jiuguan2025cc/public/css/solid.min.css b/jiuguan2025cc/public/css/solid.min.css new file mode 100644 index 0000000000000000000000000000000000000000..e7d97d261527801d14db9d51d33d1e507a92eacc --- /dev/null +++ b/jiuguan2025cc/public/css/solid.min.css @@ -0,0 +1,6 @@ +/*! + * Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-solid:normal 900 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}.fa-solid,.fas{font-weight:900} \ No newline at end of file diff --git a/jiuguan2025cc/public/css/st-tailwind.css b/jiuguan2025cc/public/css/st-tailwind.css new file mode 100644 index 0000000000000000000000000000000000000000..e40041c3c15a50aff0bd8cfe51adef1c616a479e --- /dev/null +++ b/jiuguan2025cc/public/css/st-tailwind.css @@ -0,0 +1,613 @@ +.text_warning { + color: rgb(220 173 16); +} + +.text_danger { + color: var(--fullred); +} + +.highlighted { + color: black; + background-color: yellow; + text-shadow: none !important; +} + +.m-t-0 { + margin-top: 0; +} + +.m-t-1 { + margin-top: 1em; +} + +.m-t-2 { + margin-top: 2em; +} + +.m-t-3 { + margin-top: 3em; +} + +.m-t-4 { + margin-top: 4em; +} + +.m-t-5 { + margin-top: 5em; +} + +.m-b-1 { + margin-bottom: 1em; +} + +.m-b-2 { + margin-bottom: 2em; +} + +.m-b-3 { + margin-bottom: 3em; +} + +.m-b-4 { + margin-bottom: 4em; +} + +.m-b-5 { + margin-bottom: 5em; +} + +.tooltip { + cursor: help; +} + +.margin-bot-10px, +.marginBot10 { + margin-bottom: 10px !important; +} + +.marginTop10 { + margin-top: 10px !important; +} + +.marginBot5 { + margin-bottom: 5px !important; +} + +.marginTop5 { + margin-top: 5px !important; +} + +.marginTopBot5 { + margin-top: 5px !important; + margin-bottom: 5px !important; +} + +.margin5 { + margin: 5px; +} + +.marginLeft5 { + margin-left: 5px; +} + +.overflowYAuto { + overflow-y: auto; +} + +.heightMinContent { + height: min-content; +} + +.justifySpaceBetween { + justify-content: space-between; +} + +.justifySpaceEvenly { + justify-content: space-evenly; +} + +.justifySpaceAround { + justify-content: space-around; +} + +.alignitemsflexstart { + align-items: flex-start !important; +} + +.alignItemsFlexEnd { + align-items: flex-end !important; +} + +.alignItemsBaseline { + align-items: baseline !important; +} + +.alignSelfStart { + align-self: start; +} + +.gap0 { + gap: 0 !important; +} + +.gap3px { + gap: 3px !important; +} + +.gap5px { + gap: 5px !important; +} + +.gap10px { + gap: 10px !important; +} + +.gap10h20v { + gap: 10px 20px !important; +} + +.gap10h5v { + gap: 5px 10px !important; +} + +.wide10pMinFit { + width: 10%; + min-width: fit-content; +} + +.wide100pLess70px { + width: calc(100% - 70px); +} + +.wideMax100px { + max-width: 100px; +} + +.width100px { + width: 100px; +} + +.widthUnset { + width: unset; +} + +.no-border { + border: none !important; +} + +.no-shadow { + box-shadow: none !important; +} + +.height100p { + height: 100%; +} + +.height100pSpaceEvenly { + align-content: space-evenly; + height: 100%; +} + +.height32px { + height: 32px; +} + +.TxtLrgBoldCenter { + text-align: center; + font-size: large; + font-weight: 600; +} + +.textAlignCenter { + text-align: center; +} + +.margin-right-10px { + margin-right: 10px; +} + + +.success { + color: green; +} + +.failure { + color: red; +} + +.optional { + color: lightgray; +} + +.monospace { + font-family: var(--monoFontFamily); +} + +.expander { + flex-grow: 1; +} + +.redOverlayGlow { + color: #800; + opacity: 0.8 !important; + text-shadow: none !important; +} + +.width100p { + width: 100%; +} + +.flex { + display: flex; +} + +.flexBasis100p { + flex-basis: 100%; +} + +.flexBasis50p { + flex-basis: 50% +} + +.flexBasis25p { + flex-basis: 25% +} + +.flexBasis200px { + flex-basis: 200px +} + +.flexBasis48p { + flex-basis: 48% +} + +.flexBasis30p { + flex-basis: 30%; +} + +.flex-container { + display: flex; + gap: 5px; + flex-wrap: wrap; +} + +.flexNoGap { + gap: unset !important; +} + +.flexGrow { + flex-grow: 1; +} + +.flexShrink { + flex-shrink: 1 +} + +.flexWrap { + flex-wrap: wrap; +} + +.flexnowrap, +.flexNoWrap { + flex-wrap: nowrap; +} + +.inline-flex { + display: inline-flex; +} + +.inline-block { + display: inline-block; +} + +.alignitemscenter, +.alignItemsCenter { + align-items: center; +} + +.alignitemsstart, +.alignItemsStart { + align-items: start; +} + +.overflow-hidden { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.maxWidth200px { + max-width: 200px; +} + +.alignContentFlexStart { + align-content: flex-start; +} + +.alignContentCenter { + align-content: center; +} + +.overflowHidden { + overflow: hidden; +} + +.padding0 { + padding: 0; +} + +.padding5 { + padding: 5px; +} + +.padding10 { + padding: 10px; +} + +.margin0 { + margin: 0; +} + +.margin0auto { + margin: 0 auto; +} + +.margin-r5 { + margin-right: 5px; +} + +.margin-r2 { + margin-right: 2px; +} + +.flexAuto { + flex: auto; +} + +.flex0 { + flex: 0; +} + +.flex1 { + flex: 1; +} + +.flex2 { + flex: 2 !important; +} + +.flex3 { + flex: 3; +} + +.flex4 { + flex: 4; +} + +.flexFlowColumn { + flex-flow: column; +} + +.flexFlowRow { + flex-flow: row; +} + +.wideMinContent { + width: min-content; +} + +.flexWide50p { + flex: 50%; +} + +.wide25p { + width: 25%; +} + +.wide30p { + width: 30% !important; +} + +.justifyLeft { + text-align: start; + justify-content: left; + margin-left: unset; +} + +.justifyCenter { + justify-content: center; + margin: 0 auto; +} + +.justifyContentSpaceAround { + justify-content: space-around; +} + +.justifyContentFlexStart { + justify-content: flex-start; +} + +.justifyContentFlexEnd { + justify-content: flex-end; +} + +.spaceEvenly { + justify-content: space-evenly; +} + +.spaceBetween { + justify-content: space-between; +} + +.widthNatural { + width: unset !important; + min-width: unset !important; + max-width: unset !important; +} + +.widthFreeExpand { + width: -webkit-fill-available; + width: -moz-available; +} + +.wide100p { + width: 100%; +} + +.wide50p { + width: 50%; +} + +.wide50px { + width: 50px; +} + +.indent20p { + margin-left: 20px; +} + +/*used to fix smallness of certain FontAwesome glyph which break button squareness*/ +/*currently used on: CharList Import*/ + +.faSmallFontSquareFix { + font-size: calc(var(--mainFontSize) *1.25); + width: calc(var(--mainFontSize) *1.95); +} + +.textarea_compact { + font-size: calc(var(--mainFontSize) * 0.95); + line-height: 1.2; +} + +.hoverglow { + transition: opacity 200ms; +} + +.hoverglow:hover { + opacity: 1 !important; + cursor: pointer; +} + +input:disabled, +textarea:disabled { + cursor: not-allowed; + filter: brightness(0.5); +} + +#AdvancedFormatting .disabled { + filter: brightness(0.5); +} + +.debug-red { + border: 1px solid red !important; +} + +.debug-yellow { + border: 1px solid yellow !important; +} + +.debug-green { + border: 1px solid green !important; +} + +.debug-blue { + border: 1px solid blue !important; +} + +.debug-purple { + border: 1px solid purple !important; +} + +.fontsize120p { + font-size: calc(var(--mainFontSize) * 1.2) !important; +} + +.fontsize90p { + font-size: calc(var(--mainFontSize) * 0.9) !important; +} + +.fontsize80p { + font-size: calc(var(--mainFontSize) * 0.8) !important; +} + +.fontsize60p { + font-size: calc(var(--mainFontSize) * 0.6) !important; +} + +.paddingBottom5px { + padding: unset; + padding-bottom: 5px; +} + +.paddingTopBot5 { + padding: 5px 0; +} + +.paddingLeftRight5 { + padding: 0 5px; +} + +.heightFitContent { + height: fit-content; +} + +.widthFitContent { + width: fit-content; + min-width: fit-content; +} + +.flexGap5 { + gap: 5px; +} + +.flexGap10 { + gap: 10px; +} + +.opacity50p { + opacity: 0.5 +} + +.grayscale { + filter: grayscale(100%); +} + +.opacity1 { + opacity: 1 !important; +} + +.circleborder30px { + right: 30px; + top: 10px; + position: absolute; + border: 1px solid var(--SmartThemeBodyColor); + border-radius: 100%; + aspect-ratio: 1 / 1; + height: 30px; + text-align: center; + padding: 5px; +} + +ul.li-padding-b-1 li { + padding-bottom: 1em; +} + +ul.li-padding-b-2 li { + padding-bottom: 2em; +} + +ul.li-padding-b-5 li { + padding-bottom: 5em; +} + +ul.li-padding-bot5 li { + padding-bottom: 5px; +} + +ul.li-padding-bot10 li { + padding-bottom: 10px; +} + +.wordBreakAll { + word-break: break-all; +} diff --git a/jiuguan2025cc/public/css/tags.css b/jiuguan2025cc/public/css/tags.css new file mode 100644 index 0000000000000000000000000000000000000000..fb2c165fedd8c8ddcf944ba330faf16e9c628e0d --- /dev/null +++ b/jiuguan2025cc/public/css/tags.css @@ -0,0 +1,286 @@ +#bulk_tags_div, +#tags_div { + min-width: 0; +} + +.tag_controls { + display: flex; + flex-direction: row; + gap: 5px; + align-items: center; +} + +.tag_view_item { + display: flex; + flex-direction: row; + align-items: center; + gap: 6px; + margin-bottom: 5px; +} + +.tag_view_name { + text-align: left; +} + +.tag_view_counter { + text-align: right; + flex: 1; +} + +.tag_view_color_picker { + position: relative; +} + +.tag_view_color_picker .link_icon { + position: absolute; + top: 50%; + right: 0px; + opacity: 0.5; +} + +.tag_delete { + padding: 2px 4px; + color: var(--SmartThemeBodyColor) !important; +} + +.tag { + border-radius: 5px; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + color: var(--SmartThemeBodyColor); + background-color: var(--black30a); + border-color: var(--white50a); + padding: 0.1rem 0.2rem; + font-size: calc(var(--mainFontSize) - 5%); + display: flex; + flex-direction: row; + align-items: center; + position: relative; + gap: 10px; + width: fit-content; + min-width: 0; + text-shadow: none !important; +} + +.rm_tag_filter .tag:not(.actionable) { + display: none; +} + +.tag.actionable { + border-radius: 50%; + aspect-ratio: 1 / 1; + min-height: calc(var(--mainFontSize) * 2); + min-width: calc(var(--mainFontSize) * 2); + font-size: calc(var(--mainFontSize) * 1); + padding: 0; + display: flex; + justify-content: center; + align-items: center; +} + +.tag.actionable.clearAllFilters { + border: 0; + background: none; +} + +.tag.placeholder-expander { + cursor: alias; + border: 0; +} + +.tagListHint { + align-self: center; + display: flex; + margin-right: 10px; +} + +.tag_remove { + cursor: pointer; +} + +.tags { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: flex-start; + gap: 0.2rem; + align-items: flex-end; +} + +#bulkTagsList, +#tagList.tags { + margin: 5px 0; +} + +#bulkTagsList, +#tagList .tag, +#groupTagList .tag { + opacity: 0.6; +} + +#tagList .tag:has(.tag_remove:hover) { + opacity: 1; +} + +#tagList .tag:has(.tag_remove:hover) .tag_name { + opacity: 0.6; +} + +.tags.tags_inline { + opacity: 0.6; + column-gap: 0.2rem; + row-gap: 0.2rem; + justify-content: flex-start; + max-height: 66%; + overflow: hidden; + flex-basis: 100%; +} + +.tag_name { + text-overflow: ellipsis; + overflow: hidden; + text-align: left; + white-space: nowrap; + text-shadow: none !important; +} + +.tags_inline .tag { + font-size: calc(var(--mainFontSize) - 15%); + padding: 0 0.15rem; +} + +.rm_tag_controls { + display: flex; + column-gap: 10px; + row-gap: 5px; + flex-direction: row; + flex-wrap: wrap; + align-items: flex-start; + margin: 5px; +} + +.rm_tag_filter .tag { + cursor: pointer; + opacity: 0.6; + filter: brightness(0.8); +} + +.rm_tag_filter .tag.actionable { + transition: opacity 200ms; +} + +.rm_tag_filter .tag:hover { + opacity: 1; + filter: brightness(1); +} + +.tags_view { + margin: 0; + aspect-ratio: 1 / 1; +} + +.tag.selected { + opacity: 1 !important; + filter: none !important; +} + +.tag.excluded { + opacity: 1 !important; + filter: saturate(0.4) !important; + border: 1px solid red; +} + +.tag.excluded::after { + position: absolute; + height: calc(var(--mainFontSize)*1.5); + left: 0; + right: 0; + content: "\d7"; + pointer-events: none; + font-size: calc(var(--mainFontSize) *3); + color: red; + line-height: calc(var(--mainFontSize)*1.3); + text-align: center; + text-shadow: 1px 1px 0px black, + -1px -1px 0px black, + -1px 1px 0px black, + 1px -1px 0px black; + opacity: 1; +} + +.tag_as_folder.right_menu_button { + filter: brightness(75%) saturate(0.6); +} + +.tag_as_folder.right_menu_button:hover, +.tag_as_folder.right_menu_button.flash { + filter: brightness(150%) saturate(0.6); +} + +.tag_as_folder.right_menu_button.no_folder { + filter: brightness(25%) saturate(0.25); +} + +.tag_as_folder.right_menu_button .tag_folder_indicator { + position: absolute; + top: calc(var(--mainFontSize) * -0.5); + right: calc(var(--mainFontSize) * -0.5); + font-size: calc(var(--mainFontSize) * 1); + line-height: calc(var(--mainFontSize) * 1.3); + text-align: center; + text-shadow: 1px 1px 0px black, + -1px -1px 0px black, + -1px 1px 0px black, + 1px -1px 0px black; + opacity: 1; +} + +.tag.indicator::after { + position: absolute; + top: calc(var(--mainFontSize) * -0.5); + right: -2px; + content: "\25CF"; + font-size: calc(var(--mainFontSize) * 1); + color: var(--SmartThemeBodyColor); + line-height: calc(var(--mainFontSize) * 1.3); + text-align: center; + text-shadow: 1px 1px 0px black, + -1px -1px 0px black, + -1px 1px 0px black, + 1px -1px 0px black; + opacity: 1; +} + +.rm_tag_bogus_drilldown { + height: calc(var(--mainFontSize)* 2 - 2); +} + +.rm_tag_bogus_drilldown .tag:not(:first-child) { + position: relative; + margin-left: 1em; +} + +.rm_tag_bogus_drilldown .tag:not(:first-child)::before { + font-family: 'Font Awesome 6 Free'; + content: "\f054"; + position: absolute; + left: -1em; + top: auto; + color: var(--SmartThemeBodyColor); + text-shadow: 1px 1px 0px black, + -1px -1px 0px black, + -1px 1px 0px black, + 1px -1px 0px black; + opacity: 1; +} + +.bogus_folder_select_back .avatar { + display: none !important; +} + +.bogus_folder_select_back .bogus_folder_back_placeholder { + min-height: calc(var(--mainFontSize)*2); + width: var(--avatar-base-width); + justify-content: center; +} diff --git a/jiuguan2025cc/public/css/toastr.min.css b/jiuguan2025cc/public/css/toastr.min.css new file mode 100644 index 0000000000000000000000000000000000000000..643135ea0afb93b8dd90bfb697e693990a89fec9 --- /dev/null +++ b/jiuguan2025cc/public/css/toastr.min.css @@ -0,0 +1 @@ +/* * Note that this is toastr v2.1.3, the "latest" version in url has no more maintenance, * please go to https://cdnjs.com/libraries/toastr.js and pick a certain version you want to use, * make sure you copy the url from the website since the url may change between versions. * */ .toast-title{font-weight:700}.toast-message{-ms-word-wrap:break-word;word-wrap:break-word}.toast-message a,.toast-message label{color:#FFF}.toast-message a:hover{color:#CCC;text-decoration:none}.toast-close-button{position:relative;right:-.3em;top:-.3em;float:right;font-size:20px;font-weight:700;color:#FFF;-webkit-text-shadow:0 1px 0 #fff;text-shadow:0 1px 0 #fff;opacity:.8;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);filter:alpha(opacity=80);line-height:1}.toast-close-button:focus,.toast-close-button:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)}.rtl .toast-close-button{left:-.3em;float:left;right:.3em}button.toast-close-button{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.toast-top-center{top:0;right:0;width:100%}.toast-bottom-center{bottom:0;right:0;width:100%}.toast-top-full-width{top:0;right:0;width:100%}.toast-bottom-full-width{bottom:0;right:0;width:100%}.toast-top-left{top:12px;left:12px}.toast-top-right{top:12px;right:12px}.toast-bottom-right{right:12px;bottom:12px}.toast-bottom-left{bottom:12px;left:12px}#toast-container{position:fixed;z-index:999999;pointer-events:none}#toast-container *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}#toast-container>div{position:relative;pointer-events:auto;overflow:hidden;margin:0 0 6px;padding:15px 15px 15px 50px;width:300px;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;background-position:15px center;background-repeat:no-repeat;-moz-box-shadow:0 0 12px #999;-webkit-box-shadow:0 0 12px #999;box-shadow:0 0 12px #999;color:#FFF;opacity:.8;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);filter:alpha(opacity=80)}#toast-container>div.rtl{direction:rtl;padding:15px 50px 15px 15px;background-position:right 15px center}#toast-container>div:hover{-moz-box-shadow:0 0 12px #000;-webkit-box-shadow:0 0 12px #000;box-shadow:0 0 12px #000;opacity:1;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);filter:alpha(opacity=100);cursor:pointer}#toast-container>.toast-info{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=)!important}#toast-container>.toast-error{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=)!important}#toast-container>.toast-success{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==)!important}#toast-container>.toast-warning{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=)!important}#toast-container.toast-bottom-center>div,#toast-container.toast-top-center>div{width:300px;margin-left:auto;margin-right:auto}#toast-container.toast-bottom-full-width>div,#toast-container.toast-top-full-width>div{width:96%;margin-left:auto;margin-right:auto}.toast{background-color:#030303}.toast-success{background-color:#51A351}.toast-error{background-color:#BD362F}.toast-info{background-color:#2F96B4}.toast-warning{background-color:#F89406}.toast-progress{position:absolute;left:0;bottom:0;height:4px;background-color:#000;opacity:.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)}@media all and (max-width:240px){#toast-container>div{padding:8px 8px 8px 50px;width:11em}#toast-container>div.rtl{padding:8px 50px 8px 8px}#toast-container .toast-close-button{right:-.2em;top:-.2em}#toast-container .rtl .toast-close-button{left:-.2em;right:.2em}}@media all and (min-width:241px) and (max-width:480px){#toast-container>div{padding:8px 8px 8px 50px;width:18em}#toast-container>div.rtl{padding:8px 50px 8px 8px}#toast-container .toast-close-button{right:-.2em;top:-.2em}#toast-container .rtl .toast-close-button{left:-.2em;right:.2em}}@media all and (min-width:481px) and (max-width:768px){#toast-container>div{padding:15px 15px 15px 50px;width:25em}#toast-container>div.rtl{padding:15px 50px 15px 15px}} \ No newline at end of file diff --git a/jiuguan2025cc/public/css/toggle-dependent.css b/jiuguan2025cc/public/css/toggle-dependent.css new file mode 100644 index 0000000000000000000000000000000000000000..d582cbbd85ad850cb4d6133069555d2028d52d15 --- /dev/null +++ b/jiuguan2025cc/public/css/toggle-dependent.css @@ -0,0 +1,500 @@ +:root { + --big-avatar-height-factor: 1.8; + --big-avatar-width-factor: 1.2; + --big-avatar-border-factor: 5; +} + +body.tts .mes[is_system="true"] .mes_narrate { + display: none; +} + +body.sd .sd_message_gen, +body.translate .mes_translate, +body.tts .mes_narrate { + display: inline-block; +} + +body:not(.tts) #ttsExtensionNarrateAll { + display: none; +} + +body.no-hotswap .hotswap, +body.no-timer .mes_timer, +body.no-timestamps .timestamp, +body.no-tokenCount .tokenCounterDisplay, +body.no-mesIDDisplay .mesIDDisplay, +body.no-modelIcons .icon-svg, +body.hideChatAvatars .mesAvatarWrapper .avatar { + display: none !important; +} + +body.hideChatAvatars .last_mes:not(.smallSysMes) { + padding-bottom: 20px !important; +} + +body.hideChatAvatars.no-timer.no-tokenCount.no-mesIDDisplay .swipe_left { + left: 0px; +} + +body.hideChatAvatars .swipe_left { + left: 7px; +} + +body.square-avatars .avatar, +body.square-avatars .avatar img { + border-radius: var(--avatar-base-border-radius) !important; +} + +/*char list grid mode*/ + +body.charListGrid #rm_print_characters_block { + display: flex; + gap: 5px; + flex-wrap: wrap; + flex-direction: row; + justify-content: space-around; + align-content: flex-start; +} + +body.charListGrid #rm_print_characters_block .bogus_folder_select, +body.charListGrid #rm_print_characters_block .character_select, +body.charListGrid #rm_print_characters_block .group_select, +#user_avatar_block.gridView .avatar-container { + width: 30%; + align-items: flex-start; + height: min-content; + flex-direction: column; + overflow: hidden; + max-width: 100px; +} + +/* Save a bit of space here */ +body.charListGrid #rm_print_characters_block .character_name_block { + gap: 0; + margin-bottom: 0; +} + +body.charListGrid #rm_print_characters_block .bogus_folder_select .ch_name, +body.charListGrid #rm_print_characters_block .bogus_folder_select .bogus_folder_counter, +body.charListGrid #rm_print_characters_block .character_select .ch_name, +body.charListGrid #rm_print_characters_block .group_select .ch_name, +body.charListGrid #rm_print_characters_block .group_select .group_select_counter, +#user_avatar_block.gridView .avatar-container .ch_name, +#user_avatar_block.gridView .avatar-container .bogus_folder_counter, +#user_avatar_block.gridView .avatar-container .group_select_counter { + width: 100%; + max-width: 100px; + text-align: center; + font-size: calc(var(--mainFontSize) * .8); +} + +body.charListGrid #rm_print_characters_block .bogus_folder_select .character_name_block, +body.charListGrid #rm_print_characters_block .character_select .character_name_block, +body.charListGrid #rm_print_characters_block .group_select .group_name_block, +#user_avatar_block.gridView .avatar-container .character_name_block { + width: 100%; + flex-direction: column; +} + +body.charListGrid #rm_print_characters_block .bogus_folder_select .character_select_container, +body.charListGrid #rm_print_characters_block .character_select .character_select_container, +body.charListGrid #rm_print_characters_block .group_select .group_select_container, +#user_avatar_block.gridView .avatar-container .character_select_container, +#user_avatar_block.gridView .avatar-container .group_select_container { + width: 100%; + justify-content: center; + max-width: 100px; +} + +body.charListGrid #rm_print_characters_block .group_select { + width: 30%; + height: min-content; + align-items: center !important; + flex-direction: column; + overflow: hidden; + max-width: 100px; +} + +body.charListGrid #rm_print_characters_block .group_select .group_name_block { + width: 100%; +} + +body.charListGrid #rm_print_characters_block .ch_description, +body.charListGrid #rm_print_characters_block .tags_inline, +body.charListGrid #rm_print_characters_block .group_select_block_list, +body.charListGrid #rm_print_characters_block .ch_avatar_url, +body.charListGrid #rm_print_characters_block .character_version, +body.charListGrid #rm_print_characters_block .character_name_block_sub_line, +#user_avatar_block.gridView .avatar-container .ch_description, +body.charListGrid #rm_print_characters_block .bogus_folder_select_back .bogus_folder_back_placeholder { + display: none; +} + +body.charListGrid #rm_print_characters_block .bogus_folder_select_back .avatar { + display: flex !important; +} + +/* Hack for keeping the spacing */ +/* +body.charListGrid #rm_print_characters_block .ch_add_placeholder { + display: flex !important; + opacity: 0; +} +*/ + +body.charListGrid #rm_print_characters_block .ch_additional_info { + display: none; +} + +/*big avatars mode page-wide changes*/ + +body.big-avatars .character_select .avatar, +body.big-avatars .group_select .avatar, +body.big-avatars .bogus_folder_select .avatar { + flex: unset; +} + +body.big-avatars .avatar { + width: calc(var(--avatar-base-width) * var(--big-avatar-width-factor)); + height: calc(var(--avatar-base-height) * var(--big-avatar-height-factor)); + /* width: unset; */ + border-style: none; + display: flex; + justify-content: center; + flex-direction: column; + align-items: center; + /* align-self: unset; */ + overflow: visible; + border-radius: calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)); +} + +body.big-avatars #user_avatar_block .avatar, +body.big-avatars #user_avatar_block .avatar_upload { + width: calc(var(--avatar-base-width) * var(--big-avatar-width-factor)); + height: calc(var(--avatar-base-height) * var(--big-avatar-height-factor)); + border-radius: calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)); +} + +body.big-avatars #user_avatar_block .avatar img { + width: calc(var(--avatar-base-width) * var(--big-avatar-width-factor)); + height: calc(var(--avatar-base-height) * var(--big-avatar-height-factor)); +} + +body.big-avatars .avatar img { + width: calc(var(--avatar-base-width) * var(--big-avatar-width-factor)); + height: calc(var(--avatar-base-height) * var(--big-avatar-height-factor)); + object-fit: cover; + object-position: center; + border: 1px solid var(--SmartThemeBorderColor); + border-radius: calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)); +} + +body.big-avatars .bogus_folder_select_back .bogus_folder_back_placeholder { + width: calc(var(--avatar-base-width) * var(--big-avatar-width-factor)); +} + +body:not(.big-avatars) .avatar_collage { + min-width: var(--avatar-base-width); + aspect-ratio: 1 / 1; +} + +body:not(.big-avatars) .avatar_collage img { + border-radius: 0% !important; +} + +body.big-avatars .avatar_collage { + min-width: calc(var(--avatar-base-width) * var(--big-avatar-width-factor)); + max-width: calc(var(--avatar-base-width) * var(--big-avatar-width-factor)); + aspect-ratio: 2 / 3; +} + +body.big-avatars .ch_description, +body.big-avatars .avatar-container .ch_description { + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + white-space: pre-line; + text-overflow: unset; +} + +body.big-avatars .avatars_inline_small .avatar, +body.big-avatars .avatars_inline_small .avatar img { + width: calc(var(--avatar-base-width) * var(--big-avatar-width-factor) * var(--inline-avatar-small-factor)); + height: calc(var(--avatar-base-height) * var(--big-avatar-height-factor) * var(--inline-avatar-small-factor)); +} + +body.big-avatars .avatars_inline { + max-height: calc(var(--avatar-base-height) * var(--big-avatar-height-factor) + 2 * var(--avatar-base-border-radius)); +} +body.big-avatars .avatars_inline.avatars_multiline { + max-height: fit-content; +} + +body.big-avatars .avatars_inline.avatars_inline_small { + height: calc(var(--avatar-base-height) * var(--big-avatar-height-factor) * var(--inline-avatar-small-factor) + 2 * var(--avatar-base-border-radius)); +} +body.big-avatars .avatars_inline.avatars_inline_small.avatars_multiline { + height: inherit; +} + +body:not(.big-avatars) .avatars_inline_small .avatar_collage { + min-width: calc(var(--avatar-base-width) * var(--inline-avatar-small-factor)); +} + +body.big-avatars .avatars_inline_small .avatar_collage { + min-width: calc(var(--avatar-base-width) * var(--big-avatar-width-factor) * var(--inline-avatar-small-factor)); + max-width: calc(var(--avatar-base-width) * var(--big-avatar-width-factor) * var(--inline-avatar-small-factor)); +} + +/* border radius for big avatars collages */ + +body.big-avatars .collage_2 .img_1 { + border-radius: calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) 0 0 calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) !important; +} + +body.big-avatars .collage_2 .img_2 { + border-radius: 0 calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) 0 !important; +} + +body.big-avatars .collage_3 .img_1 { + border-radius: calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) 0 0 0 !important; +} + +body.big-avatars .collage_3 .img_2 { + border-radius: 0 calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) 0 0 !important; +} + +body.big-avatars .collage_3 .img_3 { + border-radius: 0 0 calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) !important; +} + +body.big-avatars .collage_4 .img_1 { + border-radius: calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) 0 0 0 !important; +} + +body.big-avatars .collage_4 .img_2 { + border-radius: 0 calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) 0 0 !important; +} + +body.big-avatars .collage_4 .img_3 { + border-radius: 0 0 0 calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) !important; +} + +body.big-avatars .collage_4 .img_4 { + border-radius: 0 0 calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) 0 !important; +} + + + +/*bubble chat style*/ + +body.bubblechat .mes { + padding: 10px; + border-radius: 10px; + background-color: var(--SmartThemeBotMesBlurTintColor); + margin-bottom: 5px; + border: 1px solid var(--SmartThemeBorderColor); +} + +body.bubblechat .mes[is_user="true"] { + background-color: var(--SmartThemeUserMesBlurTintColor); +} + + +/* Document Style */ + +body.documentstyle #chat .mes:not(.last_mes) { + padding: 5px 10px 0px 10px; +} + +body.documentstyle .last_mes { + padding-top: 0; +} + +body.documentstyle #chat .mes .mes_text { + padding: 0; +} + +body.documentstyle #chat .mes .mes_block { + margin-right: 30px; +} + +body.documentstyle #chat .mes .mes_text { + margin-left: 20px; +} + +body.documentstyle #chat .last_mes .mes_text { + margin-left: 20px; + min-height: 70px; +} + +body.documentstyle #chat .last_mes:has(> .del_checkbox[style*="display: block"]) .mes_text { + margin-left: 0px; +} + +body.documentstyle #chat .last_mes .swipe_left { + left: 5px; +} + +body.documentstyle #chat .mes .mesAvatarWrapper, +body.documentstyle #chat .mes .mes_block .ch_name .name_text, +body.documentstyle #chat .mes .mes_block .ch_name .timestamp, +body.documentstyle .mes:not(.last_mes) .ch_name .mes_buttons { + display: none !important; +} + +/*FastUI blur removal*/ + +body.no-blur * { + backdrop-filter: unset !important; +} + +/* body.no-blur #send_form.no-connection { + background-color: rgba(100, 0, 0, 0.9) !important; +} */ + +body.no-blur #bg1, +body.no-blur #bg_custom { + filter: unset; + +} + +body.no-blur #top-bar, +body.no-blur #send_form { + background-color: var(--SmartThemeBlurTintColor) !important; +} + +/* wAIfu mode*/ + +body.waifuMode #top-bar { + border-radius: 0 0 20px 20px; + border: 1px solid var(--SmartThemeBorderColor); +} + +body.waifuMode #sheld { + height: 40vh; + height: 40dvh; + top: calc(100% - 40vh); + bottom: 0; +} + +body.waifuMode #chat { + border-top: 1px solid var(--SmartThemeBorderColor); + border-radius: 20px 20px 0 0; +} + +body.waifuMode #expression-wrapper { + justify-content: center; +} + +body.waifuMode .expression-holder { + max-height: 90vh; + max-width: 90vw; + height: 90vh; + width: fit-content; + bottom: 0; + filter: drop-shadow(2px 2px 2px #51515199); + z-index: 2; + margin: 0 auto; + left: 0; + right: 0; +} + +body.waifuMode .zoomed_avatar { + min-width: 100px; + min-height: 100px; + max-height: 90vh; + max-width: 90vh; + width: calc((100vw - var(--sheldWidth)) /2); + position: absolute; + padding: 0; + filter: drop-shadow(2px 2px 2px #51515199); + z-index: 29; + overflow: hidden; + display: none; + left: 0; + right: 0; + margin: 0 auto; + top: 50px; + aspect-ratio: 2 / 3; + height: auto; +} + +/* movingUI*/ + +body.movingUI .drag-grabber { + display: inline; +} + +body.movingUI #sheld, +body.movingUI .drawer-content, +body.movingUI #expression-holder, +body.movingUI .zoomed_avatar, +body.movingUI .draggable, +body.movingUI #floatingPrompt { + resize: both; +} + +#expression-image.default, +#expression-holder:has(.default) { + height: 120px; + margin-top: 0; + top: 50px; + justify-content: center; +} + +/*No Text Shadows Mode*/ + +body.noShadows * { + text-shadow: none !important; +} + +body.expandMessageActions .mes .mes_buttons .extraMesButtons { + display: inherit !important; +} + +body.expandMessageActions .mes .mes_buttons .extraMesButtonsHint { + display: none !important; +} + +#smooth_streaming:not(:checked)~#smooth_streaming_speed_control { + display: none; +} + +#smooth_streaming:checked~#smooth_streaming_speed_control { + display: block; +} + +.mdhotkey_icon { + opacity: 0.6; +} + +label[for="trim_spaces"]:has(input:checked) i.warning { + display: none; +} + +label[for="trim_spaces"]:not(:has(input:checked)) small { + color: var(--warning); + opacity: 1; +} + +#claude_function_prefill_warning { + display: none; + color: red; + font-weight: bold; +} + +#openai_settings:has(#openai_function_calling:checked):has(#claude_assistant_prefill:not(:placeholder-shown), #claude_assistant_impersonation:not(:placeholder-shown)) #claude_function_prefill_warning { + display: flex; + align-items: center; + gap: 5px; + margin: 10px 0; +} + +#mistralai_other_models:empty { + display: none; +} + +#banned_tokens_block_ooba:not(:has(#send_banned_tokens_textgenerationwebui:checked)) #banned_tokens_controls_ooba { + filter: brightness(0.5); +} diff --git a/jiuguan2025cc/public/css/world-info.css b/jiuguan2025cc/public/css/world-info.css new file mode 100644 index 0000000000000000000000000000000000000000..e7e03ad4188bb46a721b31ccedba10bbc52cfe85 --- /dev/null +++ b/jiuguan2025cc/public/css/world-info.css @@ -0,0 +1,280 @@ +.world_info_select_block { + display: flex; + flex-direction: row; + align-items: baseline; + gap: 5px; +} + +.budget_cap_note { + flex-basis: 100%; + line-height: 0.1; +} + +#world_popup { + min-height: 100px; + min-width: 100px; + left: 0; + right: 0; + flex-direction: column; + z-index: 3010; + overflow-y: hidden; +} + +.WIEntryContentAndMemo { + width: 100% !important; + flex-wrap: nowrap !important; +} + +.WIEntryContentAndMemo .world_entry_thin_controls { + flex: 1; +} + +#world_popup_bottom_holder { + display: flex; + flex-flow: row; + justify-content: space-evenly; + align-items: center; +} + +#world_popup_bottom_holder div { + width: fit-content; + user-select: none; +} + +#form_rename_world { + display: flex; + align-items: center; + gap: 5px; +} + +.world_popup_expander { + flex-grow: 1; +} + +#world_popup_entries_list { + flex-grow: 1; + overflow-y: auto; +} + +#world_popup_entries_list:empty { + width: 100%; + height: 100%; +} + +#world_popup_entries_list:empty::before { + content: 'No entries found.'; + font-size: calc(var(--mainFontSize) + .1rem); + font-weight: bolder; + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + opacity: 0.8; +} + +.world_entry_form_control { + display: flex; + flex-direction: column; + position: relative; +} + +.world_entry_form_control .keyprimarytextpole, +.world_entry_form_control .keysecondarytextpole { + padding-right: 25px; +} + +.world_entry_thin_controls { + display: flex; + flex-direction: row; +} + +/* .world_entry_thin_controls>div { + flex: 1; +} */ + +.world_entry_form_control label h4 { + margin-bottom: 0; + margin-top: 0; +} + +.world_entry_form_control label h5 { + margin-top: 3px; + margin-bottom: 3px; +} + +.world_entry_form_control textarea { + height: auto; + margin-top: 0; + margin-bottom: 0; + min-height: calc(var(--mainFontSize) + 14px); +} + +.delete_entry_button { + height: min-content; +} + +.world_entry_form_control.world_entry_form_horizontal { + flex-direction: row; + align-items: center; + flex-wrap: wrap; +} + +.world_entry .inline-drawer-header { + cursor: initial; +} + +.world_entry .killSwitch { + cursor: pointer; +} + +.world_entry_form_control input[type=button] { + cursor: pointer; +} + +.world_entry_form_horizontal h5 { + margin: 0 1rem; +} + +.world_entry_form_control .checkbox { + align-items: center; + display: flex; + flex-direction: row; + column-gap: 10px; +} + +.world_entry_form_control .checkbox h4 { + margin: 0; + display: inline-block; +} + +.world_entry_form_radios label { + margin-left: 0; +} + +.world_entry_form_radios h4 { + display: inline; +} + +#world_popup h5 { + color: var(--grey70); +} + +/* possible place for WI Entry header styling */ +/* .world_entry_form .inline-drawer-header { + background-color: var(--SmartThemeShadowColor); +} */ + +#world_editor_select { + text-overflow: ellipsis; + white-space: nowrap; + width: 10em; +} + +#world_info_search { + width: 10em; + min-width: 10em; + flex-grow: 1; +} + +#world_info_sort_order { + width: 7em; +} + +.world_entry .killSwitch.fa-toggle-on { + color: var(--SmartThemeQuoteColor); +} + +.wi-card-entry { + border: 1px solid; + border-color: var(--SmartThemeBorderColor); + border-radius: 10px; + padding: 0 5px; + margin-bottom: 1px; +} + +.world_entry { + transition: opacity 500ms; +} + +.disabledWIEntry { + opacity: 0.4; + filter: grayscale(1); +} + +.disabledWIEntry:not(input):hover { + opacity: 1; + filter: grayscale(0.5); +} + +.height32px { + height: 32px; +} + +.WIEntryHeaderTitleMobile { + display: none; +} + +span.select2-container .select2-selection__choice__display:has(> .regex_item), +span.select2-container .select2-results__option:has(> .result_block .regex_item) { + background-color: #D27D2D30; +} + +.regex_item .regex_icon { + background-color: var(--black30a); + color: var(--SmartThemeBodyColor); + border: 1px solid var(--SmartThemeBorderColor); + border-radius: 7px; + font-weight: bold; + font-size: calc(var(--mainFontSize) * 0.75); + padding: 0px 3px; + position: relative; + top: -1px; + margin-right: 3px; +} + +.select2-results__option .regex_item .regex_icon { + margin-right: 6px; +} + +.select2-results__option .item_count { + margin-left: 10px; + float: right; +} + +select.keyselect+span.select2-container .select2-selection--multiple { + padding-right: 30px; +} + +.switch_input_type_icon { + cursor: pointer; + font-weight: bold; + height: 20px; + width: fit-content; + margin-right: 5px; + margin-top: calc(5px + var(--mainFontSize)); + position: absolute; + right: 0; + padding: 1px; + + background-color: transparent; + border: none; + font-size: 1em; + + opacity: 0.5; + color: var(--SmartThemeBodyColor); + transition: opacity 0.3s; +} + +.switch_input_type_icon:hover { + opacity: 1; +} + +#wiCheckboxes { + align-self: center; + width: 100%; +} + +.world_entry:has(input[name="delay_until_recursion"]:not(:checked)) .world_entry_form_control:has(input[name="delayUntilRecursionLevel"]) { + display: none; +} diff --git a/jiuguan2025cc/public/favicon.ico b/jiuguan2025cc/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..6a1844535037f293800129d65e118ba7d0daf939 Binary files /dev/null and b/jiuguan2025cc/public/favicon.ico differ diff --git a/jiuguan2025cc/public/global.d.ts b/jiuguan2025cc/public/global.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..4c90a854ffb0d894d376d03167f5e304145350e3 --- /dev/null +++ b/jiuguan2025cc/public/global.d.ts @@ -0,0 +1,54 @@ +import libs from './lib'; +import getContext from './scripts/st-context'; + +declare global { + // Global namespace modules + interface Window { + ai: any; + } + + declare var pdfjsLib; + declare var ePub; + + declare var SillyTavern: { + getContext(): typeof getContext; + llm: any; + libs: typeof libs; + }; + + // Jquery plugins + interface JQuery { + nanogallery2(options?: any): JQuery; + nanogallery2(method: string, options?: any): JQuery; + pagination(method: 'getCurrentPageNum'): number; + pagination(method: string, options?: any): JQuery; + pagination(options?: any): JQuery; + izoomify(options?: any): JQuery; + } + + namespace Select2 { + interface Options { + /** + * Extends Select2 v4 plugin by adding an option to set a placeholder for the 'search' input field + * [Custom Field] + * @default '' + */ + searchInputPlaceholder?: string; + + /** + * Extends select2 plugin by adding a custom css class for the 'search' input field + * [Custom Field] + * @default '' + */ + searchInputCssClass?: string; + } + } + + /** + * Translates a text to a target language using a translation provider. + * @param text Text to translate + * @param lang Target language + * @param provider Translation provider + */ + async function translate(text: string, lang: string, provider: string = null): Promise; +} diff --git a/jiuguan2025cc/public/img/01ai.svg b/jiuguan2025cc/public/img/01ai.svg new file mode 100644 index 0000000000000000000000000000000000000000..317a5da590fdf0d7c0d613f2a048d2ee3f3ba528 --- /dev/null +++ b/jiuguan2025cc/public/img/01ai.svg @@ -0,0 +1,59 @@ + + + + + + + + + diff --git a/jiuguan2025cc/public/img/No-Image-Placeholder.svg b/jiuguan2025cc/public/img/No-Image-Placeholder.svg new file mode 100644 index 0000000000000000000000000000000000000000..d2113750600e95d236593b8218ff295a5c836b1a --- /dev/null +++ b/jiuguan2025cc/public/img/No-Image-Placeholder.svg @@ -0,0 +1,309 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + NO IMAGEAVAILABLE + + diff --git a/jiuguan2025cc/public/img/addbg3.png b/jiuguan2025cc/public/img/addbg3.png new file mode 100644 index 0000000000000000000000000000000000000000..1b7dd7113fa566b700f95ab8e1f66e0e54d2d70d Binary files /dev/null and b/jiuguan2025cc/public/img/addbg3.png differ diff --git a/jiuguan2025cc/public/img/ai21.svg b/jiuguan2025cc/public/img/ai21.svg new file mode 100644 index 0000000000000000000000000000000000000000..891beda5a6dab16062ee995a76acd1be5514d865 --- /dev/null +++ b/jiuguan2025cc/public/img/ai21.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + diff --git a/jiuguan2025cc/public/img/ai4.png b/jiuguan2025cc/public/img/ai4.png new file mode 100644 index 0000000000000000000000000000000000000000..ecb6751f690fcf4b9404b6aec0a1c06ce5fc2758 Binary files /dev/null and b/jiuguan2025cc/public/img/ai4.png differ diff --git a/jiuguan2025cc/public/img/aphrodite.svg b/jiuguan2025cc/public/img/aphrodite.svg new file mode 100644 index 0000000000000000000000000000000000000000..f9d6f41824dd24d11446b1d6dea2dfbd79666250 --- /dev/null +++ b/jiuguan2025cc/public/img/aphrodite.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + diff --git a/jiuguan2025cc/public/img/apple-icon-114x114.png b/jiuguan2025cc/public/img/apple-icon-114x114.png new file mode 100644 index 0000000000000000000000000000000000000000..cc947f79c6db01c0c18c41424a056ea563aff947 Binary files /dev/null and b/jiuguan2025cc/public/img/apple-icon-114x114.png differ diff --git a/jiuguan2025cc/public/img/apple-icon-144x144.png b/jiuguan2025cc/public/img/apple-icon-144x144.png new file mode 100644 index 0000000000000000000000000000000000000000..7f5635e41f230e80bb32b0591bd8f3f205101a2e Binary files /dev/null and b/jiuguan2025cc/public/img/apple-icon-144x144.png differ diff --git a/jiuguan2025cc/public/img/apple-icon-57x57.png b/jiuguan2025cc/public/img/apple-icon-57x57.png new file mode 100644 index 0000000000000000000000000000000000000000..88879c3714fa414ed5c3bb61faf1e850e24da498 Binary files /dev/null and b/jiuguan2025cc/public/img/apple-icon-57x57.png differ diff --git a/jiuguan2025cc/public/img/apple-icon-72x72.png b/jiuguan2025cc/public/img/apple-icon-72x72.png new file mode 100644 index 0000000000000000000000000000000000000000..48c7ff21500ceb6182db55d51f52e90a46232de8 Binary files /dev/null and b/jiuguan2025cc/public/img/apple-icon-72x72.png differ diff --git a/jiuguan2025cc/public/img/blockentropy.svg b/jiuguan2025cc/public/img/blockentropy.svg new file mode 100644 index 0000000000000000000000000000000000000000..fa52c3ea8d43e940559dd0de6c771e5d5a77e5c8 --- /dev/null +++ b/jiuguan2025cc/public/img/blockentropy.svg @@ -0,0 +1,3 @@ + + + diff --git a/jiuguan2025cc/public/img/claude.svg b/jiuguan2025cc/public/img/claude.svg new file mode 100644 index 0000000000000000000000000000000000000000..f542c5d753d533a7936b8d8a0963c76e6257668e --- /dev/null +++ b/jiuguan2025cc/public/img/claude.svg @@ -0,0 +1,25 @@ + + + + + + + + + diff --git a/jiuguan2025cc/public/img/cohere.svg b/jiuguan2025cc/public/img/cohere.svg new file mode 100644 index 0000000000000000000000000000000000000000..a213ae8d88af609f35cc959faec548cea590df4f --- /dev/null +++ b/jiuguan2025cc/public/img/cohere.svg @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/jiuguan2025cc/public/img/custom.svg b/jiuguan2025cc/public/img/custom.svg new file mode 100644 index 0000000000000000000000000000000000000000..0daa6c3027a6bd109a571e95e3d9e51f9681f000 --- /dev/null +++ b/jiuguan2025cc/public/img/custom.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + diff --git a/jiuguan2025cc/public/img/deepseek.svg b/jiuguan2025cc/public/img/deepseek.svg new file mode 100644 index 0000000000000000000000000000000000000000..43e32a7263fc4829be4a43ffca3b5378b54aee1a --- /dev/null +++ b/jiuguan2025cc/public/img/deepseek.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/jiuguan2025cc/public/img/default-expressions/admiration.png b/jiuguan2025cc/public/img/default-expressions/admiration.png new file mode 100644 index 0000000000000000000000000000000000000000..a9001bb64c475ba7dd3a974b4e7f09ece5bb5e5d Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/admiration.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/amusement.png b/jiuguan2025cc/public/img/default-expressions/amusement.png new file mode 100644 index 0000000000000000000000000000000000000000..493880a8a242fb89376ec4098b01cd5c2098a344 Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/amusement.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/anger.png b/jiuguan2025cc/public/img/default-expressions/anger.png new file mode 100644 index 0000000000000000000000000000000000000000..6d7398d5b5a1105bf88b5c61e7fd9a08224e743f Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/anger.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/annoyance.png b/jiuguan2025cc/public/img/default-expressions/annoyance.png new file mode 100644 index 0000000000000000000000000000000000000000..1c3c20e6edb1d1cc0ddc0cf33e007f98181ea36a Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/annoyance.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/approval.png b/jiuguan2025cc/public/img/default-expressions/approval.png new file mode 100644 index 0000000000000000000000000000000000000000..db2fd7fc1f38e98f58c88e6189c5cca1169db0f6 Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/approval.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/caring.png b/jiuguan2025cc/public/img/default-expressions/caring.png new file mode 100644 index 0000000000000000000000000000000000000000..676794920ed0b5fa43d46ae985e04db98a29217a Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/caring.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/confusion.png b/jiuguan2025cc/public/img/default-expressions/confusion.png new file mode 100644 index 0000000000000000000000000000000000000000..b57949cb3dd6ef0a81f0a52d543a845e8479cacb Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/confusion.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/curiosity.png b/jiuguan2025cc/public/img/default-expressions/curiosity.png new file mode 100644 index 0000000000000000000000000000000000000000..e0d4061c8ec1d813b105b08331740e94745f90e9 Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/curiosity.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/desire.png b/jiuguan2025cc/public/img/default-expressions/desire.png new file mode 100644 index 0000000000000000000000000000000000000000..98b88fb6f0143462b32c71caf7ab561c5202e07d Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/desire.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/desire1.png b/jiuguan2025cc/public/img/default-expressions/desire1.png new file mode 100644 index 0000000000000000000000000000000000000000..d4c6964b6b85880d8aaf5db45f859a3407545882 Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/desire1.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/desire2.png b/jiuguan2025cc/public/img/default-expressions/desire2.png new file mode 100644 index 0000000000000000000000000000000000000000..fd31e6b19a0ac42c55a22e20902d92e7913be63f Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/desire2.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/disappointment.png b/jiuguan2025cc/public/img/default-expressions/disappointment.png new file mode 100644 index 0000000000000000000000000000000000000000..a2fbb03aff6d939261430d5a231143b04fb8106d Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/disappointment.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/disapproval.png b/jiuguan2025cc/public/img/default-expressions/disapproval.png new file mode 100644 index 0000000000000000000000000000000000000000..cb14abbf4319d77888ab3fa82f051b69f50d290f Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/disapproval.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/disgust.png b/jiuguan2025cc/public/img/default-expressions/disgust.png new file mode 100644 index 0000000000000000000000000000000000000000..bbb6dc5fffd351f372d01d05e293263f58d5c224 Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/disgust.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/embarrassment.png b/jiuguan2025cc/public/img/default-expressions/embarrassment.png new file mode 100644 index 0000000000000000000000000000000000000000..5481a5c45ecbccfc02c85382707f30f77baa177e Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/embarrassment.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/excitement.png b/jiuguan2025cc/public/img/default-expressions/excitement.png new file mode 100644 index 0000000000000000000000000000000000000000..3ba87d41dc63c1f74bd3f541755091d7a8883493 Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/excitement.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/fear.png b/jiuguan2025cc/public/img/default-expressions/fear.png new file mode 100644 index 0000000000000000000000000000000000000000..c1ada3db9bb532603499323607036abe05fc5a08 Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/fear.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/gratitude.png b/jiuguan2025cc/public/img/default-expressions/gratitude.png new file mode 100644 index 0000000000000000000000000000000000000000..e304a102d07b96ed352778eda70aac0c74de9a93 Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/gratitude.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/grief.png b/jiuguan2025cc/public/img/default-expressions/grief.png new file mode 100644 index 0000000000000000000000000000000000000000..ae97d3486737b0666021a664b3213d67b324e800 Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/grief.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/joy.png b/jiuguan2025cc/public/img/default-expressions/joy.png new file mode 100644 index 0000000000000000000000000000000000000000..939a8760c2bb802bfe8204a4cf60652c78492bf1 Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/joy.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/love.png b/jiuguan2025cc/public/img/default-expressions/love.png new file mode 100644 index 0000000000000000000000000000000000000000..8c0556fd772dd67ade7e98bf666945e7c447ee72 Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/love.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/nervousness.png b/jiuguan2025cc/public/img/default-expressions/nervousness.png new file mode 100644 index 0000000000000000000000000000000000000000..d08554eede50cf52a04f1529b326c5945f0d4c67 Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/nervousness.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/neutral.png b/jiuguan2025cc/public/img/default-expressions/neutral.png new file mode 100644 index 0000000000000000000000000000000000000000..61c65b4d2311dcae29cabd90087b76c6485264cf Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/neutral.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/optimism.png b/jiuguan2025cc/public/img/default-expressions/optimism.png new file mode 100644 index 0000000000000000000000000000000000000000..fab101a79930361f4607d851ff4a32afee0b50ff Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/optimism.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/pride.png b/jiuguan2025cc/public/img/default-expressions/pride.png new file mode 100644 index 0000000000000000000000000000000000000000..16dae6fca5243af9085462a31589cfa756160745 Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/pride.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/realization.png b/jiuguan2025cc/public/img/default-expressions/realization.png new file mode 100644 index 0000000000000000000000000000000000000000..cc8738986b3c043d1c7638c554fdcb537ae6946a Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/realization.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/relief.png b/jiuguan2025cc/public/img/default-expressions/relief.png new file mode 100644 index 0000000000000000000000000000000000000000..8731cd6350ae25f51578aa3786c9c39ab48b6812 Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/relief.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/remorse.png b/jiuguan2025cc/public/img/default-expressions/remorse.png new file mode 100644 index 0000000000000000000000000000000000000000..abf7c262350471ef2e0c8114088426437c53b2d4 Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/remorse.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/sadness.png b/jiuguan2025cc/public/img/default-expressions/sadness.png new file mode 100644 index 0000000000000000000000000000000000000000..bcba564aaf37629530949baa563991437d7deab0 Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/sadness.png differ diff --git a/jiuguan2025cc/public/img/default-expressions/surprise.png b/jiuguan2025cc/public/img/default-expressions/surprise.png new file mode 100644 index 0000000000000000000000000000000000000000..a45a8dab926dcaa0d77f10903b96f418fda02c6d Binary files /dev/null and b/jiuguan2025cc/public/img/default-expressions/surprise.png differ diff --git a/jiuguan2025cc/public/img/down-arrow.svg b/jiuguan2025cc/public/img/down-arrow.svg new file mode 100644 index 0000000000000000000000000000000000000000..6704feda74cccfffd1a59ebd438d6e0612a9beca --- /dev/null +++ b/jiuguan2025cc/public/img/down-arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/jiuguan2025cc/public/img/dreamgen.svg b/jiuguan2025cc/public/img/dreamgen.svg new file mode 100644 index 0000000000000000000000000000000000000000..c62958a12d283ee01ce2d34cfc21599377eb4d05 --- /dev/null +++ b/jiuguan2025cc/public/img/dreamgen.svg @@ -0,0 +1 @@ + diff --git a/jiuguan2025cc/public/img/featherless.svg b/jiuguan2025cc/public/img/featherless.svg new file mode 100644 index 0000000000000000000000000000000000000000..b386387f4efdcda73fe8c779fd0a689e8eeeb576 --- /dev/null +++ b/jiuguan2025cc/public/img/featherless.svg @@ -0,0 +1,39 @@ + + diff --git a/jiuguan2025cc/public/img/five.png b/jiuguan2025cc/public/img/five.png new file mode 100644 index 0000000000000000000000000000000000000000..04a8422e773060ce7de933a7ea8c09bc557ac8fa Binary files /dev/null and b/jiuguan2025cc/public/img/five.png differ diff --git a/jiuguan2025cc/public/img/generic.svg b/jiuguan2025cc/public/img/generic.svg new file mode 100644 index 0000000000000000000000000000000000000000..2411ed06974e7d889dbf6847f4ae06d702ea0f35 --- /dev/null +++ b/jiuguan2025cc/public/img/generic.svg @@ -0,0 +1,15 @@ + + + + + diff --git a/jiuguan2025cc/public/img/groq.svg b/jiuguan2025cc/public/img/groq.svg new file mode 100644 index 0000000000000000000000000000000000000000..b1945dc1dbc9a2b28dc78b00e870883af23cfc4f --- /dev/null +++ b/jiuguan2025cc/public/img/groq.svg @@ -0,0 +1,48 @@ + + + + + + + + + + diff --git a/jiuguan2025cc/public/img/huggingface.svg b/jiuguan2025cc/public/img/huggingface.svg new file mode 100644 index 0000000000000000000000000000000000000000..3acb82a27ab22f082438c59d0333d19def5462b9 --- /dev/null +++ b/jiuguan2025cc/public/img/huggingface.svg @@ -0,0 +1,40 @@ + + + + + + diff --git a/jiuguan2025cc/public/img/infermaticai.svg b/jiuguan2025cc/public/img/infermaticai.svg new file mode 100644 index 0000000000000000000000000000000000000000..7f88c643c1fdef03153ad97df0cffb2d3b3349cb --- /dev/null +++ b/jiuguan2025cc/public/img/infermaticai.svg @@ -0,0 +1,40 @@ + + + + + + diff --git a/jiuguan2025cc/public/img/kobold.svg b/jiuguan2025cc/public/img/kobold.svg new file mode 100644 index 0000000000000000000000000000000000000000..9e543d633a764a12dcb24eaae6fbabafcfce5dc5 --- /dev/null +++ b/jiuguan2025cc/public/img/kobold.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + diff --git a/jiuguan2025cc/public/img/koboldcpp.svg b/jiuguan2025cc/public/img/koboldcpp.svg new file mode 100644 index 0000000000000000000000000000000000000000..9e543d633a764a12dcb24eaae6fbabafcfce5dc5 --- /dev/null +++ b/jiuguan2025cc/public/img/koboldcpp.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + diff --git a/jiuguan2025cc/public/img/koboldhorde.svg b/jiuguan2025cc/public/img/koboldhorde.svg new file mode 100644 index 0000000000000000000000000000000000000000..46a71498cc94adb8c3ed3ae348262ecb66b7ea1c --- /dev/null +++ b/jiuguan2025cc/public/img/koboldhorde.svg @@ -0,0 +1,48 @@ + + + + + + + + + diff --git a/jiuguan2025cc/public/img/llamacpp.svg b/jiuguan2025cc/public/img/llamacpp.svg new file mode 100644 index 0000000000000000000000000000000000000000..d3237d24767e04cdb23073e13630bf0d751729fd --- /dev/null +++ b/jiuguan2025cc/public/img/llamacpp.svg @@ -0,0 +1,39 @@ + + + + + + diff --git a/jiuguan2025cc/public/img/logo.png b/jiuguan2025cc/public/img/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..14768e82b32b78bd51e3233742667dc3b369a8b2 Binary files /dev/null and b/jiuguan2025cc/public/img/logo.png differ diff --git a/jiuguan2025cc/public/img/makersuite.svg b/jiuguan2025cc/public/img/makersuite.svg new file mode 100644 index 0000000000000000000000000000000000000000..4d70f69cfbac7e58342a34676df1053a47b95363 --- /dev/null +++ b/jiuguan2025cc/public/img/makersuite.svg @@ -0,0 +1,38 @@ + + + + + + + + + diff --git a/jiuguan2025cc/public/img/mancer.svg b/jiuguan2025cc/public/img/mancer.svg new file mode 100644 index 0000000000000000000000000000000000000000..6f84d4c453e76906b61ce6ee448dadda3d65978c --- /dev/null +++ b/jiuguan2025cc/public/img/mancer.svg @@ -0,0 +1,3 @@ + + + diff --git a/jiuguan2025cc/public/img/manual.svg b/jiuguan2025cc/public/img/manual.svg new file mode 100644 index 0000000000000000000000000000000000000000..e313ab59c184df1bbc9cac4b510a450b10810c10 --- /dev/null +++ b/jiuguan2025cc/public/img/manual.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/jiuguan2025cc/public/img/mistralai.svg b/jiuguan2025cc/public/img/mistralai.svg new file mode 100644 index 0000000000000000000000000000000000000000..8c9dabdb20d0f46cfbbdf8e7faa928b0c5bf4fb0 --- /dev/null +++ b/jiuguan2025cc/public/img/mistralai.svg @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/jiuguan2025cc/public/img/nanogpt.svg b/jiuguan2025cc/public/img/nanogpt.svg new file mode 100644 index 0000000000000000000000000000000000000000..945d9c2e879ceb96b691bf377ab5529d1ad9e9c9 --- /dev/null +++ b/jiuguan2025cc/public/img/nanogpt.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + diff --git a/jiuguan2025cc/public/img/novel.svg b/jiuguan2025cc/public/img/novel.svg new file mode 100644 index 0000000000000000000000000000000000000000..d74243194d20b3793947b8feafa79d24e9a00858 --- /dev/null +++ b/jiuguan2025cc/public/img/novel.svg @@ -0,0 +1,3 @@ + + + diff --git a/jiuguan2025cc/public/img/ollama.svg b/jiuguan2025cc/public/img/ollama.svg new file mode 100644 index 0000000000000000000000000000000000000000..9600c03c6b1cb980dd2316f48bf3dfc326fbfa33 --- /dev/null +++ b/jiuguan2025cc/public/img/ollama.svg @@ -0,0 +1,56 @@ + + + + + + + + + + + + diff --git a/jiuguan2025cc/public/img/openai.svg b/jiuguan2025cc/public/img/openai.svg new file mode 100644 index 0000000000000000000000000000000000000000..e04db75a5bbdc4e398618e87f762b75a2ab0d34e --- /dev/null +++ b/jiuguan2025cc/public/img/openai.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/jiuguan2025cc/public/img/openrouter.svg b/jiuguan2025cc/public/img/openrouter.svg new file mode 100644 index 0000000000000000000000000000000000000000..0452cf4dbc8852d596991d28d722acd6da5a9d25 --- /dev/null +++ b/jiuguan2025cc/public/img/openrouter.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + diff --git a/jiuguan2025cc/public/img/palm.svg b/jiuguan2025cc/public/img/palm.svg new file mode 100644 index 0000000000000000000000000000000000000000..8f57163a29f5ee605cc5d81fc7ada2470b81af64 --- /dev/null +++ b/jiuguan2025cc/public/img/palm.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jiuguan2025cc/public/img/perplexity.svg b/jiuguan2025cc/public/img/perplexity.svg new file mode 100644 index 0000000000000000000000000000000000000000..1c10790e3f008a079e4c1d9fafbc3c20b0960551 --- /dev/null +++ b/jiuguan2025cc/public/img/perplexity.svg @@ -0,0 +1,3 @@ + + + diff --git a/jiuguan2025cc/public/img/quill.png b/jiuguan2025cc/public/img/quill.png new file mode 100644 index 0000000000000000000000000000000000000000..8edd69153c981d9780a0d1b1fcbe9c73e57c535f Binary files /dev/null and b/jiuguan2025cc/public/img/quill.png differ diff --git a/jiuguan2025cc/public/img/scale.svg b/jiuguan2025cc/public/img/scale.svg new file mode 100644 index 0000000000000000000000000000000000000000..5d0f87ceac27620110e17d206199f5a9b345ba5a --- /dev/null +++ b/jiuguan2025cc/public/img/scale.svg @@ -0,0 +1,60 @@ + + + + diff --git a/jiuguan2025cc/public/img/step-into.svg b/jiuguan2025cc/public/img/step-into.svg new file mode 100644 index 0000000000000000000000000000000000000000..fcfa7ef16e103977ea86a160ef07418c3847385b --- /dev/null +++ b/jiuguan2025cc/public/img/step-into.svg @@ -0,0 +1,149 @@ + + + + diff --git a/jiuguan2025cc/public/img/step-out.svg b/jiuguan2025cc/public/img/step-out.svg new file mode 100644 index 0000000000000000000000000000000000000000..aa7dd3ea211800ae6617e5f6d4db7f1b3a7f3f50 --- /dev/null +++ b/jiuguan2025cc/public/img/step-out.svg @@ -0,0 +1,149 @@ + + + + diff --git a/jiuguan2025cc/public/img/step-over.svg b/jiuguan2025cc/public/img/step-over.svg new file mode 100644 index 0000000000000000000000000000000000000000..6f23ff22aafab8a599be87649be6fb37863b4729 --- /dev/null +++ b/jiuguan2025cc/public/img/step-over.svg @@ -0,0 +1,149 @@ + + + + diff --git a/jiuguan2025cc/public/img/step-resume.svg b/jiuguan2025cc/public/img/step-resume.svg new file mode 100644 index 0000000000000000000000000000000000000000..bf3e0647fd14ebd54ab89ff499cccee463e649b2 --- /dev/null +++ b/jiuguan2025cc/public/img/step-resume.svg @@ -0,0 +1,218 @@ + + + + diff --git a/jiuguan2025cc/public/img/tabby.svg b/jiuguan2025cc/public/img/tabby.svg new file mode 100644 index 0000000000000000000000000000000000000000..cc19e6ed5e50503ecc144c9c849e9e260530c650 --- /dev/null +++ b/jiuguan2025cc/public/img/tabby.svg @@ -0,0 +1,23 @@ + + + + + + + + diff --git a/jiuguan2025cc/public/img/textgenerationwebui.svg b/jiuguan2025cc/public/img/textgenerationwebui.svg new file mode 100644 index 0000000000000000000000000000000000000000..b453a385e7c3be7402bfde01410e563849547e88 --- /dev/null +++ b/jiuguan2025cc/public/img/textgenerationwebui.svg @@ -0,0 +1,88 @@ + + + + +Created by potrace 1.15, written by Peter Selinger 2001-2017 + + + + + diff --git a/jiuguan2025cc/public/img/times-circle.svg b/jiuguan2025cc/public/img/times-circle.svg new file mode 100644 index 0000000000000000000000000000000000000000..cdee94147a728113176bdf1ba8aca185f21a23ee --- /dev/null +++ b/jiuguan2025cc/public/img/times-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/jiuguan2025cc/public/img/togetherai.svg b/jiuguan2025cc/public/img/togetherai.svg new file mode 100644 index 0000000000000000000000000000000000000000..e1e4c0407bdcb636cf29006255148f46b2f1475e --- /dev/null +++ b/jiuguan2025cc/public/img/togetherai.svg @@ -0,0 +1,55 @@ + + + + + + + + + + + + + diff --git a/jiuguan2025cc/public/img/user-default.png b/jiuguan2025cc/public/img/user-default.png new file mode 100644 index 0000000000000000000000000000000000000000..cfe32e4b3c1f7ce26d41ff58d553aa6081e9f3ab Binary files /dev/null and b/jiuguan2025cc/public/img/user-default.png differ diff --git a/jiuguan2025cc/public/img/vllm.svg b/jiuguan2025cc/public/img/vllm.svg new file mode 100644 index 0000000000000000000000000000000000000000..764d5d4c861279252461c242f99d9b1e5d3dcea7 --- /dev/null +++ b/jiuguan2025cc/public/img/vllm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/jiuguan2025cc/public/index.html b/jiuguan2025cc/public/index.html new file mode 100644 index 0000000000000000000000000000000000000000..0753e3134be035a3e3e14756237d17aa7635a679 --- /dev/null +++ b/jiuguan2025cc/public/index.html @@ -0,0 +1,7149 @@ + + + + + SillyTavern + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+
+ +
+
+
+
+
+
+
+ + +
+
+ Click slider numbers to input manually. +
+
MAD LAB MODE ON
+ + + +
+
+
+
+
+ + Kobold Presets + + +
+ + + +
+
+
+ +
+ + + + + +
+
+
+
+
+ + NovelAI Presets + + + + + +
+ + + +
+
+
+ +
+ + + + + +
+
+
+
+
+
+ + Chat Completion Presets + + +
+ + + +
+
+ +
+ +
+ + + +
+
+
+
+
+
+ + Text Completion presets + + +
+ + + +
+
+
+ +
+ + + + + +
+
+
+
+
+
+
+ Response (tokens) + +
+ +
+
+ +
+
+ +
+
+ +
+
+
+ Context (tokens) + +
+ +
+
+ +
+
+ + Max prompt cost: + +
+
+
+
+ AI Module +
+
+ Changes the style of the generated text. +
+ +
+
+
+
+
+ +
+
+
+ Temperature +
+
+
+ +
+
+ +
+
+
+
+
+ Repetition Penalty +
+
+
+ +
+
+ +
+
+
+
+
+ Rep Pen Range +
+
+
+ +
+
+ +
+
+
+
+
+ Repetition Penalty Slope +
+
+
+ +
+
+ +
+
+
+
+
+ Repetition Penalty Frequency +
+
+
+ +
+
+ +
+
+
+
+
+ Repetition Penalty Presence +
+
+
+ +
+
+ +
+
+
+
+
+ Min P +
+
+
+ +
+
+ +
+
+
+
+
+ TFS +
+
+
+ +
+
+ +
+
+
+
+
+ Top P +
+
+
+ +
+
+ +
+
+
+
+
+ Top A +
+
+
+ +
+
+ +
+
+
+
+
+ Top K +
+
+
+ +
+
+ +
+
+
+
+
+ Mirostat Tau +
+
+
+ +
+
+ +
+
+
+
+
+ Mirostat LR +
+
+
+ +
+
+ +
+
+
+
+
+ Typical P +
+
+
+ +
+
+ +
+
+
+
+
+ Linear +
+
+
+ +
+
+ +
+
+
+
+
+ Quad +
+
+
+ +
+
+ +
+
+
+
+
+ Conf +
+
+
+ +
+
+ +
+
+
+
+
+ Min Length +
+
+
+ +
+
+ +
+
+
+
+
+ Phrase Repetition Penalty +
+ +
+
+
+ Preamble +
+
+
+
+
+ Use style tags to modify the writing style of the output. +
+
+ +
+
+
+
+ Banned Tokens +
+
+ Sequences you don't want to appear in the output. One per line. Text or [token ids]. +
+
+ +
+
+
+
+ Logit Bias +
+ + Add +
+
+
+ Helps to ban or reinforce the usage of certain tokens. +
+
+
+
+
+
+
+
+ +
+ + Unrestricted maximum value for the context size slider. Enable only if you know + what you're doing. + +
+
+
+
+ Context Size (tokens) +
+
+
+ +
+
+ +
+
+
+
+
+ Max Response Length (tokens) +
+
+ +
+
+
+
+ Multiple swipes per generation +
+
+ +
+
+
+
+ Middle-out Transform + +
+
+ +
+
+
+ Max prompt cost: Unknown +
+
+
+ +
+ + Display the response bit by bit as it is generated. +
+ + When this is off, responses will be displayed all at once when they are complete. + +
+
+
+
+ Temperature +
+
+
+ +
+
+ +
+
+
+
+
+ Frequency Penalty +
+
+
+ +
+
+ +
+
+
+
+
+ Presence Penalty +
+
+
+ +
+
+ +
+
+
+
+
+ Top K +
+
+
+ +
+
+ +
+
+
+
+
+ Top P +
+
+
+ +
+
+ +
+
+
+
+
+ Repetition Penalty +
+
+
+ +
+
+ +
+
+
+
+
+ Min P +
+
+
+ +
+
+ +
+
+
+
+
+ Top A +
+
+
+ +
+
+ +
+
+
+
+
+ Quick Prompts Edit +
+
+
+
+
Main
+
+ +
+
+
+
Auxiliary
+
+ +
+
+
+
Post-History Instructions
+
+ +
+
+
+
+
+
+ Utility Prompts +
+
+
+
+
+ Impersonation prompt +
+
+
+
+
+ Prompt that is used for Impersonation function +
+
+ +
+
+
+
+ World Info format template +
+
+
+
+
+ Wraps activated World Info entries before inserting into the prompt. + Use{0} + to mark a place where the content is inserted. +
+
+ +
+
+
+
+ Scenario format template +
+
+
+
+
+ Use {{scenario}} to mark a place where the content is inserted. +
+
+ +
+
+
+
+ Personality format template +
+
+
+
+
+ Use {{personality}} to mark a place where the content is inserted. +
+
+ +
+
+
+
+ Group Nudge prompt template +
+
+
+
+
+ + Sent at the end of the group chat history to force reply from a specific character. + +
+
+ +
+
+
+
+ New Chat +
+
+
+
+
+ + Set at the beginning of the chat history to indicate that a new chat is about to start. + +
+
+ +
+
+
+
+ New Group Chat +
+
+
+
+
+ + Set at the beginning of the chat history to indicate that a new group chat is about to start. + +
+
+ +
+
+
+
+ New Example Chat +
+
+
+
+
+ + Set at the beginning of Dialogue examples to indicate that a new example chat is about to start. + +
+
+ +
+
+
+
+ Continue nudge +
+
+
+
+
+ + Set at the end of the chat history when the continue button is pressed. + +
+
+ +
+
+
+
+ Replace empty message +
+
+ + Send this text instead of nothing when the text box is empty. + +
+
+ +
+
+
+
+
+
+ Seed +
+
+ Set to get deterministic results. Use -1 for random seed. +
+
+ +
+
+
+
+
+
+
+
+ + Temperature +
+
+ + +
+
+ + Top K +
+
+ + +
+
+ + Top P +
+
+ + +
+
+ + Typical P +
+
+ + +
+
+ + Min P +
+
+ + +
+
+ + Top A +
+
+ + +
+
+ + TFS +
+
+ + +
+
+ + Repetition Penalty + + + +
+
+ + Rep Pen Range + + + +
+
+ + Repetition Penalty Slope + + + +
+
+

Mirostat

+
+
+ + Mode +
+
+ + +
+
+ + Tau +
+
+ + +
+
+ + Eta +
+
+ + +
+
+
+
+
+ +
+
+ + Seed + + +
+
+
+

GBNF Grammar + + + + + +

+ +
+
+
+
+ Samplers Order +
+
+ Samplers will be applied in a top-down order. + Use with caution. +
+
+
+ Top K + 0 +
+
+ Top A + 1 +
+
+ Top P & Min P + 2 +
+
+ Tail Free Sampling + 3 +
+
+ Typical P + 4 +
+
+ Temperature + 5 +
+
+ Repetition Penalty + 6 +
+
+ +
+
+
+
+
+
+ Samplers Order +
+
+ Samplers will be applied in a top-down order. Use with caution. +
+
+
+ Temperature + 0 +
+
+
+ Top K Sampling + 1 +
+
+
+ Nucleus Sampling + 2 +
+
+
+ Tail Free Sampling + 3 +
+
+
+ Top A Sampling + 4 +
+
+
+ Typical P + 5 +
+
+ +
+ Mirostat + 8 +
+
+
+ Unified Sampling + 9 +
+
+
+ Min P + 10 +
+
+
+
+
+
+
+ + +
+
+ + + +
+
+
+
+ Multiple swipes per generation + +
+
+
+ + Temperature +
+
+ + +
+ +
+ + Top K +
+
+ + +
+
+ + Top P +
+
+ + +
+
+ + Typical P +
+
+ + +
+
+ + Min P +
+
+ + +
+
+ + Top A +
+
+ + +
+
+ + TFS +
+
+ + +
+
+ + Epsilon Cutoff +
+
+ + +
+
+ + Top nsigma +
+
+ + +
+
+ + Eta Cutoff +
+
+ + +
+
+ Repetition Penalty + + +
+
+ Rep Pen Range + + +
+
+ Rep Pen Slope + + +
+
+ Rep Pen Decay + + +
+
+ Encoder Penalty + + +
+
+ Frequency Penalty + + +
+
+ Presence Penalty + + +
+
+ No Repeat Ngram Size + + +
+
+ Skew + + +
+
+ Min Length + + +
+
+ Maximum tokens/second + + +
+
+

+ +
+

+
+
+ Smoothing Factor + + +
+
+ Smoothing Curve + + +
+
+
+ +
+

+ + +
+
+

+
+
+ Threshold + + +
+
+ Probability + + +
+
+
+ +
+

+ + +
+
+

+
+
+ Multiplier + + +
+
+ Base + + +
+
+ Allowed Length + + +
+
+ Penalty Range + + +
+
+
+
+ Sequence Breakers +
+
+ +
+
+
+
+

+
+
+ +
+ Dynamic Temperature +
+
+

+
+
+ Minimum Temp + + +
+
+ Maximum Temp + + +
+
+ Exponent + + +
+
+
+
+

+ +
+

+
+
+ Mode + + +
+
+ + + +
+
+ + + +
+
+
+
+

+ +

+
+
+ + + +
+
+ + + +
+
+ +
+
+
+
+

+ Contrastive Search +
+

+
+ + + +
+
+
+
+ + + + + + + + + + +
+
+
+ + +
+
+
+
+
+ Banned Tokens/Strings +
+
+ +
+
+
+ Global list +
+
+ +
+
+ Preset-specific list +
+
+ +
+
+
+
+
+ Logit Bias +
+ + Add +
+
+
+ Helps to ban or reinforce the usage of certain tokens. +
+
+
+
+
+
+
+

+ CFG +
+

+
+ Scale + + +
+
+
+ Negative Prompt + +
+
+
+
+ +
+
+
+
+
+

+ +

+ +
+
+
+

JSON Schema + + + + + +

+ +
+
+
+
+ Samplers Order +
+
+ kcpp only. Samplers will be applied in a top-down order. + Use with caution. +
+
+
+ Top K + 0 +
+
+ Top A + 1 +
+
+ Top P & Min P + 2 +
+
+ Tail Free Sampling + 3 +
+
+ Typical P + 4 +
+
+ Temperature + 5 +
+
+ Repetition Penalty + 6 +
+
+ +
+
+
+

+ Sampler Order +
+

+
+ llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored. +
+
+
Temperature
+
Top K
+
Top P
+
Typical P
+
Tail Free Sampling
+
Min P
+
Exclude Top Choices
+
DRY
+
+ +
+
+
+

+ Sampler Priority +
+

+
+ Ooba only. Determines the order of samplers. +
+
+
Repetition Penalty
+
Presence Penalty
+
Frequency Penalty
+
DRY
+
Temperature
+
Dynamic Temperature
+
Quadratic / Smooth Sampling
+
Top K
+
Top P
+
Typical P
+
Epsilon Cutoff
+
Eta Cutoff
+
Tail Free Sampling
+
Top A
+
Min P
+
Mirostat
+
XTC
+
Encoder Repetition Penalty
+
No Repeat Ngram
+
+ +
+
+
+

+ Sampler Order +
+

+
+ Aphrodite only. Determines the order of samplers. +
+
+
DRY
+
Penalties
+
No Repeat Ngram
+
Dynatemp & Temperature
+
Top Nsigma
+
Top P & Top K
+
Top A
+
Min P
+
Tail-Free Sampling
+
Eta Cutoff
+
Epsilon Cutoff
+
Typical P
+
Cubic and Quadratic Sampling
+
XTC
+
+ +
+
+
+
+
+
+
+
+ Character Names Behavior + + () +
+
+
+
+ + + + + + +
+
+
+
+
+ Continue Postfix + + () +
+
+
+
+ + + + + + +
+
+
+ +
+ Wrap + entire user message in quotes before sending.
+ Leave off + if you use quotes manually for speech. +
+
+
+ +
+ + Continue sends the last message as assistant role instead of system message with instruction. + +
+
+
+ +
+ + Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models. + +
+
+
+ +
+ + Use search capabilities provided by the backend. + +
+
+
+ +
+ Allows using function tools. + Can be utilized by various extensions to provide additional functionality. +
+
+
+ +
+ Sends images in prompts if the model supports it (e.g. GPT-4V, Claude 3 or Llava 13B). Use the + + action on any message or the + + menu to attach an image file to the chat. +
+
+
+ + +
+
+
+
+ +
+ + Allows the model to return image attachments. + + + Incompatible with the following features: function calling, web search, system prompt. + +
+
+
+ +
+ + Merges all system messages up until the first message with a non-system role, and sends them in a system_instruction field. + +
+
+
+ +
+ + Allows the model to return its thinking process. + +
+
+
+
+ + +
+
+
+
+
+ Assistant Prefill + +
+ +
+ Assistant Impersonation Prefill + +
+ +
+
+ + Prefills won't work when function calling is enabled and any tools are registered. +
+ +
+ + Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt. + +
+
+
+
+
+ Logit Bias +
+
+ Helps to ban or reinforce the usage of certain tokens. + Confirm token parsing with + Tokenizer. +
+
+ + + + + + +
+
+
+ View / Edit bias preset +
+
+
+
+ Add bias entry +
+
+
+ + +   + + Most tokens have a leading space. + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

API

+
+
+ +
+
+
+
+ + + + + Context: --, Response: -- +

API key

+ + Get it here: Register (View my Kudos)
+ Enter 0000000000 to use anonymous mode. +
+
+ + +
+
+ For privacy reasons, your API key will be hidden after you reload the page. +
+

+ Models +
+
+
+

+ +
+
+
+
Not connected...
+
+
+
+
+
+
+

API url

+ Example: http://127.0.0.1:5000/api + +
+ KoboldCpp works better when you select the Text Completion API and then KoboldCpp as a type! +
+
+ + +
+
+
+
+
Not connected...
+
+
+
+ + + +
+
+ + View hidden API keys +
+
+
+
+
+
+
+
+
+

+ + Advanced Formatting + + + + + +

+
+ + + +
+
+
+
+
+

+
+ Context Template +
+
+ +
+

+
+ +
+ + + + + + + + +
+
+
+ + +
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+

+ + Context Formatting + +

+ + + + + + + + +
+ + +
+
+
+
+

+
+ Instruct Template +
+
+ + + +
+

+
+ + +
+ +
+ + + + + + + + +
+
+ +
+ +
+
+ + + +
+ + Include Names + + +
+
+
+
+

+ + + Instruct Sequences + + +

+ +
+ User Message Sequences +
+
+ User Message Prefix + +
+
+ User Message Suffix + +
+
+
+
+ Assistant Message Sequences +
+
+ Assistant Message Prefix + +
+
+ Assistant Message Suffix + +
+
+
+
+ System Message Sequences +
+
+ System Message Prefix + +
+
+ System Message Suffix + +
+
+
+ +
+
+
+ System Prompt Sequences +
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+ Misc. Sequences +
+
+ First Assistant Prefix + +
+
+ Last Assistant Prefix + +
+
+
+
+ First User Prefix + +
+
+ Last User Prefix + +
+
+
+
+ System Instruction Prefix + +
+
+ Stop Sequence + +
+
+
+
+ User Filler Message + +
+
+
+
+
+
+

+
+ System Prompt +
+
+ +
+

+
+ + +
+ +
+ + + + + + + + +
+
+ +
+ + +
+
+ +
+   +
+ +
+

+ + Custom Stopping Strings + + + + +

+
+ + JSON serialized array of strings + + +
+
+ +
+ +
+ +
+
+

Tokenizer + + + +

+ +
+
+
+ + Token Padding + +
+ +
+
+
+

+ Reasoning +

+
+
+ + + +
+
+ +
+ + Max +
+
+
+ + Reasoning Formatting + +
+
+ Prefix + +
+
+ Suffix + +
+
+
+
+ Separator + +
+
+
+
+
+
+

Miscellaneous

+
+ + + Non-markdown strings + + +
+ +
+
+ +
+
+ + + Start Reply With + + +
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + +
+

+ Worlds/Lorebooks + + + +

+
+
+
+
+
+ + + Active World(s) for all chats + + +
+
+ +
+
+
+
+ + Global World Info/Lorebook activation settings + +
+
+
+ Click to expand +
+
+
+
+
+
+ + Scan Depth + + + +
+ +
+ + Context % + + + +
+ +
+ + Budget Cap +
+
+ + +
+ +
+ + Min Activations +
+
+ + +
+ +
+ + Max Depth +
+
+ + +
+
+ + Max Recursion Steps +
+
+ + +
+ +
+ + Insertion Strategy + + +
+
+
+ + + + + + +
+
+
+
+
+
+
+
+
+ + + or + + + + + + + + + + + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ User Settings + + + + +

+
+
+
+ Language: + +
+ +
+
+
+ + + +
+ +
+
+
+
+
+

+ UI Theme +
+ + + +
+ +

+
+ + + +
+
+
+ +
+
+ Avatars: + +
+
+ Chat Style:
+ +
+
+
+
+ Theme Colors +
+
+
+
+
+ + Main Text +
+
+ + Italics Text +
+
+ + Underlined Text +
+
+ + Quote Text +
+
+ + Text Shadow +
+
+ + Chat Background +
+
+ + UI Background +
+
+ + UI Border +
+
+ + User Message +
+
+ + AI Message +
+
+
+
+
+
+ +
+ + + Chat Width + + +
+
+ + +
+ +
+ + Font Scale +
+
+ + +
+ +
+ + Blur Strength +
+
+ + +
+ +
+ + Shadow Width +
+
+ + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+

+ Character Handling +

+
+ + +
+
+ + +
+ + + + + + + +
+ +
+

Miscellaneous

+
+ + +
+ + + + + + + + + +
+ + +
+
+
+ + +
+
+
+

+ Custom CSS + +

+
+ +
+
+
+
+
+
+ +
+

Chat/Message Handling

+
+
+ + # Msg. to Load + +
+
+ + + (0 = All) +
+ +
+ + Streaming FPS +
+
+ + +
+
+
+ + +
+
+ + Enter to Send: + + +
+ + + +
+ + +
+ + + + + + + + + + + + + +
+
+ Auto-swipe +
+
+
+ + Minimum generated message length + + Blacklisted words +
+ + Blacklisted word count to swipe + +
+
+
+
+
+ Auto-Continue +
+
+
+
+ + +
+
+ +
+
+ + +
+
+
+
+ AutoComplete Settings +
+
+
+ +
+
+ + +
+
+ +
+ + +
+
+
+
+ + +
+
+ + + +
+
+ +
+
+ + + + + + +
+
+ + + + + + +
+
+
+
+
+
+

STscript Settings

+
+ + + +
+
+
+
+
+
+
+
+ +
+
+
+

+ Background Image +

+ + + +
+

+ System Backgrounds +

+
+
+ +
+
+

+ Chat Backgrounds +

+
+ Chat backgrounds generated with the  Image Generation extension will appear here. +
+
+
+
+
+
+
+
+
+
+
+
+
+

+ Extensions +

+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ (DEPRECATED) + Extras API: +

+
+
Not connected...
+ +
+
+
+ + +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+

+ Persona Management + + + +

+
+
+ + + + +
+
+
+
+
+ + + +
+ +
+
+
+
+
+
+ + +
+
+
+
+

Current Persona

+ +
+
[Persona Name]
+
+ + + + + + + +
+
+ +

Persona Description

+ + +
+

Position

+
+ Tokens: 0 +
+
+ +
+ +
+
+ + +
+
+ + +
+
+
+ +

Connections

+
+ + + +
+
+
+
+
+ +
+

Global Settings

+ +
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+ + +
+
PNG
+
JSON
+
+
+
+
+
+
+
+
+ +
+
+
+ +
+
+
+ User Avatar +
+
+
+ +
+
+
+ + +
+
+
+
+ +
+
+
+
+

text

+
+ +
+ + +
+
+
+
+
+
+

- Advanced + Definitions +
+
+
+
+
+

+ Prompt Overrides + (For Chat Completion and Instruct Mode) +

+
+
+
+ Insert {{original}} into either box to include the respective default prompt from system settings. +
+

+ Main Prompt + +

+ +
+ Tokens: counting... +
+
+
+

+ Post-History Instructions + +

+ +
+ Tokens: counting... +
+
+
+
+
+
+
+

+ Creator's Metadata + (Not sent with the AI Prompt) +

+
+
+
+ Everything here is optional +
+
+

Created by

+ +
+
+

Character Version

+ +
+
+
+
+

+ Creator's Notes + +

+ +
+
+

+ Tags to Embed + +

+ +
+
+
+
+
+
+

+ Personality summary + + +

+ +
+ Tokens: counting... +
+
+
+

+ Scenario + + + + +

+ +
+ Tokens: counting... +
+
+
+
+

+ + Character's Note + + +

+ +
+
+

+ + @ Depth + +

+ +

+ + Role + +

+ +
+ Tokens: counting... +
+
+
+
+

Talkativeness

+
+ How often the character speaks in group chats! +
+ +
+ Shy + Normal + Chatty +
+
+
+
+
+

+ Examples of dialogue + +

+
+ Important to set the character's writing style. + + + +
+
+ +
+ Tokens: counting... +
+ +
+ +
+ +
+
+
+
+ +
+
+ Chat History + +
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ Select a World Info file for + : +

+
+

Primary Lorebook

+
+ A selected World Info will be bound to this character as its own Lorebook. + When generating an AI reply, it will be combined with the entries from a global World Info selector. + Exporting a character would also export the selected Lorebook file embedded in the JSON data. +
+
+ +
+
+

+ Additional Lorebooks +

+
+
+ Associate one or more auxillary Lorebooks with this character.
+ NOTE: These choices are optional and won't be preserved on character export! +
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
 entries
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+
+
+
+ + + Comma separated (required) + + + Primary Keywords + + + +
+
+ Logic + +
+
+ + + (ignored if empty) + + + Optional Filter + + + +
+
+
+
+ Scan Depth + +
+
+ Case-Sensitive + +
+
+ Whole Words + +
+
+ Group Scoring + +
+
+ Automation ID + +
+
+ + Recursion Level +
+
+ +
+
+
+
+ + +
+
+
+
+
+
+
+
+ + Inclusion Group + + + + + +
+
+ +
+
+
+
+ + Group Weight + +
+
+ +
+
+
+
+ + + Sticky + + + +
+
+ +
+
+
+
+ + + Cooldown + + + +
+
+ +
+
+
+
+ + + Delay + + + +
+
+ +
+
+
+
+
+
+ + Filter to Characters or Tags + + +
+
+ +
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+ + +++ + + +
+ + +
+
+
+
+
+
+ + + + +
+
+
+ + + + +
+
+
+
+ + + + +
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+ ${characterName} + + +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+ + + + + + + +
+
+
+ +
+
+ Thought for some time +
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
1/1
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+ img1 +
+
+ img1 + img2 +
+
+ img1 + img2 + img3 +
+
+ img1 + img2 + img3 + img4 +
+
+ +
+
+

Welcome to SillyTavern!

+
+ Language: + +
+ + SillyTavern is aimed at advanced users. + + +
+
+

+ Looking for AI characters? +

+ + + + Import + + + from supported sources or view + + + + Sample characters + + +
+
+

+ Your Persona +

+
+ + Before you get started, you must select a persona name. + +
+ This can be changed at any time via the icon. +
+

Persona Name:

+
+
+
+
+
+ Avatar +
+
+
+ + +
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+ in this group + + +
+
+
+
+
+
+
+
+ +
+
+
+ + +
+ +
+
+
+
+
+
+
+ +
+
+ +
+
+
+ Go back +
+
+
+
+
+
+ +
+
+
+
+
+

Alternate Greetings

+ +
+ + These will be displayed as swipes on the first message when starting a new chat. + Group members can select one of them to initiate the conversation. + +
+
+ + Click the button to get started! + +
+
+
+
+
+
+ +
+ Alternate Greeting # + +
+
+ +
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ Author's Note +
+
+
+ + Unique to this chat.
+ Checkpoints inherit the Note from their parent, and can be changed individually after that.
+
+ +
+ Tokens: 0 +
+ +
+ + + +
+ +
+ + +
+
+ User inputs until next insertion: (disabled) +
+
+
+
+
+
+ + Character Author's Note (Private) + + + Won't be shared with the character card on export. + +
+
+
+
+ Will be automatically added as the author's note for this character. Will be used in groups, but + can't be modified when a group chat is open. + +
+ Tokens: 0 +
+ +
+ + + +
+
+
+
+
+
+ Default Author's Note +
+
+
+ Will be automatically added as the Author's Note for all new chats. + +
+ Tokens: 0 +
+
+ + + +
+
+ + +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ Chat CFG +
+
+
+ + Unique to this chat.
+
+ +
+
+ +
+
+ +
+
+
+ + + + +
+
+ +
+
+
+
+ +
+
+
+
+ Global CFG +
+
+
+ Will be used as the default CFG options for every chat unless overridden. +
+ +
+
+ +
+
+ +
+
+
+ + + + +
+
+
+
+
+
+
+
+ CFG Prompt Cascading +
+
+
+
+ + Combine positive/negative prompts from other boxes. +
+ For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string. +
+
+
+
+ + + + +
+
+ + +
+
+
+
+
+
+
+
+
+ Token Probabilities +
+
+
+ +
+
+ +
+
+ +
+
+
+
+
+ + Select a token to see alternatives considered by the AI. + + +
+
+
+
+
+ +
+
+
+
+
+
+
+ + +
+
+
+
+ + + + File Name + File Size + +
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jiuguan2025cc/public/jsconfig.json b/jiuguan2025cc/public/jsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..f034fb31bb5addc523d290dbe5d8b1549b1d8abf --- /dev/null +++ b/jiuguan2025cc/public/jsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "checkJs": true, + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "node", + "allowUmdGlobalAccess": true, + "allowSyntheticDefaultImports": true, + "strictBindCallApply": true + }, + "exclude": [ + "**/node_modules/**", + "**/dist/**", + "**/.git/**", + "lib/**", + "**/*.min.js", + "scripts/extensions/quick-reply/lib/**", + "scripts/extensions/tts/lib/**" + ], + "typeAcquisition": { + "include": [] + } +} diff --git a/jiuguan2025cc/public/lib.js b/jiuguan2025cc/public/lib.js new file mode 100644 index 0000000000000000000000000000000000000000..a615a1df49970149dfcf23dc0e3dc6b8bd225f9b --- /dev/null +++ b/jiuguan2025cc/public/lib.js @@ -0,0 +1,124 @@ +/** + * Add all the libraries that you want to expose to the client here. + * They are bundled and exposed by Webpack in the /lib.js file. + */ +import lodash from 'lodash'; +import Fuse from 'fuse.js'; +import DOMPurify from 'dompurify'; +import hljs from 'highlight.js'; +import localforage from 'localforage'; +import Handlebars from 'handlebars'; +import css from '@adobe/css-tools'; +import Bowser from 'bowser'; +import DiffMatchPatch from 'diff-match-patch'; +import { isProbablyReaderable, Readability } from '@mozilla/readability'; +import SVGInject from '@iconfu/svg-inject'; +import showdown from 'showdown'; +import moment from 'moment'; +import seedrandom from 'seedrandom'; +import * as Popper from '@popperjs/core'; +import droll from 'droll'; +import morphdom from 'morphdom'; +import { toggle as slideToggle } from 'slidetoggle'; +import chalk from 'chalk'; + +/** + * Expose the libraries to the 'window' object. + * Needed for compatibility with old extensions. + * Note: New extensions are encouraged to import the libraries directly from lib.js. + */ +export function initLibraryShims() { + if (!window) { + return; + } + if (!('Fuse' in window)) { + // @ts-ignore + window.Fuse = Fuse; + } + if (!('DOMPurify' in window)) { + // @ts-ignore + window.DOMPurify = DOMPurify; + } + if (!('hljs' in window)) { + // @ts-ignore + window.hljs = hljs; + } + if (!('localforage' in window)) { + // @ts-ignore + window.localforage = localforage; + } + if (!('Handlebars' in window)) { + // @ts-ignore + window.Handlebars = Handlebars; + } + if (!('diff_match_patch' in window)) { + // @ts-ignore + window.diff_match_patch = DiffMatchPatch; + } + if (!('SVGInject' in window)) { + // @ts-ignore + window.SVGInject = SVGInject; + } + if (!('showdown' in window)) { + // @ts-ignore + window.showdown = showdown; + } + if (!('moment' in window)) { + // @ts-ignore + window.moment = moment; + } + if (!('Popper' in window)) { + // @ts-ignore + window.Popper = Popper; + } + if (!('droll' in window)) { + // @ts-ignore + window.droll = droll; + } +} + +export default { + lodash, + Fuse, + DOMPurify, + hljs, + localforage, + Handlebars, + css, + Bowser, + DiffMatchPatch, + Readability, + isProbablyReaderable, + SVGInject, + showdown, + moment, + seedrandom, + Popper, + droll, + morphdom, + slideToggle, + chalk, +}; + +export { + lodash, + Fuse, + DOMPurify, + hljs, + localforage, + Handlebars, + css, + Bowser, + DiffMatchPatch, + Readability, + isProbablyReaderable, + SVGInject, + showdown, + moment, + seedrandom, + Popper, + droll, + morphdom, + slideToggle, + chalk, +}; diff --git a/jiuguan2025cc/public/lib/cropper.min.js b/jiuguan2025cc/public/lib/cropper.min.js new file mode 100644 index 0000000000000000000000000000000000000000..03aed4cc9e787b1f75b1cf70d7d30d6787bf5996 --- /dev/null +++ b/jiuguan2025cc/public/lib/cropper.min.js @@ -0,0 +1,10 @@ +/*! + * Cropper.js v1.5.13 + * https://fengyuanchen.github.io/cropperjs + * + * Copyright 2015-present Chen Fengyuan + * Released under the MIT license + * + * Date: 2022-11-20T05:30:46.114Z + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).Cropper=e()}(this,function(){"use strict";function C(e,t){var i,a=Object.keys(e);return Object.getOwnPropertySymbols&&(i=Object.getOwnPropertySymbols(e),t&&(i=i.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),a.push.apply(a,i)),a}function S(a){for(var t=1;tt.length)&&(e=t.length);for(var i=0,a=new Array(e);it.width?3===i?o=t.height*e:h=t.width/e:3===i?h=t.width/e:o=t.height*e,{aspectRatio:e,naturalWidth:n,naturalHeight:a,width:o,height:h});this.canvasData=e,this.limited=1===i||2===i,this.limitCanvas(!0,!0),e.width=Math.min(Math.max(e.width,e.minWidth),e.maxWidth),e.height=Math.min(Math.max(e.height,e.minHeight),e.maxHeight),e.left=(t.width-e.width)/2,e.top=(t.height-e.height)/2,e.oldLeft=e.left,e.oldTop=e.top,this.initialCanvasData=g({},e)},limitCanvas:function(t,e){var i=this.options,a=this.containerData,n=this.canvasData,o=this.cropBoxData,h=i.viewMode,r=n.aspectRatio,s=this.cropped&&o;t&&(t=Number(i.minCanvasWidth)||0,i=Number(i.minCanvasHeight)||0,1=a.width&&(n.minLeft=Math.min(0,r),n.maxLeft=Math.max(0,r)),n.height>=a.height)&&(n.minTop=Math.min(0,t),n.maxTop=Math.max(0,t))):(n.minLeft=-n.width,n.minTop=-n.height,n.maxLeft=a.width,n.maxTop=a.height))},renderCanvas:function(t,e){var i,a,n,o,h=this.canvasData,r=this.imageData;e&&(e={width:r.naturalWidth*Math.abs(r.scaleX||1),height:r.naturalHeight*Math.abs(r.scaleY||1),degree:r.rotate||0},r=e.width,o=e.height,e=e.degree,i=90==(e=Math.abs(e)%180)?{width:o,height:r}:(a=e%90*Math.PI/180,i=Math.sin(a),n=r*(a=Math.cos(a))+o*i,r=r*i+o*a,90h.maxWidth||h.widthh.maxHeight||h.heighte.width?a.height=a.width/i:a.width=a.height*i),this.cropBoxData=a,this.limitCropBox(!0,!0),a.width=Math.min(Math.max(a.width,a.minWidth),a.maxWidth),a.height=Math.min(Math.max(a.height,a.minHeight),a.maxHeight),a.width=Math.max(a.minWidth,a.width*t),a.height=Math.max(a.minHeight,a.height*t),a.left=e.left+(e.width-a.width)/2,a.top=e.top+(e.height-a.height)/2,a.oldLeft=a.left,a.oldTop=a.top,this.initialCropBoxData=g({},a)},limitCropBox:function(t,e){var i,a,n=this.options,o=this.containerData,h=this.canvasData,r=this.cropBoxData,s=this.limited,c=n.aspectRatio;t&&(t=Number(n.minCropBoxWidth)||0,n=Number(n.minCropBoxHeight)||0,i=s?Math.min(o.width,h.width,h.width+h.left,o.width-h.left):o.width,a=s?Math.min(o.height,h.height,h.height+h.top,o.height-h.top):o.height,t=Math.min(t,o.width),n=Math.min(n,o.height),c&&(t&&n?ti.maxWidth||i.widthi.maxHeight||i.height=e.width&&i.height>=e.height?U:P),f(this.cropBox,g({width:i.width,height:i.height},x({translateX:i.left,translateY:i.top}))),this.cropped&&this.limited&&this.limitCanvas(!0,!0),this.disabled||this.output()},output:function(){this.preview(),y(this.element,_,this.getData())}},i={initPreview:function(){var t=this.element,i=this.crossOrigin,e=this.options.preview,a=i?this.crossOriginUrl:this.url,n=t.alt||"The image to preview",o=document.createElement("img");i&&(o.crossOrigin=i),o.src=a,o.alt=n,this.viewBox.appendChild(o),this.viewBoxImage=o,e&&("string"==typeof(o=e)?o=t.ownerDocument.querySelectorAll(e):e.querySelector&&(o=[e]),z(this.previews=o,function(t){var e=document.createElement("img");w(t,m,{width:t.offsetWidth,height:t.offsetHeight,html:t.innerHTML}),i&&(e.crossOrigin=i),e.src=a,e.alt=n,e.style.cssText='display:block;width:100%;height:auto;min-width:0!important;min-height:0!important;max-width:none!important;max-height:none!important;image-orientation:0deg!important;"',t.innerHTML="",t.appendChild(e)}))},resetPreview:function(){z(this.previews,function(e){var i=Dt(e,m),i=(f(e,{width:i.width,height:i.height}),e.innerHTML=i.html,e),e=m;if(o(i[e]))try{delete i[e]}catch(t){i[e]=void 0}else if(i.dataset)try{delete i.dataset[e]}catch(t){i.dataset[e]=void 0}else i.removeAttribute("data-".concat(Ct(e)))})},preview:function(){var h=this.imageData,t=this.canvasData,e=this.cropBoxData,r=e.width,s=e.height,c=h.width,d=h.height,l=e.left-t.left-h.left,p=e.top-t.top-h.top;this.cropped&&!this.disabled&&(f(this.viewBoxImage,g({width:c,height:d},x(g({translateX:-l,translateY:-p},h)))),z(this.previews,function(t){var e=Dt(t,m),i=e.width,e=e.height,a=i,n=e,o=1;r&&(n=s*(o=i/r)),s&&eMath.abs(a-1)?i:a)&&(t.restore&&(o=this.getCanvasData(),h=this.getCropBoxData()),this.render(),t.restore)&&(this.setCanvasData(z(o,function(t,e){o[e]=t*n})),this.setCropBoxData(z(h,function(t,e){h[e]=t*n}))))},dblclick:function(){var t,e;this.disabled||this.options.dragMode===J||this.setDragMode((t=this.dragBox,e=$,(t.classList?t.classList.contains(e):-1y&&(D.x=y-f);break;case k:p+D.xx&&(D.y=x-v)}}var i,a,o,n=this.options,h=this.canvasData,r=this.containerData,s=this.cropBoxData,c=this.pointers,d=this.action,l=n.aspectRatio,p=s.left,m=s.top,u=s.width,g=s.height,f=p+u,v=m+g,w=0,b=0,y=r.width,x=r.height,M=!0,C=(!l&&t.shiftKey&&(l=u&&g?u/g:1),this.limited&&(w=s.minLeft,b=s.minTop,y=w+Math.min(r.width,h.width,h.left+h.width),x=b+Math.min(r.height,h.height,h.top+h.height)),c[Object.keys(c)[0]]),D={x:C.endX-C.startX,y:C.endY-C.startY};switch(d){case P:p+=D.x,m+=D.y;break;case B:0<=D.x&&(y<=f||l&&(m<=b||x<=v))?M=!1:(e(B),(u+=D.x)<0&&(d=k,p-=u=-u),l&&(m+=(s.height-(g=u/l))/2));break;case T:D.y<=0&&(m<=b||l&&(p<=w||y<=f))?M=!1:(e(T),g-=D.y,m+=D.y,g<0&&(d=O,m-=g=-g),l&&(p+=(s.width-(u=g*l))/2));break;case k:D.x<=0&&(p<=w||l&&(m<=b||x<=v))?M=!1:(e(k),u-=D.x,p+=D.x,u<0&&(d=B,p-=u=-u),l&&(m+=(s.height-(g=u/l))/2));break;case O:0<=D.y&&(x<=v||l&&(p<=w||y<=f))?M=!1:(e(O),(g+=D.y)<0&&(d=T,m-=g=-g),l&&(p+=(s.width-(u=g*l))/2));break;case E:if(l){if(D.y<=0&&(m<=b||y<=f)){M=!1;break}e(T),g-=D.y,m+=D.y,u=g*l}else e(T),e(B),!(0<=D.x)||fMath.abs(o)&&(o=i)})}),o),t),M=!1;break;case I:D.x&&D.y?(i=Et(this.cropper),p=C.startX-i.left,m=C.startY-i.top,u=s.minWidth,g=s.minHeight,0 or element.");this.element=t,this.options=g({},mt,u(e)&&e),this.cropped=!1,this.disabled=!1,this.pointers={},this.ready=!1,this.reloading=!1,this.replaced=!1,this.sized=!1,this.sizing=!1,this.init()}var t,e,i;return t=n,i=[{key:"noConflict",value:function(){return window.Cropper=jt,n}},{key:"setDefaults",value:function(t){g(mt,u(t)&&t)}}],(e=[{key:"init",value:function(){var t,e=this.element,i=e.tagName.toLowerCase();if(!e[c]){if(e[c]=this,"img"===i){if(this.isImg=!0,t=e.getAttribute("src")||"",!(this.originalUrl=t))return;t=e.src}else"canvas"===i&&window.HTMLCanvasElement&&(t=e.toDataURL());this.load(t)}}},{key:"load",value:function(t){var e,i,a,n,o,h,r=this;t&&(this.url=t,this.imageData={},e=this.element,(i=this.options).rotatable||i.scalable||(i.checkOrientation=!1),i.checkOrientation&&window.ArrayBuffer?dt.test(t)?lt.test(t)?this.read((h=(h=t).replace(Yt,""),a=atob(h),h=new ArrayBuffer(a.length),z(n=new Uint8Array(h),function(t,e){n[e]=a.charCodeAt(e)}),h)):this.clone():(o=new XMLHttpRequest,h=this.clone.bind(this),this.reloading=!0,(this.xhr=o).onabort=h,o.onerror=h,o.ontimeout=h,o.onprogress=function(){o.getResponseHeader("content-type")!==st&&o.abort()},o.onload=function(){r.read(o.response)},o.onloadend=function(){r.reloading=!1,r.xhr=null},i.checkCrossOrigin&&Nt(t)&&e.crossOrigin&&(t=Lt(t)),o.open("GET",t,!0),o.responseType="arraybuffer",o.withCredentials="use-credentials"===e.crossOrigin,o.send()):this.clone())}},{key:"read",value:function(t){var e=this.options,i=this.imageData,a=Xt(t),n=0,o=1,h=1;1
',o=(n=n.querySelector(".".concat(c,"-container"))).querySelector(".".concat(c,"-canvas")),h=n.querySelector(".".concat(c,"-drag-box")),s=(r=n.querySelector(".".concat(c,"-crop-box"))).querySelector(".".concat(c,"-face")),this.container=a,this.cropper=n,this.canvas=o,this.dragBox=h,this.cropBox=r,this.viewBox=n.querySelector(".".concat(c,"-view-box")),this.face=s,o.appendChild(i),v(t,L),a.insertBefore(n,t.nextSibling),X(i,K),this.initPreview(),this.bind(),e.initialAspectRatio=Math.max(0,e.initialAspectRatio)||NaN,e.aspectRatio=Math.max(0,e.aspectRatio)||NaN,e.viewMode=Math.max(0,Math.min(3,Math.round(e.viewMode)))||0,v(r,L),e.guides||v(r.getElementsByClassName("".concat(c,"-dashed")),L),e.center||v(r.getElementsByClassName("".concat(c,"-center")),L),e.background&&v(n,"".concat(c,"-bg")),e.highlight||v(s,Z),e.cropBoxMovable&&(v(s,G),w(s,d,P)),e.cropBoxResizable||(v(r.getElementsByClassName("".concat(c,"-line")),L),v(r.getElementsByClassName("".concat(c,"-point")),L)),this.render(),this.ready=!0,this.setDragMode(e.dragMode),e.autoCrop&&this.crop(),this.setData(e.data),l(e.ready)&&b(t,"ready",e.ready,{once:!0}),y(t,"ready"))}},{key:"unbuild",value:function(){var t;this.ready&&(this.ready=!1,this.unbind(),this.resetPreview(),(t=this.cropper.parentNode)&&t.removeChild(this.cropper),X(this.element,L))}},{key:"uncreate",value:function(){this.ready?(this.unbuild(),this.ready=!1,this.cropped=!1):this.sizing?(this.sizingImage.onload=null,this.sizing=!1,this.sized=!1):this.reloading?(this.xhr.onabort=null,this.xhr.abort()):this.image&&this.stop()}}])&&A(t.prototype,e),i&&A(t,i),Object.defineProperty(t,"prototype",{writable:!1}),n}();return g(Pt.prototype,t,i,e,Rt,St,At),Pt}); \ No newline at end of file diff --git a/jiuguan2025cc/public/lib/dialog-polyfill.css b/jiuguan2025cc/public/lib/dialog-polyfill.css new file mode 100644 index 0000000000000000000000000000000000000000..6dee42bff19082310a06bc7dbb5abff1f7330ff7 --- /dev/null +++ b/jiuguan2025cc/public/lib/dialog-polyfill.css @@ -0,0 +1,37 @@ +.poly_dialog { + position: absolute; + left: 0; right: 0; + width: -moz-fit-content; + width: -webkit-fit-content; + width: fit-content; + height: -moz-fit-content; + height: -webkit-fit-content; + height: fit-content; + margin: auto; + border: solid; + padding: 1em; + background: white; + color: black; + display: block; +} + +.poly_dialog:not([open]) { + display: none; +} + +.poly_dialog + .backdrop { + position: fixed; + top: 0; right: 0; bottom: 0; left: 0; + background: rgba(0,0,0,0.1); +} + +._poly_dialog_overlay { + position: fixed; + top: 0; right: 0; bottom: 0; left: 0; +} + +.poly_dialog.fixed { + position: fixed; + top: 50%; + transform: translate(0, -50%); +} \ No newline at end of file diff --git a/jiuguan2025cc/public/lib/dialog-polyfill.esm.js b/jiuguan2025cc/public/lib/dialog-polyfill.esm.js new file mode 100644 index 0000000000000000000000000000000000000000..f40e02f5896153cdb960f1e77c69cb66d3a3f2fe --- /dev/null +++ b/jiuguan2025cc/public/lib/dialog-polyfill.esm.js @@ -0,0 +1,858 @@ +// nb. This is for IE10 and lower _only_. +var supportCustomEvent = window.CustomEvent; +if (!supportCustomEvent || typeof supportCustomEvent === 'object') { + supportCustomEvent = function CustomEvent(event, x) { + x = x || {}; + var ev = document.createEvent('CustomEvent'); + ev.initCustomEvent(event, !!x.bubbles, !!x.cancelable, x.detail || null); + return ev; + }; + supportCustomEvent.prototype = window.Event.prototype; +} + +/** + * Dispatches the passed event to both an "on" handler as well as via the + * normal dispatch operation. Does not bubble. + * + * @param {!EventTarget} target + * @param {!Event} event + * @return {boolean} + */ +function safeDispatchEvent(target, event) { + var check = 'on' + event.type.toLowerCase(); + if (typeof target[check] === 'function') { + target[check](event); + } + return target.dispatchEvent(event); +} + +/** + * @param {Element} el to check for stacking context + * @return {boolean} whether this el or its parents creates a stacking context + */ +function createsStackingContext(el) { + while (el && el !== document.body) { + var s = window.getComputedStyle(el); + var invalid = function(k, ok) { + return !(s[k] === undefined || s[k] === ok); + }; + + if (s.opacity < 1 || + invalid('zIndex', 'auto') || + invalid('transform', 'none') || + invalid('mixBlendMode', 'normal') || + invalid('filter', 'none') || + invalid('perspective', 'none') || + s['isolation'] === 'isolate' || + s.position === 'fixed' || + s.webkitOverflowScrolling === 'touch') { + return true; + } + el = el.parentElement; + } + return false; +} + +/** + * Finds the nearest from the passed element. + * + * @param {Element} el to search from + * @return {HTMLDialogElement} dialog found + */ +function findNearestDialog(el) { + while (el) { + if (el.localName === 'dialog') { + return /** @type {HTMLDialogElement} */ (el); + } + if (el.parentElement) { + el = el.parentElement; + } else if (el.parentNode) { + el = el.parentNode.host; + } else { + el = null; + } + } + return null; +} + +/** + * Blur the specified element, as long as it's not the HTML body element. + * This works around an IE9/10 bug - blurring the body causes Windows to + * blur the whole application. + * + * @param {Element} el to blur + */ +function safeBlur(el) { + // Find the actual focused element when the active element is inside a shadow root + while (el && el.shadowRoot && el.shadowRoot.activeElement) { + el = el.shadowRoot.activeElement; + } + + if (el && el.blur && el !== document.body) { + el.blur(); + } +} + +/** + * @param {!NodeList} nodeList to search + * @param {Node} node to find + * @return {boolean} whether node is inside nodeList + */ +function inNodeList(nodeList, node) { + for (var i = 0; i < nodeList.length; ++i) { + if (nodeList[i] === node) { + return true; + } + } + return false; +} + +/** + * @param {HTMLFormElement} el to check + * @return {boolean} whether this form has method="dialog" + */ +function isFormMethodDialog(el) { + if (!el || !el.hasAttribute('method')) { + return false; + } + return el.getAttribute('method').toLowerCase() === 'dialog'; +} + +/** + * @param {!DocumentFragment|!Element} hostElement + * @return {?Element} + */ +function findFocusableElementWithin(hostElement) { + // Note that this is 'any focusable area'. This list is probably not exhaustive, but the + // alternative involves stepping through and trying to focus everything. + var opts = ['button', 'input', 'keygen', 'select', 'textarea']; + var query = opts.map(function(el) { + return el + ':not([disabled])'; + }); + // TODO(samthor): tabindex values that are not numeric are not focusable. + query.push('[tabindex]:not([disabled]):not([tabindex=""])'); // tabindex != "", not disabled + var target = hostElement.querySelector(query.join(', ')); + + if (!target && 'attachShadow' in Element.prototype) { + // If we haven't found a focusable target, see if the host element contains an element + // which has a shadowRoot. + // Recursively search for the first focusable item in shadow roots. + var elems = hostElement.querySelectorAll('*'); + for (var i = 0; i < elems.length; i++) { + if (elems[i].tagName && elems[i].shadowRoot) { + target = findFocusableElementWithin(elems[i].shadowRoot); + if (target) { + break; + } + } + } + } + return target; +} + +/** + * Determines if an element is attached to the DOM. + * @param {Element} element to check + * @return {boolean} whether the element is in DOM + */ +function isConnected(element) { + return element.isConnected || document.body.contains(element); +} + +/** + * @param {!Event} event + * @return {?Element} + */ +function findFormSubmitter(event) { + if (event.submitter) { + return event.submitter; + } + + var form = event.target; + if (!(form instanceof HTMLFormElement)) { + return null; + } + + var submitter = dialogPolyfill.formSubmitter; + if (!submitter) { + var target = event.target; + var root = ('getRootNode' in target && target.getRootNode() || document); + submitter = root.activeElement; + } + + if (!submitter || submitter.form !== form) { + return null; + } + return submitter; +} + +/** + * @param {!Event} event + */ +function maybeHandleSubmit(event) { + if (event.defaultPrevented) { + return; + } + var form = /** @type {!HTMLFormElement} */ (event.target); + + // We'd have a value if we clicked on an imagemap. + var value = dialogPolyfill.imagemapUseValue; + var submitter = findFormSubmitter(event); + if (value === null && submitter) { + value = submitter.value; + } + + // There should always be a dialog as this handler is added specifically on them, but check just + // in case. + var dialog = findNearestDialog(form); + if (!dialog) { + return; + } + + // Prefer formmethod on the button. + var formmethod = submitter && submitter.getAttribute('formmethod') || form.getAttribute('method'); + if (formmethod !== 'dialog') { + return; + } + event.preventDefault(); + + if (value != null) { + // nb. we explicitly check against null/undefined + dialog.close(value); + } else { + dialog.close(); + } +} + +/** + * @param {!HTMLDialogElement} dialog to upgrade + * @constructor + */ +function dialogPolyfillInfo(dialog) { + this.dialog_ = dialog; + this.replacedStyleTop_ = false; + this.openAsModal_ = false; + + // Set a11y role. Browsers that support dialog implicitly know this already. + if (!dialog.hasAttribute('role')) { + dialog.setAttribute('role', 'dialog'); + } + + dialog.show = this.show.bind(this); + dialog.showModal = this.showModal.bind(this); + dialog.close = this.close.bind(this); + + dialog.addEventListener('submit', maybeHandleSubmit, false); + + if (!('returnValue' in dialog)) { + dialog.returnValue = ''; + } + + if ('MutationObserver' in window) { + var mo = new MutationObserver(this.maybeHideModal.bind(this)); + mo.observe(dialog, {attributes: true, attributeFilter: ['open']}); + } else { + // IE10 and below support. Note that DOMNodeRemoved etc fire _before_ removal. They also + // seem to fire even if the element was removed as part of a parent removal. Use the removed + // events to force downgrade (useful if removed/immediately added). + var removed = false; + var cb = function() { + removed ? this.downgradeModal() : this.maybeHideModal(); + removed = false; + }.bind(this); + var timeout; + var delayModel = function(ev) { + if (ev.target !== dialog) { return; } // not for a child element + var cand = 'DOMNodeRemoved'; + removed |= (ev.type.substr(0, cand.length) === cand); + window.clearTimeout(timeout); + timeout = window.setTimeout(cb, 0); + }; + ['DOMAttrModified', 'DOMNodeRemoved', 'DOMNodeRemovedFromDocument'].forEach(function(name) { + dialog.addEventListener(name, delayModel); + }); + } + // Note that the DOM is observed inside DialogManager while any dialog + // is being displayed as a modal, to catch modal removal from the DOM. + + Object.defineProperty(dialog, 'open', { + set: this.setOpen.bind(this), + get: dialog.hasAttribute.bind(dialog, 'open') + }); + + this.backdrop_ = document.createElement('div'); + this.backdrop_.className = 'backdrop'; + this.backdrop_.addEventListener('mouseup' , this.backdropMouseEvent_.bind(this)); + this.backdrop_.addEventListener('mousedown', this.backdropMouseEvent_.bind(this)); + this.backdrop_.addEventListener('click' , this.backdropMouseEvent_.bind(this)); +} + +dialogPolyfillInfo.prototype = /** @type {HTMLDialogElement.prototype} */ ({ + + get dialog() { + return this.dialog_; + }, + + /** + * Maybe remove this dialog from the modal top layer. This is called when + * a modal dialog may no longer be tenable, e.g., when the dialog is no + * longer open or is no longer part of the DOM. + */ + maybeHideModal: function() { + if (this.dialog_.hasAttribute('open') && isConnected(this.dialog_)) { return; } + this.downgradeModal(); + }, + + /** + * Remove this dialog from the modal top layer, leaving it as a non-modal. + */ + downgradeModal: function() { + if (!this.openAsModal_) { return; } + this.openAsModal_ = false; + this.dialog_.style.zIndex = ''; + + // This won't match the native exactly because if the user set top on a centered + // polyfill dialog, that top gets thrown away when the dialog is closed. Not sure it's + // possible to polyfill this perfectly. + if (this.replacedStyleTop_) { + this.dialog_.style.top = ''; + this.replacedStyleTop_ = false; + } + + // Clear the backdrop and remove from the manager. + this.backdrop_.parentNode && this.backdrop_.parentNode.removeChild(this.backdrop_); + dialogPolyfill.dm.removeDialog(this); + }, + + /** + * @param {boolean} value whether to open or close this dialog + */ + setOpen: function(value) { + if (value) { + this.dialog_.hasAttribute('open') || this.dialog_.setAttribute('open', ''); + } else { + this.dialog_.removeAttribute('open'); + this.maybeHideModal(); // nb. redundant with MutationObserver + } + }, + + /** + * Handles mouse events ('mouseup', 'mousedown', 'click') on the fake .backdrop element, redirecting them as if + * they were on the dialog itself. + * + * @param {!Event} e to redirect + */ + backdropMouseEvent_: function(e) { + if (!this.dialog_.hasAttribute('tabindex')) { + // Clicking on the backdrop should move the implicit cursor, even if dialog cannot be + // focused. Create a fake thing to focus on. If the backdrop was _before_ the dialog, this + // would not be needed - clicks would move the implicit cursor there. + var fake = document.createElement('div'); + this.dialog_.insertBefore(fake, this.dialog_.firstChild); + fake.tabIndex = -1; + fake.focus(); + this.dialog_.removeChild(fake); + } else { + this.dialog_.focus(); + } + + var redirectedEvent = document.createEvent('MouseEvents'); + redirectedEvent.initMouseEvent(e.type, e.bubbles, e.cancelable, window, + e.detail, e.screenX, e.screenY, e.clientX, e.clientY, e.ctrlKey, + e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget); + this.dialog_.dispatchEvent(redirectedEvent); + e.stopPropagation(); + }, + + /** + * Focuses on the first focusable element within the dialog. This will always blur the current + * focus, even if nothing within the dialog is found. + */ + focus_: function() { + // Find element with `autofocus` attribute, or fall back to the first form/tabindex control. + var target = this.dialog_.querySelector('[autofocus]:not([disabled])'); + if (!target && this.dialog_.tabIndex >= 0) { + target = this.dialog_; + } + if (!target) { + target = findFocusableElementWithin(this.dialog_); + } + safeBlur(document.activeElement); + target && target.focus(); + }, + + /** + * Sets the zIndex for the backdrop and dialog. + * + * @param {number} dialogZ + * @param {number} backdropZ + */ + updateZIndex: function(dialogZ, backdropZ) { + if (dialogZ < backdropZ) { + throw new Error('dialogZ should never be < backdropZ'); + } + this.dialog_.style.zIndex = dialogZ; + this.backdrop_.style.zIndex = backdropZ; + }, + + /** + * Shows the dialog. If the dialog is already open, this does nothing. + */ + show: function() { + if (!this.dialog_.open) { + this.setOpen(true); + this.focus_(); + } + }, + + /** + * Show this dialog modally. + */ + showModal: function() { + if (this.dialog_.hasAttribute('open')) { + throw new Error('Failed to execute \'showModal\' on dialog: The element is already open, and therefore cannot be opened modally.'); + } + if (!isConnected(this.dialog_)) { + throw new Error('Failed to execute \'showModal\' on dialog: The element is not in a Document.'); + } + if (!dialogPolyfill.dm.pushDialog(this)) { + throw new Error('Failed to execute \'showModal\' on dialog: There are too many open modal dialogs.'); + } + + if (createsStackingContext(this.dialog_.parentElement)) { + console.warn('A dialog is being shown inside a stacking context. ' + + 'This may cause it to be unusable. For more information, see this link: ' + + 'https://github.com/GoogleChrome/dialog-polyfill/#stacking-context'); + } + + this.setOpen(true); + this.openAsModal_ = true; + + // Optionally center vertically, relative to the current viewport. + if (dialogPolyfill.needsCentering(this.dialog_)) { + dialogPolyfill.reposition(this.dialog_); + this.replacedStyleTop_ = true; + } else { + this.replacedStyleTop_ = false; + } + + // Insert backdrop. + this.dialog_.parentNode.insertBefore(this.backdrop_, this.dialog_.nextSibling); + + // Focus on whatever inside the dialog. + this.focus_(); + }, + + /** + * Closes this HTMLDialogElement. This is optional vs clearing the open + * attribute, however this fires a 'close' event. + * + * @param {string=} opt_returnValue to use as the returnValue + */ + close: function(opt_returnValue) { + if (!this.dialog_.hasAttribute('open')) { + throw new Error('Failed to execute \'close\' on dialog: The element does not have an \'open\' attribute, and therefore cannot be closed.'); + } + this.setOpen(false); + + // Leave returnValue untouched in case it was set directly on the element + if (opt_returnValue !== undefined) { + this.dialog_.returnValue = opt_returnValue; + } + + // Triggering "close" event for any attached listeners on the . + var closeEvent = new supportCustomEvent('close', { + bubbles: false, + cancelable: false + }); + safeDispatchEvent(this.dialog_, closeEvent); + } + +}); + +var dialogPolyfill = {}; + +dialogPolyfill.reposition = function(element) { + var scrollTop = document.body.scrollTop || document.documentElement.scrollTop; + var topValue = scrollTop + (window.innerHeight - element.offsetHeight) / 2; + element.style.top = Math.max(scrollTop, topValue) + 'px'; +}; + +dialogPolyfill.isInlinePositionSetByStylesheet = function(element) { + for (var i = 0; i < document.styleSheets.length; ++i) { + var styleSheet = document.styleSheets[i]; + var cssRules = null; + // Some browsers throw on cssRules. + try { + cssRules = styleSheet.cssRules; + } catch (e) {} + if (!cssRules) { continue; } + for (var j = 0; j < cssRules.length; ++j) { + var rule = cssRules[j]; + var selectedNodes = null; + // Ignore errors on invalid selector texts. + try { + selectedNodes = document.querySelectorAll(rule.selectorText); + } catch(e) {} + if (!selectedNodes || !inNodeList(selectedNodes, element)) { + continue; + } + var cssTop = rule.style.getPropertyValue('top'); + var cssBottom = rule.style.getPropertyValue('bottom'); + if ((cssTop && cssTop !== 'auto') || (cssBottom && cssBottom !== 'auto')) { + return true; + } + } + } + return false; +}; + +dialogPolyfill.needsCentering = function(dialog) { + var computedStyle = window.getComputedStyle(dialog); + if (computedStyle.position !== 'absolute') { + return false; + } + + // We must determine whether the top/bottom specified value is non-auto. In + // WebKit/Blink, checking computedStyle.top == 'auto' is sufficient, but + // Firefox returns the used value. So we do this crazy thing instead: check + // the inline style and then go through CSS rules. + if ((dialog.style.top !== 'auto' && dialog.style.top !== '') || + (dialog.style.bottom !== 'auto' && dialog.style.bottom !== '')) { + return false; + } + return !dialogPolyfill.isInlinePositionSetByStylesheet(dialog); +}; + +/** + * @param {!Element} element to force upgrade + */ +dialogPolyfill.forceRegisterDialog = function(element) { + if (window.HTMLDialogElement || element.showModal) { + console.warn('This browser already supports , the polyfill ' + + 'may not work correctly', element); + } + if (element.localName !== 'dialog') { + throw new Error('Failed to register dialog: The element is not a dialog.'); + } + new dialogPolyfillInfo(/** @type {!HTMLDialogElement} */ (element)); +}; + +/** + * @param {!Element} element to upgrade, if necessary + */ +dialogPolyfill.registerDialog = function(element) { + if (!element.showModal) { + dialogPolyfill.forceRegisterDialog(element); + } +}; + +/** + * @constructor + */ +dialogPolyfill.DialogManager = function() { + /** @type {!Array} */ + this.pendingDialogStack = []; + + var checkDOM = this.checkDOM_.bind(this); + + // The overlay is used to simulate how a modal dialog blocks the document. + // The blocking dialog is positioned on top of the overlay, and the rest of + // the dialogs on the pending dialog stack are positioned below it. In the + // actual implementation, the modal dialog stacking is controlled by the + // top layer, where z-index has no effect. + this.overlay = document.createElement('div'); + this.overlay.className = '_poly_dialog_overlay'; + this.overlay.addEventListener('click', function(e) { + this.forwardTab_ = undefined; + e.stopPropagation(); + checkDOM([]); // sanity-check DOM + }.bind(this)); + + this.handleKey_ = this.handleKey_.bind(this); + this.handleFocus_ = this.handleFocus_.bind(this); + + this.zIndexLow_ = 100000; + this.zIndexHigh_ = 100000 + 150; + + this.forwardTab_ = undefined; + + if ('MutationObserver' in window) { + this.mo_ = new MutationObserver(function(records) { + var removed = []; + records.forEach(function(rec) { + for (var i = 0, c; c = rec.removedNodes[i]; ++i) { + if (!(c instanceof Element)) { + continue; + } else if (c.localName === 'dialog') { + removed.push(c); + } + removed = removed.concat(c.querySelectorAll('dialog')); + } + }); + removed.length && checkDOM(removed); + }); + } +}; + +/** + * Called on the first modal dialog being shown. Adds the overlay and related + * handlers. + */ +dialogPolyfill.DialogManager.prototype.blockDocument = function() { + document.documentElement.addEventListener('focus', this.handleFocus_, true); + document.addEventListener('keydown', this.handleKey_); + this.mo_ && this.mo_.observe(document, {childList: true, subtree: true}); +}; + +/** + * Called on the first modal dialog being removed, i.e., when no more modal + * dialogs are visible. + */ +dialogPolyfill.DialogManager.prototype.unblockDocument = function() { + document.documentElement.removeEventListener('focus', this.handleFocus_, true); + document.removeEventListener('keydown', this.handleKey_); + this.mo_ && this.mo_.disconnect(); +}; + +/** + * Updates the stacking of all known dialogs. + */ +dialogPolyfill.DialogManager.prototype.updateStacking = function() { + var zIndex = this.zIndexHigh_; + + for (var i = 0, dpi; dpi = this.pendingDialogStack[i]; ++i) { + dpi.updateZIndex(--zIndex, --zIndex); + if (i === 0) { + this.overlay.style.zIndex = --zIndex; + } + } + + // Make the overlay a sibling of the dialog itself. + var last = this.pendingDialogStack[0]; + if (last) { + var p = last.dialog.parentNode || document.body; + p.appendChild(this.overlay); + } else if (this.overlay.parentNode) { + this.overlay.parentNode.removeChild(this.overlay); + } +}; + +/** + * @param {Element} candidate to check if contained or is the top-most modal dialog + * @return {boolean} whether candidate is contained in top dialog + */ +dialogPolyfill.DialogManager.prototype.containedByTopDialog_ = function(candidate) { + while (candidate = findNearestDialog(candidate)) { + for (var i = 0, dpi; dpi = this.pendingDialogStack[i]; ++i) { + if (dpi.dialog === candidate) { + return i === 0; // only valid if top-most + } + } + candidate = candidate.parentElement; + } + return false; +}; + +dialogPolyfill.DialogManager.prototype.handleFocus_ = function(event) { + var target = event.composedPath ? event.composedPath()[0] : event.target; + + if (this.containedByTopDialog_(target)) { return; } + + if (document.activeElement === document.documentElement) { return; } + + event.preventDefault(); + event.stopPropagation(); + safeBlur(/** @type {Element} */ (target)); + + if (this.forwardTab_ === undefined) { return; } // move focus only from a tab key + + var dpi = this.pendingDialogStack[0]; + var dialog = dpi.dialog; + var position = dialog.compareDocumentPosition(target); + if (position & Node.DOCUMENT_POSITION_PRECEDING) { + if (this.forwardTab_) { + // forward + dpi.focus_(); + } else if (target !== document.documentElement) { + // backwards if we're not already focused on + document.documentElement.focus(); + } + } + + return false; +}; + +dialogPolyfill.DialogManager.prototype.handleKey_ = function(event) { + this.forwardTab_ = undefined; + if (event.keyCode === 27) { + event.preventDefault(); + event.stopPropagation(); + var cancelEvent = new supportCustomEvent('cancel', { + bubbles: false, + cancelable: true + }); + var dpi = this.pendingDialogStack[0]; + if (dpi && safeDispatchEvent(dpi.dialog, cancelEvent)) { + dpi.dialog.close(); + } + } else if (event.keyCode === 9) { + this.forwardTab_ = !event.shiftKey; + } +}; + +/** + * Finds and downgrades any known modal dialogs that are no longer displayed. Dialogs that are + * removed and immediately readded don't stay modal, they become normal. + * + * @param {!Array} removed that have definitely been removed + */ +dialogPolyfill.DialogManager.prototype.checkDOM_ = function(removed) { + // This operates on a clone because it may cause it to change. Each change also calls + // updateStacking, which only actually needs to happen once. But who removes many modal dialogs + // at a time?! + var clone = this.pendingDialogStack.slice(); + clone.forEach(function(dpi) { + if (removed.indexOf(dpi.dialog) !== -1) { + dpi.downgradeModal(); + } else { + dpi.maybeHideModal(); + } + }); +}; + +/** + * @param {!dialogPolyfillInfo} dpi + * @return {boolean} whether the dialog was allowed + */ +dialogPolyfill.DialogManager.prototype.pushDialog = function(dpi) { + var allowed = (this.zIndexHigh_ - this.zIndexLow_) / 2 - 1; + if (this.pendingDialogStack.length >= allowed) { + return false; + } + if (this.pendingDialogStack.unshift(dpi) === 1) { + this.blockDocument(); + } + this.updateStacking(); + return true; +}; + +/** + * @param {!dialogPolyfillInfo} dpi + */ +dialogPolyfill.DialogManager.prototype.removeDialog = function(dpi) { + var index = this.pendingDialogStack.indexOf(dpi); + if (index === -1) { return; } + + this.pendingDialogStack.splice(index, 1); + if (this.pendingDialogStack.length === 0) { + this.unblockDocument(); + } + this.updateStacking(); +}; + +dialogPolyfill.dm = new dialogPolyfill.DialogManager(); +dialogPolyfill.formSubmitter = null; +dialogPolyfill.imagemapUseValue = null; + +/** + * Installs global handlers, such as click listers and native method overrides. These are needed + * even if a no dialog is registered, as they deal with
. + */ +if (window.HTMLDialogElement === undefined) { + + /** + * If HTMLFormElement translates method="DIALOG" into 'get', then replace the descriptor with + * one that returns the correct value. + */ + var testForm = document.createElement('form'); + testForm.setAttribute('method', 'dialog'); + if (testForm.method !== 'dialog') { + var methodDescriptor = Object.getOwnPropertyDescriptor(HTMLFormElement.prototype, 'method'); + if (methodDescriptor) { + // nb. Some older iOS and older PhantomJS fail to return the descriptor. Don't do anything + // and don't bother to update the element. + var realGet = methodDescriptor.get; + methodDescriptor.get = function() { + if (isFormMethodDialog(this)) { + return 'dialog'; + } + return realGet.call(this); + }; + var realSet = methodDescriptor.set; + /** @this {HTMLElement} */ + methodDescriptor.set = function(v) { + if (typeof v === 'string' && v.toLowerCase() === 'dialog') { + return this.setAttribute('method', v); + } + return realSet.call(this, v); + }; + Object.defineProperty(HTMLFormElement.prototype, 'method', methodDescriptor); + } + } + + /** + * Global 'click' handler, to capture the or
").button({label:V("").text(this.options.closeText).html(),icon:"ui-icon-closethick",showLabel:!1}).appendTo(this.uiDialogTitlebar),this._addClass(this.uiDialogTitlebarClose,"ui-dialog-titlebar-close"),this._on(this.uiDialogTitlebarClose,{click:function(t){t.preventDefault(),this.close(t)}}),t=V("").uniqueId().prependTo(this.uiDialogTitlebar),this._addClass(t,"ui-dialog-title"),this._title(t),this.uiDialogTitlebar.prependTo(this.uiDialog),this.uiDialog.attr({"aria-labelledby":t.attr("id")})},_title:function(t){this.options.title?t.text(this.options.title):t.html(" ")},_createButtonPane:function(){this.uiDialogButtonPane=V("
"),this._addClass(this.uiDialogButtonPane,"ui-dialog-buttonpane","ui-widget-content ui-helper-clearfix"),this.uiButtonSet=V("
").appendTo(this.uiDialogButtonPane),this._addClass(this.uiButtonSet,"ui-dialog-buttonset"),this._createButtons()},_createButtons:function(){var s=this,t=this.options.buttons;this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),V.isEmptyObject(t)||Array.isArray(t)&&!t.length?this._removeClass(this.uiDialog,"ui-dialog-buttons"):(V.each(t,function(t,e){var i;e=V.extend({type:"button"},e="function"==typeof e?{click:e,text:t}:e),i=e.click,t={icon:e.icon,iconPosition:e.iconPosition,showLabel:e.showLabel,icons:e.icons,text:e.text},delete e.click,delete e.icon,delete e.iconPosition,delete e.showLabel,delete e.icons,"boolean"==typeof e.text&&delete e.text,V("",e).button(t).appendTo(s.uiButtonSet).on("click",function(){i.apply(s.element[0],arguments)})}),this._addClass(this.uiDialog,"ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog))},_makeDraggable:function(){var n=this,o=this.options;function a(t){return{position:t.position,offset:t.offset}}this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(t,e){n._addClass(V(this),"ui-dialog-dragging"),n._blockFrames(),n._trigger("dragStart",t,a(e))},drag:function(t,e){n._trigger("drag",t,a(e))},stop:function(t,e){var i=e.offset.left-n.document.scrollLeft(),s=e.offset.top-n.document.scrollTop();o.position={my:"left top",at:"left"+(0<=i?"+":"")+i+" top"+(0<=s?"+":"")+s,of:n.window},n._removeClass(V(this),"ui-dialog-dragging"),n._unblockFrames(),n._trigger("dragStop",t,a(e))}})},_makeResizable:function(){var n=this,o=this.options,t=o.resizable,e=this.uiDialog.css("position"),t="string"==typeof t?t:"n,e,s,w,se,sw,ne,nw";function a(t){return{originalPosition:t.originalPosition,originalSize:t.originalSize,position:t.position,size:t.size}}this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:o.maxWidth,maxHeight:o.maxHeight,minWidth:o.minWidth,minHeight:this._minHeight(),handles:t,start:function(t,e){n._addClass(V(this),"ui-dialog-resizing"),n._blockFrames(),n._trigger("resizeStart",t,a(e))},resize:function(t,e){n._trigger("resize",t,a(e))},stop:function(t,e){var i=n.uiDialog.offset(),s=i.left-n.document.scrollLeft(),i=i.top-n.document.scrollTop();o.height=n.uiDialog.height(),o.width=n.uiDialog.width(),o.position={my:"left top",at:"left"+(0<=s?"+":"")+s+" top"+(0<=i?"+":"")+i,of:n.window},n._removeClass(V(this),"ui-dialog-resizing"),n._unblockFrames(),n._trigger("resizeStop",t,a(e))}}).css("position",e)},_trackFocus:function(){this._on(this.widget(),{focusin:function(t){this._makeFocusTarget(),this._focusedElement=V(t.target)}})},_makeFocusTarget:function(){this._untrackInstance(),this._trackingInstances().unshift(this)},_untrackInstance:function(){var t=this._trackingInstances(),e=V.inArray(this,t);-1!==e&&t.splice(e,1)},_trackingInstances:function(){var t=this.document.data("ui-dialog-instances");return t||this.document.data("ui-dialog-instances",t=[]),t},_minHeight:function(){var t=this.options;return"auto"===t.height?t.minHeight:Math.min(t.minHeight,t.height)},_position:function(){var t=this.uiDialog.is(":visible");t||this.uiDialog.show(),this.uiDialog.position(this.options.position),t||this.uiDialog.hide()},_setOptions:function(t){var i=this,s=!1,n={};V.each(t,function(t,e){i._setOption(t,e),t in i.sizeRelatedOptions&&(s=!0),t in i.resizableRelatedOptions&&(n[t]=e)}),s&&(this._size(),this._position()),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option",n)},_setOption:function(t,e){var i,s=this.uiDialog;"disabled"!==t&&(this._super(t,e),"appendTo"===t&&this.uiDialog.appendTo(this._appendTo()),"buttons"===t&&this._createButtons(),"closeText"===t&&this.uiDialogTitlebarClose.button({label:V("").text(""+this.options.closeText).html()}),"draggable"===t&&((i=s.is(":data(ui-draggable)"))&&!e&&s.draggable("destroy"),!i&&e&&this._makeDraggable()),"position"===t&&this._position(),"resizable"===t&&((i=s.is(":data(ui-resizable)"))&&!e&&s.resizable("destroy"),i&&"string"==typeof e&&s.resizable("option","handles",e),i||!1===e||this._makeResizable()),"title"===t&&this._title(this.uiDialogTitlebar.find(".ui-dialog-title")))},_size:function(){var t,e,i,s=this.options;this.element.show().css({width:"auto",minHeight:0,maxHeight:"none",height:0}),s.minWidth>s.width&&(s.width=s.minWidth),t=this.uiDialog.css({height:"auto",width:s.width}).outerHeight(),e=Math.max(0,s.minHeight-t),i="number"==typeof s.maxHeight?Math.max(0,s.maxHeight-t):"none","auto"===s.height?this.element.css({minHeight:e,maxHeight:i,height:"auto"}):this.element.height(Math.max(0,s.height-t)),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())},_blockFrames:function(){this.iframeBlocks=this.document.find("iframe").map(function(){var t=V(this);return V("
").css({position:"absolute",width:t.outerWidth(),height:t.outerHeight()}).appendTo(t.parent()).offset(t.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_allowInteraction:function(t){return!!V(t.target).closest(".ui-dialog").length||!!V(t.target).closest(".ui-datepicker").length},_createOverlay:function(){var i,s;this.options.modal&&(i=V.fn.jquery.substring(0,4),s=!0,this._delay(function(){s=!1}),this.document.data("ui-dialog-overlays")||this.document.on("focusin.ui-dialog",function(t){var e;s||((e=this._trackingInstances()[0])._allowInteraction(t)||(t.preventDefault(),e._focusTabbable(),"3.4."!==i&&"3.5."!==i||e._delay(e._restoreTabbableFocus)))}.bind(this)),this.overlay=V("
").appendTo(this._appendTo()),this._addClass(this.overlay,null,"ui-widget-overlay ui-front"),this._on(this.overlay,{mousedown:"_keepFocus"}),this.document.data("ui-dialog-overlays",(this.document.data("ui-dialog-overlays")||0)+1))},_destroyOverlay:function(){var t;this.options.modal&&this.overlay&&((t=this.document.data("ui-dialog-overlays")-1)?this.document.data("ui-dialog-overlays",t):(this.document.off("focusin.ui-dialog"),this.document.removeData("ui-dialog-overlays")),this.overlay.remove(),this.overlay=null)}}),!1!==V.uiBackCompat&&V.widget("ui.dialog",V.ui.dialog,{options:{dialogClass:""},_createWrapper:function(){this._super(),this.uiDialog.addClass(this.options.dialogClass)},_setOption:function(t,e){"dialogClass"===t&&this.uiDialog.removeClass(this.options.dialogClass).addClass(e),this._superApply(arguments)}});V.ui.dialog;function lt(t,e,i){return e<=t&&t").appendTo(this.element),this._addClass(this.valueDiv,"ui-progressbar-value","ui-widget-header"),this._refreshValue()},_destroy:function(){this.element.removeAttr("role aria-valuemin aria-valuemax aria-valuenow"),this.valueDiv.remove()},value:function(t){if(void 0===t)return this.options.value;this.options.value=this._constrainedValue(t),this._refreshValue()},_constrainedValue:function(t){return void 0===t&&(t=this.options.value),this.indeterminate=!1===t,"number"!=typeof t&&(t=0),!this.indeterminate&&Math.min(this.options.max,Math.max(this.min,t))},_setOptions:function(t){var e=t.value;delete t.value,this._super(t),this.options.value=this._constrainedValue(e),this._refreshValue()},_setOption:function(t,e){"max"===t&&(e=Math.max(this.min,e)),this._super(t,e)},_setOptionDisabled:function(t){this._super(t),this.element.attr("aria-disabled",t),this._toggleClass(null,"ui-state-disabled",!!t)},_percentage:function(){return this.indeterminate?100:100*(this.options.value-this.min)/(this.options.max-this.min)},_refreshValue:function(){var t=this.options.value,e=this._percentage();this.valueDiv.toggle(this.indeterminate||t>this.min).width(e.toFixed(0)+"%"),this._toggleClass(this.valueDiv,"ui-progressbar-complete",null,t===this.options.max)._toggleClass("ui-progressbar-indeterminate",null,this.indeterminate),this.indeterminate?(this.element.removeAttr("aria-valuenow"),this.overlayDiv||(this.overlayDiv=V("
").appendTo(this.valueDiv),this._addClass(this.overlayDiv,"ui-progressbar-overlay"))):(this.element.attr({"aria-valuemax":this.options.max,"aria-valuenow":t}),this.overlayDiv&&(this.overlayDiv.remove(),this.overlayDiv=null)),this.oldValue!==t&&(this.oldValue=t,this._trigger("change")),t===this.options.max&&this._trigger("complete")}}),V.widget("ui.selectable",V.ui.mouse,{version:"1.13.2",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch",selected:null,selecting:null,start:null,stop:null,unselected:null,unselecting:null},_create:function(){var i=this;this._addClass("ui-selectable"),this.dragged=!1,this.refresh=function(){i.elementPos=V(i.element[0]).offset(),i.selectees=V(i.options.filter,i.element[0]),i._addClass(i.selectees,"ui-selectee"),i.selectees.each(function(){var t=V(this),e=t.offset(),e={left:e.left-i.elementPos.left,top:e.top-i.elementPos.top};V.data(this,"selectable-item",{element:this,$element:t,left:e.left,top:e.top,right:e.left+t.outerWidth(),bottom:e.top+t.outerHeight(),startselected:!1,selected:t.hasClass("ui-selected"),selecting:t.hasClass("ui-selecting"),unselecting:t.hasClass("ui-unselecting")})})},this.refresh(),this._mouseInit(),this.helper=V("
"),this._addClass(this.helper,"ui-selectable-helper")},_destroy:function(){this.selectees.removeData("selectable-item"),this._mouseDestroy()},_mouseStart:function(i){var s=this,t=this.options;this.opos=[i.pageX,i.pageY],this.elementPos=V(this.element[0]).offset(),this.options.disabled||(this.selectees=V(t.filter,this.element[0]),this._trigger("start",i),V(t.appendTo).append(this.helper),this.helper.css({left:i.pageX,top:i.pageY,width:0,height:0}),t.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var t=V.data(this,"selectable-item");t.startselected=!0,i.metaKey||i.ctrlKey||(s._removeClass(t.$element,"ui-selected"),t.selected=!1,s._addClass(t.$element,"ui-unselecting"),t.unselecting=!0,s._trigger("unselecting",i,{unselecting:t.element}))}),V(i.target).parents().addBack().each(function(){var t,e=V.data(this,"selectable-item");if(e)return t=!i.metaKey&&!i.ctrlKey||!e.$element.hasClass("ui-selected"),s._removeClass(e.$element,t?"ui-unselecting":"ui-selected")._addClass(e.$element,t?"ui-selecting":"ui-unselecting"),e.unselecting=!t,e.selecting=t,(e.selected=t)?s._trigger("selecting",i,{selecting:e.element}):s._trigger("unselecting",i,{unselecting:e.element}),!1}))},_mouseDrag:function(s){if(this.dragged=!0,!this.options.disabled){var t,n=this,o=this.options,a=this.opos[0],r=this.opos[1],l=s.pageX,h=s.pageY;return ll||i.righth||i.bottoma&&i.rightr&&i.bottom",options:{appendTo:null,classes:{"ui-selectmenu-button-open":"ui-corner-top","ui-selectmenu-button-closed":"ui-corner-all"},disabled:null,icons:{button:"ui-icon-triangle-1-s"},position:{my:"left top",at:"left bottom",collision:"none"},width:!1,change:null,close:null,focus:null,open:null,select:null},_create:function(){var t=this.element.uniqueId().attr("id");this.ids={element:t,button:t+"-button",menu:t+"-menu"},this._drawButton(),this._drawMenu(),this._bindFormResetHandler(),this._rendered=!1,this.menuItems=V()},_drawButton:function(){var t,e=this,i=this._parseOption(this.element.find("option:selected"),this.element[0].selectedIndex);this.labels=this.element.labels().attr("for",this.ids.button),this._on(this.labels,{click:function(t){this.button.trigger("focus"),t.preventDefault()}}),this.element.hide(),this.button=V("",{tabindex:this.options.disabled?-1:0,id:this.ids.button,role:"combobox","aria-expanded":"false","aria-autocomplete":"list","aria-owns":this.ids.menu,"aria-haspopup":"true",title:this.element.attr("title")}).insertAfter(this.element),this._addClass(this.button,"ui-selectmenu-button ui-selectmenu-button-closed","ui-button ui-widget"),t=V("").appendTo(this.button),this._addClass(t,"ui-selectmenu-icon","ui-icon "+this.options.icons.button),this.buttonItem=this._renderButtonItem(i).appendTo(this.button),!1!==this.options.width&&this._resizeButton(),this._on(this.button,this._buttonEvents),this.button.one("focusin",function(){e._rendered||e._refreshMenu()})},_drawMenu:function(){var i=this;this.menu=V("
    ",{"aria-hidden":"true","aria-labelledby":this.ids.button,id:this.ids.menu}),this.menuWrap=V("
    ").append(this.menu),this._addClass(this.menuWrap,"ui-selectmenu-menu","ui-front"),this.menuWrap.appendTo(this._appendTo()),this.menuInstance=this.menu.menu({classes:{"ui-menu":"ui-corner-bottom"},role:"listbox",select:function(t,e){t.preventDefault(),i._setSelection(),i._select(e.item.data("ui-selectmenu-item"),t)},focus:function(t,e){e=e.item.data("ui-selectmenu-item");null!=i.focusIndex&&e.index!==i.focusIndex&&(i._trigger("focus",t,{item:e}),i.isOpen||i._select(e,t)),i.focusIndex=e.index,i.button.attr("aria-activedescendant",i.menuItems.eq(e.index).attr("id"))}}).menu("instance"),this.menuInstance._off(this.menu,"mouseleave"),this.menuInstance._closeOnDocumentClick=function(){return!1},this.menuInstance._isDivider=function(){return!1}},refresh:function(){this._refreshMenu(),this.buttonItem.replaceWith(this.buttonItem=this._renderButtonItem(this._getSelectedItem().data("ui-selectmenu-item")||{})),null===this.options.width&&this._resizeButton()},_refreshMenu:function(){var t=this.element.find("option");this.menu.empty(),this._parseOptions(t),this._renderMenu(this.menu,this.items),this.menuInstance.refresh(),this.menuItems=this.menu.find("li").not(".ui-selectmenu-optgroup").find(".ui-menu-item-wrapper"),this._rendered=!0,t.length&&(t=this._getSelectedItem(),this.menuInstance.focus(null,t),this._setAria(t.data("ui-selectmenu-item")),this._setOption("disabled",this.element.prop("disabled")))},open:function(t){this.options.disabled||(this._rendered?(this._removeClass(this.menu.find(".ui-state-active"),null,"ui-state-active"),this.menuInstance.focus(null,this._getSelectedItem())):this._refreshMenu(),this.menuItems.length&&(this.isOpen=!0,this._toggleAttr(),this._resizeMenu(),this._position(),this._on(this.document,this._documentClick),this._trigger("open",t)))},_position:function(){this.menuWrap.position(V.extend({of:this.button},this.options.position))},close:function(t){this.isOpen&&(this.isOpen=!1,this._toggleAttr(),this.range=null,this._off(this.document),this._trigger("close",t))},widget:function(){return this.button},menuWidget:function(){return this.menu},_renderButtonItem:function(t){var e=V("");return this._setText(e,t.label),this._addClass(e,"ui-selectmenu-text"),e},_renderMenu:function(s,t){var n=this,o="";V.each(t,function(t,e){var i;e.optgroup!==o&&(i=V("
  • ",{text:e.optgroup}),n._addClass(i,"ui-selectmenu-optgroup","ui-menu-divider"+(e.element.parent("optgroup").prop("disabled")?" ui-state-disabled":"")),i.appendTo(s),o=e.optgroup),n._renderItemData(s,e)})},_renderItemData:function(t,e){return this._renderItem(t,e).data("ui-selectmenu-item",e)},_renderItem:function(t,e){var i=V("
  • "),s=V("
    ",{title:e.element.attr("title")});return e.disabled&&this._addClass(i,null,"ui-state-disabled"),this._setText(s,e.label),i.append(s).appendTo(t)},_setText:function(t,e){e?t.text(e):t.html(" ")},_move:function(t,e){var i,s=".ui-menu-item";this.isOpen?i=this.menuItems.eq(this.focusIndex).parent("li"):(i=this.menuItems.eq(this.element[0].selectedIndex).parent("li"),s+=":not(.ui-state-disabled)"),(s="first"===t||"last"===t?i["first"===t?"prevAll":"nextAll"](s).eq(-1):i[t+"All"](s).eq(0)).length&&this.menuInstance.focus(e,s)},_getSelectedItem:function(){return this.menuItems.eq(this.element[0].selectedIndex).parent("li")},_toggle:function(t){this[this.isOpen?"close":"open"](t)},_setSelection:function(){var t;this.range&&(window.getSelection?((t=window.getSelection()).removeAllRanges(),t.addRange(this.range)):this.range.select(),this.button.trigger("focus"))},_documentClick:{mousedown:function(t){this.isOpen&&(V(t.target).closest(".ui-selectmenu-menu, #"+V.escapeSelector(this.ids.button)).length||this.close(t))}},_buttonEvents:{mousedown:function(){var t;window.getSelection?(t=window.getSelection()).rangeCount&&(this.range=t.getRangeAt(0)):this.range=document.selection.createRange()},click:function(t){this._setSelection(),this._toggle(t)},keydown:function(t){var e=!0;switch(t.keyCode){case V.ui.keyCode.TAB:case V.ui.keyCode.ESCAPE:this.close(t),e=!1;break;case V.ui.keyCode.ENTER:this.isOpen&&this._selectFocusedItem(t);break;case V.ui.keyCode.UP:t.altKey?this._toggle(t):this._move("prev",t);break;case V.ui.keyCode.DOWN:t.altKey?this._toggle(t):this._move("next",t);break;case V.ui.keyCode.SPACE:this.isOpen?this._selectFocusedItem(t):this._toggle(t);break;case V.ui.keyCode.LEFT:this._move("prev",t);break;case V.ui.keyCode.RIGHT:this._move("next",t);break;case V.ui.keyCode.HOME:case V.ui.keyCode.PAGE_UP:this._move("first",t);break;case V.ui.keyCode.END:case V.ui.keyCode.PAGE_DOWN:this._move("last",t);break;default:this.menu.trigger(t),e=!1}e&&t.preventDefault()}},_selectFocusedItem:function(t){var e=this.menuItems.eq(this.focusIndex).parent("li");e.hasClass("ui-state-disabled")||this._select(e.data("ui-selectmenu-item"),t)},_select:function(t,e){var i=this.element[0].selectedIndex;this.element[0].selectedIndex=t.index,this.buttonItem.replaceWith(this.buttonItem=this._renderButtonItem(t)),this._setAria(t),this._trigger("select",e,{item:t}),t.index!==i&&this._trigger("change",e,{item:t}),this.close(e)},_setAria:function(t){t=this.menuItems.eq(t.index).attr("id");this.button.attr({"aria-labelledby":t,"aria-activedescendant":t}),this.menu.attr("aria-activedescendant",t)},_setOption:function(t,e){var i;"icons"===t&&(i=this.button.find("span.ui-icon"),this._removeClass(i,null,this.options.icons.button)._addClass(i,null,e.button)),this._super(t,e),"appendTo"===t&&this.menuWrap.appendTo(this._appendTo()),"width"===t&&this._resizeButton()},_setOptionDisabled:function(t){this._super(t),this.menuInstance.option("disabled",t),this.button.attr("aria-disabled",t),this._toggleClass(this.button,null,"ui-state-disabled",t),this.element.prop("disabled",t),t?(this.button.attr("tabindex",-1),this.close()):this.button.attr("tabindex",0)},_appendTo:function(){var t=this.options.appendTo;return t=!(t=!(t=t&&(t.jquery||t.nodeType?V(t):this.document.find(t).eq(0)))||!t[0]?this.element.closest(".ui-front, dialog"):t).length?this.document[0].body:t},_toggleAttr:function(){this.button.attr("aria-expanded",this.isOpen),this._removeClass(this.button,"ui-selectmenu-button-"+(this.isOpen?"closed":"open"))._addClass(this.button,"ui-selectmenu-button-"+(this.isOpen?"open":"closed"))._toggleClass(this.menuWrap,"ui-selectmenu-open",null,this.isOpen),this.menu.attr("aria-hidden",!this.isOpen)},_resizeButton:function(){var t=this.options.width;!1!==t?(null===t&&(t=this.element.show().outerWidth(),this.element.hide()),this.button.outerWidth(t)):this.button.css("width","")},_resizeMenu:function(){this.menu.outerWidth(Math.max(this.button.outerWidth(),this.menu.width("").outerWidth()+1))},_getCreateOptions:function(){var t=this._super();return t.disabled=this.element.prop("disabled"),t},_parseOptions:function(t){var i=this,s=[];t.each(function(t,e){e.hidden||s.push(i._parseOption(V(e),t))}),this.items=s},_parseOption:function(t,e){var i=t.parent("optgroup");return{element:t,index:e,value:t.val(),label:t.text(),optgroup:i.attr("label")||"",disabled:i.prop("disabled")||t.prop("disabled")}},_destroy:function(){this._unbindFormResetHandler(),this.menuWrap.remove(),this.button.remove(),this.element.show(),this.element.removeUniqueId(),this.labels.attr("for",this.ids.element)}}]),V.widget("ui.slider",V.ui.mouse,{version:"1.13.2",widgetEventPrefix:"slide",options:{animate:!1,classes:{"ui-slider":"ui-corner-all","ui-slider-handle":"ui-corner-all","ui-slider-range":"ui-corner-all ui-widget-header"},distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null,change:null,slide:null,start:null,stop:null},numPages:5,_create:function(){this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this._calculateNewMax(),this._addClass("ui-slider ui-slider-"+this.orientation,"ui-widget ui-widget-content"),this._refresh(),this._animateOff=!1},_refresh:function(){this._createRange(),this._createHandles(),this._setupEvents(),this._refreshValue()},_createHandles:function(){var t,e=this.options,i=this.element.find(".ui-slider-handle"),s=[],n=e.values&&e.values.length||1;for(i.length>n&&(i.slice(n).remove(),i=i.slice(0,n)),t=i.length;t");this.handles=i.add(V(s.join("")).appendTo(this.element)),this._addClass(this.handles,"ui-slider-handle","ui-state-default"),this.handle=this.handles.eq(0),this.handles.each(function(t){V(this).data("ui-slider-handle-index",t).attr("tabIndex",0)})},_createRange:function(){var t=this.options;t.range?(!0===t.range&&(t.values?t.values.length&&2!==t.values.length?t.values=[t.values[0],t.values[0]]:Array.isArray(t.values)&&(t.values=t.values.slice(0)):t.values=[this._valueMin(),this._valueMin()]),this.range&&this.range.length?(this._removeClass(this.range,"ui-slider-range-min ui-slider-range-max"),this.range.css({left:"",bottom:""})):(this.range=V("
    ").appendTo(this.element),this._addClass(this.range,"ui-slider-range")),"min"!==t.range&&"max"!==t.range||this._addClass(this.range,"ui-slider-range-"+t.range)):(this.range&&this.range.remove(),this.range=null)},_setupEvents:function(){this._off(this.handles),this._on(this.handles,this._handleEvents),this._hoverable(this.handles),this._focusable(this.handles)},_destroy:function(){this.handles.remove(),this.range&&this.range.remove(),this._mouseDestroy()},_mouseCapture:function(t){var i,s,n,o,e,a,r=this,l=this.options;return!l.disabled&&(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),a={x:t.pageX,y:t.pageY},i=this._normValueFromMouse(a),s=this._valueMax()-this._valueMin()+1,this.handles.each(function(t){var e=Math.abs(i-r.values(t));(e=this._valueMax())return this._valueMax();var e=0=e&&(t+=0this.options.max&&(t-=i),this.max=parseFloat(t.toFixed(this._precision()))},_precision:function(){var t=this._precisionOf(this.options.step);return t=null!==this.options.min?Math.max(t,this._precisionOf(this.options.min)):t},_precisionOf:function(t){var e=t.toString(),t=e.indexOf(".");return-1===t?0:e.length-t-1},_valueMin:function(){return this.options.min},_valueMax:function(){return this.max},_refreshRange:function(t){"vertical"===t&&this.range.css({width:"",left:""}),"horizontal"===t&&this.range.css({height:"",bottom:""})},_refreshValue:function(){var e,i,t,s,n,o=this.options.range,a=this.options,r=this,l=!this._animateOff&&a.animate,h={};this._hasMultipleValues()?this.handles.each(function(t){i=(r.values(t)-r._valueMin())/(r._valueMax()-r._valueMin())*100,h["horizontal"===r.orientation?"left":"bottom"]=i+"%",V(this).stop(1,1)[l?"animate":"css"](h,a.animate),!0===r.options.range&&("horizontal"===r.orientation?(0===t&&r.range.stop(1,1)[l?"animate":"css"]({left:i+"%"},a.animate),1===t&&r.range[l?"animate":"css"]({width:i-e+"%"},{queue:!1,duration:a.animate})):(0===t&&r.range.stop(1,1)[l?"animate":"css"]({bottom:i+"%"},a.animate),1===t&&r.range[l?"animate":"css"]({height:i-e+"%"},{queue:!1,duration:a.animate}))),e=i}):(t=this.value(),s=this._valueMin(),n=this._valueMax(),i=n!==s?(t-s)/(n-s)*100:0,h["horizontal"===this.orientation?"left":"bottom"]=i+"%",this.handle.stop(1,1)[l?"animate":"css"](h,a.animate),"min"===o&&"horizontal"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({width:i+"%"},a.animate),"max"===o&&"horizontal"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({width:100-i+"%"},a.animate),"min"===o&&"vertical"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({height:i+"%"},a.animate),"max"===o&&"vertical"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({height:100-i+"%"},a.animate))},_handleEvents:{keydown:function(t){var e,i,s,n=V(t.target).data("ui-slider-handle-index");switch(t.keyCode){case V.ui.keyCode.HOME:case V.ui.keyCode.END:case V.ui.keyCode.PAGE_UP:case V.ui.keyCode.PAGE_DOWN:case V.ui.keyCode.UP:case V.ui.keyCode.RIGHT:case V.ui.keyCode.DOWN:case V.ui.keyCode.LEFT:if(t.preventDefault(),!this._keySliding&&(this._keySliding=!0,this._addClass(V(t.target),null,"ui-state-active"),!1===this._start(t,n)))return}switch(s=this.options.step,e=i=this._hasMultipleValues()?this.values(n):this.value(),t.keyCode){case V.ui.keyCode.HOME:i=this._valueMin();break;case V.ui.keyCode.END:i=this._valueMax();break;case V.ui.keyCode.PAGE_UP:i=this._trimAlignValue(e+(this._valueMax()-this._valueMin())/this.numPages);break;case V.ui.keyCode.PAGE_DOWN:i=this._trimAlignValue(e-(this._valueMax()-this._valueMin())/this.numPages);break;case V.ui.keyCode.UP:case V.ui.keyCode.RIGHT:if(e===this._valueMax())return;i=this._trimAlignValue(e+s);break;case V.ui.keyCode.DOWN:case V.ui.keyCode.LEFT:if(e===this._valueMin())return;i=this._trimAlignValue(e-s)}this._slide(t,n,i)},keyup:function(t){var e=V(t.target).data("ui-slider-handle-index");this._keySliding&&(this._keySliding=!1,this._stop(t,e),this._change(t,e),this._removeClass(V(t.target),null,"ui-state-active"))}}}),V.widget("ui.sortable",V.ui.mouse,{version:"1.13.2",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_isOverAxis:function(t,e,i){return e<=t&&t*{ cursor: "+o.cursor+" !important; }").appendTo(n)),o.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",o.zIndex)),o.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",o.opacity)),this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",t,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!i)for(s=this.containers.length-1;0<=s;s--)this.containers[s]._trigger("activate",t,this._uiHash(this));return V.ui.ddmanager&&(V.ui.ddmanager.current=this),V.ui.ddmanager&&!o.dropBehaviour&&V.ui.ddmanager.prepareOffsets(this,t),this.dragging=!0,this._addClass(this.helper,"ui-sortable-helper"),this.helper.parent().is(this.appendTo)||(this.helper.detach().appendTo(this.appendTo),this.offset.parent=this._getParentOffset()),this.position=this.originalPosition=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,this.lastPositionAbs=this.positionAbs=this._convertPositionTo("absolute"),this._mouseDrag(t),!0},_scroll:function(t){var e=this.options,i=!1;return this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-t.pageYt[this.floating?"width":"height"]?h&&c:o",i.document[0]);return i._addClass(t,"ui-sortable-placeholder",s||i.currentItem[0].className)._removeClass(t,"ui-sortable-helper"),"tbody"===n?i._createTrPlaceholder(i.currentItem.find("tr").eq(0),V("",i.document[0]).appendTo(t)):"tr"===n?i._createTrPlaceholder(i.currentItem,t):"img"===n&&t.attr("src",i.currentItem.attr("src")),s||t.css("visibility","hidden"),t},update:function(t,e){s&&!o.forcePlaceholderSize||(e.height()&&(!o.forcePlaceholderSize||"tbody"!==n&&"tr"!==n)||e.height(i.currentItem.innerHeight()-parseInt(i.currentItem.css("paddingTop")||0,10)-parseInt(i.currentItem.css("paddingBottom")||0,10)),e.width()||e.width(i.currentItem.innerWidth()-parseInt(i.currentItem.css("paddingLeft")||0,10)-parseInt(i.currentItem.css("paddingRight")||0,10)))}}),i.placeholder=V(o.placeholder.element.call(i.element,i.currentItem)),i.currentItem.after(i.placeholder),o.placeholder.update(i,i.placeholder)},_createTrPlaceholder:function(t,e){var i=this;t.children().each(function(){V(" ",i.document[0]).attr("colspan",V(this).attr("colspan")||1).appendTo(e)})},_contactContainers:function(t){for(var e,i,s,n,o,a,r,l,h,c=null,u=null,d=this.containers.length-1;0<=d;d--)V.contains(this.currentItem[0],this.containers[d].element[0])||(this._intersectsWith(this.containers[d].containerCache)?c&&V.contains(this.containers[d].element[0],c.element[0])||(c=this.containers[d],u=d):this.containers[d].containerCache.over&&(this.containers[d]._trigger("out",t,this._uiHash(this)),this.containers[d].containerCache.over=0));if(c)if(1===this.containers.length)this.containers[u].containerCache.over||(this.containers[u]._trigger("over",t,this._uiHash(this)),this.containers[u].containerCache.over=1);else{for(i=1e4,s=null,n=(l=c.floating||this._isFloating(this.currentItem))?"left":"top",o=l?"width":"height",h=l?"pageX":"pageY",e=this.items.length-1;0<=e;e--)V.contains(this.containers[u].element[0],this.items[e].item[0])&&this.items[e].item[0]!==this.currentItem[0]&&(a=this.items[e].item.offset()[n],r=!1,t[h]-a>this.items[e][o]/2&&(r=!0),Math.abs(t[h]-a)this.containment[2]&&(i=this.containment[2]+this.offset.click.left),t.pageY-this.offset.click.top>this.containment[3]&&(s=this.containment[3]+this.offset.click.top)),e.grid&&(t=this.originalPageY+Math.round((s-this.originalPageY)/e.grid[1])*e.grid[1],s=!this.containment||t-this.offset.click.top>=this.containment[1]&&t-this.offset.click.top<=this.containment[3]?t:t-this.offset.click.top>=this.containment[1]?t-e.grid[1]:t+e.grid[1],t=this.originalPageX+Math.round((i-this.originalPageX)/e.grid[0])*e.grid[0],i=!this.containment||t-this.offset.click.left>=this.containment[0]&&t-this.offset.click.left<=this.containment[2]?t:t-this.offset.click.left>=this.containment[0]?t-e.grid[0]:t+e.grid[0])),{top:s-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():o?0:n.scrollTop()),left:i-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():o?0:n.scrollLeft())}},_rearrange:function(t,e,i,s){i?i[0].appendChild(this.placeholder[0]):e.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?e.item[0]:e.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var n=this.counter;this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(t,e){this.reverting=!1;var i,s=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(i in this._storedCSS)"auto"!==this._storedCSS[i]&&"static"!==this._storedCSS[i]||(this._storedCSS[i]="");this.currentItem.css(this._storedCSS),this._removeClass(this.currentItem,"ui-sortable-helper")}else this.currentItem.show();function n(e,i,s){return function(t){s._trigger(e,t,i._uiHash(i))}}for(this.fromOutside&&!e&&s.push(function(t){this._trigger("receive",t,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||e||s.push(function(t){this._trigger("update",t,this._uiHash())}),this!==this.currentContainer&&(e||(s.push(function(t){this._trigger("remove",t,this._uiHash())}),s.push(function(e){return function(t){e._trigger("receive",t,this._uiHash(this))}}.call(this,this.currentContainer)),s.push(function(e){return function(t){e._trigger("update",t,this._uiHash(this))}}.call(this,this.currentContainer)))),i=this.containers.length-1;0<=i;i--)e||s.push(n("deactivate",this,this.containers[i])),this.containers[i].containerCache.over&&(s.push(n("out",this,this.containers[i])),this.containers[i].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,e||this._trigger("beforeStop",t,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.cancelHelperRemoval||(this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null),!e){for(i=0;i",widgetEventPrefix:"spin",options:{classes:{"ui-spinner":"ui-corner-all","ui-spinner-down":"ui-corner-br","ui-spinner-up":"ui-corner-tr"},culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),""!==this.value()&&this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var s=this._super(),n=this.element;return V.each(["min","max","step"],function(t,e){var i=n.attr(e);null!=i&&i.length&&(s[e]=i)}),s},_events:{keydown:function(t){this._start(t)&&this._keydown(t)&&t.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(t){this.cancelBlur?delete this.cancelBlur:(this._stop(),this._refresh(),this.previous!==this.element.val()&&this._trigger("change",t))},mousewheel:function(t,e){var i=V.ui.safeActiveElement(this.document[0]);if(this.element[0]===i&&e){if(!this.spinning&&!this._start(t))return!1;this._spin((0").parent().append("")},_draw:function(){this._enhance(),this._addClass(this.uiSpinner,"ui-spinner","ui-widget ui-widget-content"),this._addClass("ui-spinner-input"),this.element.attr("role","spinbutton"),this.buttons=this.uiSpinner.children("a").attr("tabIndex",-1).attr("aria-hidden",!0).button({classes:{"ui-button":""}}),this._removeClass(this.buttons,"ui-corner-all"),this._addClass(this.buttons.first(),"ui-spinner-button ui-spinner-up"),this._addClass(this.buttons.last(),"ui-spinner-button ui-spinner-down"),this.buttons.first().button({icon:this.options.icons.up,showLabel:!1}),this.buttons.last().button({icon:this.options.icons.down,showLabel:!1}),this.buttons.height()>Math.ceil(.5*this.uiSpinner.height())&&0e.max?e.max:null!==e.min&&t"},_buttonHtml:function(){return""}});var ct;V.ui.spinner;V.widget("ui.tabs",{version:"1.13.2",delay:300,options:{active:null,classes:{"ui-tabs":"ui-corner-all","ui-tabs-nav":"ui-corner-all","ui-tabs-panel":"ui-corner-bottom","ui-tabs-tab":"ui-corner-top"},collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_isLocal:(ct=/#.*$/,function(t){var e=t.href.replace(ct,""),i=location.href.replace(ct,"");try{e=decodeURIComponent(e)}catch(t){}try{i=decodeURIComponent(i)}catch(t){}return 1?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var t=this.options,e=this.tablist.children(":has(a[href])");t.disabled=V.map(e.filter(".ui-state-disabled"),function(t){return e.index(t)}),this._processTabs(),!1!==t.active&&this.anchors.length?this.active.length&&!V.contains(this.tablist[0],this.active[0])?this.tabs.length===t.disabled.length?(t.active=!1,this.active=V()):this._activate(this._findNextTab(Math.max(0,t.active-1),!1)):t.active=this.tabs.index(this.active):(t.active=!1,this.active=V()),this._refresh()},_refresh:function(){this._setOptionDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-hidden":"true"}),this.active.length?(this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}),this._addClass(this.active,"ui-tabs-active","ui-state-active"),this._getPanelForTab(this.active).show().attr({"aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var l=this,t=this.tabs,e=this.anchors,i=this.panels;this.tablist=this._getList().attr("role","tablist"),this._addClass(this.tablist,"ui-tabs-nav","ui-helper-reset ui-helper-clearfix ui-widget-header"),this.tablist.on("mousedown"+this.eventNamespace,"> li",function(t){V(this).is(".ui-state-disabled")&&t.preventDefault()}).on("focus"+this.eventNamespace,".ui-tabs-anchor",function(){V(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this.tabs=this.tablist.find("> li:has(a[href])").attr({role:"tab",tabIndex:-1}),this._addClass(this.tabs,"ui-tabs-tab","ui-state-default"),this.anchors=this.tabs.map(function(){return V("a",this)[0]}).attr({tabIndex:-1}),this._addClass(this.anchors,"ui-tabs-anchor"),this.panels=V(),this.anchors.each(function(t,e){var i,s,n,o=V(e).uniqueId().attr("id"),a=V(e).closest("li"),r=a.attr("aria-controls");l._isLocal(e)?(n=(i=e.hash).substring(1),s=l.element.find(l._sanitizeSelector(i))):(n=a.attr("aria-controls")||V({}).uniqueId()[0].id,(s=l.element.find(i="#"+n)).length||(s=l._createPanel(n)).insertAfter(l.panels[t-1]||l.tablist),s.attr("aria-live","polite")),s.length&&(l.panels=l.panels.add(s)),r&&a.data("ui-tabs-aria-controls",r),a.attr({"aria-controls":n,"aria-labelledby":o}),s.attr("aria-labelledby",o)}),this.panels.attr("role","tabpanel"),this._addClass(this.panels,"ui-tabs-panel","ui-widget-content"),t&&(this._off(t.not(this.tabs)),this._off(e.not(this.anchors)),this._off(i.not(this.panels)))},_getList:function(){return this.tablist||this.element.find("ol, ul").eq(0)},_createPanel:function(t){return V("
    ").attr("id",t).data("ui-tabs-destroy",!0)},_setOptionDisabled:function(t){var e,i;for(Array.isArray(t)&&(t.length?t.length===this.anchors.length&&(t=!0):t=!1),i=0;e=this.tabs[i];i++)e=V(e),!0===t||-1!==V.inArray(i,t)?(e.attr("aria-disabled","true"),this._addClass(e,null,"ui-state-disabled")):(e.removeAttr("aria-disabled"),this._removeClass(e,null,"ui-state-disabled"));this.options.disabled=t,this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,!0===t)},_setupEvents:function(t){var i={};t&&V.each(t.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(!0,this.anchors,{click:function(t){t.preventDefault()}}),this._on(this.anchors,i),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(t){var i,e=this.element.parent();"fill"===t?(i=e.height(),i-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var t=V(this),e=t.css("position");"absolute"!==e&&"fixed"!==e&&(i-=t.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){i-=V(this).outerHeight(!0)}),this.panels.each(function(){V(this).height(Math.max(0,i-V(this).innerHeight()+V(this).height()))}).css("overflow","auto")):"auto"===t&&(i=0,this.panels.each(function(){i=Math.max(i,V(this).height("").height())}).height(i))},_eventHandler:function(t){var e=this.options,i=this.active,s=V(t.currentTarget).closest("li"),n=s[0]===i[0],o=n&&e.collapsible,a=o?V():this._getPanelForTab(s),r=i.length?this._getPanelForTab(i):V(),i={oldTab:i,oldPanel:r,newTab:o?V():s,newPanel:a};t.preventDefault(),s.hasClass("ui-state-disabled")||s.hasClass("ui-tabs-loading")||this.running||n&&!e.collapsible||!1===this._trigger("beforeActivate",t,i)||(e.active=!o&&this.tabs.index(s),this.active=n?V():s,this.xhr&&this.xhr.abort(),r.length||a.length||V.error("jQuery UI Tabs: Mismatching fragment identifier."),a.length&&this.load(this.tabs.index(s),t),this._toggle(t,i))},_toggle:function(t,e){var i=this,s=e.newPanel,n=e.oldPanel;function o(){i.running=!1,i._trigger("activate",t,e)}function a(){i._addClass(e.newTab.closest("li"),"ui-tabs-active","ui-state-active"),s.length&&i.options.show?i._show(s,i.options.show,o):(s.show(),o())}this.running=!0,n.length&&this.options.hide?this._hide(n,this.options.hide,function(){i._removeClass(e.oldTab.closest("li"),"ui-tabs-active","ui-state-active"),a()}):(this._removeClass(e.oldTab.closest("li"),"ui-tabs-active","ui-state-active"),n.hide(),a()),n.attr("aria-hidden","true"),e.oldTab.attr({"aria-selected":"false","aria-expanded":"false"}),s.length&&n.length?e.oldTab.attr("tabIndex",-1):s.length&&this.tabs.filter(function(){return 0===V(this).attr("tabIndex")}).attr("tabIndex",-1),s.attr("aria-hidden","false"),e.newTab.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_activate:function(t){var t=this._findActive(t);t[0]!==this.active[0]&&(t=(t=!t.length?this.active:t).find(".ui-tabs-anchor")[0],this._eventHandler({target:t,currentTarget:t,preventDefault:V.noop}))},_findActive:function(t){return!1===t?V():this.tabs.eq(t)},_getIndex:function(t){return t="string"==typeof t?this.anchors.index(this.anchors.filter("[href$='"+V.escapeSelector(t)+"']")):t},_destroy:function(){this.xhr&&this.xhr.abort(),this.tablist.removeAttr("role").off(this.eventNamespace),this.anchors.removeAttr("role tabIndex").removeUniqueId(),this.tabs.add(this.panels).each(function(){V.data(this,"ui-tabs-destroy")?V(this).remove():V(this).removeAttr("role tabIndex aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded")}),this.tabs.each(function(){var t=V(this),e=t.data("ui-tabs-aria-controls");e?t.attr("aria-controls",e).removeData("ui-tabs-aria-controls"):t.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(i){var t=this.options.disabled;!1!==t&&(t=void 0!==i&&(i=this._getIndex(i),Array.isArray(t)?V.map(t,function(t){return t!==i?t:null}):V.map(this.tabs,function(t,e){return e!==i?e:null})),this._setOptionDisabled(t))},disable:function(t){var e=this.options.disabled;if(!0!==e){if(void 0===t)e=!0;else{if(t=this._getIndex(t),-1!==V.inArray(t,e))return;e=Array.isArray(e)?V.merge([t],e).sort():[t]}this._setOptionDisabled(e)}},load:function(t,s){t=this._getIndex(t);function n(t,e){"abort"===e&&o.panels.stop(!1,!0),o._removeClass(i,"ui-tabs-loading"),a.removeAttr("aria-busy"),t===o.xhr&&delete o.xhr}var o=this,i=this.tabs.eq(t),t=i.find(".ui-tabs-anchor"),a=this._getPanelForTab(i),r={tab:i,panel:a};this._isLocal(t[0])||(this.xhr=V.ajax(this._ajaxSettings(t,s,r)),this.xhr&&"canceled"!==this.xhr.statusText&&(this._addClass(i,"ui-tabs-loading"),a.attr("aria-busy","true"),this.xhr.done(function(t,e,i){setTimeout(function(){a.html(t),o._trigger("load",s,r),n(i,e)},1)}).fail(function(t,e){setTimeout(function(){n(t,e)},1)})))},_ajaxSettings:function(t,i,s){var n=this;return{url:t.attr("href").replace(/#.*$/,""),beforeSend:function(t,e){return n._trigger("beforeLoad",i,V.extend({jqXHR:t,ajaxSettings:e},s))}}},_getPanelForTab:function(t){t=V(t).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+t))}}),!1!==V.uiBackCompat&&V.widget("ui.tabs",V.ui.tabs,{_processTabs:function(){this._superApply(arguments),this._addClass(this.tabs,"ui-tab")}});V.ui.tabs;V.widget("ui.tooltip",{version:"1.13.2",options:{classes:{"ui-tooltip":"ui-corner-all ui-widget-shadow"},content:function(){var t=V(this).attr("title");return V("").text(t).html()},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,track:!1,close:null,open:null},_addDescribedBy:function(t,e){var i=(t.attr("aria-describedby")||"").split(/\s+/);i.push(e),t.data("ui-tooltip-id",e).attr("aria-describedby",String.prototype.trim.call(i.join(" ")))},_removeDescribedBy:function(t){var e=t.data("ui-tooltip-id"),i=(t.attr("aria-describedby")||"").split(/\s+/),e=V.inArray(e,i);-1!==e&&i.splice(e,1),t.removeData("ui-tooltip-id"),(i=String.prototype.trim.call(i.join(" ")))?t.attr("aria-describedby",i):t.removeAttr("aria-describedby")},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.liveRegion=V("
    ").attr({role:"log","aria-live":"assertive","aria-relevant":"additions"}).appendTo(this.document[0].body),this._addClass(this.liveRegion,null,"ui-helper-hidden-accessible"),this.disabledTitles=V([])},_setOption:function(t,e){var i=this;this._super(t,e),"content"===t&&V.each(this.tooltips,function(t,e){i._updateContent(e.element)})},_setOptionDisabled:function(t){this[t?"_disable":"_enable"]()},_disable:function(){var s=this;V.each(this.tooltips,function(t,e){var i=V.Event("blur");i.target=i.currentTarget=e.element[0],s.close(i,!0)}),this.disabledTitles=this.disabledTitles.add(this.element.find(this.options.items).addBack().filter(function(){var t=V(this);if(t.is("[title]"))return t.data("ui-tooltip-title",t.attr("title")).removeAttr("title")}))},_enable:function(){this.disabledTitles.each(function(){var t=V(this);t.data("ui-tooltip-title")&&t.attr("title",t.data("ui-tooltip-title"))}),this.disabledTitles=V([])},open:function(t){var i=this,e=V(t?t.target:this.element).closest(this.options.items);e.length&&!e.data("ui-tooltip-id")&&(e.attr("title")&&e.data("ui-tooltip-title",e.attr("title")),e.data("ui-tooltip-open",!0),t&&"mouseover"===t.type&&e.parents().each(function(){var t,e=V(this);e.data("ui-tooltip-open")&&((t=V.Event("blur")).target=t.currentTarget=this,i.close(t,!0)),e.attr("title")&&(e.uniqueId(),i.parents[this.id]={element:this,title:e.attr("title")},e.attr("title",""))}),this._registerCloseHandlers(t,e),this._updateContent(e,t))},_updateContent:function(e,i){var t=this.options.content,s=this,n=i?i.type:null;if("string"==typeof t||t.nodeType||t.jquery)return this._open(i,e,t);(t=t.call(e[0],function(t){s._delay(function(){e.data("ui-tooltip-open")&&(i&&(i.type=n),this._open(i,e,t))})}))&&this._open(i,e,t)},_open:function(t,e,i){var s,n,o,a=V.extend({},this.options.position);function r(t){a.of=t,n.is(":hidden")||n.position(a)}i&&((s=this._find(e))?s.tooltip.find(".ui-tooltip-content").html(i):(e.is("[title]")&&(t&&"mouseover"===t.type?e.attr("title",""):e.removeAttr("title")),s=this._tooltip(e),n=s.tooltip,this._addDescribedBy(e,n.attr("id")),n.find(".ui-tooltip-content").html(i),this.liveRegion.children().hide(),(i=V("
    ").html(n.find(".ui-tooltip-content").html())).removeAttr("name").find("[name]").removeAttr("name"),i.removeAttr("id").find("[id]").removeAttr("id"),i.appendTo(this.liveRegion),this.options.track&&t&&/^mouse/.test(t.type)?(this._on(this.document,{mousemove:r}),r(t)):n.position(V.extend({of:e},this.options.position)),n.hide(),this._show(n,this.options.show),this.options.track&&this.options.show&&this.options.show.delay&&(o=this.delayedShow=setInterval(function(){n.is(":visible")&&(r(a.of),clearInterval(o))},13)),this._trigger("open",t,{tooltip:n})))},_registerCloseHandlers:function(t,e){var i={keyup:function(t){t.keyCode===V.ui.keyCode.ESCAPE&&((t=V.Event(t)).currentTarget=e[0],this.close(t,!0))}};e[0]!==this.element[0]&&(i.remove=function(){var t=this._find(e);t&&this._removeTooltip(t.tooltip)}),t&&"mouseover"!==t.type||(i.mouseleave="close"),t&&"focusin"!==t.type||(i.focusout="close"),this._on(!0,e,i)},close:function(t){var e,i=this,s=V(t?t.currentTarget:this.element),n=this._find(s);n?(e=n.tooltip,n.closing||(clearInterval(this.delayedShow),s.data("ui-tooltip-title")&&!s.attr("title")&&s.attr("title",s.data("ui-tooltip-title")),this._removeDescribedBy(s),n.hiding=!0,e.stop(!0),this._hide(e,this.options.hide,function(){i._removeTooltip(V(this))}),s.removeData("ui-tooltip-open"),this._off(s,"mouseleave focusout keyup"),s[0]!==this.element[0]&&this._off(s,"remove"),this._off(this.document,"mousemove"),t&&"mouseleave"===t.type&&V.each(this.parents,function(t,e){V(e.element).attr("title",e.title),delete i.parents[t]}),n.closing=!0,this._trigger("close",t,{tooltip:e}),n.hiding||(n.closing=!1))):s.removeData("ui-tooltip-open")},_tooltip:function(t){var e=V("
    ").attr("role","tooltip"),i=V("
    ").appendTo(e),s=e.uniqueId().attr("id");return this._addClass(i,"ui-tooltip-content"),this._addClass(e,"ui-tooltip","ui-widget ui-widget-content"),e.appendTo(this._appendTo(t)),this.tooltips[s]={element:t,tooltip:e}},_find:function(t){t=t.data("ui-tooltip-id");return t?this.tooltips[t]:null},_removeTooltip:function(t){clearInterval(this.delayedShow),t.remove(),delete this.tooltips[t.attr("id")]},_appendTo:function(t){t=t.closest(".ui-front, dialog");return t=!t.length?this.document[0].body:t},_destroy:function(){var s=this;V.each(this.tooltips,function(t,e){var i=V.Event("blur"),e=e.element;i.target=i.currentTarget=e[0],s.close(i,!0),V("#"+t).remove(),e.data("ui-tooltip-title")&&(e.attr("title")||e.attr("title",e.data("ui-tooltip-title")),e.removeData("ui-tooltip-title"))}),this.liveRegion.remove()}}),!1!==V.uiBackCompat&&V.widget("ui.tooltip",V.ui.tooltip,{options:{tooltipClass:null},_tooltip:function(){var t=this._superApply(arguments);return this.options.tooltipClass&&t.tooltip.addClass(this.options.tooltipClass),t}});V.ui.tooltip}); \ No newline at end of file diff --git a/jiuguan2025cc/public/lib/jquery.izoomify.js b/jiuguan2025cc/public/lib/jquery.izoomify.js new file mode 100644 index 0000000000000000000000000000000000000000..f8a9e1e911ac9cb19ce0dc87f6b1ae64d43c6ef4 --- /dev/null +++ b/jiuguan2025cc/public/lib/jquery.izoomify.js @@ -0,0 +1,216 @@ +/*! +* @name: jquery-izoomify +* @version: 1.0 +* @author: Carl Lomer Abia +*/ + +(function ($) { + var defaults = { + callback: false, + target: false, + duration: 120, + magnify: 1.2, + touch: true, + url: false + }; + + var _izoomify = function (target, duration, magnify, url) { + var xPos, + yPos, + $elTarget = $(target), + $imgTarget = $elTarget.find('img:first'), + imgOrigSrc = $imgTarget.attr('src'), + imgSwapSrc, + defaultOrigin = 'center top ' + 0 + 'px', + resultOrigin, + dUrl = 'data-izoomify-url', + dMagnify = 'data-izoomify-magnify', + dDuration = 'data-izoomify-duration', + eClass = 'izoomify-in', + eMagnify, + eDuration; + + function imageSource(imgSource) { + var _img = new Image(); + _img.src = imgSource; + return _img.src; + } + + function getImageAttribute($img, dataAttribute, defaultAttribute) { + if ($img.attr(dataAttribute)) { + return $img.attr(dataAttribute); + } + + return defaultAttribute; + } + + function getImageSource($img, dataImageSource, defaultImageSource) { + if ($img.attr(dataImageSource)) { + return imageSource($img.attr(dataImageSource)); + } + + return defaultImageSource ? imageSource(defaultImageSource) : false; + } + + function getTouches(e) { + return e.touches || e.originalEvent.touches; + } + + imgSwapSrc = getImageSource($imgTarget, dUrl, url); + + eMagnify = getImageAttribute($imgTarget, dMagnify, magnify); + + eDuration = getImageAttribute($imgTarget, dDuration, duration); + + $elTarget + .addClass(eClass) + .css({ + 'position': 'relative', + 'overflow': 'hidden' + }); + + $imgTarget.css({ + '-webkit-transition-property': '-webkit-transform', + 'transition-property': '-webkit-transform', + '-o-transition-property': 'transform', + 'transition-property': 'transform', + 'transition-property': 'transform, -webkit-transform', + '-webkit-transition-timing-function': 'ease', + '-o-transition-timing-function': 'ease', + 'transition-timing-function': 'ease', + '-webkit-transition-duration': eDuration + 'ms', + '-o-transition-duration': eDuration + 'ms', + 'transition-duration': eDuration + 'ms', + '-webkit-transform': 'scale(1)', + '-ms-transform': 'scale(1)', + 'transform': 'scale(1)', + '-webkit-transform-origin': defaultOrigin, + '-ms-transform-origin': defaultOrigin, + 'transform-origin': defaultOrigin + }); + + return { + moveStart: function (e, hasTouch) { + var o = $(target).offset(); + + if (hasTouch) { + e.preventDefault(); + xPos = getTouches(e)[0].clientX - o.left; + yPos = getTouches(e)[0].clientY - o.top; + } else { + xPos = e.pageX - o.left; + yPos = e.pageY - o.top; + } + + resultOrigin = xPos + 'px ' + yPos + 'px ' + 0 + 'px'; + + $imgTarget + .css({ + '-webkit-transform': 'scale(' + eMagnify + ')', + '-ms-transform': 'scale(' + eMagnify + ')', + 'transform': 'scale(' + eMagnify + ')', + '-webkit-transform-origin': resultOrigin, + '-ms-transform-origin': resultOrigin, + 'transform-origin': resultOrigin + }) + .attr('src', imgSwapSrc || imgOrigSrc); + }, + moveEnd: function () { + this.reset(); + }, + reset: function () { + resultOrigin = defaultOrigin; + + $imgTarget + .css({ + '-webkit-transform': 'scale(1)', + '-ms-transform': 'scale(1)', + 'transform': 'scale(1)', + '-webkit-transform-origin': resultOrigin, + '-ms-transform-origin': resultOrigin, + 'transform-origin': resultOrigin + }) + .attr('src', imgOrigSrc); + } + } + }; + + $.fn.izoomify = function (options) { + return this.each(function () { + var settings = $.extend({}, defaults, options || {}), + $target = settings.target && $(settings.target)[0] || this, + src = this, + $src = $(src), + mouseStartEvents = 'mouseover.izoomify mousemove.izoomify', + mouseEndEvents = 'mouseleave.izoomify mouseout.izoomify', + touchStartEvents = 'touchstart.izoomify touchmove.izoomify', + touchEndEvents = 'touchend.izoomify'; + + var izoomify = _izoomify($target, settings.duration, settings.magnify, settings.url); + + function startEvent(e, hasTouch) { + izoomify.moveStart(e, hasTouch); + } + + function endEvent($src) { + izoomify.moveEnd(); + + if ($src) { + $src + .off(touchStartEvents) + .off(touchEndEvents); + } + } + + function resetImage() { + izoomify.reset(); + } + + $src.one('izoomify.destroy', function () { + + $src.removeClass('izoomify-in'); + + resetImage(); + + $src + .off(mouseStartEvents) + .off(mouseEndEvents); + + if (settings.touch) { + $src + .off(touchStartEvents) + .off(touchStartEvents); + } + + $target.style.position = ''; + $target.style.overflow = ''; + + }.bind(this)); + + $src + .on(mouseStartEvents, function (e) { + startEvent(e); + }) + .on(mouseEndEvents, function () { + endEvent(); + }); + + if (settings.touch) { + $src + .on(touchStartEvents, function (e) { + e.preventDefault(); + startEvent(e, true); + }) + .on(touchEndEvents, function () { + endEvent(); + }); + } + + if ($.isFunction(settings.callback)) { + settings.callback.call($src); + } + }); + }; + + $.fn.izoomify.defaults = defaults; +}(window.jQuery)); \ No newline at end of file diff --git a/jiuguan2025cc/public/lib/jquery.transit.min.js b/jiuguan2025cc/public/lib/jquery.transit.min.js new file mode 100644 index 0000000000000000000000000000000000000000..8e144fb14d601ef3c77ff6bf53d03bb36a62a882 --- /dev/null +++ b/jiuguan2025cc/public/lib/jquery.transit.min.js @@ -0,0 +1 @@ +(function(t,e){if(typeof define==="function"&&define.amd){define(["jquery"],e)}else if(typeof exports==="object"){module.exports=e(require("jquery"))}else{e(t.jQuery)}})(this,function(t){t.transit={version:"0.9.12",propertyMap:{marginLeft:"margin",marginRight:"margin",marginBottom:"margin",marginTop:"margin",paddingLeft:"padding",paddingRight:"padding",paddingBottom:"padding",paddingTop:"padding"},enabled:true,useTransitionEnd:false};var e=document.createElement("div");var n={};function i(t){if(t in e.style)return t;var n=["Moz","Webkit","O","ms"];var i=t.charAt(0).toUpperCase()+t.substr(1);for(var r=0;r-1;n.transition=i("transition");n.transitionDelay=i("transitionDelay");n.transform=i("transform");n.transformOrigin=i("transformOrigin");n.filter=i("Filter");n.transform3d=r();var a={transition:"transitionend",MozTransition:"transitionend",OTransition:"oTransitionEnd",WebkitTransition:"webkitTransitionEnd",msTransition:"MSTransitionEnd"};var o=n.transitionEnd=a[n.transition]||null;for(var u in n){if(n.hasOwnProperty(u)&&typeof t.support[u]==="undefined"){t.support[u]=n[u]}}e=null;t.cssEase={_default:"ease","in":"ease-in",out:"ease-out","in-out":"ease-in-out",snap:"cubic-bezier(0,1,.5,1)",easeInCubic:"cubic-bezier(.550,.055,.675,.190)",easeOutCubic:"cubic-bezier(.215,.61,.355,1)",easeInOutCubic:"cubic-bezier(.645,.045,.355,1)",easeInCirc:"cubic-bezier(.6,.04,.98,.335)",easeOutCirc:"cubic-bezier(.075,.82,.165,1)",easeInOutCirc:"cubic-bezier(.785,.135,.15,.86)",easeInExpo:"cubic-bezier(.95,.05,.795,.035)",easeOutExpo:"cubic-bezier(.19,1,.22,1)",easeInOutExpo:"cubic-bezier(1,0,0,1)",easeInQuad:"cubic-bezier(.55,.085,.68,.53)",easeOutQuad:"cubic-bezier(.25,.46,.45,.94)",easeInOutQuad:"cubic-bezier(.455,.03,.515,.955)",easeInQuart:"cubic-bezier(.895,.03,.685,.22)",easeOutQuart:"cubic-bezier(.165,.84,.44,1)",easeInOutQuart:"cubic-bezier(.77,0,.175,1)",easeInQuint:"cubic-bezier(.755,.05,.855,.06)",easeOutQuint:"cubic-bezier(.23,1,.32,1)",easeInOutQuint:"cubic-bezier(.86,0,.07,1)",easeInSine:"cubic-bezier(.47,0,.745,.715)",easeOutSine:"cubic-bezier(.39,.575,.565,1)",easeInOutSine:"cubic-bezier(.445,.05,.55,.95)",easeInBack:"cubic-bezier(.6,-.28,.735,.045)",easeOutBack:"cubic-bezier(.175, .885,.32,1.275)",easeInOutBack:"cubic-bezier(.68,-.55,.265,1.55)"};t.cssHooks["transit:transform"]={get:function(e){return t(e).data("transform")||new f},set:function(e,i){var r=i;if(!(r instanceof f)){r=new f(r)}if(n.transform==="WebkitTransform"&&!s){e.style[n.transform]=r.toString(true)}else{e.style[n.transform]=r.toString()}t(e).data("transform",r)}};t.cssHooks.transform={set:t.cssHooks["transit:transform"].set};t.cssHooks.filter={get:function(t){return t.style[n.filter]},set:function(t,e){t.style[n.filter]=e}};if(t.fn.jquery<"1.8"){t.cssHooks.transformOrigin={get:function(t){return t.style[n.transformOrigin]},set:function(t,e){t.style[n.transformOrigin]=e}};t.cssHooks.transition={get:function(t){return t.style[n.transition]},set:function(t,e){t.style[n.transition]=e}}}p("scale");p("scaleX");p("scaleY");p("translate");p("rotate");p("rotateX");p("rotateY");p("rotate3d");p("perspective");p("skewX");p("skewY");p("x",true);p("y",true);function f(t){if(typeof t==="string"){this.parse(t)}return this}f.prototype={setFromString:function(t,e){var n=typeof e==="string"?e.split(","):e.constructor===Array?e:[e];n.unshift(t);f.prototype.set.apply(this,n)},set:function(t){var e=Array.prototype.slice.apply(arguments,[1]);if(this.setter[t]){this.setter[t].apply(this,e)}else{this[t]=e.join(",")}},get:function(t){if(this.getter[t]){return this.getter[t].apply(this)}else{return this[t]||0}},setter:{rotate:function(t){this.rotate=b(t,"deg")},rotateX:function(t){this.rotateX=b(t,"deg")},rotateY:function(t){this.rotateY=b(t,"deg")},scale:function(t,e){if(e===undefined){e=t}this.scale=t+","+e},skewX:function(t){this.skewX=b(t,"deg")},skewY:function(t){this.skewY=b(t,"deg")},perspective:function(t){this.perspective=b(t,"px")},x:function(t){this.set("translate",t,null)},y:function(t){this.set("translate",null,t)},translate:function(t,e){if(this._translateX===undefined){this._translateX=0}if(this._translateY===undefined){this._translateY=0}if(t!==null&&t!==undefined){this._translateX=b(t,"px")}if(e!==null&&e!==undefined){this._translateY=b(e,"px")}this.translate=this._translateX+","+this._translateY}},getter:{x:function(){return this._translateX||0},y:function(){return this._translateY||0},scale:function(){var t=(this.scale||"1,1").split(",");if(t[0]){t[0]=parseFloat(t[0])}if(t[1]){t[1]=parseFloat(t[1])}return t[0]===t[1]?t[0]:t},rotate3d:function(){var t=(this.rotate3d||"0,0,0,0deg").split(",");for(var e=0;e<=3;++e){if(t[e]){t[e]=parseFloat(t[e])}}if(t[3]){t[3]=b(t[3],"deg")}return t}},parse:function(t){var e=this;t.replace(/([a-zA-Z0-9]+)\((.*?)\)/g,function(t,n,i){e.setFromString(n,i)})},toString:function(t){var e=[];for(var i in this){if(this.hasOwnProperty(i)){if(!n.transform3d&&(i==="rotateX"||i==="rotateY"||i==="perspective"||i==="transformOrigin")){continue}if(i[0]!=="_"){if(t&&i==="scale"){e.push(i+"3d("+this[i]+",1)")}else if(t&&i==="translate"){e.push(i+"3d("+this[i]+",0)")}else{e.push(i+"("+this[i]+")")}}}}return e.join(" ")}};function c(t,e,n){if(e===true){t.queue(n)}else if(e){t.queue(e,n)}else{t.each(function(){n.call(this)})}}function l(e){var i=[];t.each(e,function(e){e=t.camelCase(e);e=t.transit.propertyMap[e]||t.cssProps[e]||e;e=h(e);if(n[e])e=h(n[e]);if(t.inArray(e,i)===-1){i.push(e)}});return i}function d(e,n,i,r){var s=l(e);if(t.cssEase[i]){i=t.cssEase[i]}var a=""+y(n)+" "+i;if(parseInt(r,10)>0){a+=" "+y(r)}var o=[];t.each(s,function(t,e){o.push(e+" "+a)});return o.join(", ")}t.fn.transition=t.fn.transit=function(e,i,r,s){var a=this;var u=0;var f=true;var l=t.extend(true,{},e);if(typeof i==="function"){s=i;i=undefined}if(typeof i==="object"){r=i.easing;u=i.delay||0;f=typeof i.queue==="undefined"?true:i.queue;s=i.complete;i=i.duration}if(typeof r==="function"){s=r;r=undefined}if(typeof l.easing!=="undefined"){r=l.easing;delete l.easing}if(typeof l.duration!=="undefined"){i=l.duration;delete l.duration}if(typeof l.complete!=="undefined"){s=l.complete;delete l.complete}if(typeof l.queue!=="undefined"){f=l.queue;delete l.queue}if(typeof l.delay!=="undefined"){u=l.delay;delete l.delay}if(typeof i==="undefined"){i=t.fx.speeds._default}if(typeof r==="undefined"){r=t.cssEase._default}i=y(i);var p=d(l,i,r,u);var h=t.transit.enabled&&n.transition;var b=h?parseInt(i,10)+parseInt(u,10):0;if(b===0){var g=function(t){a.css(l);if(s){s.apply(a)}if(t){t()}};c(a,f,g);return a}var m={};var v=function(e){var i=false;var r=function(){if(i){a.unbind(o,r)}if(b>0){a.each(function(){this.style[n.transition]=m[this]||null})}if(typeof s==="function"){s.apply(a)}if(typeof e==="function"){e()}};if(b>0&&o&&t.transit.useTransitionEnd){i=true;a.bind(o,r)}else{window.setTimeout(r,b)}a.each(function(){if(b>0){this.style[n.transition]=p}t(this).css(l)})};var z=function(t){this.offsetWidth;v(t)};c(a,f,z);return this};function p(e,i){if(!i){t.cssNumber[e]=true}t.transit.propertyMap[e]=n.transform;t.cssHooks[e]={get:function(n){var i=t(n).css("transit:transform");return i.get(e)},set:function(n,i){var r=t(n).css("transit:transform");r.setFromString(e,i);t(n).css({"transit:transform":r})}}}function h(t){return t.replace(/([A-Z])/g,function(t){return"-"+t.toLowerCase()})}function b(t,e){if(typeof t==="string"&&!t.match(/^[\-0-9\.]+$/)){return t}else{return""+t+e}}function y(e){var n=e;if(typeof n==="string"&&!n.match(/^[\-0-9\.]+/)){n=t.fx.speeds[n]||t.fx.speeds._default}return b(n,"ms")}t.transit.getTransitionValue=d;return t}); \ No newline at end of file diff --git a/jiuguan2025cc/public/lib/jquery.ui.touch-punch.min.js b/jiuguan2025cc/public/lib/jquery.ui.touch-punch.min.js new file mode 100644 index 0000000000000000000000000000000000000000..e1799f62c1149cf337fb1f25bf71c68307d199b5 --- /dev/null +++ b/jiuguan2025cc/public/lib/jquery.ui.touch-punch.min.js @@ -0,0 +1,249 @@ +/*! + * jQuery UI Touch Punch 1.0.9 as modified by RWAP Software + * based on original touchpunch v0.2.3 which has not been updated since 2014 + * + * Updates by RWAP Software to take account of various suggested changes on the original code issues + * + * Original: https://github.com/furf/jquery-ui-touch-punch + * Copyright 2011–2014, Dave Furfero + * Dual licensed under the MIT or GPL Version 2 licenses. + * + * Fork: https://github.com/RWAP/jquery-ui-touch-punch + * + * Depends: + * jquery.ui.widget.js + * jquery.ui.mouse.js + */ + +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define([ "jquery", "jquery-ui" ], factory ); + } else { + + // Browser globals + factory( jQuery ); + } +}(function ($) { + + // Detect touch support - Windows Surface devices and other touch devices + $.mspointer = window.navigator.msPointerEnabled; + $.touch = ( 'ontouchstart' in document + || 'ontouchstart' in window + || window.TouchEvent + || (window.DocumentTouch && document instanceof DocumentTouch) + || navigator.maxTouchPoints > 0 + || navigator.msMaxTouchPoints > 0 + ); + + // Ignore browsers without touch or mouse support + if ((!$.touch && !$.mspointer) || !$.ui.mouse) { + return; + } + + let mouseProto = $.ui.mouse.prototype, + _mouseInit = mouseProto._mouseInit, + _mouseDestroy = mouseProto._mouseDestroy, + touchHandled; + + /** + * Get the x,y position of a touch event + * @param {Object} event A touch event + */ + function getTouchCoords (event) { + return { + x: event.originalEvent.changedTouches[0].pageX, + y: event.originalEvent.changedTouches[0].pageY + }; + } + + /** + * Simulate a mouse event based on a corresponding touch event + * @param {Object} event A touch event + * @param {String} simulatedType The corresponding mouse event + */ + function simulateMouseEvent (event, simulatedType) { + + // Ignore multi-touch events + if (event.originalEvent.touches.length > 1) { + return; + } + + //Ignore input or textarea elements so user can still enter text + if ($(event.target).is("input") || $(event.target).is("textarea")) { + return; + } + + // Prevent "Ignored attempt to cancel a touchmove event with cancelable=false" errors + if (event.cancelable) { + event.preventDefault(); + } + + let touch = event.originalEvent.changedTouches[0], + simulatedEvent = document.createEvent('MouseEvents'); + + // Initialize the simulated mouse event using the touch event's coordinates + simulatedEvent.initMouseEvent( + simulatedType, // type + true, // bubbles + true, // cancelable + window, // view + 1, // detail + touch.screenX, // screenX + touch.screenY, // screenY + touch.clientX, // clientX + touch.clientY, // clientY + false, // ctrlKey + false, // altKey + false, // shiftKey + false, // metaKey + 0, // button + null // relatedTarget + ); + + // Dispatch the simulated event to the target element + event.target.dispatchEvent(simulatedEvent); + } + + /** + * Handle the jQuery UI widget's touchstart events + * @param {Object} event The widget element's touchstart event + */ + mouseProto._touchStart = function (event) { + + let self = this; + + // Interaction time + this._startedMove = event.timeStamp; + + // Track movement to determine if interaction was a click + self._startPos = getTouchCoords(event); + + // Ignore the event if another widget is already being handled + if (touchHandled || !self._mouseCapture(event.originalEvent.changedTouches[0])) { + return; + } + + // Set the flag to prevent other widgets from inheriting the touch event + touchHandled = true; + + // Track movement to determine if interaction was a click + self._touchMoved = false; + + // Simulate the mouseover event + simulateMouseEvent(event, 'mouseover'); + + // Simulate the mousemove event + simulateMouseEvent(event, 'mousemove'); + + // Simulate the mousedown event + simulateMouseEvent(event, 'mousedown'); + }; + + /** + * Handle the jQuery UI widget's touchmove events + * @param {Object} event The document's touchmove event + */ + mouseProto._touchMove = function (event) { + + // Ignore event if not handled + if (!touchHandled) { + return; + } + + // Interaction was moved + this._touchMoved = true; + + // Simulate the mousemove event + simulateMouseEvent(event, 'mousemove'); + }; + + /** + * Handle the jQuery UI widget's touchend events + * @param {Object} event The document's touchend event + */ + mouseProto._touchEnd = function (event) { + + // Ignore event if not handled + if (!touchHandled) { + return; + } + + // Simulate the mouseup event + simulateMouseEvent(event, 'mouseup'); + + // Simulate the mouseout event + simulateMouseEvent(event, 'mouseout'); + + // If the touch interaction did not move, it should trigger a click + // Check for this in two ways - length of time of simulation and distance moved + // Allow for Apple Stylus to be used also + let timeMoving = event.timeStamp - this._startedMove; + if (!this._touchMoved || timeMoving < 500) { + // Simulate the click event + simulateMouseEvent(event, 'click'); + } else { + let endPos = getTouchCoords(event); + if ((Math.abs(endPos.x - this._startPos.x) < 10) && (Math.abs(endPos.y - this._startPos.y) < 10)) { + + // If the touch interaction did not move, it should trigger a click + if (!this._touchMoved || event.originalEvent.changedTouches[0].touchType === 'stylus') { + // Simulate the click event + simulateMouseEvent(event, 'click'); + } + } + } + + // Unset the flag to determine the touch movement stopped + this._touchMoved = false; + + // Unset the flag to allow other widgets to inherit the touch event + touchHandled = false; + }; + + /** + * A duck punch of the $.ui.mouse _mouseInit method to support touch events. + * This method extends the widget with bound touch event handlers that + * translate touch events to mouse events and pass them to the widget's + * original mouse event handling methods. + */ + mouseProto._mouseInit = function () { + + let self = this; + + // Microsoft Surface Support = remove original touch Action + if ($.support.mspointer) { + self.element[0].style.msTouchAction = 'none'; + } + + // Delegate the touch handlers to the widget's element + self.element.on({ + touchstart: $.proxy(self, '_touchStart'), + touchmove: $.proxy(self, '_touchMove'), + touchend: $.proxy(self, '_touchEnd') + }); + + // Call the original $.ui.mouse init method + _mouseInit.call(self); + }; + + /** + * Remove the touch event handlers + */ + mouseProto._mouseDestroy = function () { + + let self = this; + + // Delegate the touch handlers to the widget's element + self.element.off({ + touchstart: $.proxy(self, '_touchStart'), + touchmove: $.proxy(self, '_touchMove'), + touchend: $.proxy(self, '_touchEnd') + }); + + // Call the original $.ui.mouse destroy method + _mouseDestroy.call(self); + }; + +})); diff --git a/jiuguan2025cc/public/lib/jszip.min.js b/jiuguan2025cc/public/lib/jszip.min.js new file mode 100644 index 0000000000000000000000000000000000000000..ff4cfd5e8fdc49176c2d1d409afa897f40be01f4 --- /dev/null +++ b/jiuguan2025cc/public/lib/jszip.min.js @@ -0,0 +1,13 @@ +/*! + +JSZip v3.10.1 - A JavaScript class for generating and reading zip files + + +(c) 2009-2016 Stuart Knightley +Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/main/LICENSE.markdown. + +JSZip uses the library pako released under the MIT license : +https://github.com/nodeca/pako/blob/main/LICENSE +*/ + +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).JSZip=e()}}(function(){return function s(a,o,h){function u(r,e){if(!o[r]){if(!a[r]){var t="function"==typeof require&&require;if(!e&&t)return t(r,!0);if(l)return l(r,!0);var n=new Error("Cannot find module '"+r+"'");throw n.code="MODULE_NOT_FOUND",n}var i=o[r]={exports:{}};a[r][0].call(i.exports,function(e){var t=a[r][1][e];return u(t||e)},i,i.exports,s,a,o,h)}return o[r].exports}for(var l="function"==typeof require&&require,e=0;e>2,s=(3&t)<<4|r>>4,a=1>6:64,o=2>4,r=(15&i)<<4|(s=p.indexOf(e.charAt(o++)))>>2,n=(3&s)<<6|(a=p.indexOf(e.charAt(o++))),l[h++]=t,64!==s&&(l[h++]=r),64!==a&&(l[h++]=n);return l}},{"./support":30,"./utils":32}],2:[function(e,t,r){"use strict";var n=e("./external"),i=e("./stream/DataWorker"),s=e("./stream/Crc32Probe"),a=e("./stream/DataLengthProbe");function o(e,t,r,n,i){this.compressedSize=e,this.uncompressedSize=t,this.crc32=r,this.compression=n,this.compressedContent=i}o.prototype={getContentWorker:function(){var e=new i(n.Promise.resolve(this.compressedContent)).pipe(this.compression.uncompressWorker()).pipe(new a("data_length")),t=this;return e.on("end",function(){if(this.streamInfo.data_length!==t.uncompressedSize)throw new Error("Bug : uncompressed data size mismatch")}),e},getCompressedWorker:function(){return new i(n.Promise.resolve(this.compressedContent)).withStreamInfo("compressedSize",this.compressedSize).withStreamInfo("uncompressedSize",this.uncompressedSize).withStreamInfo("crc32",this.crc32).withStreamInfo("compression",this.compression)}},o.createWorkerFrom=function(e,t,r){return e.pipe(new s).pipe(new a("uncompressedSize")).pipe(t.compressWorker(r)).pipe(new a("compressedSize")).withStreamInfo("compression",t)},t.exports=o},{"./external":6,"./stream/Crc32Probe":25,"./stream/DataLengthProbe":26,"./stream/DataWorker":27}],3:[function(e,t,r){"use strict";var n=e("./stream/GenericWorker");r.STORE={magic:"\0\0",compressWorker:function(){return new n("STORE compression")},uncompressWorker:function(){return new n("STORE decompression")}},r.DEFLATE=e("./flate")},{"./flate":7,"./stream/GenericWorker":28}],4:[function(e,t,r){"use strict";var n=e("./utils");var o=function(){for(var e,t=[],r=0;r<256;r++){e=r;for(var n=0;n<8;n++)e=1&e?3988292384^e>>>1:e>>>1;t[r]=e}return t}();t.exports=function(e,t){return void 0!==e&&e.length?"string"!==n.getTypeOf(e)?function(e,t,r,n){var i=o,s=n+r;e^=-1;for(var a=n;a>>8^i[255&(e^t[a])];return-1^e}(0|t,e,e.length,0):function(e,t,r,n){var i=o,s=n+r;e^=-1;for(var a=n;a>>8^i[255&(e^t.charCodeAt(a))];return-1^e}(0|t,e,e.length,0):0}},{"./utils":32}],5:[function(e,t,r){"use strict";r.base64=!1,r.binary=!1,r.dir=!1,r.createFolders=!0,r.date=null,r.compression=null,r.compressionOptions=null,r.comment=null,r.unixPermissions=null,r.dosPermissions=null},{}],6:[function(e,t,r){"use strict";var n=null;n="undefined"!=typeof Promise?Promise:e("lie"),t.exports={Promise:n}},{lie:37}],7:[function(e,t,r){"use strict";var n="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,i=e("pako"),s=e("./utils"),a=e("./stream/GenericWorker"),o=n?"uint8array":"array";function h(e,t){a.call(this,"FlateWorker/"+e),this._pako=null,this._pakoAction=e,this._pakoOptions=t,this.meta={}}r.magic="\b\0",s.inherits(h,a),h.prototype.processChunk=function(e){this.meta=e.meta,null===this._pako&&this._createPako(),this._pako.push(s.transformTo(o,e.data),!1)},h.prototype.flush=function(){a.prototype.flush.call(this),null===this._pako&&this._createPako(),this._pako.push([],!0)},h.prototype.cleanUp=function(){a.prototype.cleanUp.call(this),this._pako=null},h.prototype._createPako=function(){this._pako=new i[this._pakoAction]({raw:!0,level:this._pakoOptions.level||-1});var t=this;this._pako.onData=function(e){t.push({data:e,meta:t.meta})}},r.compressWorker=function(e){return new h("Deflate",e)},r.uncompressWorker=function(){return new h("Inflate",{})}},{"./stream/GenericWorker":28,"./utils":32,pako:38}],8:[function(e,t,r){"use strict";function A(e,t){var r,n="";for(r=0;r>>=8;return n}function n(e,t,r,n,i,s){var a,o,h=e.file,u=e.compression,l=s!==O.utf8encode,f=I.transformTo("string",s(h.name)),c=I.transformTo("string",O.utf8encode(h.name)),d=h.comment,p=I.transformTo("string",s(d)),m=I.transformTo("string",O.utf8encode(d)),_=c.length!==h.name.length,g=m.length!==d.length,b="",v="",y="",w=h.dir,k=h.date,x={crc32:0,compressedSize:0,uncompressedSize:0};t&&!r||(x.crc32=e.crc32,x.compressedSize=e.compressedSize,x.uncompressedSize=e.uncompressedSize);var S=0;t&&(S|=8),l||!_&&!g||(S|=2048);var z=0,C=0;w&&(z|=16),"UNIX"===i?(C=798,z|=function(e,t){var r=e;return e||(r=t?16893:33204),(65535&r)<<16}(h.unixPermissions,w)):(C=20,z|=function(e){return 63&(e||0)}(h.dosPermissions)),a=k.getUTCHours(),a<<=6,a|=k.getUTCMinutes(),a<<=5,a|=k.getUTCSeconds()/2,o=k.getUTCFullYear()-1980,o<<=4,o|=k.getUTCMonth()+1,o<<=5,o|=k.getUTCDate(),_&&(v=A(1,1)+A(B(f),4)+c,b+="up"+A(v.length,2)+v),g&&(y=A(1,1)+A(B(p),4)+m,b+="uc"+A(y.length,2)+y);var E="";return E+="\n\0",E+=A(S,2),E+=u.magic,E+=A(a,2),E+=A(o,2),E+=A(x.crc32,4),E+=A(x.compressedSize,4),E+=A(x.uncompressedSize,4),E+=A(f.length,2),E+=A(b.length,2),{fileRecord:R.LOCAL_FILE_HEADER+E+f+b,dirRecord:R.CENTRAL_FILE_HEADER+A(C,2)+E+A(p.length,2)+"\0\0\0\0"+A(z,4)+A(n,4)+f+b+p}}var I=e("../utils"),i=e("../stream/GenericWorker"),O=e("../utf8"),B=e("../crc32"),R=e("../signature");function s(e,t,r,n){i.call(this,"ZipFileWorker"),this.bytesWritten=0,this.zipComment=t,this.zipPlatform=r,this.encodeFileName=n,this.streamFiles=e,this.accumulate=!1,this.contentBuffer=[],this.dirRecords=[],this.currentSourceOffset=0,this.entriesCount=0,this.currentFile=null,this._sources=[]}I.inherits(s,i),s.prototype.push=function(e){var t=e.meta.percent||0,r=this.entriesCount,n=this._sources.length;this.accumulate?this.contentBuffer.push(e):(this.bytesWritten+=e.data.length,i.prototype.push.call(this,{data:e.data,meta:{currentFile:this.currentFile,percent:r?(t+100*(r-n-1))/r:100}}))},s.prototype.openedSource=function(e){this.currentSourceOffset=this.bytesWritten,this.currentFile=e.file.name;var t=this.streamFiles&&!e.file.dir;if(t){var r=n(e,t,!1,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);this.push({data:r.fileRecord,meta:{percent:0}})}else this.accumulate=!0},s.prototype.closedSource=function(e){this.accumulate=!1;var t=this.streamFiles&&!e.file.dir,r=n(e,t,!0,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);if(this.dirRecords.push(r.dirRecord),t)this.push({data:function(e){return R.DATA_DESCRIPTOR+A(e.crc32,4)+A(e.compressedSize,4)+A(e.uncompressedSize,4)}(e),meta:{percent:100}});else for(this.push({data:r.fileRecord,meta:{percent:0}});this.contentBuffer.length;)this.push(this.contentBuffer.shift());this.currentFile=null},s.prototype.flush=function(){for(var e=this.bytesWritten,t=0;t=this.index;t--)r=(r<<8)+this.byteAt(t);return this.index+=e,r},readString:function(e){return n.transformTo("string",this.readData(e))},readData:function(){},lastIndexOfSignature:function(){},readAndCheckSignature:function(){},readDate:function(){var e=this.readInt(4);return new Date(Date.UTC(1980+(e>>25&127),(e>>21&15)-1,e>>16&31,e>>11&31,e>>5&63,(31&e)<<1))}},t.exports=i},{"../utils":32}],19:[function(e,t,r){"use strict";var n=e("./Uint8ArrayReader");function i(e){n.call(this,e)}e("../utils").inherits(i,n),i.prototype.readData=function(e){this.checkOffset(e);var t=this.data.slice(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i},{"../utils":32,"./Uint8ArrayReader":21}],20:[function(e,t,r){"use strict";var n=e("./DataReader");function i(e){n.call(this,e)}e("../utils").inherits(i,n),i.prototype.byteAt=function(e){return this.data.charCodeAt(this.zero+e)},i.prototype.lastIndexOfSignature=function(e){return this.data.lastIndexOf(e)-this.zero},i.prototype.readAndCheckSignature=function(e){return e===this.readData(4)},i.prototype.readData=function(e){this.checkOffset(e);var t=this.data.slice(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i},{"../utils":32,"./DataReader":18}],21:[function(e,t,r){"use strict";var n=e("./ArrayReader");function i(e){n.call(this,e)}e("../utils").inherits(i,n),i.prototype.readData=function(e){if(this.checkOffset(e),0===e)return new Uint8Array(0);var t=this.data.subarray(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i},{"../utils":32,"./ArrayReader":17}],22:[function(e,t,r){"use strict";var n=e("../utils"),i=e("../support"),s=e("./ArrayReader"),a=e("./StringReader"),o=e("./NodeBufferReader"),h=e("./Uint8ArrayReader");t.exports=function(e){var t=n.getTypeOf(e);return n.checkSupport(t),"string"!==t||i.uint8array?"nodebuffer"===t?new o(e):i.uint8array?new h(n.transformTo("uint8array",e)):new s(n.transformTo("array",e)):new a(e)}},{"../support":30,"../utils":32,"./ArrayReader":17,"./NodeBufferReader":19,"./StringReader":20,"./Uint8ArrayReader":21}],23:[function(e,t,r){"use strict";r.LOCAL_FILE_HEADER="PK",r.CENTRAL_FILE_HEADER="PK",r.CENTRAL_DIRECTORY_END="PK",r.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK",r.ZIP64_CENTRAL_DIRECTORY_END="PK",r.DATA_DESCRIPTOR="PK\b"},{}],24:[function(e,t,r){"use strict";var n=e("./GenericWorker"),i=e("../utils");function s(e){n.call(this,"ConvertWorker to "+e),this.destType=e}i.inherits(s,n),s.prototype.processChunk=function(e){this.push({data:i.transformTo(this.destType,e.data),meta:e.meta})},t.exports=s},{"../utils":32,"./GenericWorker":28}],25:[function(e,t,r){"use strict";var n=e("./GenericWorker"),i=e("../crc32");function s(){n.call(this,"Crc32Probe"),this.withStreamInfo("crc32",0)}e("../utils").inherits(s,n),s.prototype.processChunk=function(e){this.streamInfo.crc32=i(e.data,this.streamInfo.crc32||0),this.push(e)},t.exports=s},{"../crc32":4,"../utils":32,"./GenericWorker":28}],26:[function(e,t,r){"use strict";var n=e("../utils"),i=e("./GenericWorker");function s(e){i.call(this,"DataLengthProbe for "+e),this.propName=e,this.withStreamInfo(e,0)}n.inherits(s,i),s.prototype.processChunk=function(e){if(e){var t=this.streamInfo[this.propName]||0;this.streamInfo[this.propName]=t+e.data.length}i.prototype.processChunk.call(this,e)},t.exports=s},{"../utils":32,"./GenericWorker":28}],27:[function(e,t,r){"use strict";var n=e("../utils"),i=e("./GenericWorker");function s(e){i.call(this,"DataWorker");var t=this;this.dataIsReady=!1,this.index=0,this.max=0,this.data=null,this.type="",this._tickScheduled=!1,e.then(function(e){t.dataIsReady=!0,t.data=e,t.max=e&&e.length||0,t.type=n.getTypeOf(e),t.isPaused||t._tickAndRepeat()},function(e){t.error(e)})}n.inherits(s,i),s.prototype.cleanUp=function(){i.prototype.cleanUp.call(this),this.data=null},s.prototype.resume=function(){return!!i.prototype.resume.call(this)&&(!this._tickScheduled&&this.dataIsReady&&(this._tickScheduled=!0,n.delay(this._tickAndRepeat,[],this)),!0)},s.prototype._tickAndRepeat=function(){this._tickScheduled=!1,this.isPaused||this.isFinished||(this._tick(),this.isFinished||(n.delay(this._tickAndRepeat,[],this),this._tickScheduled=!0))},s.prototype._tick=function(){if(this.isPaused||this.isFinished)return!1;var e=null,t=Math.min(this.max,this.index+16384);if(this.index>=this.max)return this.end();switch(this.type){case"string":e=this.data.substring(this.index,t);break;case"uint8array":e=this.data.subarray(this.index,t);break;case"array":case"nodebuffer":e=this.data.slice(this.index,t)}return this.index=t,this.push({data:e,meta:{percent:this.max?this.index/this.max*100:0}})},t.exports=s},{"../utils":32,"./GenericWorker":28}],28:[function(e,t,r){"use strict";function n(e){this.name=e||"default",this.streamInfo={},this.generatedError=null,this.extraStreamInfo={},this.isPaused=!0,this.isFinished=!1,this.isLocked=!1,this._listeners={data:[],end:[],error:[]},this.previous=null}n.prototype={push:function(e){this.emit("data",e)},end:function(){if(this.isFinished)return!1;this.flush();try{this.emit("end"),this.cleanUp(),this.isFinished=!0}catch(e){this.emit("error",e)}return!0},error:function(e){return!this.isFinished&&(this.isPaused?this.generatedError=e:(this.isFinished=!0,this.emit("error",e),this.previous&&this.previous.error(e),this.cleanUp()),!0)},on:function(e,t){return this._listeners[e].push(t),this},cleanUp:function(){this.streamInfo=this.generatedError=this.extraStreamInfo=null,this._listeners=[]},emit:function(e,t){if(this._listeners[e])for(var r=0;r "+e:e}},t.exports=n},{}],29:[function(e,t,r){"use strict";var h=e("../utils"),i=e("./ConvertWorker"),s=e("./GenericWorker"),u=e("../base64"),n=e("../support"),a=e("../external"),o=null;if(n.nodestream)try{o=e("../nodejs/NodejsStreamOutputAdapter")}catch(e){}function l(e,o){return new a.Promise(function(t,r){var n=[],i=e._internalType,s=e._outputType,a=e._mimeType;e.on("data",function(e,t){n.push(e),o&&o(t)}).on("error",function(e){n=[],r(e)}).on("end",function(){try{var e=function(e,t,r){switch(e){case"blob":return h.newBlob(h.transformTo("arraybuffer",t),r);case"base64":return u.encode(t);default:return h.transformTo(e,t)}}(s,function(e,t){var r,n=0,i=null,s=0;for(r=0;r>>6:(r<65536?t[s++]=224|r>>>12:(t[s++]=240|r>>>18,t[s++]=128|r>>>12&63),t[s++]=128|r>>>6&63),t[s++]=128|63&r);return t}(e)},s.utf8decode=function(e){return h.nodebuffer?o.transformTo("nodebuffer",e).toString("utf-8"):function(e){var t,r,n,i,s=e.length,a=new Array(2*s);for(t=r=0;t>10&1023,a[r++]=56320|1023&n)}return a.length!==r&&(a.subarray?a=a.subarray(0,r):a.length=r),o.applyFromCharCode(a)}(e=o.transformTo(h.uint8array?"uint8array":"array",e))},o.inherits(a,n),a.prototype.processChunk=function(e){var t=o.transformTo(h.uint8array?"uint8array":"array",e.data);if(this.leftOver&&this.leftOver.length){if(h.uint8array){var r=t;(t=new Uint8Array(r.length+this.leftOver.length)).set(this.leftOver,0),t.set(r,this.leftOver.length)}else t=this.leftOver.concat(t);this.leftOver=null}var n=function(e,t){var r;for((t=t||e.length)>e.length&&(t=e.length),r=t-1;0<=r&&128==(192&e[r]);)r--;return r<0?t:0===r?t:r+u[e[r]]>t?r:t}(t),i=t;n!==t.length&&(h.uint8array?(i=t.subarray(0,n),this.leftOver=t.subarray(n,t.length)):(i=t.slice(0,n),this.leftOver=t.slice(n,t.length))),this.push({data:s.utf8decode(i),meta:e.meta})},a.prototype.flush=function(){this.leftOver&&this.leftOver.length&&(this.push({data:s.utf8decode(this.leftOver),meta:{}}),this.leftOver=null)},s.Utf8DecodeWorker=a,o.inherits(l,n),l.prototype.processChunk=function(e){this.push({data:s.utf8encode(e.data),meta:e.meta})},s.Utf8EncodeWorker=l},{"./nodejsUtils":14,"./stream/GenericWorker":28,"./support":30,"./utils":32}],32:[function(e,t,a){"use strict";var o=e("./support"),h=e("./base64"),r=e("./nodejsUtils"),u=e("./external");function n(e){return e}function l(e,t){for(var r=0;r>8;this.dir=!!(16&this.externalFileAttributes),0==e&&(this.dosPermissions=63&this.externalFileAttributes),3==e&&(this.unixPermissions=this.externalFileAttributes>>16&65535),this.dir||"/"!==this.fileNameStr.slice(-1)||(this.dir=!0)},parseZIP64ExtraField:function(){if(this.extraFields[1]){var e=n(this.extraFields[1].value);this.uncompressedSize===s.MAX_VALUE_32BITS&&(this.uncompressedSize=e.readInt(8)),this.compressedSize===s.MAX_VALUE_32BITS&&(this.compressedSize=e.readInt(8)),this.localHeaderOffset===s.MAX_VALUE_32BITS&&(this.localHeaderOffset=e.readInt(8)),this.diskNumberStart===s.MAX_VALUE_32BITS&&(this.diskNumberStart=e.readInt(4))}},readExtraFields:function(e){var t,r,n,i=e.index+this.extraFieldsLength;for(this.extraFields||(this.extraFields={});e.index+4>>6:(r<65536?t[s++]=224|r>>>12:(t[s++]=240|r>>>18,t[s++]=128|r>>>12&63),t[s++]=128|r>>>6&63),t[s++]=128|63&r);return t},r.buf2binstring=function(e){return l(e,e.length)},r.binstring2buf=function(e){for(var t=new h.Buf8(e.length),r=0,n=t.length;r>10&1023,o[n++]=56320|1023&i)}return l(o,n)},r.utf8border=function(e,t){var r;for((t=t||e.length)>e.length&&(t=e.length),r=t-1;0<=r&&128==(192&e[r]);)r--;return r<0?t:0===r?t:r+u[e[r]]>t?r:t}},{"./common":41}],43:[function(e,t,r){"use strict";t.exports=function(e,t,r,n){for(var i=65535&e|0,s=e>>>16&65535|0,a=0;0!==r;){for(r-=a=2e3>>1:e>>>1;t[r]=e}return t}();t.exports=function(e,t,r,n){var i=o,s=n+r;e^=-1;for(var a=n;a>>8^i[255&(e^t[a])];return-1^e}},{}],46:[function(e,t,r){"use strict";var h,c=e("../utils/common"),u=e("./trees"),d=e("./adler32"),p=e("./crc32"),n=e("./messages"),l=0,f=4,m=0,_=-2,g=-1,b=4,i=2,v=8,y=9,s=286,a=30,o=19,w=2*s+1,k=15,x=3,S=258,z=S+x+1,C=42,E=113,A=1,I=2,O=3,B=4;function R(e,t){return e.msg=n[t],t}function T(e){return(e<<1)-(4e.avail_out&&(r=e.avail_out),0!==r&&(c.arraySet(e.output,t.pending_buf,t.pending_out,r,e.next_out),e.next_out+=r,t.pending_out+=r,e.total_out+=r,e.avail_out-=r,t.pending-=r,0===t.pending&&(t.pending_out=0))}function N(e,t){u._tr_flush_block(e,0<=e.block_start?e.block_start:-1,e.strstart-e.block_start,t),e.block_start=e.strstart,F(e.strm)}function U(e,t){e.pending_buf[e.pending++]=t}function P(e,t){e.pending_buf[e.pending++]=t>>>8&255,e.pending_buf[e.pending++]=255&t}function L(e,t){var r,n,i=e.max_chain_length,s=e.strstart,a=e.prev_length,o=e.nice_match,h=e.strstart>e.w_size-z?e.strstart-(e.w_size-z):0,u=e.window,l=e.w_mask,f=e.prev,c=e.strstart+S,d=u[s+a-1],p=u[s+a];e.prev_length>=e.good_match&&(i>>=2),o>e.lookahead&&(o=e.lookahead);do{if(u[(r=t)+a]===p&&u[r+a-1]===d&&u[r]===u[s]&&u[++r]===u[s+1]){s+=2,r++;do{}while(u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&sh&&0!=--i);return a<=e.lookahead?a:e.lookahead}function j(e){var t,r,n,i,s,a,o,h,u,l,f=e.w_size;do{if(i=e.window_size-e.lookahead-e.strstart,e.strstart>=f+(f-z)){for(c.arraySet(e.window,e.window,f,f,0),e.match_start-=f,e.strstart-=f,e.block_start-=f,t=r=e.hash_size;n=e.head[--t],e.head[t]=f<=n?n-f:0,--r;);for(t=r=f;n=e.prev[--t],e.prev[t]=f<=n?n-f:0,--r;);i+=f}if(0===e.strm.avail_in)break;if(a=e.strm,o=e.window,h=e.strstart+e.lookahead,u=i,l=void 0,l=a.avail_in,u=x)for(s=e.strstart-e.insert,e.ins_h=e.window[s],e.ins_h=(e.ins_h<=x&&(e.ins_h=(e.ins_h<=x)if(n=u._tr_tally(e,e.strstart-e.match_start,e.match_length-x),e.lookahead-=e.match_length,e.match_length<=e.max_lazy_match&&e.lookahead>=x){for(e.match_length--;e.strstart++,e.ins_h=(e.ins_h<=x&&(e.ins_h=(e.ins_h<=x&&e.match_length<=e.prev_length){for(i=e.strstart+e.lookahead-x,n=u._tr_tally(e,e.strstart-1-e.prev_match,e.prev_length-x),e.lookahead-=e.prev_length-1,e.prev_length-=2;++e.strstart<=i&&(e.ins_h=(e.ins_h<e.pending_buf_size-5&&(r=e.pending_buf_size-5);;){if(e.lookahead<=1){if(j(e),0===e.lookahead&&t===l)return A;if(0===e.lookahead)break}e.strstart+=e.lookahead,e.lookahead=0;var n=e.block_start+r;if((0===e.strstart||e.strstart>=n)&&(e.lookahead=e.strstart-n,e.strstart=n,N(e,!1),0===e.strm.avail_out))return A;if(e.strstart-e.block_start>=e.w_size-z&&(N(e,!1),0===e.strm.avail_out))return A}return e.insert=0,t===f?(N(e,!0),0===e.strm.avail_out?O:B):(e.strstart>e.block_start&&(N(e,!1),e.strm.avail_out),A)}),new M(4,4,8,4,Z),new M(4,5,16,8,Z),new M(4,6,32,32,Z),new M(4,4,16,16,W),new M(8,16,32,32,W),new M(8,16,128,128,W),new M(8,32,128,256,W),new M(32,128,258,1024,W),new M(32,258,258,4096,W)],r.deflateInit=function(e,t){return Y(e,t,v,15,8,0)},r.deflateInit2=Y,r.deflateReset=K,r.deflateResetKeep=G,r.deflateSetHeader=function(e,t){return e&&e.state?2!==e.state.wrap?_:(e.state.gzhead=t,m):_},r.deflate=function(e,t){var r,n,i,s;if(!e||!e.state||5>8&255),U(n,n.gzhead.time>>16&255),U(n,n.gzhead.time>>24&255),U(n,9===n.level?2:2<=n.strategy||n.level<2?4:0),U(n,255&n.gzhead.os),n.gzhead.extra&&n.gzhead.extra.length&&(U(n,255&n.gzhead.extra.length),U(n,n.gzhead.extra.length>>8&255)),n.gzhead.hcrc&&(e.adler=p(e.adler,n.pending_buf,n.pending,0)),n.gzindex=0,n.status=69):(U(n,0),U(n,0),U(n,0),U(n,0),U(n,0),U(n,9===n.level?2:2<=n.strategy||n.level<2?4:0),U(n,3),n.status=E);else{var a=v+(n.w_bits-8<<4)<<8;a|=(2<=n.strategy||n.level<2?0:n.level<6?1:6===n.level?2:3)<<6,0!==n.strstart&&(a|=32),a+=31-a%31,n.status=E,P(n,a),0!==n.strstart&&(P(n,e.adler>>>16),P(n,65535&e.adler)),e.adler=1}if(69===n.status)if(n.gzhead.extra){for(i=n.pending;n.gzindex<(65535&n.gzhead.extra.length)&&(n.pending!==n.pending_buf_size||(n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),F(e),i=n.pending,n.pending!==n.pending_buf_size));)U(n,255&n.gzhead.extra[n.gzindex]),n.gzindex++;n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),n.gzindex===n.gzhead.extra.length&&(n.gzindex=0,n.status=73)}else n.status=73;if(73===n.status)if(n.gzhead.name){i=n.pending;do{if(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),F(e),i=n.pending,n.pending===n.pending_buf_size)){s=1;break}s=n.gzindexi&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),0===s&&(n.gzindex=0,n.status=91)}else n.status=91;if(91===n.status)if(n.gzhead.comment){i=n.pending;do{if(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),F(e),i=n.pending,n.pending===n.pending_buf_size)){s=1;break}s=n.gzindexi&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),0===s&&(n.status=103)}else n.status=103;if(103===n.status&&(n.gzhead.hcrc?(n.pending+2>n.pending_buf_size&&F(e),n.pending+2<=n.pending_buf_size&&(U(n,255&e.adler),U(n,e.adler>>8&255),e.adler=0,n.status=E)):n.status=E),0!==n.pending){if(F(e),0===e.avail_out)return n.last_flush=-1,m}else if(0===e.avail_in&&T(t)<=T(r)&&t!==f)return R(e,-5);if(666===n.status&&0!==e.avail_in)return R(e,-5);if(0!==e.avail_in||0!==n.lookahead||t!==l&&666!==n.status){var o=2===n.strategy?function(e,t){for(var r;;){if(0===e.lookahead&&(j(e),0===e.lookahead)){if(t===l)return A;break}if(e.match_length=0,r=u._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++,r&&(N(e,!1),0===e.strm.avail_out))return A}return e.insert=0,t===f?(N(e,!0),0===e.strm.avail_out?O:B):e.last_lit&&(N(e,!1),0===e.strm.avail_out)?A:I}(n,t):3===n.strategy?function(e,t){for(var r,n,i,s,a=e.window;;){if(e.lookahead<=S){if(j(e),e.lookahead<=S&&t===l)return A;if(0===e.lookahead)break}if(e.match_length=0,e.lookahead>=x&&0e.lookahead&&(e.match_length=e.lookahead)}if(e.match_length>=x?(r=u._tr_tally(e,1,e.match_length-x),e.lookahead-=e.match_length,e.strstart+=e.match_length,e.match_length=0):(r=u._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++),r&&(N(e,!1),0===e.strm.avail_out))return A}return e.insert=0,t===f?(N(e,!0),0===e.strm.avail_out?O:B):e.last_lit&&(N(e,!1),0===e.strm.avail_out)?A:I}(n,t):h[n.level].func(n,t);if(o!==O&&o!==B||(n.status=666),o===A||o===O)return 0===e.avail_out&&(n.last_flush=-1),m;if(o===I&&(1===t?u._tr_align(n):5!==t&&(u._tr_stored_block(n,0,0,!1),3===t&&(D(n.head),0===n.lookahead&&(n.strstart=0,n.block_start=0,n.insert=0))),F(e),0===e.avail_out))return n.last_flush=-1,m}return t!==f?m:n.wrap<=0?1:(2===n.wrap?(U(n,255&e.adler),U(n,e.adler>>8&255),U(n,e.adler>>16&255),U(n,e.adler>>24&255),U(n,255&e.total_in),U(n,e.total_in>>8&255),U(n,e.total_in>>16&255),U(n,e.total_in>>24&255)):(P(n,e.adler>>>16),P(n,65535&e.adler)),F(e),0=r.w_size&&(0===s&&(D(r.head),r.strstart=0,r.block_start=0,r.insert=0),u=new c.Buf8(r.w_size),c.arraySet(u,t,l-r.w_size,r.w_size,0),t=u,l=r.w_size),a=e.avail_in,o=e.next_in,h=e.input,e.avail_in=l,e.next_in=0,e.input=t,j(r);r.lookahead>=x;){for(n=r.strstart,i=r.lookahead-(x-1);r.ins_h=(r.ins_h<>>=y=v>>>24,p-=y,0===(y=v>>>16&255))C[s++]=65535&v;else{if(!(16&y)){if(0==(64&y)){v=m[(65535&v)+(d&(1<>>=y,p-=y),p<15&&(d+=z[n++]<>>=y=v>>>24,p-=y,!(16&(y=v>>>16&255))){if(0==(64&y)){v=_[(65535&v)+(d&(1<>>=y,p-=y,(y=s-a)>3,d&=(1<<(p-=w<<3))-1,e.next_in=n,e.next_out=s,e.avail_in=n>>24&255)+(e>>>8&65280)+((65280&e)<<8)+((255&e)<<24)}function s(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new I.Buf16(320),this.work=new I.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function a(e){var t;return e&&e.state?(t=e.state,e.total_in=e.total_out=t.total=0,e.msg="",t.wrap&&(e.adler=1&t.wrap),t.mode=P,t.last=0,t.havedict=0,t.dmax=32768,t.head=null,t.hold=0,t.bits=0,t.lencode=t.lendyn=new I.Buf32(n),t.distcode=t.distdyn=new I.Buf32(i),t.sane=1,t.back=-1,N):U}function o(e){var t;return e&&e.state?((t=e.state).wsize=0,t.whave=0,t.wnext=0,a(e)):U}function h(e,t){var r,n;return e&&e.state?(n=e.state,t<0?(r=0,t=-t):(r=1+(t>>4),t<48&&(t&=15)),t&&(t<8||15=s.wsize?(I.arraySet(s.window,t,r-s.wsize,s.wsize,0),s.wnext=0,s.whave=s.wsize):(n<(i=s.wsize-s.wnext)&&(i=n),I.arraySet(s.window,t,r-n,i,s.wnext),(n-=i)?(I.arraySet(s.window,t,r-n,n,0),s.wnext=n,s.whave=s.wsize):(s.wnext+=i,s.wnext===s.wsize&&(s.wnext=0),s.whave>>8&255,r.check=B(r.check,E,2,0),l=u=0,r.mode=2;break}if(r.flags=0,r.head&&(r.head.done=!1),!(1&r.wrap)||(((255&u)<<8)+(u>>8))%31){e.msg="incorrect header check",r.mode=30;break}if(8!=(15&u)){e.msg="unknown compression method",r.mode=30;break}if(l-=4,k=8+(15&(u>>>=4)),0===r.wbits)r.wbits=k;else if(k>r.wbits){e.msg="invalid window size",r.mode=30;break}r.dmax=1<>8&1),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0)),l=u=0,r.mode=3;case 3:for(;l<32;){if(0===o)break e;o--,u+=n[s++]<>>8&255,E[2]=u>>>16&255,E[3]=u>>>24&255,r.check=B(r.check,E,4,0)),l=u=0,r.mode=4;case 4:for(;l<16;){if(0===o)break e;o--,u+=n[s++]<>8),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0)),l=u=0,r.mode=5;case 5:if(1024&r.flags){for(;l<16;){if(0===o)break e;o--,u+=n[s++]<>>8&255,r.check=B(r.check,E,2,0)),l=u=0}else r.head&&(r.head.extra=null);r.mode=6;case 6:if(1024&r.flags&&(o<(d=r.length)&&(d=o),d&&(r.head&&(k=r.head.extra_len-r.length,r.head.extra||(r.head.extra=new Array(r.head.extra_len)),I.arraySet(r.head.extra,n,s,d,k)),512&r.flags&&(r.check=B(r.check,n,d,s)),o-=d,s+=d,r.length-=d),r.length))break e;r.length=0,r.mode=7;case 7:if(2048&r.flags){if(0===o)break e;for(d=0;k=n[s+d++],r.head&&k&&r.length<65536&&(r.head.name+=String.fromCharCode(k)),k&&d>9&1,r.head.done=!0),e.adler=r.check=0,r.mode=12;break;case 10:for(;l<32;){if(0===o)break e;o--,u+=n[s++]<>>=7&l,l-=7&l,r.mode=27;break}for(;l<3;){if(0===o)break e;o--,u+=n[s++]<>>=1)){case 0:r.mode=14;break;case 1:if(j(r),r.mode=20,6!==t)break;u>>>=2,l-=2;break e;case 2:r.mode=17;break;case 3:e.msg="invalid block type",r.mode=30}u>>>=2,l-=2;break;case 14:for(u>>>=7&l,l-=7&l;l<32;){if(0===o)break e;o--,u+=n[s++]<>>16^65535)){e.msg="invalid stored block lengths",r.mode=30;break}if(r.length=65535&u,l=u=0,r.mode=15,6===t)break e;case 15:r.mode=16;case 16:if(d=r.length){if(o>>=5,l-=5,r.ndist=1+(31&u),u>>>=5,l-=5,r.ncode=4+(15&u),u>>>=4,l-=4,286>>=3,l-=3}for(;r.have<19;)r.lens[A[r.have++]]=0;if(r.lencode=r.lendyn,r.lenbits=7,S={bits:r.lenbits},x=T(0,r.lens,0,19,r.lencode,0,r.work,S),r.lenbits=S.bits,x){e.msg="invalid code lengths set",r.mode=30;break}r.have=0,r.mode=19;case 19:for(;r.have>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>>=_,l-=_,r.lens[r.have++]=b;else{if(16===b){for(z=_+2;l>>=_,l-=_,0===r.have){e.msg="invalid bit length repeat",r.mode=30;break}k=r.lens[r.have-1],d=3+(3&u),u>>>=2,l-=2}else if(17===b){for(z=_+3;l>>=_)),u>>>=3,l-=3}else{for(z=_+7;l>>=_)),u>>>=7,l-=7}if(r.have+d>r.nlen+r.ndist){e.msg="invalid bit length repeat",r.mode=30;break}for(;d--;)r.lens[r.have++]=k}}if(30===r.mode)break;if(0===r.lens[256]){e.msg="invalid code -- missing end-of-block",r.mode=30;break}if(r.lenbits=9,S={bits:r.lenbits},x=T(D,r.lens,0,r.nlen,r.lencode,0,r.work,S),r.lenbits=S.bits,x){e.msg="invalid literal/lengths set",r.mode=30;break}if(r.distbits=6,r.distcode=r.distdyn,S={bits:r.distbits},x=T(F,r.lens,r.nlen,r.ndist,r.distcode,0,r.work,S),r.distbits=S.bits,x){e.msg="invalid distances set",r.mode=30;break}if(r.mode=20,6===t)break e;case 20:r.mode=21;case 21:if(6<=o&&258<=h){e.next_out=a,e.avail_out=h,e.next_in=s,e.avail_in=o,r.hold=u,r.bits=l,R(e,c),a=e.next_out,i=e.output,h=e.avail_out,s=e.next_in,n=e.input,o=e.avail_in,u=r.hold,l=r.bits,12===r.mode&&(r.back=-1);break}for(r.back=0;g=(C=r.lencode[u&(1<>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>v)])>>>16&255,b=65535&C,!(v+(_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>>=v,l-=v,r.back+=v}if(u>>>=_,l-=_,r.back+=_,r.length=b,0===g){r.mode=26;break}if(32&g){r.back=-1,r.mode=12;break}if(64&g){e.msg="invalid literal/length code",r.mode=30;break}r.extra=15&g,r.mode=22;case 22:if(r.extra){for(z=r.extra;l>>=r.extra,l-=r.extra,r.back+=r.extra}r.was=r.length,r.mode=23;case 23:for(;g=(C=r.distcode[u&(1<>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>v)])>>>16&255,b=65535&C,!(v+(_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>>=v,l-=v,r.back+=v}if(u>>>=_,l-=_,r.back+=_,64&g){e.msg="invalid distance code",r.mode=30;break}r.offset=b,r.extra=15&g,r.mode=24;case 24:if(r.extra){for(z=r.extra;l>>=r.extra,l-=r.extra,r.back+=r.extra}if(r.offset>r.dmax){e.msg="invalid distance too far back",r.mode=30;break}r.mode=25;case 25:if(0===h)break e;if(d=c-h,r.offset>d){if((d=r.offset-d)>r.whave&&r.sane){e.msg="invalid distance too far back",r.mode=30;break}p=d>r.wnext?(d-=r.wnext,r.wsize-d):r.wnext-d,d>r.length&&(d=r.length),m=r.window}else m=i,p=a-r.offset,d=r.length;for(hd?(m=R[T+a[v]],A[I+a[v]]):(m=96,0),h=1<>S)+(u-=h)]=p<<24|m<<16|_|0,0!==u;);for(h=1<>=1;if(0!==h?(E&=h-1,E+=h):E=0,v++,0==--O[b]){if(b===w)break;b=t[r+a[v]]}if(k>>7)]}function U(e,t){e.pending_buf[e.pending++]=255&t,e.pending_buf[e.pending++]=t>>>8&255}function P(e,t,r){e.bi_valid>d-r?(e.bi_buf|=t<>d-e.bi_valid,e.bi_valid+=r-d):(e.bi_buf|=t<>>=1,r<<=1,0<--t;);return r>>>1}function Z(e,t,r){var n,i,s=new Array(g+1),a=0;for(n=1;n<=g;n++)s[n]=a=a+r[n-1]<<1;for(i=0;i<=t;i++){var o=e[2*i+1];0!==o&&(e[2*i]=j(s[o]++,o))}}function W(e){var t;for(t=0;t>1;1<=r;r--)G(e,s,r);for(i=h;r=e.heap[1],e.heap[1]=e.heap[e.heap_len--],G(e,s,1),n=e.heap[1],e.heap[--e.heap_max]=r,e.heap[--e.heap_max]=n,s[2*i]=s[2*r]+s[2*n],e.depth[i]=(e.depth[r]>=e.depth[n]?e.depth[r]:e.depth[n])+1,s[2*r+1]=s[2*n+1]=i,e.heap[1]=i++,G(e,s,1),2<=e.heap_len;);e.heap[--e.heap_max]=e.heap[1],function(e,t){var r,n,i,s,a,o,h=t.dyn_tree,u=t.max_code,l=t.stat_desc.static_tree,f=t.stat_desc.has_stree,c=t.stat_desc.extra_bits,d=t.stat_desc.extra_base,p=t.stat_desc.max_length,m=0;for(s=0;s<=g;s++)e.bl_count[s]=0;for(h[2*e.heap[e.heap_max]+1]=0,r=e.heap_max+1;r<_;r++)p<(s=h[2*h[2*(n=e.heap[r])+1]+1]+1)&&(s=p,m++),h[2*n+1]=s,u>=7;n>>=1)if(1&r&&0!==e.dyn_ltree[2*t])return o;if(0!==e.dyn_ltree[18]||0!==e.dyn_ltree[20]||0!==e.dyn_ltree[26])return h;for(t=32;t>>3,(s=e.static_len+3+7>>>3)<=i&&(i=s)):i=s=r+5,r+4<=i&&-1!==t?J(e,t,r,n):4===e.strategy||s===i?(P(e,2+(n?1:0),3),K(e,z,C)):(P(e,4+(n?1:0),3),function(e,t,r,n){var i;for(P(e,t-257,5),P(e,r-1,5),P(e,n-4,4),i=0;i>>8&255,e.pending_buf[e.d_buf+2*e.last_lit+1]=255&t,e.pending_buf[e.l_buf+e.last_lit]=255&r,e.last_lit++,0===t?e.dyn_ltree[2*r]++:(e.matches++,t--,e.dyn_ltree[2*(A[r]+u+1)]++,e.dyn_dtree[2*N(t)]++),e.last_lit===e.lit_bufsize-1},r._tr_align=function(e){P(e,2,3),L(e,m,z),function(e){16===e.bi_valid?(U(e,e.bi_buf),e.bi_buf=0,e.bi_valid=0):8<=e.bi_valid&&(e.pending_buf[e.pending++]=255&e.bi_buf,e.bi_buf>>=8,e.bi_valid-=8)}(e)}},{"../utils/common":41}],53:[function(e,t,r){"use strict";t.exports=function(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}},{}],54:[function(e,t,r){(function(e){!function(r,n){"use strict";if(!r.setImmediate){var i,s,t,a,o=1,h={},u=!1,l=r.document,e=Object.getPrototypeOf&&Object.getPrototypeOf(r);e=e&&e.setTimeout?e:r,i="[object process]"==={}.toString.call(r.process)?function(e){process.nextTick(function(){c(e)})}:function(){if(r.postMessage&&!r.importScripts){var e=!0,t=r.onmessage;return r.onmessage=function(){e=!1},r.postMessage("","*"),r.onmessage=t,e}}()?(a="setImmediate$"+Math.random()+"$",r.addEventListener?r.addEventListener("message",d,!1):r.attachEvent("onmessage",d),function(e){r.postMessage(a+e,"*")}):r.MessageChannel?((t=new MessageChannel).port1.onmessage=function(e){c(e.data)},function(e){t.port2.postMessage(e)}):l&&"onreadystatechange"in l.createElement("script")?(s=l.documentElement,function(e){var t=l.createElement("script");t.onreadystatechange=function(){c(e),t.onreadystatechange=null,s.removeChild(t),t=null},s.appendChild(t)}):function(e){setTimeout(c,0,e)},e.setImmediate=function(e){"function"!=typeof e&&(e=new Function(""+e));for(var t=new Array(arguments.length-1),r=0;r
    '); + var isForced = isBoot !== true; + + self.callHook('beforeRender', isForced); + + var currentPage = model.pageNumber || attributes.pageNumber; + var pageRange = attributes.pageRange || 0; + var totalPage = self.getTotalPage(); + + var rangeStart = currentPage - pageRange; + var rangeEnd = currentPage + pageRange; + + if (rangeEnd > totalPage) { + rangeEnd = totalPage; + rangeStart = totalPage - pageRange * 2; + rangeStart = rangeStart < 1 ? 1 : rangeStart; + } + + if (rangeStart <= 1) { + rangeStart = 1; + rangeEnd = Math.min(pageRange * 2 + 1, totalPage); + } + + el.html(self.generateHTML({ + currentPage: currentPage, + pageRange: pageRange, + rangeStart: rangeStart, + rangeEnd: rangeEnd + })); + + // Whether to hide pagination when there is only one page + if (attributes.hideOnlyOnePage) { + el[totalPage <= 1 ? 'hide' : 'show'](); + } + + self.callHook('afterRender', isForced); + + return el; + }, + + getPageLinkTag: function(index) { + var pageLink = attributes.pageLink; + return pageLink ? `
    ${index}` : `${index}`; + }, + + // Generate HTML for page numbers + generatePageNumbersHTML: function(args) { + var self = this; + var currentPage = args.currentPage; + var totalPage = self.getTotalPage(); + var getPageLinkTag = self.getPageLinkTag; + var rangeStart = args.rangeStart; + var rangeEnd = args.rangeEnd; + var html = ''; + var i; + + var ellipsisText = attributes.ellipsisText; + + var classPrefix = attributes.classPrefix; + var pageClassName = attributes.pageClassName || ''; + var activeClassName = attributes.activeClassName || ''; + var disableClassName = attributes.disableClassName || ''; + + // Display all page numbers if page range disabled + if (attributes.pageRange === null) { + for (i = 1; i <= totalPage; i++) { + if (i == currentPage) { + html += `
  • ${i}
  • `; + } else { + html += `
  • ${getPageLinkTag(i)}
  • `; + } + } + return html; + } + + if (rangeStart <= 3) { + for (i = 1; i < rangeStart; i++) { + if (i == currentPage) { + html += `
  • ${i}
  • `; + } else { + html += `
  • ${getPageLinkTag(i)}
  • `; + } + } + } else { + if (!attributes.hideFirstOnEllipsisShow) { + html += `
  • ${getPageLinkTag(1)}
  • `; + } + html += `
  • ${ellipsisText}
  • `; + } + + for (i = rangeStart; i <= rangeEnd; i++) { + if (i == currentPage) { + html += `
  • ${i}
  • `; + } else { + html += `
  • ${getPageLinkTag(i)}
  • `; + } + } + + if (rangeEnd >= totalPage - 2) { + for (i = rangeEnd + 1; i <= totalPage; i++) { + html += `
  • ${getPageLinkTag(i)}
  • `; + } + } else { + html += `
  • ${ellipsisText}
  • `; + + if (!attributes.hideLastOnEllipsisShow) { + html += `
  • ${getPageLinkTag(totalPage)}
  • `; + } + } + + return html; + }, + + // Generate HTML content + generateHTML: function(args) { + var self = this; + var currentPage = args.currentPage; + var totalPage = self.getTotalPage(); + var getPageLinkTag = self.getPageLinkTag; + + var totalNumber = self.getTotalNumber(); + + var pageSize = attributes.pageSize; + var showPrevious = attributes.showPrevious; + var showNext = attributes.showNext; + var showPageNumbers = attributes.showPageNumbers; + var showNavigator = attributes.showNavigator; + var showSizeChanger = attributes.showSizeChanger; + var sizeChangerOptions = attributes.sizeChangerOptions; + var showGoInput = attributes.showGoInput; + var showGoButton = attributes.showGoButton; + + var prevText = attributes.prevText; + var nextText = attributes.nextText; + var goButtonText = attributes.goButtonText; + + var classPrefix = attributes.classPrefix; + var disableClassName = attributes.disableClassName || ''; + var ulClassName = attributes.ulClassName || ''; + var prevClassName = attributes.prevClassName || ''; + var nextClassName = attributes.nextClassName || ''; + + var html = ''; + var sizeSelect = `'; + var goButton = ``; + var formattedString; + + var formatSizeChanger = typeof attributes.formatSizeChanger === 'function' ? attributes.formatSizeChanger(currentPage, totalPage, totalNumber) : attributes.formatSizeChanger; + var formatNavigator = typeof attributes.formatNavigator === 'function' ? attributes.formatNavigator(currentPage, totalPage, totalNumber) : attributes.formatNavigator; + var formatGoInput = typeof attributes.formatGoInput === 'function' ? attributes.formatGoInput(goInput, currentPage, totalPage, totalNumber) : attributes.formatGoInput; + var formatGoButton = typeof attributes.formatGoButton === 'function' ? attributes.formatGoButton(goButton, currentPage, totalPage, totalNumber) : attributes.formatGoButton; + + var autoHidePrevious = typeof attributes.autoHidePrevious === 'function' ? attributes.autoHidePrevious() : attributes.autoHidePrevious; + var autoHideNext = typeof attributes.autoHideNext === 'function' ? attributes.autoHideNext() : attributes.autoHideNext; + + var header = typeof attributes.header === 'function' ? attributes.header(currentPage, totalPage, totalNumber) : attributes.header; + var footer = typeof attributes.footer === 'function' ? attributes.footer(currentPage, totalPage, totalNumber) : attributes.footer; + + // Prepend extra contents to the pagination buttons + if (header) { + formattedString = self.replaceVariables(header, { + currentPage: currentPage, + totalPage: totalPage, + totalNumber: totalNumber + }); + html += formattedString; + } + + // Whether to display navigator + if (showNavigator) { + if (formatNavigator) { + formattedString = self.replaceVariables(formatNavigator, { + currentPage: currentPage, + totalPage: totalPage, + totalNumber: totalNumber, + rangeStart: (currentPage - 1) * pageSize + 1, + rangeEnd: Math.min(currentPage * pageSize, totalNumber) + }); + html += `
    ${formattedString}
    `; + } + } + + if (showPrevious || showPageNumbers || showNext) { + html += '
    '; + + if (ulClassName) { + html += `
      `; + } else { + html += '
        '; + } + + // Whether to display Previous button + if (showPrevious) { + if (currentPage <= 1) { + if (!autoHidePrevious) { + html += `
      • ${prevText}
      • `; + } + } else { + html += `
      • ${getPageLinkTag(prevText)}
      • `; + } + } + + // Whether to display page numbers + if (showPageNumbers) { + html += self.generatePageNumbersHTML(args); + } + + // Whether to display Next button + if (showNext) { + if (currentPage >= totalPage) { + if (!autoHideNext) { + html += `
      • ${nextText}
      • `; + } + } else { + html += `
      • ${getPageLinkTag(nextText)}
      • `; + } + } + html += `
    `; + } + + if (showSizeChanger) { + if (Helpers.isArray(sizeChangerOptions)) { + if (sizeChangerOptions.indexOf(pageSize) === -1) { + sizeChangerOptions.unshift(pageSize); + sizeChangerOptions.sort((a, b) => a - b); + } + for (let i = 0; i < sizeChangerOptions.length; i++) { + sizeSelect += ``; + } + sizeSelect += ``; + formattedString = sizeSelect; + + if (formatSizeChanger) { + formattedString = self.replaceVariables(formatSizeChanger, { + length: sizeSelect, + total: totalNumber + }); + } + html += `
    ${formattedString}
    `; + } + } + + // Whether to display Go input + if (showGoInput) { + if (formatGoInput) { + formattedString = self.replaceVariables(formatGoInput, { + currentPage: currentPage, + totalPage: totalPage, + totalNumber: totalNumber, + input: goInput + }); + html += `
    ${formattedString}
    `; + } + } + + // Whether to display Go button + if (showGoButton) { + if (formatGoButton) { + formattedString = self.replaceVariables(formatGoButton, { + currentPage: currentPage, + totalPage: totalPage, + totalNumber: totalNumber, + button: goButton + }); + html += `
    ${formattedString}
    `; + } + } + + // Append extra contents to the pagination buttons + if (footer) { + formattedString = self.replaceVariables(footer, { + currentPage: currentPage, + totalPage: totalPage, + totalNumber: totalNumber + }); + html += formattedString; + } + + return html; + }, + + // dataSource is a request URL and a 'totalNumberLocator' function specified + // execute it to find out 'totalNumber' from the response + findTotalNumberFromRemoteResponse: function(response) { + var self = this; + self.model.totalNumber = attributes.totalNumberLocator(response); + }, + + // Go to the specified page + go: function(number, callback) { + var self = this; + var model = self.model; + + if (self.disabled) return; + + var pageNumber = number; + pageNumber = parseInt(pageNumber); + + if (!pageNumber || pageNumber < 1) return; + + var pageSize = attributes.pageSize; + var totalNumber = self.getTotalNumber(); + var totalPage = self.getTotalPage(); + + if (totalNumber > 0 && pageNumber > totalPage) return; + + // Pick paging data in synchronous mode + if (!self.isAsync) { + render(self.getPagingData(pageNumber)); + return; + } + + var postData = {}; + var alias = attributes.alias || {}; + var pageSizeName = alias.pageSize ? alias.pageSize : 'pageSize'; + var pageNumberName = alias.pageNumber ? alias.pageNumber : 'pageNumber'; + postData[pageSizeName] = pageSize; + postData[pageNumberName] = pageNumber; + + var ajaxParams = typeof attributes.ajax === 'function' ? attributes.ajax() : attributes.ajax; + + // If the pageNumber's value starts with 0 via Ajax + if (ajaxParams && ajaxParams.pageNumberStartWithZero) { + postData[pageNumberName] = pageNumber - 1; + } + + var formatAjaxParams = { + type: 'get', + cache: false, + data: {}, + contentType: 'application/x-www-form-urlencoded; charset=UTF-8', + dataType: 'json', + async: true + }; + + $.extend(true, formatAjaxParams, ajaxParams); + $.extend(formatAjaxParams.data, postData); + + formatAjaxParams.url = attributes.dataSource; + formatAjaxParams.success = function(response) { + try { + self.model.originalResponse = response; + if (self.isDynamicTotalNumber) { + self.findTotalNumberFromRemoteResponse(response); + } else { + self.model.totalNumber = attributes.totalNumber; + } + + var finalData = self.filterDataWithLocator(response); + render(finalData); + } catch (e) { + if(typeof attributes.onError === 'function') { + attributes.onError(e, 'ajaxSuccessHandlerError'); + } else { + throw e; + } + } + }; + formatAjaxParams.error = function(jqXHR, textStatus, errorThrown) { + attributes.formatAjaxError && attributes.formatAjaxError(jqXHR, textStatus, errorThrown); + self.enable(); + }; + + self.disable(); + + if (attributes.ajaxFunction) { + attributes.ajaxFunction(formatAjaxParams); + } else { + $.ajax(formatAjaxParams); + } + + function render(data) { + if (self.callHook('beforePaging', pageNumber) === false) return false; + + // Pagination direction + model.direction = typeof model.pageNumber === 'undefined' ? 0 : (pageNumber > model.pageNumber ? 1 : -1); + + model.pageNumber = pageNumber; + + self.render(); + + if (self.disabled && self.isAsync) { + // enable pagination + self.enable(); + } + + // cache model data + container.data('pagination').model = model; + + // format result data before callback invoked + if (attributes.formatResult) { + var cloneData = $.extend(true, [], data); + if (!Helpers.isArray(data = attributes.formatResult(cloneData))) { + data = cloneData; + } + } + + container.data('pagination').currentPageData = data; + + self.doCallback(data, callback); + + self.callHook('afterPaging', pageNumber); + + if (pageNumber == 1) { + self.callHook('afterIsFirstPage'); + } else if (pageNumber == self.getTotalPage()) { + self.callHook('afterIsLastPage'); + } + } + }, + + doCallback: function(data, customCallback) { + var self = this; + var model = self.model; + + if (typeof customCallback === 'function') { + customCallback(data, model); + } else if (typeof attributes.callback === 'function') { + attributes.callback(data, model); + } + }, + + destroy: function() { + if (this.callHook('beforeDestroy') === false) return; + + this.model.el.remove(); + container.off(); + + // Remove style element + $('#paginationjs-style').remove(); + + this.callHook('afterDestroy'); + }, + + previous: function(callback) { + this.go(this.model.pageNumber - 1, callback); + }, + + next: function(callback) { + this.go(this.model.pageNumber + 1, callback); + }, + + disable: function() { + var self = this; + var source = self.isAsync ? 'async' : 'sync'; + + if (self.callHook('beforeDisable', source) === false) return; + + self.disabled = true; + self.model.disabled = true; + + self.callHook('afterDisable', source); + }, + + enable: function() { + var self = this; + var source = self.isAsync ? 'async' : 'sync'; + + if (self.callHook('beforeEnable', source) === false) return; + + self.disabled = false; + self.model.disabled = false; + + self.callHook('afterEnable', source); + }, + + refresh: function(callback) { + this.go(this.model.pageNumber, callback); + }, + + show: function() { + var self = this; + + if (self.model.el.is(':visible')) return; + + self.model.el.show(); + }, + + hide: function() { + var self = this; + + if (!self.model.el.is(':visible')) return; + + self.model.el.hide(); + }, + + // Replace variables for template string + replaceVariables: function(template, variables) { + var formattedString; + + for (var key in variables) { + var value = variables[key]; + var regexp = new RegExp('<%=\\s*' + key + '\\s*%>', 'img'); + + formattedString = (formattedString || template).replace(regexp, value); + } + + return formattedString; + }, + + getPagingData: function(number) { + var pageSize = attributes.pageSize; + var dataSource = attributes.dataSource; + var totalNumber = this.getTotalNumber(); + + var start = pageSize * (number - 1) + 1; + var end = Math.min(number * pageSize, totalNumber); + + return dataSource.slice(start - 1, end); + }, + + getTotalNumber: function() { + return this.model.totalNumber || attributes.totalNumber || 0; + }, + + getTotalPage: function() { + return Math.ceil(this.getTotalNumber() / attributes.pageSize); + }, + + getLocator: function(locator) { + var result; + + if (typeof locator === 'string') { + result = locator; + } else if (typeof locator === 'function') { + result = locator(); + } else { + throwError('"locator" is incorrect. Expect string or function type.'); + } + + return result; + }, + + // Filter data with "locator" + filterDataWithLocator: function(dataSource) { + var locator = this.getLocator(attributes.locator); + var filteredData; + + // Datasource is an Object, use "locator" to locate available data + if (Helpers.isObject(dataSource)) { + try { + $.each(locator.split('.'), function(index, item) { + filteredData = (filteredData ? filteredData : dataSource)[item]; + }); + } + catch (e) { + // ignore + } + + if (!filteredData) { + throwError('dataSource.' + locator + ' is undefined.'); + } else if (!Helpers.isArray(filteredData)) { + throwError('dataSource.' + locator + ' should be an Array.'); + } + } + + return filteredData || dataSource; + }, + + parseDataSource: function(dataSource, callback) { + var self = this; + + if (Helpers.isObject(dataSource)) { + callback(attributes.dataSource = self.filterDataWithLocator(dataSource)); + } else if (Helpers.isArray(dataSource)) { + callback(attributes.dataSource = dataSource); + } else if (typeof dataSource === 'function') { + attributes.dataSource(function(data) { + if (!Helpers.isArray(data)) { + throwError('The parameter of "done" Function should be an Array.'); + } + self.parseDataSource.call(self, data, callback); + }); + } else if (typeof dataSource === 'string') { + if (/^https?|file:/.test(dataSource)) { + attributes.ajaxDataType = 'jsonp'; + } + callback(dataSource); + } else { + throwError('Unexpected dataSource type'); + } + }, + + callHook: function(hook) { + var paginationData = container.data('pagination') || {}; + var result; + + var args = Array.prototype.slice.apply(arguments); + args.shift(); + + if (attributes[hook] && typeof attributes[hook] === 'function') { + if (attributes[hook].apply(global, args) === false) { + result = false; + } + } + + if (paginationData.hooks && paginationData.hooks[hook]) { + $.each(paginationData.hooks[hook], function(index, item) { + if (item.apply(global, args) === false) { + result = false; + } + }); + } + + return result !== false; + }, + + observer: function() { + var self = this; + var el = self.model.el; + + // Go to specified page number + container.on(eventPrefix + 'go', function(event, pageNumber, done) { + if (typeof pageNumber === 'string') { + pageNumber = parseInt(pageNumber.trim()); + } + + if (!pageNumber) return; + + if (typeof pageNumber !== 'number') { + throwError('"pageNumber" is incorrect. (Number)'); + } + + self.go(pageNumber, done); + }); + + // Page number button click listener + el.on('click', '.J-paginationjs-page', function(event) { + var current = $(event.currentTarget); + var pageNumber = current.attr('data-num').trim(); + + if (!pageNumber || current.hasClass(attributes.disableClassName) || current.hasClass(attributes.activeClassName)) return; + + if (self.callHook('beforePageOnClick', event, pageNumber) === false) return false; + + self.go(pageNumber); + + self.callHook('afterPageOnClick', event, pageNumber); + + if (!attributes.pageLink) return false; + }); + + // Previous button click listener + el.on('click', '.J-paginationjs-previous', function(event) { + var current = $(event.currentTarget); + var pageNumber = current.attr('data-num').trim(); + + if (!pageNumber || current.hasClass(attributes.disableClassName)) return; + + if (self.callHook('beforePreviousOnClick', event, pageNumber) === false) return false; + + self.go(pageNumber); + + self.callHook('afterPreviousOnClick', event, pageNumber); + + if (!attributes.pageLink) return false; + }); + + // Next button click listener + el.on('click', '.J-paginationjs-next', function(event) { + var current = $(event.currentTarget); + var pageNumber = current.attr('data-num').trim(); + + if (!pageNumber || current.hasClass(attributes.disableClassName)) return; + + if (self.callHook('beforeNextOnClick', event, pageNumber) === false) return false; + + self.go(pageNumber); + + self.callHook('afterNextOnClick', event, pageNumber); + + if (!attributes.pageLink) return false; + }); + + // Go button click listener + el.on('click', '.J-paginationjs-go-button', function(event) { + var pageNumber = $('.J-paginationjs-go-pagenumber', el).val(); + + if (self.callHook('beforeGoButtonOnClick', event, pageNumber) === false) return false; + + container.trigger(eventPrefix + 'go', pageNumber); + + self.callHook('afterGoButtonOnClick', event, pageNumber); + }); + + // go input enter keyup listener + el.on('keyup', '.J-paginationjs-go-pagenumber', function(event) { + if (event.which === 13) { + var pageNumber = $(event.currentTarget).val(); + + if (self.callHook('beforeGoInputOnEnter', event, pageNumber) === false) return false; + + container.trigger(eventPrefix + 'go', pageNumber); + + // Maintain the cursor + $('.J-paginationjs-go-pagenumber', el).focus(); + + self.callHook('afterGoInputOnEnter', event, pageNumber); + } + }); + + el.on('change', '.J-paginationjs-size-select', function(event) { + var current = $(event.currentTarget); + var size = parseInt(current.val()); + var currentPage = self.model.pageNumber || attributes.pageNumber; + + if (typeof size !== 'number') return; + + if (self.callHook('beforeSizeSelectorChange', event, size) === false) return false; + + attributes.pageSize = size; + self.model.pageSize = size; + self.model.totalPage = self.getTotalPage(); + if (currentPage > self.model.totalPage) { + currentPage = self.model.totalPage; + } + self.go(currentPage); + + self.callHook('afterSizeSelectorChange', event, size); + + if (!attributes.pageLink) return false; + }); + + // Previous page + container.on(eventPrefix + 'previous', function(event, done) { + self.previous(done); + }); + + // Next page + container.on(eventPrefix + 'next', function(event, done) { + self.next(done); + }); + + // Disable + container.on(eventPrefix + 'disable', function() { + self.disable(); + }); + + // Enable + container.on(eventPrefix + 'enable', function() { + self.enable(); + }); + + // Refresh + container.on(eventPrefix + 'refresh', function(event, done) { + self.refresh(done); + }); + + // Show + container.on(eventPrefix + 'show', function() { + self.show(); + }); + + // Hide + container.on(eventPrefix + 'hide', function() { + self.hide(); + }); + + // Destroy + container.on(eventPrefix + 'destroy', function() { + self.destroy(); + }); + + // Whether to load the default page + var validTotalPage = Math.max(self.getTotalPage(), 1) + var defaultPageNumber = attributes.pageNumber; + + // Default pageNumber should be 1 when totalNumber is dynamic + if (self.isDynamicTotalNumber) { + if (attributes.resetPageNumberOnInit) defaultPageNumber = 1; + } + + if (attributes.triggerPagingOnInit) { + container.trigger(eventPrefix + 'go', Math.min(defaultPageNumber, validTotalPage)); + } + } + }; + + // Pagination has been initialized + if (container.data('pagination') && container.data('pagination').initialized === true) { + // Handle events + if (isNumeric(options)) { + // eg: container.pagination(5) + container.trigger.call(this, eventPrefix + 'go', options, arguments[1]); + return this; + } else if (typeof options === 'string') { + var args = Array.prototype.slice.apply(arguments); + args[0] = eventPrefix + args[0]; + + switch (options) { + case 'previous': + case 'next': + case 'go': + case 'disable': + case 'enable': + case 'refresh': + case 'show': + case 'hide': + case 'destroy': + container.trigger.apply(this, args); + break; + case 'getSelectedPageNum': + case 'getCurrentPageNum': + if (container.data('pagination').model) { + return container.data('pagination').model.pageNumber; + } else { + return container.data('pagination').attributes.pageNumber; + } + case 'getTotalPage': + return Math.ceil(container.data('pagination').model.totalNumber / container.data('pagination').model.pageSize); + case 'getSelectedPageData': + case 'getCurrentPageData': + return container.data('pagination').currentPageData; + // Whether pagination has been disabled + case 'isDisabled': + return container.data('pagination').model.disabled === true; + default: + throwError('Unknown action: ' + options); + } + return this; + } else { + // Uninstall the old instance before initializing a new one + uninstallPlugin(container); + } + } else { + if (!Helpers.isObject(options)) throwError('Illegal options'); + } + + // Check parameters + parameterChecker(attributes); + + pagination.initialize(); + + return this; + }; + + // Instance defaults + $.fn[pluginName].defaults = { + + // Data source + // Array | String | Function | Object + //dataSource: '', + + // String | Function + //locator: 'data', + + // Function + //totalNumberLocator: function() {}, + + // Total number of data items + totalNumber: 0, + + // Default page number + pageNumber: 1, + + // Number of data items per page + pageSize: 10, + + // Page range (pages around current page) + pageRange: 2, + + // Whether to display the 'Previous' button + showPrevious: true, + + // Whether to display the 'Next' button + showNext: true, + + // Whether to display the page buttons + showPageNumbers: true, + + showNavigator: false, + + // Whether to display the 'Go' input + showGoInput: false, + + // Whether to display the 'Go' button + showGoButton: false, + + showSizeChanger: false, + + sizeChangerOptions: [10, 20, 50, 100], + + // Page link + pageLink: '', + + // 'Previous' text + prevText: '‹', + + // 'Next' text + nextText: '›', + + // Ellipsis text + ellipsisText: '...', + + // 'Go' button text + goButtonText: 'Go', + + // Additional class name(s) for the Pagination container + //className: '', + + classPrefix: 'paginationjs', + + activeClassName: 'active', + + // class name when disabled + disableClassName: 'disabled', + + //ulClassName: '', + + //pageClassName: '', + + //prevClassName: '', + + //nextClassName: '', + + formatNavigator: 'Total <%= totalNumber %> items', + + formatGoInput: '<%= input %>', + + formatGoButton: '<%= button %>', + + // position in the container + position: 'bottom', + + // Auto hide previous button when current page is the first + autoHidePrevious: false, + + // Auto hide next button when current page is the last + autoHideNext: false, + + //header: '', + + //footer: '', + + //alias: {}, + + // Whether to trigger pagination at initialization + triggerPagingOnInit: true, + + // Whether to reset page number at initialization, it works only if dataSource is a URL and totalNumberLocator is specified + resetPageNumberOnInit: true, + + // Whether to hide pagination when less than one page + hideOnlyOnePage: false, + + hideFirstOnEllipsisShow: false, + + hideLastOnEllipsisShow: false, + + // Customize item's innerHTML + callback: function() {} + }; + + // Hook register + $.fn[pluginHookMethod] = function(hook, callback) { + if (arguments.length < 2) { + throwError('Expect 2 arguments at least.'); + } + + if (typeof callback !== 'function') { + throwError('callback should be a function.'); + } + + var container = $(this); + var paginationData = container.data('pagination'); + + if (!paginationData) { + container.data('pagination', {}); + paginationData = container.data('pagination'); + } + + !paginationData.hooks && (paginationData.hooks = {}); + + //paginationData.hooks[hook] = callback; + paginationData.hooks[hook] = paginationData.hooks[hook] || []; + paginationData.hooks[hook].push(callback); + + }; + + // Static method + $[pluginName] = function(selector, options) { + if (arguments.length < 2) { + throwError('Requires two parameters.'); + } + + var container; + + // 'selector' is a jQuery object + if (typeof selector !== 'string' && selector instanceof jQuery) { + container = selector; + } else { + container = $(selector); + } + + if (!container.length) return; + + container.pagination(options); + + return container; + }; + + // ============================================================ + // helpers + // ============================================================ + + var Helpers = {}; + + // Throw error + function throwError(content) { + throw new Error('Pagination: ' + content); + } + + // Check parameters + function parameterChecker(args) { + if (!args.dataSource) { + throwError('"dataSource" is required.'); + } + + if (typeof args.dataSource === 'string') { + if (args.totalNumberLocator === undefined) { + if (args.totalNumber === undefined) { + throwError('"totalNumber" is required.'); + } else if (!isNumeric(args.totalNumber)) { + throwError('"totalNumber" is incorrect. Expect numberic type'); + } + } else { + if (typeof args.totalNumberLocator !== 'function') { + throwError('"totalNumberLocator" should be a Function.'); + } + } + } else if (Helpers.isObject(args.dataSource)) { + if (typeof args.locator === 'undefined') { + throwError('"dataSource" is an Object, please specify a "locator".'); + } else if (typeof args.locator !== 'string' && typeof args.locator !== 'function') { + throwError('' + args.locator + ' is incorrect. Expect string or function type'); + } + } + + if (args.formatResult !== undefined && typeof args.formatResult !== 'function') { + throwError('"formatResult" should be a Function.'); + } + + if (args.onError !== undefined && typeof args.onError !== 'function') { + throwError('"onError" should be a Function.'); + } + } + + // uninstall plugin + function uninstallPlugin(target) { + var events = ['go', 'previous', 'next', 'disable', 'enable', 'refresh', 'show', 'hide', 'destroy']; + + // off all events + $.each(events, function(index, value) { + target.off(eventPrefix + value); + }); + + // reset pagination data + target.data('pagination', {}); + + // remove pagination element + $('.paginationjs', target).remove(); + } + + // Object type detection + function getObjectType(object, tmp) { + return ( (tmp = typeof(object)) == "object" ? object == null && "null" || Object.prototype.toString.call(object).slice(8, -1) : tmp ).toLowerCase(); + } + + function isNumeric(n) { + return !isNaN(parseFloat(n)) && isFinite(n); + } + + $.each(['Object', 'Array', 'String'], function(index, name) { + Helpers['is' + name] = function(object) { + return getObjectType(object) === name.toLowerCase(); + }; + }); + + /* + * export via AMD or CommonJS + * */ + if (typeof define === 'function' && define.amd) { + define(function() { + return $; + }); + } + +})(this, window.jQuery); diff --git a/jiuguan2025cc/public/lib/pdf.min.mjs b/jiuguan2025cc/public/lib/pdf.min.mjs new file mode 100644 index 0000000000000000000000000000000000000000..f32bf4469cdaa8b421517998e30bf226e8689f1f --- /dev/null +++ b/jiuguan2025cc/public/lib/pdf.min.mjs @@ -0,0 +1,21 @@ +/** + * @licstart The following is the entire license notice for the + * JavaScript code in this page + * + * Copyright 2024 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @licend The above is the entire license notice for the + * JavaScript code in this page + */var t={d:(e,i)=>{for(var s in i)t.o(i,s)&&!t.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:i[s]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},__webpack_exports__ = globalThis.pdfjsLib = {};t.d(__webpack_exports__,{AbortException:()=>AbortException,AnnotationEditorLayer:()=>AnnotationEditorLayer,AnnotationEditorParamsType:()=>m,AnnotationEditorType:()=>g,AnnotationEditorUIManager:()=>AnnotationEditorUIManager,AnnotationLayer:()=>AnnotationLayer,AnnotationMode:()=>p,CMapCompressionType:()=>X,ColorPicker:()=>ColorPicker,DOMSVGFactory:()=>DOMSVGFactory,DrawLayer:()=>DrawLayer,FeatureTest:()=>util_FeatureTest,GlobalWorkerOptions:()=>GlobalWorkerOptions,ImageKind:()=>_,InvalidPDFException:()=>InvalidPDFException,MissingPDFException:()=>MissingPDFException,OPS:()=>K,OutputScale:()=>OutputScale,PDFDataRangeTransport:()=>PDFDataRangeTransport,PDFDateString:()=>PDFDateString,PDFWorker:()=>PDFWorker,PasswordResponses:()=>Y,PermissionFlag:()=>f,PixelsPerInch:()=>PixelsPerInch,RenderingCancelledException:()=>RenderingCancelledException,TextLayer:()=>TextLayer,UnexpectedResponseException:()=>UnexpectedResponseException,Util:()=>Util,VerbosityLevel:()=>q,XfaLayer:()=>XfaLayer,build:()=>Yt,createValidAbsoluteUrl:()=>createValidAbsoluteUrl,fetchData:()=>fetchData,getDocument:()=>getDocument,getFilenameFromUrl:()=>getFilenameFromUrl,getPdfFilenameFromUrl:()=>getPdfFilenameFromUrl,getXfaPageViewport:()=>getXfaPageViewport,isDataScheme:()=>isDataScheme,isPdfFile:()=>isPdfFile,noContextMenu:()=>noContextMenu,normalizeUnicode:()=>normalizeUnicode,setLayerDimensions:()=>setLayerDimensions,shadow:()=>shadow,version:()=>Kt});const e=!("object"!=typeof process||process+""!="[object process]"||process.versions.nw||process.versions.electron&&process.type&&"browser"!==process.type),i=[1,0,0,1,0,0],s=[.001,0,0,.001,0,0],n=1.35,a=1,r=2,o=4,l=16,h=32,d=64,c=128,u=256,p={DISABLE:0,ENABLE:1,ENABLE_FORMS:2,ENABLE_STORAGE:3},g={DISABLE:-1,NONE:0,FREETEXT:3,HIGHLIGHT:9,STAMP:13,INK:15},m={RESIZE:1,CREATE:2,FREETEXT_SIZE:11,FREETEXT_COLOR:12,FREETEXT_OPACITY:13,INK_COLOR:21,INK_THICKNESS:22,INK_OPACITY:23,HIGHLIGHT_COLOR:31,HIGHLIGHT_DEFAULT_COLOR:32,HIGHLIGHT_THICKNESS:33,HIGHLIGHT_FREE:34,HIGHLIGHT_SHOW_ALL:35},f={PRINT:4,MODIFY_CONTENTS:8,COPY:16,MODIFY_ANNOTATIONS:32,FILL_INTERACTIVE_FORMS:256,COPY_FOR_ACCESSIBILITY:512,ASSEMBLE:1024,PRINT_HIGH_QUALITY:2048},b=0,A=1,v=2,y=3,w=3,x=4,_={GRAYSCALE_1BPP:1,RGB_24BPP:2,RGBA_32BPP:3},E=1,C=2,S=3,T=4,M=5,k=6,P=7,F=8,D=9,R=10,I=11,L=12,N=13,O=14,B=15,H=16,z=17,U=20,j=1,W=2,G=3,$=4,V=5,q={ERRORS:0,WARNINGS:1,INFOS:5},X={NONE:0,BINARY:1},K={dependency:1,setLineWidth:2,setLineCap:3,setLineJoin:4,setMiterLimit:5,setDash:6,setRenderingIntent:7,setFlatness:8,setGState:9,save:10,restore:11,transform:12,moveTo:13,lineTo:14,curveTo:15,curveTo2:16,curveTo3:17,closePath:18,rectangle:19,stroke:20,closeStroke:21,fill:22,eoFill:23,fillStroke:24,eoFillStroke:25,closeFillStroke:26,closeEOFillStroke:27,endPath:28,clip:29,eoClip:30,beginText:31,endText:32,setCharSpacing:33,setWordSpacing:34,setHScale:35,setLeading:36,setFont:37,setTextRenderingMode:38,setTextRise:39,moveText:40,setLeadingMoveText:41,setTextMatrix:42,nextLine:43,showText:44,showSpacedText:45,nextLineShowText:46,nextLineSetSpacingShowText:47,setCharWidth:48,setCharWidthAndBounds:49,setStrokeColorSpace:50,setFillColorSpace:51,setStrokeColor:52,setStrokeColorN:53,setFillColor:54,setFillColorN:55,setStrokeGray:56,setFillGray:57,setStrokeRGBColor:58,setFillRGBColor:59,setStrokeCMYKColor:60,setFillCMYKColor:61,shadingFill:62,beginInlineImage:63,beginImageData:64,endInlineImage:65,paintXObject:66,markPoint:67,markPointProps:68,beginMarkedContent:69,beginMarkedContentProps:70,endMarkedContent:71,beginCompat:72,endCompat:73,paintFormXObjectBegin:74,paintFormXObjectEnd:75,beginGroup:76,endGroup:77,beginAnnotation:80,endAnnotation:81,paintImageMaskXObject:83,paintImageMaskXObjectGroup:84,paintImageXObject:85,paintInlineImageXObject:86,paintInlineImageXObjectGroup:87,paintImageXObjectRepeat:88,paintImageMaskXObjectRepeat:89,paintSolidColorImageMask:90,constructPath:91,setStrokeTransparent:92,setFillTransparent:93},Y={NEED_PASSWORD:1,INCORRECT_PASSWORD:2};let Q=q.WARNINGS;function setVerbosityLevel(t){Number.isInteger(t)&&(Q=t)}function getVerbosityLevel(){return Q}function info(t){Q>=q.INFOS&&console.log(`Info: ${t}`)}function warn(t){Q>=q.WARNINGS&&console.log(`Warning: ${t}`)}function unreachable(t){throw new Error(t)}function assert(t,e){t||unreachable(e)}function createValidAbsoluteUrl(t,e=null,i=null){if(!t)return null;try{if(i&&"string"==typeof t){if(i.addDefaultProtocol&&t.startsWith("www.")){const e=t.match(/\./g);e?.length>=2&&(t=`http://${t}`)}if(i.tryConvertEncoding)try{t=function stringToUTF8String(t){return decodeURIComponent(escape(t))}(t)}catch{}}const s=e?new URL(t,e):new URL(t);if(function _isValidProtocol(t){switch(t?.protocol){case"http:":case"https:":case"ftp:":case"mailto:":case"tel:":return!0;default:return!1}}(s))return s}catch{}return null}function shadow(t,e,i,s=!1){Object.defineProperty(t,e,{value:i,enumerable:!s,configurable:!0,writable:!1});return i}const J=function BaseExceptionClosure(){function BaseException(t,e){this.message=t;this.name=e}BaseException.prototype=new Error;BaseException.constructor=BaseException;return BaseException}();class PasswordException extends J{constructor(t,e){super(t,"PasswordException");this.code=e}}class UnknownErrorException extends J{constructor(t,e){super(t,"UnknownErrorException");this.details=e}}class InvalidPDFException extends J{constructor(t){super(t,"InvalidPDFException")}}class MissingPDFException extends J{constructor(t){super(t,"MissingPDFException")}}class UnexpectedResponseException extends J{constructor(t,e){super(t,"UnexpectedResponseException");this.status=e}}class FormatError extends J{constructor(t){super(t,"FormatError")}}class AbortException extends J{constructor(t){super(t,"AbortException")}}function bytesToString(t){"object"==typeof t&&void 0!==t?.length||unreachable("Invalid argument for bytesToString");const e=t.length,i=8192;if(et.toString(16).padStart(2,"0")));class Util{static makeHexColor(t,e,i){return`#${Z[t]}${Z[e]}${Z[i]}`}static scaleMinMax(t,e){let i;if(t[0]){if(t[0]<0){i=e[0];e[0]=e[2];e[2]=i}e[0]*=t[0];e[2]*=t[0];if(t[3]<0){i=e[1];e[1]=e[3];e[3]=i}e[1]*=t[3];e[3]*=t[3]}else{i=e[0];e[0]=e[1];e[1]=i;i=e[2];e[2]=e[3];e[3]=i;if(t[1]<0){i=e[1];e[1]=e[3];e[3]=i}e[1]*=t[1];e[3]*=t[1];if(t[2]<0){i=e[0];e[0]=e[2];e[2]=i}e[0]*=t[2];e[2]*=t[2]}e[0]+=t[4];e[1]+=t[5];e[2]+=t[4];e[3]+=t[5]}static transform(t,e){return[t[0]*e[0]+t[2]*e[1],t[1]*e[0]+t[3]*e[1],t[0]*e[2]+t[2]*e[3],t[1]*e[2]+t[3]*e[3],t[0]*e[4]+t[2]*e[5]+t[4],t[1]*e[4]+t[3]*e[5]+t[5]]}static applyTransform(t,e){return[t[0]*e[0]+t[1]*e[2]+e[4],t[0]*e[1]+t[1]*e[3]+e[5]]}static applyInverseTransform(t,e){const i=e[0]*e[3]-e[1]*e[2];return[(t[0]*e[3]-t[1]*e[2]+e[2]*e[5]-e[4]*e[3])/i,(-t[0]*e[1]+t[1]*e[0]+e[4]*e[1]-e[5]*e[0])/i]}static getAxialAlignedBoundingBox(t,e){const i=this.applyTransform(t,e),s=this.applyTransform(t.slice(2,4),e),n=this.applyTransform([t[0],t[3]],e),a=this.applyTransform([t[2],t[1]],e);return[Math.min(i[0],s[0],n[0],a[0]),Math.min(i[1],s[1],n[1],a[1]),Math.max(i[0],s[0],n[0],a[0]),Math.max(i[1],s[1],n[1],a[1])]}static inverseTransform(t){const e=t[0]*t[3]-t[1]*t[2];return[t[3]/e,-t[1]/e,-t[2]/e,t[0]/e,(t[2]*t[5]-t[4]*t[3])/e,(t[4]*t[1]-t[5]*t[0])/e]}static singularValueDecompose2dScale(t){const e=[t[0],t[2],t[1],t[3]],i=t[0]*e[0]+t[1]*e[2],s=t[0]*e[1]+t[1]*e[3],n=t[2]*e[0]+t[3]*e[2],a=t[2]*e[1]+t[3]*e[3],r=(i+a)/2,o=Math.sqrt((i+a)**2-4*(i*a-n*s))/2,l=r+o||1,h=r-o||1;return[Math.sqrt(l),Math.sqrt(h)]}static normalizeRect(t){const e=t.slice(0);if(t[0]>t[2]){e[0]=t[2];e[2]=t[0]}if(t[1]>t[3]){e[1]=t[3];e[3]=t[1]}return e}static intersect(t,e){const i=Math.max(Math.min(t[0],t[2]),Math.min(e[0],e[2])),s=Math.min(Math.max(t[0],t[2]),Math.max(e[0],e[2]));if(i>s)return null;const n=Math.max(Math.min(t[1],t[3]),Math.min(e[1],e[3])),a=Math.min(Math.max(t[1],t[3]),Math.max(e[1],e[3]));return n>a?null:[i,n,s,a]}static#t(t,e,i,s,n,a,r,o,l,h){if(l<=0||l>=1)return;const d=1-l,c=l*l,u=c*l,p=d*(d*(d*t+3*l*e)+3*c*i)+u*s,g=d*(d*(d*n+3*l*a)+3*c*r)+u*o;h[0]=Math.min(h[0],p);h[1]=Math.min(h[1],g);h[2]=Math.max(h[2],p);h[3]=Math.max(h[3],g)}static#e(t,e,i,s,n,a,r,o,l,h,d,c){if(Math.abs(l)<1e-12){Math.abs(h)>=1e-12&&this.#t(t,e,i,s,n,a,r,o,-d/h,c);return}const u=h**2-4*d*l;if(u<0)return;const p=Math.sqrt(u),g=2*l;this.#t(t,e,i,s,n,a,r,o,(-h+p)/g,c);this.#t(t,e,i,s,n,a,r,o,(-h-p)/g,c)}static bezierBoundingBox(t,e,i,s,n,a,r,o,l){if(l){l[0]=Math.min(l[0],t,r);l[1]=Math.min(l[1],e,o);l[2]=Math.max(l[2],t,r);l[3]=Math.max(l[3],e,o)}else l=[Math.min(t,r),Math.min(e,o),Math.max(t,r),Math.max(e,o)];this.#e(t,i,n,r,e,s,a,o,3*(3*(i-n)-t+r),6*(t-2*i+n),3*(i-t),l);this.#e(t,i,n,r,e,s,a,o,3*(3*(s-a)-e+o),6*(e-2*s+a),3*(s-e),l);return l}}let tt=null,et=null;function normalizeUnicode(t){if(!tt){tt=/([\u00a0\u00b5\u037e\u0eb3\u2000-\u200a\u202f\u2126\ufb00-\ufb04\ufb06\ufb20-\ufb36\ufb38-\ufb3c\ufb3e\ufb40-\ufb41\ufb43-\ufb44\ufb46-\ufba1\ufba4-\ufba9\ufbae-\ufbb1\ufbd3-\ufbdc\ufbde-\ufbe7\ufbea-\ufbf8\ufbfc-\ufbfd\ufc00-\ufc5d\ufc64-\ufcf1\ufcf5-\ufd3d\ufd88\ufdf4\ufdfa-\ufdfb\ufe71\ufe77\ufe79\ufe7b\ufe7d]+)|(\ufb05+)/gu;et=new Map([["ſt","ſt"]])}return t.replaceAll(tt,((t,e,i)=>e?e.normalize("NFKC"):et.get(i)))}const it="pdfjs_internal_id_",st=0,nt=1,at=2,rt=3,ot=4,lt=5,ht=6,dt=7,ct=8;class BaseFilterFactory{addFilter(t){return"none"}addHCMFilter(t,e){return"none"}addAlphaFilter(t){return"none"}addLuminosityFilter(t){return"none"}addHighlightHCMFilter(t,e,i,s,n){return"none"}destroy(t=!1){}}class BaseCanvasFactory{#i=!1;constructor({enableHWA:t=!1}){this.#i=t}create(t,e){if(t<=0||e<=0)throw new Error("Invalid canvas size");const i=this._createCanvas(t,e);return{canvas:i,context:i.getContext("2d",{willReadFrequently:!this.#i})}}reset(t,e,i){if(!t.canvas)throw new Error("Canvas is not specified");if(e<=0||i<=0)throw new Error("Invalid canvas size");t.canvas.width=e;t.canvas.height=i}destroy(t){if(!t.canvas)throw new Error("Canvas is not specified");t.canvas.width=0;t.canvas.height=0;t.canvas=null;t.context=null}_createCanvas(t,e){unreachable("Abstract method `_createCanvas` called.")}}class BaseCMapReaderFactory{constructor({baseUrl:t=null,isCompressed:e=!0}){this.baseUrl=t;this.isCompressed=e}async fetch({name:t}){if(!this.baseUrl)throw new Error("Ensure that the `cMapUrl` and `cMapPacked` API parameters are provided.");if(!t)throw new Error("CMap name must be specified.");const e=this.baseUrl+t+(this.isCompressed?".bcmap":""),i=this.isCompressed?X.BINARY:X.NONE;return this._fetchData(e,i).catch((t=>{throw new Error(`Unable to load ${this.isCompressed?"binary ":""}CMap at: ${e}`)}))}_fetchData(t,e){unreachable("Abstract method `_fetchData` called.")}}class BaseStandardFontDataFactory{constructor({baseUrl:t=null}){this.baseUrl=t}async fetch({filename:t}){if(!this.baseUrl)throw new Error("Ensure that the `standardFontDataUrl` API parameter is provided.");if(!t)throw new Error("Font filename must be specified.");const e=`${this.baseUrl}${t}`;return this._fetchData(e).catch((t=>{throw new Error(`Unable to load font data at: ${e}`)}))}_fetchData(t){unreachable("Abstract method `_fetchData` called.")}}class BaseSVGFactory{create(t,e,i=!1){if(t<=0||e<=0)throw new Error("Invalid SVG dimensions");const s=this._createSVG("svg:svg");s.setAttribute("version","1.1");if(!i){s.setAttribute("width",`${t}px`);s.setAttribute("height",`${e}px`)}s.setAttribute("preserveAspectRatio","none");s.setAttribute("viewBox",`0 0 ${t} ${e}`);return s}createElement(t){if("string"!=typeof t)throw new Error("Invalid SVG element type");return this._createSVG(t)}_createSVG(t){unreachable("Abstract method `_createSVG` called.")}}const ut="http://www.w3.org/2000/svg";class PixelsPerInch{static CSS=96;static PDF=72;static PDF_TO_CSS_UNITS=this.CSS/this.PDF}async function fetchData(t,e="text"){if(isValidFetchUrl(t,document.baseURI)){const i=await fetch(t);if(!i.ok)throw new Error(i.statusText);switch(e){case"arraybuffer":return i.arrayBuffer();case"blob":return i.blob();case"json":return i.json()}return i.text()}return new Promise(((i,s)=>{const n=new XMLHttpRequest;n.open("GET",t,!0);n.responseType=e;n.onreadystatechange=()=>{if(n.readyState===XMLHttpRequest.DONE)if(200!==n.status&&0!==n.status)s(new Error(n.statusText));else{switch(e){case"arraybuffer":case"blob":case"json":i(n.response);return}i(n.responseText)}};n.send(null)}))}class DOMCMapReaderFactory extends BaseCMapReaderFactory{_fetchData(t,e){return fetchData(t,this.isCompressed?"arraybuffer":"text").then((t=>({cMapData:t instanceof ArrayBuffer?new Uint8Array(t):stringToBytes(t),compressionType:e})))}}class DOMStandardFontDataFactory extends BaseStandardFontDataFactory{_fetchData(t){return fetchData(t,"arraybuffer").then((t=>new Uint8Array(t)))}}class DOMSVGFactory extends BaseSVGFactory{_createSVG(t){return document.createElementNS(ut,t)}}class PageViewport{constructor({viewBox:t,scale:e,rotation:i,offsetX:s=0,offsetY:n=0,dontFlip:a=!1}){this.viewBox=t;this.scale=e;this.rotation=i;this.offsetX=s;this.offsetY=n;const r=(t[2]+t[0])/2,o=(t[3]+t[1])/2;let l,h,d,c,u,p,g,m;(i%=360)<0&&(i+=360);switch(i){case 180:l=-1;h=0;d=0;c=1;break;case 90:l=0;h=1;d=1;c=0;break;case 270:l=0;h=-1;d=-1;c=0;break;case 0:l=1;h=0;d=0;c=-1;break;default:throw new Error("PageViewport: Invalid rotation, must be a multiple of 90 degrees.")}if(a){d=-d;c=-c}if(0===l){u=Math.abs(o-t[1])*e+s;p=Math.abs(r-t[0])*e+n;g=(t[3]-t[1])*e;m=(t[2]-t[0])*e}else{u=Math.abs(r-t[0])*e+s;p=Math.abs(o-t[1])*e+n;g=(t[2]-t[0])*e;m=(t[3]-t[1])*e}this.transform=[l*e,h*e,d*e,c*e,u-l*e*r-d*e*o,p-h*e*r-c*e*o];this.width=g;this.height=m}get rawDims(){const{viewBox:t}=this;return shadow(this,"rawDims",{pageWidth:t[2]-t[0],pageHeight:t[3]-t[1],pageX:t[0],pageY:t[1]})}clone({scale:t=this.scale,rotation:e=this.rotation,offsetX:i=this.offsetX,offsetY:s=this.offsetY,dontFlip:n=!1}={}){return new PageViewport({viewBox:this.viewBox.slice(),scale:t,rotation:e,offsetX:i,offsetY:s,dontFlip:n})}convertToViewportPoint(t,e){return Util.applyTransform([t,e],this.transform)}convertToViewportRectangle(t){const e=Util.applyTransform([t[0],t[1]],this.transform),i=Util.applyTransform([t[2],t[3]],this.transform);return[e[0],e[1],i[0],i[1]]}convertToPdfPoint(t,e){return Util.applyInverseTransform([t,e],this.transform)}}class RenderingCancelledException extends J{constructor(t,e=0){super(t,"RenderingCancelledException");this.extraDelay=e}}function isDataScheme(t){const e=t.length;let i=0;for(;i=1&&s<=12?s-1:0;let n=parseInt(e[3],10);n=n>=1&&n<=31?n:1;let a=parseInt(e[4],10);a=a>=0&&a<=23?a:0;let r=parseInt(e[5],10);r=r>=0&&r<=59?r:0;let o=parseInt(e[6],10);o=o>=0&&o<=59?o:0;const l=e[7]||"Z";let h=parseInt(e[8],10);h=h>=0&&h<=23?h:0;let d=parseInt(e[9],10)||0;d=d>=0&&d<=59?d:0;if("-"===l){a+=h;r+=d}else if("+"===l){a-=h;r-=d}return new Date(Date.UTC(i,s,n,a,r,o))}}function getXfaPageViewport(t,{scale:e=1,rotation:i=0}){const{width:s,height:n}=t.attributes.style,a=[0,0,parseInt(s),parseInt(n)];return new PageViewport({viewBox:a,scale:e,rotation:i})}function getRGB(t){if(t.startsWith("#")){const e=parseInt(t.slice(1),16);return[(16711680&e)>>16,(65280&e)>>8,255&e]}if(t.startsWith("rgb("))return t.slice(4,-1).split(",").map((t=>parseInt(t)));if(t.startsWith("rgba("))return t.slice(5,-1).split(",").map((t=>parseInt(t))).slice(0,3);warn(`Not a valid color format: "${t}"`);return[0,0,0]}function getCurrentTransform(t){const{a:e,b:i,c:s,d:n,e:a,f:r}=t.getTransform();return[e,i,s,n,a,r]}function getCurrentTransformInverse(t){const{a:e,b:i,c:s,d:n,e:a,f:r}=t.getTransform().invertSelf();return[e,i,s,n,a,r]}function setLayerDimensions(t,e,i=!1,s=!0){if(e instanceof PageViewport){const{pageWidth:s,pageHeight:n}=e.rawDims,{style:a}=t,r=util_FeatureTest.isCSSRoundSupported,o=`var(--scale-factor) * ${s}px`,l=`var(--scale-factor) * ${n}px`,h=r?`round(down, ${o}, var(--scale-round-x, 1px))`:`calc(${o})`,d=r?`round(down, ${l}, var(--scale-round-y, 1px))`:`calc(${l})`;if(i&&e.rotation%180!=0){a.width=d;a.height=h}else{a.width=h;a.height=d}}s&&t.setAttribute("data-main-rotation",e.rotation)}class OutputScale{constructor(){const t=window.devicePixelRatio||1;this.sx=t;this.sy=t}get scaled(){return 1!==this.sx||1!==this.sy}get symmetric(){return this.sx===this.sy}}class EditorToolbar{#s=null;#n=null;#a;#r=null;#o=null;static#l=null;constructor(t){this.#a=t;EditorToolbar.#l||=Object.freeze({freetext:"pdfjs-editor-remove-freetext-button",highlight:"pdfjs-editor-remove-highlight-button",ink:"pdfjs-editor-remove-ink-button",stamp:"pdfjs-editor-remove-stamp-button"})}render(){const t=this.#s=document.createElement("div");t.classList.add("editToolbar","hidden");t.setAttribute("role","toolbar");const e=this.#a._uiManager._signal;t.addEventListener("contextmenu",noContextMenu,{signal:e});t.addEventListener("pointerdown",EditorToolbar.#h,{signal:e});const i=this.#r=document.createElement("div");i.className="buttons";t.append(i);const s=this.#a.toolbarPosition;if(s){const{style:e}=t,i="ltr"===this.#a._uiManager.direction?1-s[0]:s[0];e.insetInlineEnd=100*i+"%";e.top=`calc(${100*s[1]}% + var(--editor-toolbar-vert-offset))`}this.#d();return t}get div(){return this.#s}static#h(t){t.stopPropagation()}#c(t){this.#a._focusEventsAllowed=!1;t.preventDefault();t.stopPropagation()}#u(t){this.#a._focusEventsAllowed=!0;t.preventDefault();t.stopPropagation()}#p(t){const e=this.#a._uiManager._signal;t.addEventListener("focusin",this.#c.bind(this),{capture:!0,signal:e});t.addEventListener("focusout",this.#u.bind(this),{capture:!0,signal:e});t.addEventListener("contextmenu",noContextMenu,{signal:e})}hide(){this.#s.classList.add("hidden");this.#n?.hideDropdown()}show(){this.#s.classList.remove("hidden");this.#o?.shown()}#d(){const{editorType:t,_uiManager:e}=this.#a,i=document.createElement("button");i.className="delete";i.tabIndex=0;i.setAttribute("data-l10n-id",EditorToolbar.#l[t]);this.#p(i);i.addEventListener("click",(t=>{e.delete()}),{signal:e._signal});this.#r.append(i)}get#g(){const t=document.createElement("div");t.className="divider";return t}async addAltText(t){const e=await t.render();this.#p(e);this.#r.prepend(e,this.#g);this.#o=t}addColorPicker(t){this.#n=t;const e=t.renderButton();this.#p(e);this.#r.prepend(e,this.#g)}remove(){this.#s.remove();this.#n?.destroy();this.#n=null}}class HighlightToolbar{#r=null;#s=null;#m;constructor(t){this.#m=t}#f(){const t=this.#s=document.createElement("div");t.className="editToolbar";t.setAttribute("role","toolbar");t.addEventListener("contextmenu",noContextMenu,{signal:this.#m._signal});const e=this.#r=document.createElement("div");e.className="buttons";t.append(e);this.#b();return t}#A(t,e){let i=0,s=0;for(const n of t){const t=n.y+n.height;if(ti){s=a;i=t}else e?a>s&&(s=a):a{this.#m.highlightSelection("floating_button")}),{signal:i});this.#r.append(t)}}function bindEvents(t,e,i){for(const s of i)e.addEventListener(s,t[s].bind(t))}class IdManager{#v=0;get id(){return"pdfjs_internal_editor_"+this.#v++}}class ImageManager{#y=function getUuid(){if("undefined"!=typeof crypto&&"function"==typeof crypto?.randomUUID)return crypto.randomUUID();const t=new Uint8Array(32);if("undefined"!=typeof crypto&&"function"==typeof crypto?.getRandomValues)crypto.getRandomValues(t);else for(let e=0;e<32;e++)t[e]=Math.floor(255*Math.random());return bytesToString(t)}();#v=0;#w=null;static get _isSVGFittingCanvas(){const t=new OffscreenCanvas(1,3).getContext("2d",{willReadFrequently:!0}),e=new Image;e.src='data:image/svg+xml;charset=UTF-8,';return shadow(this,"_isSVGFittingCanvas",e.decode().then((()=>{t.drawImage(e,0,0,1,1,0,0,1,3);return 0===new Uint32Array(t.getImageData(0,0,1,1).data.buffer)[0]})))}async#x(t,e){this.#w||=new Map;let i=this.#w.get(t);if(null===i)return null;if(i?.bitmap){i.refCounter+=1;return i}try{i||={bitmap:null,id:`image_${this.#y}_${this.#v++}`,refCounter:0,isSvg:!1};let t;if("string"==typeof e){i.url=e;t=await fetchData(e,"blob")}else e instanceof File?t=i.file=e:e instanceof Blob&&(t=e);if("image/svg+xml"===t.type){const e=ImageManager._isSVGFittingCanvas,s=new FileReader,n=new Image,a=new Promise(((t,a)=>{n.onload=()=>{i.bitmap=n;i.isSvg=!0;t()};s.onload=async()=>{const t=i.svgUrl=s.result;n.src=await e?`${t}#svgView(preserveAspectRatio(none))`:t};n.onerror=s.onerror=a}));s.readAsDataURL(t);await a}else i.bitmap=await createImageBitmap(t);i.refCounter=1}catch(t){console.error(t);i=null}this.#w.set(t,i);i&&this.#w.set(i.id,i);return i}async getFromFile(t){const{lastModified:e,name:i,size:s,type:n}=t;return this.#x(`${e}_${i}_${s}_${n}`,t)}async getFromUrl(t){return this.#x(t,t)}async getFromBlob(t,e){const i=await e;return this.#x(t,i)}async getFromId(t){this.#w||=new Map;const e=this.#w.get(t);if(!e)return null;if(e.bitmap){e.refCounter+=1;return e}if(e.file)return this.getFromFile(e.file);if(e.blobPromise){const{blobPromise:t}=e;delete e.blobPromise;return this.getFromBlob(e.id,t)}return this.getFromUrl(e.url)}getFromCanvas(t,e){this.#w||=new Map;let i=this.#w.get(t);if(i?.bitmap){i.refCounter+=1;return i}const s=new OffscreenCanvas(e.width,e.height);s.getContext("2d").drawImage(e,0,0);i={bitmap:s.transferToImageBitmap(),id:`image_${this.#y}_${this.#v++}`,refCounter:1,isSvg:!1};this.#w.set(t,i);this.#w.set(i.id,i);return i}getSvgUrl(t){const e=this.#w.get(t);return e?.isSvg?e.svgUrl:null}deleteId(t){this.#w||=new Map;const e=this.#w.get(t);if(!e)return;e.refCounter-=1;if(0!==e.refCounter)return;const{bitmap:i}=e;if(!e.url&&!e.file){const t=new OffscreenCanvas(i.width,i.height);t.getContext("bitmaprenderer").transferFromImageBitmap(i);e.blobPromise=t.convertToBlob()}i.close?.();e.bitmap=null}isValidId(t){return t.startsWith(`image_${this.#y}_`)}}class CommandManager{#_=[];#E=!1;#C;#S=-1;constructor(t=128){this.#C=t}add({cmd:t,undo:e,post:i,mustExec:s,type:n=NaN,overwriteIfSameType:a=!1,keepUndo:r=!1}){s&&t();if(this.#E)return;const o={cmd:t,undo:e,post:i,type:n};if(-1===this.#S){this.#_.length>0&&(this.#_.length=0);this.#S=0;this.#_.push(o);return}if(a&&this.#_[this.#S].type===n){r&&(o.undo=this.#_[this.#S].undo);this.#_[this.#S]=o;return}const l=this.#S+1;if(l===this.#C)this.#_.splice(0,1);else{this.#S=l;lt===e[i])))return ColorManager._colorsMapping.get(t);return e}getHexCode(t){const e=this._colors.get(t);return e?Util.makeHexColor(...e):t}}class AnnotationEditorUIManager{#M=new AbortController;#k=null;#P=new Map;#F=new Map;#D=null;#R=null;#I=null;#L=new CommandManager;#N=null;#O=0;#B=new Set;#H=null;#z=null;#U=new Set;#j=!1;#W=!1;#G=!1;#$=null;#V=null;#q=null;#X=null;#K=!1;#Y=null;#Q=new IdManager;#J=!1;#Z=!1;#tt=null;#et=null;#it=null;#st=null;#nt=g.NONE;#at=new Set;#rt=null;#ot=null;#lt=null;#ht={isEditing:!1,isEmpty:!0,hasSomethingToUndo:!1,hasSomethingToRedo:!1,hasSelectedEditor:!1,hasSelectedText:!1};#dt=[0,0];#ct=null;#ut=null;#pt=null;#gt=null;static TRANSLATE_SMALL=1;static TRANSLATE_BIG=10;static get _keyboardManager(){const t=AnnotationEditorUIManager.prototype,arrowChecker=t=>t.#ut.contains(document.activeElement)&&"BUTTON"!==document.activeElement.tagName&&t.hasSomethingToControl(),textInputChecker=(t,{target:e})=>{if(e instanceof HTMLInputElement){const{type:t}=e;return"text"!==t&&"number"!==t}return!0},e=this.TRANSLATE_SMALL,i=this.TRANSLATE_BIG;return shadow(this,"_keyboardManager",new KeyboardManager([[["ctrl+a","mac+meta+a"],t.selectAll,{checker:textInputChecker}],[["ctrl+z","mac+meta+z"],t.undo,{checker:textInputChecker}],[["ctrl+y","ctrl+shift+z","mac+meta+shift+z","ctrl+shift+Z","mac+meta+shift+Z"],t.redo,{checker:textInputChecker}],[["Backspace","alt+Backspace","ctrl+Backspace","shift+Backspace","mac+Backspace","mac+alt+Backspace","mac+ctrl+Backspace","Delete","ctrl+Delete","shift+Delete","mac+Delete"],t.delete,{checker:textInputChecker}],[["Enter","mac+Enter"],t.addNewEditorFromKeyboard,{checker:(t,{target:e})=>!(e instanceof HTMLButtonElement)&&t.#ut.contains(e)&&!t.isEnterHandled}],[[" ","mac+ "],t.addNewEditorFromKeyboard,{checker:(t,{target:e})=>!(e instanceof HTMLButtonElement)&&t.#ut.contains(document.activeElement)}],[["Escape","mac+Escape"],t.unselectAll],[["ArrowLeft","mac+ArrowLeft"],t.translateSelectedEditors,{args:[-e,0],checker:arrowChecker}],[["ctrl+ArrowLeft","mac+shift+ArrowLeft"],t.translateSelectedEditors,{args:[-i,0],checker:arrowChecker}],[["ArrowRight","mac+ArrowRight"],t.translateSelectedEditors,{args:[e,0],checker:arrowChecker}],[["ctrl+ArrowRight","mac+shift+ArrowRight"],t.translateSelectedEditors,{args:[i,0],checker:arrowChecker}],[["ArrowUp","mac+ArrowUp"],t.translateSelectedEditors,{args:[0,-e],checker:arrowChecker}],[["ctrl+ArrowUp","mac+shift+ArrowUp"],t.translateSelectedEditors,{args:[0,-i],checker:arrowChecker}],[["ArrowDown","mac+ArrowDown"],t.translateSelectedEditors,{args:[0,e],checker:arrowChecker}],[["ctrl+ArrowDown","mac+shift+ArrowDown"],t.translateSelectedEditors,{args:[0,i],checker:arrowChecker}]]))}constructor(t,e,i,s,n,a,r,o,l,h,d){const c=this._signal=this.#M.signal;this.#ut=t;this.#pt=e;this.#D=i;this._eventBus=s;s._on("editingaction",this.onEditingAction.bind(this),{signal:c});s._on("pagechanging",this.onPageChanging.bind(this),{signal:c});s._on("scalechanging",this.onScaleChanging.bind(this),{signal:c});s._on("rotationchanging",this.onRotationChanging.bind(this),{signal:c});s._on("setpreference",this.onSetPreference.bind(this),{signal:c});s._on("switchannotationeditorparams",(t=>this.updateParams(t.type,t.value)),{signal:c});this.#mt();this.#ft();this.#bt();this.#R=n.annotationStorage;this.#$=n.filterFactory;this.#ot=a;this.#X=r||null;this.#j=o;this.#W=l;this.#G=h;this.#st=d||null;this.viewParameters={realScale:PixelsPerInch.PDF_TO_CSS_UNITS,rotation:0};this.isShiftKeyDown=!1}destroy(){this.#gt?.resolve();this.#gt=null;this.#M?.abort();this.#M=null;this._signal=null;for(const t of this.#F.values())t.destroy();this.#F.clear();this.#P.clear();this.#U.clear();this.#k=null;this.#at.clear();this.#L.destroy();this.#D?.destroy();this.#Y?.hide();this.#Y=null;if(this.#V){clearTimeout(this.#V);this.#V=null}if(this.#ct){clearTimeout(this.#ct);this.#ct=null}}combinedSignal(t){return AbortSignal.any([this._signal,t.signal])}get mlManager(){return this.#st}get useNewAltTextFlow(){return this.#W}get useNewAltTextWhenAddingImage(){return this.#G}get hcmFilter(){return shadow(this,"hcmFilter",this.#ot?this.#$.addHCMFilter(this.#ot.foreground,this.#ot.background):"none")}get direction(){return shadow(this,"direction",getComputedStyle(this.#ut).direction)}get highlightColors(){return shadow(this,"highlightColors",this.#X?new Map(this.#X.split(",").map((t=>t.split("=").map((t=>t.trim()))))):null)}get highlightColorNames(){return shadow(this,"highlightColorNames",this.highlightColors?new Map(Array.from(this.highlightColors,(t=>t.reverse()))):null)}setMainHighlightColorPicker(t){this.#it=t}editAltText(t,e=!1){this.#D?.editAltText(this,t,e)}switchToMode(t,e){this._eventBus.on("annotationeditormodechanged",e,{once:!0,signal:this._signal});this._eventBus.dispatch("showannotationeditorui",{source:this,mode:t})}setPreference(t,e){this._eventBus.dispatch("setpreference",{source:this,name:t,value:e})}onSetPreference({name:t,value:e}){if("enableNewAltTextWhenAddingImage"===t)this.#G=e}onPageChanging({pageNumber:t}){this.#O=t-1}focusMainContainer(){this.#ut.focus()}findParent(t,e){for(const i of this.#F.values()){const{x:s,y:n,width:a,height:r}=i.div.getBoundingClientRect();if(t>=s&&t<=s+a&&e>=n&&e<=n+r)return i}return null}disableUserSelect(t=!1){this.#pt.classList.toggle("noUserSelect",t)}addShouldRescale(t){this.#U.add(t)}removeShouldRescale(t){this.#U.delete(t)}onScaleChanging({scale:t}){this.commitOrRemove();this.viewParameters.realScale=t*PixelsPerInch.PDF_TO_CSS_UNITS;for(const t of this.#U)t.onScaleChanging()}onRotationChanging({pagesRotation:t}){this.commitOrRemove();this.viewParameters.rotation=t}#At({anchorNode:t}){return t.nodeType===Node.TEXT_NODE?t.parentElement:t}#vt(t){const{currentLayer:e}=this;if(e.hasTextLayer(t))return e;for(const e of this.#F.values())if(e.hasTextLayer(t))return e;return null}highlightSelection(t=""){const e=document.getSelection();if(!e||e.isCollapsed)return;const{anchorNode:i,anchorOffset:s,focusNode:n,focusOffset:a}=e,r=e.toString(),o=this.#At(e).closest(".textLayer"),l=this.getSelectionBoxes(o);if(!l)return;e.empty();const h=this.#vt(o),d=this.#nt===g.NONE,callback=()=>{h?.createAndAddNewEditor({x:0,y:0},!1,{methodOfCreation:t,boxes:l,anchorNode:i,anchorOffset:s,focusNode:n,focusOffset:a,text:r});d&&this.showAllEditors("highlight",!0,!0)};d?this.switchToMode(g.HIGHLIGHT,callback):callback()}#yt(){const t=document.getSelection();if(!t||t.isCollapsed)return;const e=this.#At(t).closest(".textLayer"),i=this.getSelectionBoxes(e);if(i){this.#Y||=new HighlightToolbar(this);this.#Y.show(e,i,"ltr"===this.direction)}}addToAnnotationStorage(t){t.isEmpty()||!this.#R||this.#R.has(t.id)||this.#R.setValue(t.id,t)}#wt(){const t=document.getSelection();if(!t||t.isCollapsed){if(this.#rt){this.#Y?.hide();this.#rt=null;this.#xt({hasSelectedText:!1})}return}const{anchorNode:e}=t;if(e===this.#rt)return;const i=this.#At(t).closest(".textLayer");if(i){this.#Y?.hide();this.#rt=e;this.#xt({hasSelectedText:!0});if(this.#nt===g.HIGHLIGHT||this.#nt===g.NONE){this.#nt===g.HIGHLIGHT&&this.showAllEditors("highlight",!0,!0);this.#K=this.isShiftKeyDown;if(!this.isShiftKeyDown){const t=this.#nt===g.HIGHLIGHT?this.#vt(i):null;t?.toggleDrawing();const e=new AbortController,s=this.combinedSignal(e),pointerup=i=>{if("pointerup"!==i.type||0===i.button){e.abort();t?.toggleDrawing(!0);"pointerup"===i.type&&this.#_t("main_toolbar")}};window.addEventListener("pointerup",pointerup,{signal:s});window.addEventListener("blur",pointerup,{signal:s})}}}else if(this.#rt){this.#Y?.hide();this.#rt=null;this.#xt({hasSelectedText:!1})}}#_t(t=""){this.#nt===g.HIGHLIGHT?this.highlightSelection(t):this.#j&&this.#yt()}#mt(){document.addEventListener("selectionchange",this.#wt.bind(this),{signal:this._signal})}#Et(){if(this.#q)return;this.#q=new AbortController;const t=this.combinedSignal(this.#q);window.addEventListener("focus",this.focus.bind(this),{signal:t});window.addEventListener("blur",this.blur.bind(this),{signal:t})}#Ct(){this.#q?.abort();this.#q=null}blur(){this.isShiftKeyDown=!1;if(this.#K){this.#K=!1;this.#_t("main_toolbar")}if(!this.hasSelection)return;const{activeElement:t}=document;for(const e of this.#at)if(e.div.contains(t)){this.#et=[e,t];e._focusEventsAllowed=!1;break}}focus(){if(!this.#et)return;const[t,e]=this.#et;this.#et=null;e.addEventListener("focusin",(()=>{t._focusEventsAllowed=!0}),{once:!0,signal:this._signal});e.focus()}#bt(){if(this.#tt)return;this.#tt=new AbortController;const t=this.combinedSignal(this.#tt);window.addEventListener("keydown",this.keydown.bind(this),{signal:t});window.addEventListener("keyup",this.keyup.bind(this),{signal:t})}#St(){this.#tt?.abort();this.#tt=null}#Tt(){if(this.#N)return;this.#N=new AbortController;const t=this.combinedSignal(this.#N);document.addEventListener("copy",this.copy.bind(this),{signal:t});document.addEventListener("cut",this.cut.bind(this),{signal:t});document.addEventListener("paste",this.paste.bind(this),{signal:t})}#Mt(){this.#N?.abort();this.#N=null}#ft(){const t=this._signal;document.addEventListener("dragover",this.dragOver.bind(this),{signal:t});document.addEventListener("drop",this.drop.bind(this),{signal:t})}addEditListeners(){this.#bt();this.#Tt()}removeEditListeners(){this.#St();this.#Mt()}dragOver(t){for(const{type:e}of t.dataTransfer.items)for(const i of this.#z)if(i.isHandlingMimeForPasting(e)){t.dataTransfer.dropEffect="copy";t.preventDefault();return}}drop(t){for(const e of t.dataTransfer.items)for(const i of this.#z)if(i.isHandlingMimeForPasting(e.type)){i.paste(e,this.currentLayer);t.preventDefault();return}}copy(t){t.preventDefault();this.#k?.commitOrRemove();if(!this.hasSelection)return;const e=[];for(const t of this.#at){const i=t.serialize(!0);i&&e.push(i)}0!==e.length&&t.clipboardData.setData("application/pdfjs",JSON.stringify(e))}cut(t){this.copy(t);this.delete()}async paste(t){t.preventDefault();const{clipboardData:e}=t;for(const t of e.items)for(const e of this.#z)if(e.isHandlingMimeForPasting(t.type)){e.paste(t,this.currentLayer);return}let i=e.getData("application/pdfjs");if(!i)return;try{i=JSON.parse(i)}catch(t){warn(`paste: "${t.message}".`);return}if(!Array.isArray(i))return;this.unselectAll();const s=this.currentLayer;try{const t=[];for(const e of i){const i=await s.deserialize(e);if(!i)return;t.push(i)}const cmd=()=>{for(const e of t)this.#kt(e);this.#Pt(t)},undo=()=>{for(const e of t)e.remove()};this.addCommands({cmd,undo,mustExec:!0})}catch(t){warn(`paste: "${t.message}".`)}}keydown(t){this.isShiftKeyDown||"Shift"!==t.key||(this.isShiftKeyDown=!0);this.#nt===g.NONE||this.isEditorHandlingKeyboard||AnnotationEditorUIManager._keyboardManager.exec(this,t)}keyup(t){if(this.isShiftKeyDown&&"Shift"===t.key){this.isShiftKeyDown=!1;if(this.#K){this.#K=!1;this.#_t("main_toolbar")}}}onEditingAction({name:t}){switch(t){case"undo":case"redo":case"delete":case"selectAll":this[t]();break;case"highlightSelection":this.highlightSelection("context_menu")}}#xt(t){if(Object.entries(t).some((([t,e])=>this.#ht[t]!==e))){this._eventBus.dispatch("annotationeditorstateschanged",{source:this,details:Object.assign(this.#ht,t)});this.#nt===g.HIGHLIGHT&&!1===t.hasSelectedEditor&&this.#Ft([[m.HIGHLIGHT_FREE,!0]])}}#Ft(t){this._eventBus.dispatch("annotationeditorparamschanged",{source:this,details:t})}setEditingState(t){if(t){this.#Et();this.#Tt();this.#xt({isEditing:this.#nt!==g.NONE,isEmpty:this.#Dt(),hasSomethingToUndo:this.#L.hasSomethingToUndo(),hasSomethingToRedo:this.#L.hasSomethingToRedo(),hasSelectedEditor:!1})}else{this.#Ct();this.#Mt();this.#xt({isEditing:!1});this.disableUserSelect(!1)}}registerEditorTypes(t){if(!this.#z){this.#z=t;for(const t of this.#z)this.#Ft(t.defaultPropertiesToUpdate)}}getId(){return this.#Q.id}get currentLayer(){return this.#F.get(this.#O)}getLayer(t){return this.#F.get(t)}get currentPageIndex(){return this.#O}addLayer(t){this.#F.set(t.pageIndex,t);this.#J?t.enable():t.disable()}removeLayer(t){this.#F.delete(t.pageIndex)}async updateMode(t,e=null,i=!1){if(this.#nt!==t){if(this.#gt){await this.#gt.promise;if(!this.#gt)return}this.#gt=Promise.withResolvers();this.#nt=t;if(t!==g.NONE){this.setEditingState(!0);await this.#Rt();this.unselectAll();for(const e of this.#F.values())e.updateMode(t);if(e){for(const t of this.#P.values())if(t.annotationElementId===e){this.setSelected(t);t.enterInEditMode()}else t.unselect();this.#gt.resolve()}else{i&&this.addNewEditorFromKeyboard();this.#gt.resolve()}}else{this.setEditingState(!1);this.#It();this.#gt.resolve()}}}addNewEditorFromKeyboard(){this.currentLayer.canCreateNewEmptyEditor()&&this.currentLayer.addNewEditor()}updateToolbar(t){t!==this.#nt&&this._eventBus.dispatch("switchannotationeditormode",{source:this,mode:t})}updateParams(t,e){if(this.#z){switch(t){case m.CREATE:this.currentLayer.addNewEditor();return;case m.HIGHLIGHT_DEFAULT_COLOR:this.#it?.updateColor(e);break;case m.HIGHLIGHT_SHOW_ALL:this._eventBus.dispatch("reporttelemetry",{source:this,details:{type:"editing",data:{type:"highlight",action:"toggle_visibility"}}});(this.#lt||=new Map).set(t,e);this.showAllEditors("highlight",e)}for(const i of this.#at)i.updateParams(t,e);for(const i of this.#z)i.updateDefaultParams(t,e)}}showAllEditors(t,e,i=!1){for(const i of this.#P.values())i.editorType===t&&i.show(e);(this.#lt?.get(m.HIGHLIGHT_SHOW_ALL)??!0)!==e&&this.#Ft([[m.HIGHLIGHT_SHOW_ALL,e]])}enableWaiting(t=!1){if(this.#Z!==t){this.#Z=t;for(const e of this.#F.values()){t?e.disableClick():e.enableClick();e.div.classList.toggle("waiting",t)}}}async#Rt(){if(!this.#J){this.#J=!0;const t=[];for(const e of this.#F.values())t.push(e.enable());await Promise.all(t);for(const t of this.#P.values())t.enable()}}#It(){this.unselectAll();if(this.#J){this.#J=!1;for(const t of this.#F.values())t.disable();for(const t of this.#P.values())t.disable()}}getEditors(t){const e=[];for(const i of this.#P.values())i.pageIndex===t&&e.push(i);return e}getEditor(t){return this.#P.get(t)}addEditor(t){this.#P.set(t.id,t)}removeEditor(t){if(t.div.contains(document.activeElement)){this.#V&&clearTimeout(this.#V);this.#V=setTimeout((()=>{this.focusMainContainer();this.#V=null}),0)}this.#P.delete(t.id);this.unselect(t);t.annotationElementId&&this.#B.has(t.annotationElementId)||this.#R?.remove(t.id)}addDeletedAnnotationElement(t){this.#B.add(t.annotationElementId);this.addChangedExistingAnnotation(t);t.deleted=!0}isDeletedAnnotationElement(t){return this.#B.has(t)}removeDeletedAnnotationElement(t){this.#B.delete(t.annotationElementId);this.removeChangedExistingAnnotation(t);t.deleted=!1}#kt(t){const e=this.#F.get(t.pageIndex);if(e)e.addOrRebuild(t);else{this.addEditor(t);this.addToAnnotationStorage(t)}}setActiveEditor(t){if(this.#k!==t){this.#k=t;t&&this.#Ft(t.propertiesToUpdate)}}get#Lt(){let t=null;for(t of this.#at);return t}updateUI(t){this.#Lt===t&&this.#Ft(t.propertiesToUpdate)}toggleSelected(t){if(this.#at.has(t)){this.#at.delete(t);t.unselect();this.#xt({hasSelectedEditor:this.hasSelection})}else{this.#at.add(t);t.select();this.#Ft(t.propertiesToUpdate);this.#xt({hasSelectedEditor:!0})}}setSelected(t){for(const e of this.#at)e!==t&&e.unselect();this.#at.clear();this.#at.add(t);t.select();this.#Ft(t.propertiesToUpdate);this.#xt({hasSelectedEditor:!0})}isSelected(t){return this.#at.has(t)}get firstSelectedEditor(){return this.#at.values().next().value}unselect(t){t.unselect();this.#at.delete(t);this.#xt({hasSelectedEditor:this.hasSelection})}get hasSelection(){return 0!==this.#at.size}get isEnterHandled(){return 1===this.#at.size&&this.firstSelectedEditor.isEnterHandled}undo(){this.#L.undo();this.#xt({hasSomethingToUndo:this.#L.hasSomethingToUndo(),hasSomethingToRedo:!0,isEmpty:this.#Dt()})}redo(){this.#L.redo();this.#xt({hasSomethingToUndo:!0,hasSomethingToRedo:this.#L.hasSomethingToRedo(),isEmpty:this.#Dt()})}addCommands(t){this.#L.add(t);this.#xt({hasSomethingToUndo:!0,hasSomethingToRedo:!1,isEmpty:this.#Dt()})}#Dt(){if(0===this.#P.size)return!0;if(1===this.#P.size)for(const t of this.#P.values())return t.isEmpty();return!1}delete(){this.commitOrRemove();if(!this.hasSelection)return;const t=[...this.#at];this.addCommands({cmd:()=>{for(const e of t)e.remove()},undo:()=>{for(const e of t)this.#kt(e)},mustExec:!0})}commitOrRemove(){this.#k?.commitOrRemove()}hasSomethingToControl(){return this.#k||this.hasSelection}#Pt(t){for(const t of this.#at)t.unselect();this.#at.clear();for(const e of t)if(!e.isEmpty()){this.#at.add(e);e.select()}this.#xt({hasSelectedEditor:this.hasSelection})}selectAll(){for(const t of this.#at)t.commit();this.#Pt(this.#P.values())}unselectAll(){if(this.#k){this.#k.commitOrRemove();if(this.#nt!==g.NONE)return}if(this.hasSelection){for(const t of this.#at)t.unselect();this.#at.clear();this.#xt({hasSelectedEditor:!1})}}translateSelectedEditors(t,e,i=!1){i||this.commitOrRemove();if(!this.hasSelection)return;this.#dt[0]+=t;this.#dt[1]+=e;const[s,n]=this.#dt,a=[...this.#at];this.#ct&&clearTimeout(this.#ct);this.#ct=setTimeout((()=>{this.#ct=null;this.#dt[0]=this.#dt[1]=0;this.addCommands({cmd:()=>{for(const t of a)this.#P.has(t.id)&&t.translateInPage(s,n)},undo:()=>{for(const t of a)this.#P.has(t.id)&&t.translateInPage(-s,-n)},mustExec:!1})}),1e3);for(const i of a)i.translateInPage(t,e)}setUpDragSession(){if(this.hasSelection){this.disableUserSelect(!0);this.#H=new Map;for(const t of this.#at)this.#H.set(t,{savedX:t.x,savedY:t.y,savedPageIndex:t.pageIndex,newX:0,newY:0,newPageIndex:-1})}}endDragSession(){if(!this.#H)return!1;this.disableUserSelect(!1);const t=this.#H;this.#H=null;let e=!1;for(const[{x:i,y:s,pageIndex:n},a]of t){a.newX=i;a.newY=s;a.newPageIndex=n;e||=i!==a.savedX||s!==a.savedY||n!==a.savedPageIndex}if(!e)return!1;const move=(t,e,i,s)=>{if(this.#P.has(t.id)){const n=this.#F.get(s);if(n)t._setParentAndPosition(n,e,i);else{t.pageIndex=s;t.x=e;t.y=i}}};this.addCommands({cmd:()=>{for(const[e,{newX:i,newY:s,newPageIndex:n}]of t)move(e,i,s,n)},undo:()=>{for(const[e,{savedX:i,savedY:s,savedPageIndex:n}]of t)move(e,i,s,n)},mustExec:!0});return!0}dragSelectedEditors(t,e){if(this.#H)for(const i of this.#H.keys())i.drag(t,e)}rebuild(t){if(null===t.parent){const e=this.getLayer(t.pageIndex);if(e){e.changeParent(t);e.addOrRebuild(t)}else{this.addEditor(t);this.addToAnnotationStorage(t);t.rebuild()}}else t.parent.addOrRebuild(t)}get isEditorHandlingKeyboard(){return this.getActive()?.shouldGetKeyboardEvents()||1===this.#at.size&&this.firstSelectedEditor.shouldGetKeyboardEvents()}isActive(t){return this.#k===t}getActive(){return this.#k}getMode(){return this.#nt}get imageManager(){return shadow(this,"imageManager",new ImageManager)}getSelectionBoxes(t){if(!t)return null;const e=document.getSelection();for(let i=0,s=e.rangeCount;i({x:(e-s)/a,y:1-(t+r-i)/n,width:o/a,height:r/n});break;case"180":r=(t,e,r,o)=>({x:1-(t+r-i)/n,y:1-(e+o-s)/a,width:r/n,height:o/a});break;case"270":r=(t,e,r,o)=>({x:1-(e+o-s)/a,y:(t-i)/n,width:o/a,height:r/n});break;default:r=(t,e,r,o)=>({x:(t-i)/n,y:(e-s)/a,width:r/n,height:o/a})}const o=[];for(let t=0,i=e.rangeCount;tt.stopPropagation()),{signal:i});const onClick=t=>{t.preventDefault();this.#a._uiManager.editAltText(this.#a);this.#Gt&&this.#a._reportTelemetry({action:"pdfjs.image.alt_text.image_status_label_clicked",data:{label:this.#Vt}})};t.addEventListener("click",onClick,{capture:!0,signal:i});t.addEventListener("keydown",(e=>{if(e.target===t&&"Enter"===e.key){this.#zt=!0;onClick(e)}}),{signal:i});await this.#qt();return t}get#Vt(){return(this.#o?"added":null===this.#o&&this.guessedText&&"review")||"missing"}finish(){if(this.#Ot){this.#Ot.focus({focusVisible:this.#zt});this.#zt=!1}}isEmpty(){return this.#Gt?null===this.#o:!this.#o&&!this.#Nt}hasData(){return this.#Gt?null!==this.#o||!!this.#jt:this.isEmpty()}get guessedText(){return this.#jt}async setGuessedText(t){if(null===this.#o){this.#jt=t;this.#Wt=await AltText._l10nPromise.get("pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer")({generatedAltText:t});this.#qt()}}toggleAltTextBadge(t=!1){if(this.#Gt&&!this.#o){if(!this.#Ut){const t=this.#Ut=document.createElement("div");t.className="noAltTextBadge";this.#a.div.append(t)}this.#Ut.classList.toggle("hidden",!t)}else{this.#Ut?.remove();this.#Ut=null}}serialize(t){let e=this.#o;t||this.#jt!==e||(e=this.#Wt);return{altText:e,decorative:this.#Nt,guessedText:this.#jt,textWithDisclaimer:this.#Wt}}get data(){return{altText:this.#o,decorative:this.#Nt}}set data({altText:t,decorative:e,guessedText:i,textWithDisclaimer:s,cancel:n=!1}){if(i){this.#jt=i;this.#Wt=s}if(this.#o!==t||this.#Nt!==e){if(!n){this.#o=t;this.#Nt=e}this.#qt()}}toggle(t=!1){if(this.#Ot){if(!t&&this.#Ht){clearTimeout(this.#Ht);this.#Ht=null}this.#Ot.disabled=!t}}shown(){this.#a._reportTelemetry({action:"pdfjs.image.alt_text.image_status_label_displayed",data:{label:this.#Vt}})}destroy(){this.#Ot?.remove();this.#Ot=null;this.#Bt=null;this.#Ut?.remove();this.#Ut=null}async#qt(){const t=this.#Ot;if(!t)return;if(this.#Gt){t.classList.toggle("done",!!this.#o);AltText._l10nPromise.get(AltText.#$t[this.#Vt]).then((e=>{t.setAttribute("aria-label",e);for(const i of t.childNodes)if(i.nodeType===Node.TEXT_NODE){i.textContent=e;break}}));if(!this.#o){this.#Bt?.remove();return}}else{if(!this.#o&&!this.#Nt){t.classList.remove("done");this.#Bt?.remove();return}t.classList.add("done");AltText._l10nPromise.get("pdfjs-editor-alt-text-edit-button-label").then((e=>{t.setAttribute("aria-label",e)}))}let e=this.#Bt;if(!e){this.#Bt=e=document.createElement("span");e.className="tooltip";e.setAttribute("role","tooltip");e.id=`alt-text-tooltip-${this.#a.id}`;const i=100,s=this.#a._uiManager._signal;s.addEventListener("abort",(()=>{clearTimeout(this.#Ht);this.#Ht=null}),{once:!0});t.addEventListener("mouseenter",(()=>{this.#Ht=setTimeout((()=>{this.#Ht=null;this.#Bt.classList.add("show");this.#a._reportTelemetry({action:"alt_text_tooltip"})}),i)}),{signal:s});t.addEventListener("mouseleave",(()=>{if(this.#Ht){clearTimeout(this.#Ht);this.#Ht=null}this.#Bt?.classList.remove("show")}),{signal:s})}e.innerText=this.#Nt?await AltText._l10nPromise.get("pdfjs-editor-alt-text-decorative-tooltip"):this.#o;e.parentNode||t.append(e);const i=this.#a.getImageForAltText();i?.setAttribute("aria-describedby",e.id)}}class AnnotationEditor{#Xt=null;#Kt=null;#o=null;#Yt=!1;#Qt=!1;#Jt=null;#Zt=null;#te=null;#ee="";#ie=!1;#se=null;#ne=!1;#ae=!1;#re=!1;#oe=null;#le=0;#he=0;#de=null;_editToolbar=null;_initialOptions=Object.create(null);_initialData=null;_isVisible=!0;_uiManager=null;_focusEventsAllowed=!0;static _l10nPromise=null;static _l10nResizer=null;#ce=!1;#ue=AnnotationEditor._zIndex++;static _borderLineWidth=-1;static _colorManager=new ColorManager;static _zIndex=1;static _telemetryTimeout=1e3;static get _resizerKeyboardManager(){const t=AnnotationEditor.prototype._resizeWithKeyboard,e=AnnotationEditorUIManager.TRANSLATE_SMALL,i=AnnotationEditorUIManager.TRANSLATE_BIG;return shadow(this,"_resizerKeyboardManager",new KeyboardManager([[["ArrowLeft","mac+ArrowLeft"],t,{args:[-e,0]}],[["ctrl+ArrowLeft","mac+shift+ArrowLeft"],t,{args:[-i,0]}],[["ArrowRight","mac+ArrowRight"],t,{args:[e,0]}],[["ctrl+ArrowRight","mac+shift+ArrowRight"],t,{args:[i,0]}],[["ArrowUp","mac+ArrowUp"],t,{args:[0,-e]}],[["ctrl+ArrowUp","mac+shift+ArrowUp"],t,{args:[0,-i]}],[["ArrowDown","mac+ArrowDown"],t,{args:[0,e]}],[["ctrl+ArrowDown","mac+shift+ArrowDown"],t,{args:[0,i]}],[["Escape","mac+Escape"],AnnotationEditor.prototype._stopResizingWithKeyboard]]))}constructor(t){this.parent=t.parent;this.id=t.id;this.width=this.height=null;this.pageIndex=t.parent.pageIndex;this.name=t.name;this.div=null;this._uiManager=t.uiManager;this.annotationElementId=null;this._willKeepAspectRatio=!1;this._initialOptions.isCentered=t.isCentered;this._structTreeParentId=null;const{rotation:e,rawDims:{pageWidth:i,pageHeight:s,pageX:n,pageY:a}}=this.parent.viewport;this.rotation=e;this.pageRotation=(360+e-this._uiManager.viewParameters.rotation)%360;this.pageDimensions=[i,s];this.pageTranslation=[n,a];const[r,o]=this.parentDimensions;this.x=t.x/r;this.y=t.y/o;this.isAttachedToDOM=!1;this.deleted=!1}get editorType(){return Object.getPrototypeOf(this).constructor._type}static get _defaultLineColor(){return shadow(this,"_defaultLineColor",this._colorManager.getHexCode("CanvasText"))}static deleteAnnotationElement(t){const e=new FakeEditor({id:t.parent.getNextId(),parent:t.parent,uiManager:t._uiManager});e.annotationElementId=t.annotationElementId;e.deleted=!0;e._uiManager.addToAnnotationStorage(e)}static initialize(t,e,i){AnnotationEditor._l10nResizer||=Object.freeze({topLeft:"pdfjs-editor-resizer-top-left",topMiddle:"pdfjs-editor-resizer-top-middle",topRight:"pdfjs-editor-resizer-top-right",middleRight:"pdfjs-editor-resizer-middle-right",bottomRight:"pdfjs-editor-resizer-bottom-right",bottomMiddle:"pdfjs-editor-resizer-bottom-middle",bottomLeft:"pdfjs-editor-resizer-bottom-left",middleLeft:"pdfjs-editor-resizer-middle-left"});AnnotationEditor._l10nPromise||=new Map([...["pdfjs-editor-alt-text-button-label","pdfjs-editor-alt-text-edit-button-label","pdfjs-editor-alt-text-decorative-tooltip","pdfjs-editor-new-alt-text-added-button-label","pdfjs-editor-new-alt-text-missing-button-label","pdfjs-editor-new-alt-text-to-review-button-label"].map((e=>[e,t.get(e)])),...["pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer"].map((e=>[e,t.get.bind(t,e)]))]);if(i?.strings)for(const e of i.strings)AnnotationEditor._l10nPromise.set(e,t.get(e));if(-1!==AnnotationEditor._borderLineWidth)return;const s=getComputedStyle(document.documentElement);AnnotationEditor._borderLineWidth=parseFloat(s.getPropertyValue("--outline-width"))||0}static updateDefaultParams(t,e){}static get defaultPropertiesToUpdate(){return[]}static isHandlingMimeForPasting(t){return!1}static paste(t,e){unreachable("Not implemented")}get propertiesToUpdate(){return[]}get _isDraggable(){return this.#ce}set _isDraggable(t){this.#ce=t;this.div?.classList.toggle("draggable",t)}get isEnterHandled(){return!0}center(){const[t,e]=this.pageDimensions;switch(this.parentRotation){case 90:this.x-=this.height*e/(2*t);this.y+=this.width*t/(2*e);break;case 180:this.x+=this.width/2;this.y+=this.height/2;break;case 270:this.x+=this.height*e/(2*t);this.y-=this.width*t/(2*e);break;default:this.x-=this.width/2;this.y-=this.height/2}this.fixAndSetPosition()}addCommands(t){this._uiManager.addCommands(t)}get currentLayer(){return this._uiManager.currentLayer}setInBackground(){this.div.style.zIndex=0}setInForeground(){this.div.style.zIndex=this.#ue}setParent(t){if(null!==t){this.pageIndex=t.pageIndex;this.pageDimensions=t.pageDimensions}else this.#pe();this.parent=t}focusin(t){this._focusEventsAllowed&&(this.#ie?this.#ie=!1:this.parent.setSelected(this))}focusout(t){if(!this._focusEventsAllowed)return;if(!this.isAttachedToDOM)return;const e=t.relatedTarget;if(!e?.closest(`#${this.id}`)){t.preventDefault();this.parent?.isMultipleSelection||this.commitOrRemove()}}commitOrRemove(){this.isEmpty()?this.remove():this.commit()}commit(){this.addToAnnotationStorage()}addToAnnotationStorage(){this._uiManager.addToAnnotationStorage(this)}setAt(t,e,i,s){const[n,a]=this.parentDimensions;[i,s]=this.screenToPageTranslation(i,s);this.x=(t+i)/n;this.y=(e+s)/a;this.fixAndSetPosition()}#ge([t,e],i,s){[i,s]=this.screenToPageTranslation(i,s);this.x+=i/t;this.y+=s/e;this.fixAndSetPosition()}translate(t,e){this.#ge(this.parentDimensions,t,e)}translateInPage(t,e){this.#se||=[this.x,this.y];this.#ge(this.pageDimensions,t,e);this.div.scrollIntoView({block:"nearest"})}drag(t,e){this.#se||=[this.x,this.y];const[i,s]=this.parentDimensions;this.x+=t/i;this.y+=e/s;if(this.parent&&(this.x<0||this.x>1||this.y<0||this.y>1)){const{x:t,y:e}=this.div.getBoundingClientRect();if(this.parent.findNewParent(this,t,e)){this.x-=Math.floor(this.x);this.y-=Math.floor(this.y)}}let{x:n,y:a}=this;const[r,o]=this.getBaseTranslation();n+=r;a+=o;this.div.style.left=`${(100*n).toFixed(2)}%`;this.div.style.top=`${(100*a).toFixed(2)}%`;this.div.scrollIntoView({block:"nearest"})}get _hasBeenMoved(){return!!this.#se&&(this.#se[0]!==this.x||this.#se[1]!==this.y)}getBaseTranslation(){const[t,e]=this.parentDimensions,{_borderLineWidth:i}=AnnotationEditor,s=i/t,n=i/e;switch(this.rotation){case 90:return[-s,n];case 180:return[s,n];case 270:return[s,-n];default:return[-s,-n]}}get _mustFixPosition(){return!0}fixAndSetPosition(t=this.rotation){const[e,i]=this.pageDimensions;let{x:s,y:n,width:a,height:r}=this;a*=e;r*=i;s*=e;n*=i;if(this._mustFixPosition)switch(t){case 0:s=Math.max(0,Math.min(e-a,s));n=Math.max(0,Math.min(i-r,n));break;case 90:s=Math.max(0,Math.min(e-r,s));n=Math.min(i,Math.max(a,n));break;case 180:s=Math.min(e,Math.max(a,s));n=Math.min(i,Math.max(r,n));break;case 270:s=Math.min(e,Math.max(r,s));n=Math.max(0,Math.min(i-a,n))}this.x=s/=e;this.y=n/=i;const[o,l]=this.getBaseTranslation();s+=o;n+=l;const{style:h}=this.div;h.left=`${(100*s).toFixed(2)}%`;h.top=`${(100*n).toFixed(2)}%`;this.moveInDOM()}static#me(t,e,i){switch(i){case 90:return[e,-t];case 180:return[-t,-e];case 270:return[-e,t];default:return[t,e]}}screenToPageTranslation(t,e){return AnnotationEditor.#me(t,e,this.parentRotation)}pageTranslationToScreen(t,e){return AnnotationEditor.#me(t,e,360-this.parentRotation)}#fe(t){switch(t){case 90:{const[t,e]=this.pageDimensions;return[0,-t/e,e/t,0]}case 180:return[-1,0,0,-1];case 270:{const[t,e]=this.pageDimensions;return[0,t/e,-e/t,0]}default:return[1,0,0,1]}}get parentScale(){return this._uiManager.viewParameters.realScale}get parentRotation(){return(this._uiManager.viewParameters.rotation+this.pageRotation)%360}get parentDimensions(){const{parentScale:t,pageDimensions:[e,i]}=this;return[e*t,i*t]}setDims(t,e){const[i,s]=this.parentDimensions;this.div.style.width=`${(100*t/i).toFixed(2)}%`;this.#Qt||(this.div.style.height=`${(100*e/s).toFixed(2)}%`)}fixDims(){const{style:t}=this.div,{height:e,width:i}=t,s=i.endsWith("%"),n=!this.#Qt&&e.endsWith("%");if(s&&n)return;const[a,r]=this.parentDimensions;s||(t.width=`${(100*parseFloat(i)/a).toFixed(2)}%`);this.#Qt||n||(t.height=`${(100*parseFloat(e)/r).toFixed(2)}%`)}getInitialTranslation(){return[0,0]}#be(){if(this.#Jt)return;this.#Jt=document.createElement("div");this.#Jt.classList.add("resizers");const t=this._willKeepAspectRatio?["topLeft","topRight","bottomRight","bottomLeft"]:["topLeft","topMiddle","topRight","middleRight","bottomRight","bottomMiddle","bottomLeft","middleLeft"],e=this._uiManager._signal;for(const i of t){const t=document.createElement("div");this.#Jt.append(t);t.classList.add("resizer",i);t.setAttribute("data-resizer-name",i);t.addEventListener("pointerdown",this.#Ae.bind(this,i),{signal:e});t.addEventListener("contextmenu",noContextMenu,{signal:e});t.tabIndex=-1}this.div.prepend(this.#Jt)}#Ae(t,e){e.preventDefault();const{isMac:i}=util_FeatureTest.platform;if(0!==e.button||e.ctrlKey&&i)return;this.#o?.toggle(!1);const s=this._isDraggable;this._isDraggable=!1;const n=new AbortController,a=this._uiManager.combinedSignal(n);this.parent.togglePointerEvents(!1);window.addEventListener("pointermove",this.#ve.bind(this,t),{passive:!0,capture:!0,signal:a});window.addEventListener("contextmenu",noContextMenu,{signal:a});const r=this.x,o=this.y,l=this.width,h=this.height,d=this.parent.div.style.cursor,c=this.div.style.cursor;this.div.style.cursor=this.parent.div.style.cursor=window.getComputedStyle(e.target).cursor;const pointerUpCallback=()=>{n.abort();this.parent.togglePointerEvents(!0);this.#o?.toggle(!0);this._isDraggable=s;this.parent.div.style.cursor=d;this.div.style.cursor=c;this.#ye(r,o,l,h)};window.addEventListener("pointerup",pointerUpCallback,{signal:a});window.addEventListener("blur",pointerUpCallback,{signal:a})}#ye(t,e,i,s){const n=this.x,a=this.y,r=this.width,o=this.height;n===t&&a===e&&r===i&&o===s||this.addCommands({cmd:()=>{this.width=r;this.height=o;this.x=n;this.y=a;const[t,e]=this.parentDimensions;this.setDims(t*r,e*o);this.fixAndSetPosition()},undo:()=>{this.width=i;this.height=s;this.x=t;this.y=e;const[n,a]=this.parentDimensions;this.setDims(n*i,a*s);this.fixAndSetPosition()},mustExec:!0})}#ve(t,e){const[i,s]=this.parentDimensions,n=this.x,a=this.y,r=this.width,o=this.height,l=AnnotationEditor.MIN_SIZE/i,h=AnnotationEditor.MIN_SIZE/s,round=t=>Math.round(1e4*t)/1e4,d=this.#fe(this.rotation),transf=(t,e)=>[d[0]*t+d[2]*e,d[1]*t+d[3]*e],c=this.#fe(360-this.rotation);let u,p,g=!1,m=!1;switch(t){case"topLeft":g=!0;u=(t,e)=>[0,0];p=(t,e)=>[t,e];break;case"topMiddle":u=(t,e)=>[t/2,0];p=(t,e)=>[t/2,e];break;case"topRight":g=!0;u=(t,e)=>[t,0];p=(t,e)=>[0,e];break;case"middleRight":m=!0;u=(t,e)=>[t,e/2];p=(t,e)=>[0,e/2];break;case"bottomRight":g=!0;u=(t,e)=>[t,e];p=(t,e)=>[0,0];break;case"bottomMiddle":u=(t,e)=>[t/2,e];p=(t,e)=>[t/2,0];break;case"bottomLeft":g=!0;u=(t,e)=>[0,e];p=(t,e)=>[t,0];break;case"middleLeft":m=!0;u=(t,e)=>[0,e/2];p=(t,e)=>[t,e/2]}const f=u(r,o),b=p(r,o);let A=transf(...b);const v=round(n+A[0]),y=round(a+A[1]);let w=1,x=1,[_,E]=this.screenToPageTranslation(e.movementX,e.movementY);[_,E]=(C=_/i,S=E/s,[c[0]*C+c[2]*S,c[1]*C+c[3]*S]);var C,S;if(g){const t=Math.hypot(r,o);w=x=Math.max(Math.min(Math.hypot(b[0]-f[0]-_,b[1]-f[1]-E)/t,1/r,1/o),l/r,h/o)}else m?w=Math.max(l,Math.min(1,Math.abs(b[0]-f[0]-_)))/r:x=Math.max(h,Math.min(1,Math.abs(b[1]-f[1]-E)))/o;const T=round(r*w),M=round(o*x);A=transf(...p(T,M));const k=v-A[0],P=y-A[1];this.width=T;this.height=M;this.x=k;this.y=P;this.setDims(i*T,s*M);this.fixAndSetPosition()}altTextFinish(){this.#o?.finish()}async addEditToolbar(){if(this._editToolbar||this.#ae)return this._editToolbar;this._editToolbar=new EditorToolbar(this);this.div.append(this._editToolbar.render());this.#o&&await this._editToolbar.addAltText(this.#o);return this._editToolbar}removeEditToolbar(){if(this._editToolbar){this._editToolbar.remove();this._editToolbar=null;this.#o?.destroy()}}addContainer(t){const e=this._editToolbar?.div;e?e.before(t):this.div.append(t)}getClientDimensions(){return this.div.getBoundingClientRect()}async addAltTextButton(){if(!this.#o){AltText.initialize(AnnotationEditor._l10nPromise);this.#o=new AltText(this);if(this.#Xt){this.#o.data=this.#Xt;this.#Xt=null}await this.addEditToolbar()}}get altTextData(){return this.#o?.data}set altTextData(t){this.#o&&(this.#o.data=t)}get guessedAltText(){return this.#o?.guessedText}async setGuessedAltText(t){await(this.#o?.setGuessedText(t))}serializeAltText(t){return this.#o?.serialize(t)}hasAltText(){return!!this.#o&&!this.#o.isEmpty()}hasAltTextData(){return this.#o?.hasData()??!1}render(){this.div=document.createElement("div");this.div.setAttribute("data-editor-rotation",(360-this.rotation)%360);this.div.className=this.name;this.div.setAttribute("id",this.id);this.div.tabIndex=this.#Yt?-1:0;this._isVisible||this.div.classList.add("hidden");this.setInForeground();this.#we();const[t,e]=this.parentDimensions;if(this.parentRotation%180!=0){this.div.style.maxWidth=`${(100*e/t).toFixed(2)}%`;this.div.style.maxHeight=`${(100*t/e).toFixed(2)}%`}const[i,s]=this.getInitialTranslation();this.translate(i,s);bindEvents(this,this.div,["pointerdown"]);return this.div}pointerdown(t){const{isMac:e}=util_FeatureTest.platform;if(0!==t.button||t.ctrlKey&&e)t.preventDefault();else{this.#ie=!0;this._isDraggable?this.#xe(t):this.#_e(t)}}#_e(t){const{isMac:e}=util_FeatureTest.platform;t.ctrlKey&&!e||t.shiftKey||t.metaKey&&e?this.parent.toggleSelected(this):this.parent.setSelected(this)}#xe(t){const e=this._uiManager.isSelected(this);this._uiManager.setUpDragSession();const i=new AbortController,s=this._uiManager.combinedSignal(i);if(e){this.div.classList.add("moving");this.#le=t.clientX;this.#he=t.clientY;const pointerMoveCallback=t=>{const{clientX:e,clientY:i}=t,[s,n]=this.screenToPageTranslation(e-this.#le,i-this.#he);this.#le=e;this.#he=i;this._uiManager.dragSelectedEditors(s,n)};window.addEventListener("pointermove",pointerMoveCallback,{passive:!0,capture:!0,signal:s})}const pointerUpCallback=()=>{i.abort();e&&this.div.classList.remove("moving");this.#ie=!1;this._uiManager.endDragSession()||this.#_e(t)};window.addEventListener("pointerup",pointerUpCallback,{signal:s});window.addEventListener("blur",pointerUpCallback,{signal:s})}moveInDOM(){this.#oe&&clearTimeout(this.#oe);this.#oe=setTimeout((()=>{this.#oe=null;this.parent?.moveEditorInDOM(this)}),0)}_setParentAndPosition(t,e,i){t.changeParent(this);this.x=e;this.y=i;this.fixAndSetPosition()}getRect(t,e,i=this.rotation){const s=this.parentScale,[n,a]=this.pageDimensions,[r,o]=this.pageTranslation,l=t/s,h=e/s,d=this.x*n,c=this.y*a,u=this.width*n,p=this.height*a;switch(i){case 0:return[d+l+r,a-c-h-p+o,d+l+u+r,a-c-h+o];case 90:return[d+h+r,a-c+l+o,d+h+p+r,a-c+l+u+o];case 180:return[d-l-u+r,a-c+h+o,d-l+r,a-c+h+p+o];case 270:return[d-h-p+r,a-c-l-u+o,d-h+r,a-c-l+o];default:throw new Error("Invalid rotation")}}getRectInCurrentCoords(t,e){const[i,s,n,a]=t,r=n-i,o=a-s;switch(this.rotation){case 0:return[i,e-a,r,o];case 90:return[i,e-s,o,r];case 180:return[n,e-s,r,o];case 270:return[n,e-a,o,r];default:throw new Error("Invalid rotation")}}onceAdded(){}isEmpty(){return!1}enableEditMode(){this.#ae=!0}disableEditMode(){this.#ae=!1}isInEditMode(){return this.#ae}shouldGetKeyboardEvents(){return this.#re}needsToBeRebuilt(){return this.div&&!this.isAttachedToDOM}#we(){if(this.#te||!this.div)return;this.#te=new AbortController;const t=this._uiManager.combinedSignal(this.#te);this.div.addEventListener("focusin",this.focusin.bind(this),{signal:t});this.div.addEventListener("focusout",this.focusout.bind(this),{signal:t})}rebuild(){this.#we()}rotate(t){}serializeDeleted(){return{id:this.annotationElementId,deleted:!0,pageIndex:this.pageIndex,popupRef:this._initialData?.popupRef||""}}serialize(t=!1,e=null){unreachable("An editor must be serializable")}static async deserialize(t,e,i){const s=new this.prototype.constructor({parent:e,id:e.getNextId(),uiManager:i});s.rotation=t.rotation;s.#Xt=t.accessibilityData;const[n,a]=s.pageDimensions,[r,o,l,h]=s.getRectInCurrentCoords(t.rect,a);s.x=r/n;s.y=o/a;s.width=l/n;s.height=h/a;return s}get hasBeenModified(){return!!this.annotationElementId&&(this.deleted||null!==this.serialize())}remove(){this.#te?.abort();this.#te=null;this.isEmpty()||this.commit();this.parent?this.parent.remove(this):this._uiManager.removeEditor(this);if(this.#oe){clearTimeout(this.#oe);this.#oe=null}this.#pe();this.removeEditToolbar();if(this.#de){for(const t of this.#de.values())clearTimeout(t);this.#de=null}this.parent=null}get isResizable(){return!1}makeResizable(){if(this.isResizable){this.#be();this.#Jt.classList.remove("hidden");bindEvents(this,this.div,["keydown"])}}get toolbarPosition(){return null}keydown(t){if(!this.isResizable||t.target!==this.div||"Enter"!==t.key)return;this._uiManager.setSelected(this);this.#Zt={savedX:this.x,savedY:this.y,savedWidth:this.width,savedHeight:this.height};const e=this.#Jt.children;if(!this.#Kt){this.#Kt=Array.from(e);const t=this.#Ee.bind(this),i=this.#Ce.bind(this),s=this._uiManager._signal;for(const e of this.#Kt){const n=e.getAttribute("data-resizer-name");e.setAttribute("role","spinbutton");e.addEventListener("keydown",t,{signal:s});e.addEventListener("blur",i,{signal:s});e.addEventListener("focus",this.#Se.bind(this,n),{signal:s});e.setAttribute("data-l10n-id",AnnotationEditor._l10nResizer[n])}}const i=this.#Kt[0];let s=0;for(const t of e){if(t===i)break;s++}const n=(360-this.rotation+this.parentRotation)%360/90*(this.#Kt.length/4);if(n!==s){if(ns)for(let t=0;t{this.div?.classList.contains("selectedEditor")&&this._editToolbar?.show()}))}unselect(){this.#Jt?.classList.add("hidden");this.div?.classList.remove("selectedEditor");this.div?.contains(document.activeElement)&&this._uiManager.currentLayer.div.focus({preventScroll:!0});this._editToolbar?.hide();this.#o?.toggleAltTextBadge(!0)}updateParams(t,e){}disableEditing(){}enableEditing(){}enterInEditMode(){}getImageForAltText(){return null}get contentDiv(){return this.div}get isEditing(){return this.#ne}set isEditing(t){this.#ne=t;if(this.parent)if(t){this.parent.setSelected(this);this.parent.setActiveEditor(this)}else this.parent.setActiveEditor(null)}setAspectRatio(t,e){this.#Qt=!0;const i=t/e,{style:s}=this.div;s.aspectRatio=i;s.height="auto"}static get MIN_SIZE(){return 16}static canCreateNewEmptyEditor(){return!0}get telemetryInitialData(){return{action:"added"}}get telemetryFinalData(){return null}_reportTelemetry(t,e=!1){if(e){this.#de||=new Map;const{action:e}=t;let i=this.#de.get(e);i&&clearTimeout(i);i=setTimeout((()=>{this._reportTelemetry(t);this.#de.delete(e);0===this.#de.size&&(this.#de=null)}),AnnotationEditor._telemetryTimeout);this.#de.set(e,i)}else{t.type||=this.editorType;this._uiManager._eventBus.dispatch("reporttelemetry",{source:this,details:{type:"editing",data:t}})}}show(t=this._isVisible){this.div.classList.toggle("hidden",!t);this._isVisible=t}enable(){this.div&&(this.div.tabIndex=0);this.#Yt=!1}disable(){this.div&&(this.div.tabIndex=-1);this.#Yt=!0}renderAnnotationElement(t){let e=t.container.querySelector(".annotationContent");if(e){if("CANVAS"===e.nodeName){const t=e;e=document.createElement("div");e.classList.add("annotationContent",this.editorType);t.before(e)}}else{e=document.createElement("div");e.classList.add("annotationContent",this.editorType);t.container.prepend(e)}return e}resetAnnotationElement(t){const{firstChild:e}=t.container;"DIV"===e?.nodeName&&e.classList.contains("annotationContent")&&e.remove()}}class FakeEditor extends AnnotationEditor{constructor(t){super(t);this.annotationElementId=t.annotationElementId;this.deleted=!0}serialize(){return this.serializeDeleted()}}const gt=3285377520,mt=4294901760,ft=65535;class MurmurHash3_64{constructor(t){this.h1=t?4294967295&t:gt;this.h2=t?4294967295&t:gt}update(t){let e,i;if("string"==typeof t){e=new Uint8Array(2*t.length);i=0;for(let s=0,n=t.length;s>>8;e[i++]=255&n}}}else{if(!ArrayBuffer.isView(t))throw new Error("Invalid data format, must be a string or TypedArray.");e=t.slice();i=e.byteLength}const s=i>>2,n=i-4*s,a=new Uint32Array(e.buffer,0,s);let r=0,o=0,l=this.h1,h=this.h2;const d=3432918353,c=461845907,u=11601,p=13715;for(let t=0;t>>17;r=r*c&mt|r*p&ft;l^=r;l=l<<13|l>>>19;l=5*l+3864292196}else{o=a[t];o=o*d&mt|o*u&ft;o=o<<15|o>>>17;o=o*c&mt|o*p&ft;h^=o;h=h<<13|h>>>19;h=5*h+3864292196}r=0;switch(n){case 3:r^=e[4*s+2]<<16;case 2:r^=e[4*s+1]<<8;case 1:r^=e[4*s];r=r*d&mt|r*u&ft;r=r<<15|r>>>17;r=r*c&mt|r*p&ft;1&s?l^=r:h^=r}this.h1=l;this.h2=h}hexdigest(){let t=this.h1,e=this.h2;t^=e>>>1;t=3981806797*t&mt|36045*t&ft;e=4283543511*e&mt|(2950163797*(e<<16|t>>>16)&mt)>>>16;t^=e>>>1;t=444984403*t&mt|60499*t&ft;e=3301882366*e&mt|(3120437893*(e<<16|t>>>16)&mt)>>>16;t^=e>>>1;return(t>>>0).toString(16).padStart(8,"0")+(e>>>0).toString(16).padStart(8,"0")}}const bt=Object.freeze({map:null,hash:"",transfer:void 0});class AnnotationStorage{#Me=!1;#ke=null;#Pe=new Map;constructor(){this.onSetModified=null;this.onResetModified=null;this.onAnnotationEditor=null}getValue(t,e){const i=this.#Pe.get(t);return void 0===i?e:Object.assign(e,i)}getRawValue(t){return this.#Pe.get(t)}remove(t){this.#Pe.delete(t);0===this.#Pe.size&&this.resetModified();if("function"==typeof this.onAnnotationEditor){for(const t of this.#Pe.values())if(t instanceof AnnotationEditor)return;this.onAnnotationEditor(null)}}setValue(t,e){const i=this.#Pe.get(t);let s=!1;if(void 0!==i){for(const[t,n]of Object.entries(e))if(i[t]!==n){s=!0;i[t]=n}}else{s=!0;this.#Pe.set(t,e)}s&&this.#Fe();e instanceof AnnotationEditor&&"function"==typeof this.onAnnotationEditor&&this.onAnnotationEditor(e.constructor._type)}has(t){return this.#Pe.has(t)}getAll(){return this.#Pe.size>0?objectFromMap(this.#Pe):null}setAll(t){for(const[e,i]of Object.entries(t))this.setValue(e,i)}get size(){return this.#Pe.size}#Fe(){if(!this.#Me){this.#Me=!0;"function"==typeof this.onSetModified&&this.onSetModified()}}resetModified(){if(this.#Me){this.#Me=!1;"function"==typeof this.onResetModified&&this.onResetModified()}}get print(){return new PrintAnnotationStorage(this)}get serializable(){if(0===this.#Pe.size)return bt;const t=new Map,e=new MurmurHash3_64,i=[],s=Object.create(null);let n=!1;for(const[i,a]of this.#Pe){const r=a instanceof AnnotationEditor?a.serialize(!1,s):a;if(r){t.set(i,r);e.update(`${i}:${JSON.stringify(r)}`);n||=!!r.bitmap}}if(n)for(const e of t.values())e.bitmap&&i.push(e.bitmap);return t.size>0?{map:t,hash:e.hexdigest(),transfer:i}:bt}get editorStats(){let t=null;const e=new Map;for(const i of this.#Pe.values()){if(!(i instanceof AnnotationEditor))continue;const s=i.telemetryFinalData;if(!s)continue;const{type:n}=s;e.has(n)||e.set(n,Object.getPrototypeOf(i).constructor);t||=Object.create(null);const a=t[n]||=new Map;for(const[t,e]of Object.entries(s)){if("type"===t)continue;let i=a.get(t);if(!i){i=new Map;a.set(t,i)}const s=i.get(e)??0;i.set(e,s+1)}}for(const[i,s]of e)t[i]=s.computeTelemetryFinalData(t[i]);return t}resetModifiedIds(){this.#ke=null}get modifiedIds(){if(this.#ke)return this.#ke;const t=[];for(const e of this.#Pe.values())e instanceof AnnotationEditor&&e.annotationElementId&&e.serialize()&&t.push(e.annotationElementId);return this.#ke={ids:new Set(t),hash:t.join(",")}}}class PrintAnnotationStorage extends AnnotationStorage{#De;constructor(t){super();const{map:e,hash:i,transfer:s}=t.serializable,n=structuredClone(e,s?{transfer:s}:null);this.#De={map:n,hash:i,transfer:s}}get print(){unreachable("Should not call PrintAnnotationStorage.print")}get serializable(){return this.#De}get modifiedIds(){return shadow(this,"modifiedIds",{ids:new Set,hash:""})}}class FontLoader{#Re=new Set;constructor({ownerDocument:t=globalThis.document,styleElement:e=null}){this._document=t;this.nativeFontFaces=new Set;this.styleElement=null;this.loadingRequests=[];this.loadTestFontId=0}addNativeFontFace(t){this.nativeFontFaces.add(t);this._document.fonts.add(t)}removeNativeFontFace(t){this.nativeFontFaces.delete(t);this._document.fonts.delete(t)}insertRule(t){if(!this.styleElement){this.styleElement=this._document.createElement("style");this._document.documentElement.getElementsByTagName("head")[0].append(this.styleElement)}const e=this.styleElement.sheet;e.insertRule(t,e.cssRules.length)}clear(){for(const t of this.nativeFontFaces)this._document.fonts.delete(t);this.nativeFontFaces.clear();this.#Re.clear();if(this.styleElement){this.styleElement.remove();this.styleElement=null}}async loadSystemFont({systemFontInfo:t,_inspectFont:e}){if(t&&!this.#Re.has(t.loadedName)){assert(!this.disableFontFace,"loadSystemFont shouldn't be called when `disableFontFace` is set.");if(this.isFontLoadingAPISupported){const{loadedName:i,src:s,style:n}=t,a=new FontFace(i,s,n);this.addNativeFontFace(a);try{await a.load();this.#Re.add(i);e?.(t)}catch{warn(`Cannot load system font: ${t.baseFontName}, installing it could help to improve PDF rendering.`);this.removeNativeFontFace(a)}}else unreachable("Not implemented: loadSystemFont without the Font Loading API.")}}async bind(t){if(t.attached||t.missingFile&&!t.systemFontInfo)return;t.attached=!0;if(t.systemFontInfo){await this.loadSystemFont(t);return}if(this.isFontLoadingAPISupported){const e=t.createNativeFontFace();if(e){this.addNativeFontFace(e);try{await e.loaded}catch(i){warn(`Failed to load font '${e.family}': '${i}'.`);t.disableFontFace=!0;throw i}}return}const e=t.createFontFaceRule();if(e){this.insertRule(e);if(this.isSyncFontLoadingSupported)return;await new Promise((e=>{const i=this._queueLoadingCallback(e);this._prepareFontLoadEvent(t,i)}))}}get isFontLoadingAPISupported(){return shadow(this,"isFontLoadingAPISupported",!!this._document?.fonts)}get isSyncFontLoadingSupported(){let t=!1;(e||"undefined"!=typeof navigator&&"string"==typeof navigator?.userAgent&&/Mozilla\/5.0.*?rv:\d+.*? Gecko/.test(navigator.userAgent))&&(t=!0);return shadow(this,"isSyncFontLoadingSupported",t)}_queueLoadingCallback(t){const{loadingRequests:e}=this,i={done:!1,complete:function completeRequest(){assert(!i.done,"completeRequest() cannot be called twice.");i.done=!0;for(;e.length>0&&e[0].done;){const t=e.shift();setTimeout(t.callback,0)}},callback:t};e.push(i);return i}get _loadTestFont(){return shadow(this,"_loadTestFont",atob("T1RUTwALAIAAAwAwQ0ZGIDHtZg4AAAOYAAAAgUZGVE1lkzZwAAAEHAAAABxHREVGABQAFQAABDgAAAAeT1MvMlYNYwkAAAEgAAAAYGNtYXABDQLUAAACNAAAAUJoZWFk/xVFDQAAALwAAAA2aGhlYQdkA+oAAAD0AAAAJGhtdHgD6AAAAAAEWAAAAAZtYXhwAAJQAAAAARgAAAAGbmFtZVjmdH4AAAGAAAAAsXBvc3T/hgAzAAADeAAAACAAAQAAAAEAALZRFsRfDzz1AAsD6AAAAADOBOTLAAAAAM4KHDwAAAAAA+gDIQAAAAgAAgAAAAAAAAABAAADIQAAAFoD6AAAAAAD6AABAAAAAAAAAAAAAAAAAAAAAQAAUAAAAgAAAAQD6AH0AAUAAAKKArwAAACMAooCvAAAAeAAMQECAAACAAYJAAAAAAAAAAAAAQAAAAAAAAAAAAAAAFBmRWQAwAAuAC4DIP84AFoDIQAAAAAAAQAAAAAAAAAAACAAIAABAAAADgCuAAEAAAAAAAAAAQAAAAEAAAAAAAEAAQAAAAEAAAAAAAIAAQAAAAEAAAAAAAMAAQAAAAEAAAAAAAQAAQAAAAEAAAAAAAUAAQAAAAEAAAAAAAYAAQAAAAMAAQQJAAAAAgABAAMAAQQJAAEAAgABAAMAAQQJAAIAAgABAAMAAQQJAAMAAgABAAMAAQQJAAQAAgABAAMAAQQJAAUAAgABAAMAAQQJAAYAAgABWABYAAAAAAAAAwAAAAMAAAAcAAEAAAAAADwAAwABAAAAHAAEACAAAAAEAAQAAQAAAC7//wAAAC7////TAAEAAAAAAAABBgAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAD/gwAyAAAAAQAAAAAAAAAAAAAAAAAAAAABAAQEAAEBAQJYAAEBASH4DwD4GwHEAvgcA/gXBIwMAYuL+nz5tQXkD5j3CBLnEQACAQEBIVhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYAAABAQAADwACAQEEE/t3Dov6fAH6fAT+fPp8+nwHDosMCvm1Cvm1DAz6fBQAAAAAAAABAAAAAMmJbzEAAAAAzgTjFQAAAADOBOQpAAEAAAAAAAAADAAUAAQAAAABAAAAAgABAAAAAAAAAAAD6AAAAAAAAA=="))}_prepareFontLoadEvent(t,e){function int32(t,e){return t.charCodeAt(e)<<24|t.charCodeAt(e+1)<<16|t.charCodeAt(e+2)<<8|255&t.charCodeAt(e+3)}function spliceString(t,e,i,s){return t.substring(0,e)+s+t.substring(e+i)}let i,s;const n=this._document.createElement("canvas");n.width=1;n.height=1;const a=n.getContext("2d");let r=0;const o=`lt${Date.now()}${this.loadTestFontId++}`;let l=this._loadTestFont;l=spliceString(l,976,o.length,o);const h=1482184792;let d=int32(l,16);for(i=0,s=o.length-3;i>24&255,t>>16&255,t>>8&255,255&t)}(d));const c=`@font-face {font-family:"${o}";src:${`url(data:font/opentype;base64,${btoa(l)});`}}`;this.insertRule(c);const u=this._document.createElement("div");u.style.visibility="hidden";u.style.width=u.style.height="10px";u.style.position="absolute";u.style.top=u.style.left="0px";for(const e of[t.loadedName,o]){const t=this._document.createElement("span");t.textContent="Hi";t.style.fontFamily=e;u.append(t)}this._document.body.append(u);!function isFontReady(t,e){if(++r>30){warn("Load test font never loaded.");e();return}a.font="30px "+t;a.fillText(".",0,20);a.getImageData(0,0,1,1).data[3]>0?e():setTimeout(isFontReady.bind(null,t,e))}(o,(()=>{u.remove();e.complete()}))}}class FontFaceObject{constructor(t,{disableFontFace:e=!1,inspectFont:i=null}){this.compiledGlyphs=Object.create(null);for(const e in t)this[e]=t[e];this.disableFontFace=!0===e;this._inspectFont=i}createNativeFontFace(){if(!this.data||this.disableFontFace)return null;let t;if(this.cssFontInfo){const e={weight:this.cssFontInfo.fontWeight};this.cssFontInfo.italicAngle&&(e.style=`oblique ${this.cssFontInfo.italicAngle}deg`);t=new FontFace(this.cssFontInfo.fontFamily,this.data,e)}else t=new FontFace(this.loadedName,this.data,{});this._inspectFont?.(this);return t}createFontFaceRule(){if(!this.data||this.disableFontFace)return null;const t=bytesToString(this.data),e=`url(data:${this.mimetype};base64,${btoa(t)});`;let i;if(this.cssFontInfo){let t=`font-weight: ${this.cssFontInfo.fontWeight};`;this.cssFontInfo.italicAngle&&(t+=`font-style: oblique ${this.cssFontInfo.italicAngle}deg;`);i=`@font-face {font-family:"${this.cssFontInfo.fontFamily}";${t}src:${e}}`}else i=`@font-face {font-family:"${this.loadedName}";src:${e}}`;this._inspectFont?.(this,e);return i}getPathGenerator(t,e){if(void 0!==this.compiledGlyphs[e])return this.compiledGlyphs[e];let i;try{i=t.get(this.loadedName+"_path_"+e)}catch(t){warn(`getPathGenerator - ignoring character: "${t}".`)}if(!Array.isArray(i)||0===i.length)return this.compiledGlyphs[e]=function(t,e){};const s=[];for(let t=0,e=i.length;tt.bezierCurveTo(e,n,a,r,o,l)));t+=6}break;case nt:{const[e,n]=i.slice(t,t+2);s.push((t=>t.moveTo(e,n)));t+=2}break;case at:{const[e,n]=i.slice(t,t+2);s.push((t=>t.lineTo(e,n)));t+=2}break;case rt:{const[e,n,a,r]=i.slice(t,t+4);s.push((t=>t.quadraticCurveTo(e,n,a,r)));t+=4}break;case ot:s.push((t=>t.restore()));break;case lt:s.push((t=>t.save()));break;case ht:assert(2===s.length,"Scale command is only valid at the third position.");break;case dt:{const[e,n,a,r,o,l]=i.slice(t,t+6);s.push((t=>t.transform(e,n,a,r,o,l)));t+=6}break;case ct:{const[e,n]=i.slice(t,t+2);s.push((t=>t.translate(e,n)));t+=2}}return this.compiledGlyphs[e]=function glyphDrawer(t,e){s[0](t);s[1](t);t.scale(e,-e);for(let e=2,i=s.length;e{const t=await import("fs"),e=await import("http"),i=await import("https"),s=await import("url");return new Map(Object.entries({fs:t,http:e,https:i,url:s,canvas:undefined,path2d:undefined}))})().then((t=>{vt=t;At.resolve()}),(t=>{warn(`loadPackages: ${t}`);vt=new Map;At.resolve()}))}class NodePackages{static get promise(){return At.promise}static get(t){return vt?.get(t)}}const node_utils_fetchData=function(t){return NodePackages.get("fs").promises.readFile(t).then((t=>new Uint8Array(t)))};const yt="Fill",wt="Stroke",xt="Shading";function applyBoundingBox(t,e){if(!e)return;const i=e[2]-e[0],s=e[3]-e[1],n=new Path2D;n.rect(e[0],e[1],i,s);t.clip(n)}class BaseShadingPattern{getPattern(){unreachable("Abstract method `getPattern` called.")}}class RadialAxialShadingPattern extends BaseShadingPattern{constructor(t){super();this._type=t[1];this._bbox=t[2];this._colorStops=t[3];this._p0=t[4];this._p1=t[5];this._r0=t[6];this._r1=t[7];this.matrix=null}_createGradient(t){let e;"axial"===this._type?e=t.createLinearGradient(this._p0[0],this._p0[1],this._p1[0],this._p1[1]):"radial"===this._type&&(e=t.createRadialGradient(this._p0[0],this._p0[1],this._r0,this._p1[0],this._p1[1],this._r1));for(const t of this._colorStops)e.addColorStop(t[0],t[1]);return e}getPattern(t,e,i,s){let n;if(s===wt||s===yt){const a=e.current.getClippedPathBoundingBox(s,getCurrentTransform(t))||[0,0,0,0],r=Math.ceil(a[2]-a[0])||1,o=Math.ceil(a[3]-a[1])||1,l=e.cachedCanvases.getCanvas("pattern",r,o),h=l.context;h.clearRect(0,0,h.canvas.width,h.canvas.height);h.beginPath();h.rect(0,0,h.canvas.width,h.canvas.height);h.translate(-a[0],-a[1]);i=Util.transform(i,[1,0,0,1,a[0],a[1]]);h.transform(...e.baseTransform);this.matrix&&h.transform(...this.matrix);applyBoundingBox(h,this._bbox);h.fillStyle=this._createGradient(h);h.fill();n=t.createPattern(l.canvas,"no-repeat");const d=new DOMMatrix(i);n.setTransform(d)}else{applyBoundingBox(t,this._bbox);n=this._createGradient(t)}return n}}function drawTriangle(t,e,i,s,n,a,r,o){const l=e.coords,h=e.colors,d=t.data,c=4*t.width;let u;if(l[i+1]>l[s+1]){u=i;i=s;s=u;u=a;a=r;r=u}if(l[s+1]>l[n+1]){u=s;s=n;n=u;u=r;r=o;o=u}if(l[i+1]>l[s+1]){u=i;i=s;s=u;u=a;a=r;r=u}const p=(l[i]+e.offsetX)*e.scaleX,g=(l[i+1]+e.offsetY)*e.scaleY,m=(l[s]+e.offsetX)*e.scaleX,f=(l[s+1]+e.offsetY)*e.scaleY,b=(l[n]+e.offsetX)*e.scaleX,A=(l[n+1]+e.offsetY)*e.scaleY;if(g>=A)return;const v=h[a],y=h[a+1],w=h[a+2],x=h[r],_=h[r+1],E=h[r+2],C=h[o],S=h[o+1],T=h[o+2],M=Math.round(g),k=Math.round(A);let P,F,D,R,I,L,N,O;for(let t=M;t<=k;t++){if(tA?1:f===A?0:(f-t)/(f-A);P=m-(m-b)*e;F=x-(x-C)*e;D=_-(_-S)*e;R=E-(E-T)*e}let e;e=tA?1:(g-t)/(g-A);I=p-(p-b)*e;L=v-(v-C)*e;N=y-(y-S)*e;O=w-(w-T)*e;const i=Math.round(Math.min(P,I)),s=Math.round(Math.max(P,I));let n=c*t+4*i;for(let t=i;t<=s;t++){e=(P-t)/(P-I);e<0?e=0:e>1&&(e=1);d[n++]=F-(F-L)*e|0;d[n++]=D-(D-N)*e|0;d[n++]=R-(R-O)*e|0;d[n++]=255}}}function drawFigure(t,e,i){const s=e.coords,n=e.colors;let a,r;switch(e.type){case"lattice":const o=e.verticesPerRow,l=Math.floor(s.length/o)-1,h=o-1;for(a=0;a=Math.ceil(p*b)?v=o:w=!0;E>=Math.ceil(g*A)?y=l:x=!0;const C=this.getSizeAndScale(v,this.ctx.canvas.width,b),S=this.getSizeAndScale(y,this.ctx.canvas.height,A),T=t.cachedCanvases.getCanvas("pattern",C.size,S.size),M=T.context,k=r.createCanvasGraphics(M);k.groupLevel=t.groupLevel;this.setFillAndStrokeStyleToContext(k,s,a);M.translate(-C.scale*h,-S.scale*d);k.transform(C.scale,0,0,S.scale,0,0);M.save();this.clipBbox(k,h,d,c,u);k.baseTransform=getCurrentTransform(k.ctx);k.executeOperatorList(i);k.endDrawing();M.restore();if(w||x){const e=T.canvas;w&&(v=o);x&&(y=l);const i=this.getSizeAndScale(v,this.ctx.canvas.width,b),s=this.getSizeAndScale(y,this.ctx.canvas.height,A),n=i.size,a=s.size,r=t.cachedCanvases.getCanvas("pattern-workaround",n,a),c=r.context,u=w?Math.floor(p/o):0,m=x?Math.floor(g/l):0;for(let t=0;t<=u;t++)for(let i=0;i<=m;i++)c.drawImage(e,n*t,a*i,n,a,0,0,n,a);return{canvas:r.canvas,scaleX:i.scale,scaleY:s.scale,offsetX:h,offsetY:d}}return{canvas:T.canvas,scaleX:C.scale,scaleY:S.scale,offsetX:h,offsetY:d}}getSizeAndScale(t,e,i){const s=Math.max(TilingPattern.MAX_PATTERN_SIZE,e);let n=Math.ceil(t*i);n>=s?n=s:i=n/t;return{scale:i,size:n}}clipBbox(t,e,i,s,n){const a=s-e,r=n-i;t.ctx.rect(e,i,a,r);t.current.updateRectMinMax(getCurrentTransform(t.ctx),[e,i,s,n]);t.clip();t.endPath()}setFillAndStrokeStyleToContext(t,e,i){const s=t.ctx,n=t.current;switch(e){case _t:const t=this.ctx;s.fillStyle=t.fillStyle;s.strokeStyle=t.strokeStyle;n.fillColor=t.fillStyle;n.strokeColor=t.strokeStyle;break;case Et:const a=Util.makeHexColor(i[0],i[1],i[2]);s.fillStyle=a;s.strokeStyle=a;n.fillColor=a;n.strokeColor=a;break;default:throw new FormatError(`Unsupported paint type: ${e}`)}}getPattern(t,e,i,s){let n=i;if(s!==xt){n=Util.transform(n,e.baseTransform);this.matrix&&(n=Util.transform(n,this.matrix))}const a=this.createPatternCanvas(e);let r=new DOMMatrix(n);r=r.translate(a.offsetX,a.offsetY);r=r.scale(1/a.scaleX,1/a.scaleY);const o=t.createPattern(a.canvas,"repeat");o.setTransform(r);return o}}function convertBlackAndWhiteToRGBA({src:t,srcPos:e=0,dest:i,width:s,height:n,nonBlackColor:a=4294967295,inverseDecode:r=!1}){const o=util_FeatureTest.isLittleEndian?4278190080:255,[l,h]=r?[a,o]:[o,a],d=s>>3,c=7&s,u=t.length;i=new Uint32Array(i.buffer);let p=0;for(let s=0;s>2),m=i.length,f=s+7>>3,b=4294967295,A=util_FeatureTest.isLittleEndian?4278190080:255;for(u=0;uf?s:8*t-7,r=-8&a;let o=0,c=0;for(;n>=1}}for(;l=a){g=n;m=s*g}l=0;for(p=m;p--;){c[l++]=d[h++];c[l++]=d[h++];c[l++]=d[h++];c[l++]=255}t.putImageData(o,0,u*Ct)}}}function putBinaryImageMask(t,e){if(e.bitmap){t.drawImage(e.bitmap,0,0);return}const i=e.height,s=e.width,n=i%Ct,a=(i-n)/Ct,r=0===n?a:a+1,o=t.createImageData(s,Ct);let l=0;const h=e.data,d=o.data;for(let e=0;e10&&"function"==typeof i,h=l?Date.now()+15:0;let d=0;const c=this.commonObjs,u=this.objs;let p;for(;;){if(void 0!==s&&r===s.nextBreakPoint){s.breakIt(r,i);return r}p=a[r];if(p!==K.dependency)this[p].apply(this,n[r]);else for(const t of n[r]){const e=t.startsWith("g_")?c:u;if(!e.has(t)){e.get(t,i);return r}}r++;if(r===o)return r;if(l&&++d>10){if(Date.now()>h){i();return r}d=0}}}#Ie(){for(;this.stateStack.length||this.inSMaskMode;)this.restore();this.current.activeSMask=null;this.ctx.restore();if(this.transparentCanvas){this.ctx=this.compositeCtx;this.ctx.save();this.ctx.setTransform(1,0,0,1,0,0);this.ctx.drawImage(this.transparentCanvas,0,0);this.ctx.restore();this.transparentCanvas=null}}endDrawing(){this.#Ie();this.cachedCanvases.clear();this.cachedPatterns.clear();for(const t of this._cachedBitmapsMap.values()){for(const e of t.values())"undefined"!=typeof HTMLCanvasElement&&e instanceof HTMLCanvasElement&&(e.width=e.height=0);t.clear()}this._cachedBitmapsMap.clear();this.#Le()}#Le(){if(this.pageColors){const t=this.filterFactory.addHCMFilter(this.pageColors.foreground,this.pageColors.background);if("none"!==t){const e=this.ctx.filter;this.ctx.filter=t;this.ctx.drawImage(this.ctx.canvas,0,0);this.ctx.filter=e}}}_scaleImage(t,e){const i=t.width,s=t.height;let n,a,r=Math.max(Math.hypot(e[0],e[1]),1),o=Math.max(Math.hypot(e[2],e[3]),1),l=i,h=s,d="prescale1";for(;r>2&&l>1||o>2&&h>1;){let e=l,i=h;if(r>2&&l>1){e=l>=16384?Math.floor(l/2)-1||1:Math.ceil(l/2);r/=l/e}if(o>2&&h>1){i=h>=16384?Math.floor(h/2)-1||1:Math.ceil(h)/2;o/=h/i}n=this.cachedCanvases.getCanvas(d,e,i);a=n.context;a.clearRect(0,0,e,i);a.drawImage(t,0,0,l,h,0,0,e,i);t=n.canvas;l=e;h=i;d="prescale1"===d?"prescale2":"prescale1"}return{img:t,paintWidth:l,paintHeight:h}}_createMaskCanvas(t){const e=this.ctx,{width:i,height:s}=t,n=this.current.fillColor,a=this.current.patternFill,r=getCurrentTransform(e);let o,l,h,d;if((t.bitmap||t.data)&&t.count>1){const e=t.bitmap||t.data.buffer;l=JSON.stringify(a?r:[r.slice(0,4),n]);o=this._cachedBitmapsMap.get(e);if(!o){o=new Map;this._cachedBitmapsMap.set(e,o)}const i=o.get(l);if(i&&!a){return{canvas:i,offsetX:Math.round(Math.min(r[0],r[2])+r[4]),offsetY:Math.round(Math.min(r[1],r[3])+r[5])}}h=i}if(!h){d=this.cachedCanvases.getCanvas("maskCanvas",i,s);putBinaryImageMask(d.context,t)}let c=Util.transform(r,[1/i,0,0,-1/s,0,0]);c=Util.transform(c,[1,0,0,1,0,-s]);const[u,p,g,m]=Util.getAxialAlignedBoundingBox([0,0,i,s],c),f=Math.round(g-u)||1,b=Math.round(m-p)||1,A=this.cachedCanvases.getCanvas("fillCanvas",f,b),v=A.context,y=u,w=p;v.translate(-y,-w);v.transform(...c);if(!h){h=this._scaleImage(d.canvas,getCurrentTransformInverse(v));h=h.img;o&&a&&o.set(l,h)}v.imageSmoothingEnabled=getImageSmoothingEnabled(getCurrentTransform(v),t.interpolate);drawImageAtIntegerCoords(v,h,0,0,h.width,h.height,0,0,i,s);v.globalCompositeOperation="source-in";const x=Util.transform(getCurrentTransformInverse(v),[1,0,0,1,-y,-w]);v.fillStyle=a?n.getPattern(e,this,x,yt):n;v.fillRect(0,0,i,s);if(o&&!a){this.cachedCanvases.delete("fillCanvas");o.set(l,A.canvas)}return{canvas:A.canvas,offsetX:Math.round(y),offsetY:Math.round(w)}}setLineWidth(t){t!==this.current.lineWidth&&(this._cachedScaleForStroking[0]=-1);this.current.lineWidth=t;this.ctx.lineWidth=t}setLineCap(t){this.ctx.lineCap=St[t]}setLineJoin(t){this.ctx.lineJoin=Tt[t]}setMiterLimit(t){this.ctx.miterLimit=t}setDash(t,e){const i=this.ctx;if(void 0!==i.setLineDash){i.setLineDash(t);i.lineDashOffset=e}}setRenderingIntent(t){}setFlatness(t){}setGState(t){for(const[e,i]of t)switch(e){case"LW":this.setLineWidth(i);break;case"LC":this.setLineCap(i);break;case"LJ":this.setLineJoin(i);break;case"ML":this.setMiterLimit(i);break;case"D":this.setDash(i[0],i[1]);break;case"RI":this.setRenderingIntent(i);break;case"FL":this.setFlatness(i);break;case"Font":this.setFont(i[0],i[1]);break;case"CA":this.current.strokeAlpha=i;break;case"ca":this.current.fillAlpha=i;this.ctx.globalAlpha=i;break;case"BM":this.ctx.globalCompositeOperation=i;break;case"SMask":this.current.activeSMask=i?this.tempSMask:null;this.tempSMask=null;this.checkSMaskState();break;case"TR":this.ctx.filter=this.current.transferMaps=this.filterFactory.addFilter(i)}}get inSMaskMode(){return!!this.suspendedCtx}checkSMaskState(){const t=this.inSMaskMode;this.current.activeSMask&&!t?this.beginSMaskMode():!this.current.activeSMask&&t&&this.endSMaskMode()}beginSMaskMode(){if(this.inSMaskMode)throw new Error("beginSMaskMode called while already in smask mode");const t=this.ctx.canvas.width,e=this.ctx.canvas.height,i="smaskGroupAt"+this.groupLevel,s=this.cachedCanvases.getCanvas(i,t,e);this.suspendedCtx=this.ctx;this.ctx=s.context;const n=this.ctx;n.setTransform(...getCurrentTransform(this.suspendedCtx));copyCtxState(this.suspendedCtx,n);!function mirrorContextOperations(t,e){if(t._removeMirroring)throw new Error("Context is already forwarding operations.");t.__originalSave=t.save;t.__originalRestore=t.restore;t.__originalRotate=t.rotate;t.__originalScale=t.scale;t.__originalTranslate=t.translate;t.__originalTransform=t.transform;t.__originalSetTransform=t.setTransform;t.__originalResetTransform=t.resetTransform;t.__originalClip=t.clip;t.__originalMoveTo=t.moveTo;t.__originalLineTo=t.lineTo;t.__originalBezierCurveTo=t.bezierCurveTo;t.__originalRect=t.rect;t.__originalClosePath=t.closePath;t.__originalBeginPath=t.beginPath;t._removeMirroring=()=>{t.save=t.__originalSave;t.restore=t.__originalRestore;t.rotate=t.__originalRotate;t.scale=t.__originalScale;t.translate=t.__originalTranslate;t.transform=t.__originalTransform;t.setTransform=t.__originalSetTransform;t.resetTransform=t.__originalResetTransform;t.clip=t.__originalClip;t.moveTo=t.__originalMoveTo;t.lineTo=t.__originalLineTo;t.bezierCurveTo=t.__originalBezierCurveTo;t.rect=t.__originalRect;t.closePath=t.__originalClosePath;t.beginPath=t.__originalBeginPath;delete t._removeMirroring};t.save=function ctxSave(){e.save();this.__originalSave()};t.restore=function ctxRestore(){e.restore();this.__originalRestore()};t.translate=function ctxTranslate(t,i){e.translate(t,i);this.__originalTranslate(t,i)};t.scale=function ctxScale(t,i){e.scale(t,i);this.__originalScale(t,i)};t.transform=function ctxTransform(t,i,s,n,a,r){e.transform(t,i,s,n,a,r);this.__originalTransform(t,i,s,n,a,r)};t.setTransform=function ctxSetTransform(t,i,s,n,a,r){e.setTransform(t,i,s,n,a,r);this.__originalSetTransform(t,i,s,n,a,r)};t.resetTransform=function ctxResetTransform(){e.resetTransform();this.__originalResetTransform()};t.rotate=function ctxRotate(t){e.rotate(t);this.__originalRotate(t)};t.clip=function ctxRotate(t){e.clip(t);this.__originalClip(t)};t.moveTo=function(t,i){e.moveTo(t,i);this.__originalMoveTo(t,i)};t.lineTo=function(t,i){e.lineTo(t,i);this.__originalLineTo(t,i)};t.bezierCurveTo=function(t,i,s,n,a,r){e.bezierCurveTo(t,i,s,n,a,r);this.__originalBezierCurveTo(t,i,s,n,a,r)};t.rect=function(t,i,s,n){e.rect(t,i,s,n);this.__originalRect(t,i,s,n)};t.closePath=function(){e.closePath();this.__originalClosePath()};t.beginPath=function(){e.beginPath();this.__originalBeginPath()}}(n,this.suspendedCtx);this.setGState([["BM","source-over"],["ca",1],["CA",1]])}endSMaskMode(){if(!this.inSMaskMode)throw new Error("endSMaskMode called while not in smask mode");this.ctx._removeMirroring();copyCtxState(this.ctx,this.suspendedCtx);this.ctx=this.suspendedCtx;this.suspendedCtx=null}compose(t){if(!this.current.activeSMask)return;if(t){t[0]=Math.floor(t[0]);t[1]=Math.floor(t[1]);t[2]=Math.ceil(t[2]);t[3]=Math.ceil(t[3])}else t=[0,0,this.ctx.canvas.width,this.ctx.canvas.height];const e=this.current.activeSMask,i=this.suspendedCtx;this.composeSMask(i,e,this.ctx,t);this.ctx.save();this.ctx.setTransform(1,0,0,1,0,0);this.ctx.clearRect(0,0,this.ctx.canvas.width,this.ctx.canvas.height);this.ctx.restore()}composeSMask(t,e,i,s){const n=s[0],a=s[1],r=s[2]-n,o=s[3]-a;if(0!==r&&0!==o){this.genericComposeSMask(e.context,i,r,o,e.subtype,e.backdrop,e.transferMap,n,a,e.offsetX,e.offsetY);t.save();t.globalAlpha=1;t.globalCompositeOperation="source-over";t.setTransform(1,0,0,1,0,0);t.drawImage(i.canvas,0,0);t.restore()}}genericComposeSMask(t,e,i,s,n,a,r,o,l,h,d){let c=t.canvas,u=o-h,p=l-d;if(a)if(u<0||p<0||u+i>c.width||p+s>c.height){const t=this.cachedCanvases.getCanvas("maskExtension",i,s),e=t.context;e.drawImage(c,-u,-p);if(a.some((t=>0!==t))){e.globalCompositeOperation="destination-atop";e.fillStyle=Util.makeHexColor(...a);e.fillRect(0,0,i,s);e.globalCompositeOperation="source-over"}c=t.canvas;u=p=0}else if(a.some((t=>0!==t))){t.save();t.globalAlpha=1;t.setTransform(1,0,0,1,0,0);const e=new Path2D;e.rect(u,p,i,s);t.clip(e);t.globalCompositeOperation="destination-atop";t.fillStyle=Util.makeHexColor(...a);t.fillRect(u,p,i,s);t.restore()}e.save();e.globalAlpha=1;e.setTransform(1,0,0,1,0,0);"Alpha"===n&&r?e.filter=this.filterFactory.addAlphaFilter(r):"Luminosity"===n&&(e.filter=this.filterFactory.addLuminosityFilter(r));const g=new Path2D;g.rect(o,l,i,s);e.clip(g);e.globalCompositeOperation="destination-in";e.drawImage(c,u,p,i,s,o,l,i,s);e.restore()}save(){if(this.inSMaskMode){copyCtxState(this.ctx,this.suspendedCtx);this.suspendedCtx.save()}else this.ctx.save();const t=this.current;this.stateStack.push(t);this.current=t.clone()}restore(){0===this.stateStack.length&&this.inSMaskMode&&this.endSMaskMode();if(0!==this.stateStack.length){this.current=this.stateStack.pop();if(this.inSMaskMode){this.suspendedCtx.restore();copyCtxState(this.suspendedCtx,this.ctx)}else this.ctx.restore();this.checkSMaskState();this.pendingClip=null;this._cachedScaleForStroking[0]=-1;this._cachedGetSinglePixelWidth=null}}transform(t,e,i,s,n,a){this.ctx.transform(t,e,i,s,n,a);this._cachedScaleForStroking[0]=-1;this._cachedGetSinglePixelWidth=null}constructPath(t,e,i){const s=this.ctx,n=this.current;let a,r,o=n.x,l=n.y;const h=getCurrentTransform(s),d=0===h[0]&&0===h[3]||0===h[1]&&0===h[2],c=d?i.slice(0):null;for(let i=0,u=0,p=t.length;i100&&(h=100);this.current.fontSizeScale=e/h;this.ctx.font=`${l} ${o} ${h}px ${r}`}setTextRenderingMode(t){this.current.textRenderingMode=t}setTextRise(t){this.current.textRise=t}moveText(t,e){this.current.x=this.current.lineX+=t;this.current.y=this.current.lineY+=e}setLeadingMoveText(t,e){this.setLeading(-e);this.moveText(t,e)}setTextMatrix(t,e,i,s,n,a){this.current.textMatrix=[t,e,i,s,n,a];this.current.textMatrixScale=Math.hypot(t,e);this.current.x=this.current.lineX=0;this.current.y=this.current.lineY=0}nextLine(){this.moveText(0,this.current.leading)}paintChar(t,e,i,s){const n=this.ctx,a=this.current,r=a.font,o=a.textRenderingMode,l=a.fontSize/a.fontSizeScale,h=o&w,d=!!(o&x),c=a.patternFill&&!r.missingFile;let u;(r.disableFontFace||d||c)&&(u=r.getPathGenerator(this.commonObjs,t));if(r.disableFontFace||c){n.save();n.translate(e,i);n.beginPath();u(n,l);s&&n.setTransform(...s);h!==b&&h!==v||n.fill();h!==A&&h!==v||n.stroke();n.restore()}else{h!==b&&h!==v||n.fillText(t,e,i);h!==A&&h!==v||n.strokeText(t,e,i)}if(d){(this.pendingTextPaths||=[]).push({transform:getCurrentTransform(n),x:e,y:i,fontSize:l,addToPath:u})}}get isFontSubpixelAAEnabled(){const{context:t}=this.cachedCanvases.getCanvas("isFontSubpixelAAEnabled",10,10);t.scale(1.5,1);t.fillText("I",0,10);const e=t.getImageData(0,0,10,10).data;let i=!1;for(let t=3;t0&&e[t]<255){i=!0;break}return shadow(this,"isFontSubpixelAAEnabled",i)}showText(t){const e=this.current,i=e.font;if(i.isType3Font)return this.showType3Text(t);const s=e.fontSize;if(0===s)return;const n=this.ctx,a=e.fontSizeScale,r=e.charSpacing,o=e.wordSpacing,l=e.fontDirection,h=e.textHScale*l,d=t.length,c=i.vertical,u=c?1:-1,p=i.defaultVMetrics,g=s*e.fontMatrix[0],m=e.textRenderingMode===b&&!i.disableFontFace&&!e.patternFill;n.save();n.transform(...e.textMatrix);n.translate(e.x,e.y+e.textRise);l>0?n.scale(h,-1):n.scale(h,1);let f;if(e.patternFill){n.save();const t=e.fillColor.getPattern(n,this,getCurrentTransformInverse(n),yt);f=getCurrentTransform(n);n.restore();n.fillStyle=t}let y=e.lineWidth;const x=e.textMatrixScale;if(0===x||0===y){const t=e.textRenderingMode&w;t!==A&&t!==v||(y=this.getSinglePixelWidth())}else y/=x;if(1!==a){n.scale(a,a);y/=a}n.lineWidth=y;if(i.isInvalidPDFjsFont){const i=[];let s=0;for(const e of t){i.push(e.unicode);s+=e.width}n.fillText(i.join(""),0,0);e.x+=s*g*h;n.restore();this.compose();return}let _,E=0;for(_=0;_0){const t=1e3*n.measureText(b).width/s*a;if(wnew CanvasGraphics(t,this.commonObjs,this.objs,this.canvasFactory,this.filterFactory,{optionalContentConfig:this.optionalContentConfig,markedContentStack:this.markedContentStack})};e=new TilingPattern(t,i,this.ctx,n,s)}else e=this._getPattern(t[1],t[2]);return e}setStrokeColorN(){this.current.strokeColor=this.getColorN_Pattern(arguments)}setFillColorN(){this.current.fillColor=this.getColorN_Pattern(arguments);this.current.patternFill=!0}setStrokeRGBColor(t,e,i){this.ctx.strokeStyle=this.current.strokeColor=Util.makeHexColor(t,e,i)}setStrokeTransparent(){this.ctx.strokeStyle=this.current.strokeColor="transparent"}setFillRGBColor(t,e,i){this.ctx.fillStyle=this.current.fillColor=Util.makeHexColor(t,e,i);this.current.patternFill=!1}setFillTransparent(){this.ctx.fillStyle=this.current.fillColor="transparent";this.current.patternFill=!1}_getPattern(t,e=null){let i;if(this.cachedPatterns.has(t))i=this.cachedPatterns.get(t);else{i=function getShadingPattern(t){switch(t[0]){case"RadialAxial":return new RadialAxialShadingPattern(t);case"Mesh":return new MeshShadingPattern(t);case"Dummy":return new DummyShadingPattern}throw new Error(`Unknown IR type: ${t[0]}`)}(this.getObject(t));this.cachedPatterns.set(t,i)}e&&(i.matrix=e);return i}shadingFill(t){if(!this.contentVisible)return;const e=this.ctx;this.save();const i=this._getPattern(t);e.fillStyle=i.getPattern(e,this,getCurrentTransformInverse(e),xt);const s=getCurrentTransformInverse(e);if(s){const{width:t,height:i}=e.canvas,[n,a,r,o]=Util.getAxialAlignedBoundingBox([0,0,t,i],s);this.ctx.fillRect(n,a,r-n,o-a)}else this.ctx.fillRect(-1e10,-1e10,2e10,2e10);this.compose(this.current.getClippedPathBoundingBox());this.restore()}beginInlineImage(){unreachable("Should not call beginInlineImage")}beginImageData(){unreachable("Should not call beginImageData")}paintFormXObjectBegin(t,e){if(this.contentVisible){this.save();this.baseTransformStack.push(this.baseTransform);t&&this.transform(...t);this.baseTransform=getCurrentTransform(this.ctx);if(e){const t=e[2]-e[0],i=e[3]-e[1];this.ctx.rect(e[0],e[1],t,i);this.current.updateRectMinMax(getCurrentTransform(this.ctx),e);this.clip();this.endPath()}}}paintFormXObjectEnd(){if(this.contentVisible){this.restore();this.baseTransform=this.baseTransformStack.pop()}}beginGroup(t){if(!this.contentVisible)return;this.save();if(this.inSMaskMode){this.endSMaskMode();this.current.activeSMask=null}const e=this.ctx;t.isolated||info("TODO: Support non-isolated groups.");t.knockout&&warn("Knockout groups not supported.");const i=getCurrentTransform(e);t.matrix&&e.transform(...t.matrix);if(!t.bbox)throw new Error("Bounding box is required.");let s=Util.getAxialAlignedBoundingBox(t.bbox,getCurrentTransform(e));const n=[0,0,e.canvas.width,e.canvas.height];s=Util.intersect(s,n)||[0,0,0,0];const a=Math.floor(s[0]),r=Math.floor(s[1]),o=Math.max(Math.ceil(s[2])-a,1),l=Math.max(Math.ceil(s[3])-r,1);this.current.startNewPathAndClipBox([0,0,o,l]);let h="groupAt"+this.groupLevel;t.smask&&(h+="_smask_"+this.smaskCounter++%2);const d=this.cachedCanvases.getCanvas(h,o,l),c=d.context;c.translate(-a,-r);c.transform(...i);if(t.smask)this.smaskStack.push({canvas:d.canvas,context:c,offsetX:a,offsetY:r,subtype:t.smask.subtype,backdrop:t.smask.backdrop,transferMap:t.smask.transferMap||null,startTransformInverse:null});else{e.setTransform(1,0,0,1,0,0);e.translate(a,r);e.save()}copyCtxState(e,c);this.ctx=c;this.setGState([["BM","source-over"],["ca",1],["CA",1]]);this.groupStack.push(e);this.groupLevel++}endGroup(t){if(!this.contentVisible)return;this.groupLevel--;const e=this.ctx,i=this.groupStack.pop();this.ctx=i;this.ctx.imageSmoothingEnabled=!1;if(t.smask){this.tempSMask=this.smaskStack.pop();this.restore()}else{this.ctx.restore();const t=getCurrentTransform(this.ctx);this.restore();this.ctx.save();this.ctx.setTransform(...t);const i=Util.getAxialAlignedBoundingBox([0,0,e.canvas.width,e.canvas.height],t);this.ctx.drawImage(e.canvas,0,0);this.ctx.restore();this.compose(i)}}beginAnnotation(t,e,i,s,n){this.#Ie();resetCtxToDefault(this.ctx);this.ctx.save();this.save();this.baseTransform&&this.ctx.setTransform(...this.baseTransform);if(e){const s=e[2]-e[0],a=e[3]-e[1];if(n&&this.annotationCanvasMap){(i=i.slice())[4]-=e[0];i[5]-=e[1];(e=e.slice())[0]=e[1]=0;e[2]=s;e[3]=a;const[n,r]=Util.singularValueDecompose2dScale(getCurrentTransform(this.ctx)),{viewportScale:o}=this,l=Math.ceil(s*this.outputScaleX*o),h=Math.ceil(a*this.outputScaleY*o);this.annotationCanvas=this.canvasFactory.create(l,h);const{canvas:d,context:c}=this.annotationCanvas;this.annotationCanvasMap.set(t,d);this.annotationCanvas.savedCtx=this.ctx;this.ctx=c;this.ctx.save();this.ctx.setTransform(n,0,0,-r,0,a*r);resetCtxToDefault(this.ctx)}else{resetCtxToDefault(this.ctx);this.endPath();this.ctx.rect(e[0],e[1],s,a);this.ctx.clip();this.ctx.beginPath()}}this.current=new CanvasExtraState(this.ctx.canvas.width,this.ctx.canvas.height);this.transform(...i);this.transform(...s)}endAnnotation(){if(this.annotationCanvas){this.ctx.restore();this.#Le();this.ctx=this.annotationCanvas.savedCtx;delete this.annotationCanvas.savedCtx;delete this.annotationCanvas}}paintImageMaskXObject(t){if(!this.contentVisible)return;const e=t.count;(t=this.getObject(t.data,t)).count=e;const i=this.ctx,s=this.processingType3;if(s){void 0===s.compiled&&(s.compiled=function compileType3Glyph(t){const{width:e,height:i}=t;if(e>1e3||i>1e3)return null;const s=new Uint8Array([0,2,4,0,1,0,5,4,8,10,0,8,0,2,1,0]),n=e+1;let a,r,o,l=new Uint8Array(n*(i+1));const h=e+7&-8;let d=new Uint8Array(h*i),c=0;for(const e of t.data){let t=128;for(;t>0;){d[c++]=e&t?0:255;t>>=1}}let u=0;c=0;if(0!==d[c]){l[0]=1;++u}for(r=1;r>2)+(d[c+1]?4:0)+(d[c-h+1]?8:0);if(s[t]){l[o+r]=s[t];++u}c++}if(d[c-h]!==d[c]){l[o+r]=d[c]?2:4;++u}if(u>1e3)return null}c=h*(i-1);o=a*n;if(0!==d[c]){l[o]=8;++u}for(r=1;r1e3)return null;const p=new Int32Array([0,n,-1,0,-n,0,0,0,1]),g=new Path2D;for(a=0;u&&a<=i;a++){let t=a*n;const i=t+e;for(;t>4;l[t]&=r>>2|r<<2}g.lineTo(t%n,t/n|0);l[t]||--u}while(s!==t);--a}d=null;l=null;return function(t){t.save();t.scale(1/e,-1/i);t.translate(0,-i);t.fill(g);t.beginPath();t.restore()}}(t));if(s.compiled){s.compiled(i);return}}const n=this._createMaskCanvas(t),a=n.canvas;i.save();i.setTransform(1,0,0,1,0,0);i.drawImage(a,n.offsetX,n.offsetY);i.restore();this.compose()}paintImageMaskXObjectRepeat(t,e,i=0,s=0,n,a){if(!this.contentVisible)return;t=this.getObject(t.data,t);const r=this.ctx;r.save();const o=getCurrentTransform(r);r.transform(e,i,s,n,0,0);const l=this._createMaskCanvas(t);r.setTransform(1,0,0,1,l.offsetX-o[4],l.offsetY-o[5]);for(let t=0,h=a.length;te?h/e:1;r=l>e?l/e:1}}this._cachedScaleForStroking[0]=a;this._cachedScaleForStroking[1]=r}return this._cachedScaleForStroking}rescaleAndStroke(t){const{ctx:e}=this,{lineWidth:i}=this.current,[s,n]=this.getScaleForStroking();e.lineWidth=i||1;if(1===s&&1===n){e.stroke();return}const a=e.getLineDash();t&&e.save();e.scale(s,n);if(a.length>0){const t=Math.max(s,n);e.setLineDash(a.map((e=>e/t)));e.lineDashOffset/=t}e.stroke();t&&e.restore()}isContentVisible(){for(let t=this.markedContentStack.length-1;t>=0;t--)if(!this.markedContentStack[t].visible)return!1;return!0}}for(const t in K)void 0!==CanvasGraphics.prototype[t]&&(CanvasGraphics.prototype[K[t]]=CanvasGraphics.prototype[t]);class GlobalWorkerOptions{static#Ne=null;static#Oe="";static get workerPort(){return this.#Ne}static set workerPort(t){if(!("undefined"!=typeof Worker&&t instanceof Worker)&&null!==t)throw new Error("Invalid `workerPort` type.");this.#Ne=t}static get workerSrc(){return this.#Oe}static set workerSrc(t){if("string"!=typeof t)throw new Error("Invalid `workerSrc` type.");this.#Oe=t}}const Pt=1,Ft=2,Dt=1,Rt=2,It=3,Lt=4,Nt=5,Ot=6,Bt=7,Ht=8;function wrapReason(t){t instanceof Error||"object"==typeof t&&null!==t||unreachable('wrapReason: Expected "reason" to be a (possibly cloned) Error.');switch(t.name){case"AbortException":return new AbortException(t.message);case"MissingPDFException":return new MissingPDFException(t.message);case"PasswordException":return new PasswordException(t.message,t.code);case"UnexpectedResponseException":return new UnexpectedResponseException(t.message,t.status);case"UnknownErrorException":return new UnknownErrorException(t.message,t.details);default:return new UnknownErrorException(t.message,t.toString())}}class MessageHandler{constructor(t,e,i){this.sourceName=t;this.targetName=e;this.comObj=i;this.callbackId=1;this.streamId=1;this.streamSinks=Object.create(null);this.streamControllers=Object.create(null);this.callbackCapabilities=Object.create(null);this.actionHandler=Object.create(null);this._onComObjOnMessage=t=>{const e=t.data;if(e.targetName!==this.sourceName)return;if(e.stream){this.#Be(e);return}if(e.callback){const t=e.callbackId,i=this.callbackCapabilities[t];if(!i)throw new Error(`Cannot resolve callback ${t}`);delete this.callbackCapabilities[t];if(e.callback===Pt)i.resolve(e.data);else{if(e.callback!==Ft)throw new Error("Unexpected callback case");i.reject(wrapReason(e.reason))}return}const s=this.actionHandler[e.action];if(!s)throw new Error(`Unknown action from worker: ${e.action}`);if(e.callbackId){const t=this.sourceName,n=e.sourceName;new Promise((function(t){t(s(e.data))})).then((function(s){i.postMessage({sourceName:t,targetName:n,callback:Pt,callbackId:e.callbackId,data:s})}),(function(s){i.postMessage({sourceName:t,targetName:n,callback:Ft,callbackId:e.callbackId,reason:wrapReason(s)})}))}else e.streamId?this.#He(e):s(e.data)};i.addEventListener("message",this._onComObjOnMessage)}on(t,e){const i=this.actionHandler;if(i[t])throw new Error(`There is already an actionName called "${t}"`);i[t]=e}send(t,e,i){this.comObj.postMessage({sourceName:this.sourceName,targetName:this.targetName,action:t,data:e},i)}sendWithPromise(t,e,i){const s=this.callbackId++,n=Promise.withResolvers();this.callbackCapabilities[s]=n;try{this.comObj.postMessage({sourceName:this.sourceName,targetName:this.targetName,action:t,callbackId:s,data:e},i)}catch(t){n.reject(t)}return n.promise}sendWithStream(t,e,i,s){const n=this.streamId++,a=this.sourceName,r=this.targetName,o=this.comObj;return new ReadableStream({start:i=>{const l=Promise.withResolvers();this.streamControllers[n]={controller:i,startCall:l,pullCall:null,cancelCall:null,isClosed:!1};o.postMessage({sourceName:a,targetName:r,action:t,streamId:n,data:e,desiredSize:i.desiredSize},s);return l.promise},pull:t=>{const e=Promise.withResolvers();this.streamControllers[n].pullCall=e;o.postMessage({sourceName:a,targetName:r,stream:Ot,streamId:n,desiredSize:t.desiredSize});return e.promise},cancel:t=>{assert(t instanceof Error,"cancel must have a valid reason");const e=Promise.withResolvers();this.streamControllers[n].cancelCall=e;this.streamControllers[n].isClosed=!0;o.postMessage({sourceName:a,targetName:r,stream:Dt,streamId:n,reason:wrapReason(t)});return e.promise}},i)}#He(t){const e=t.streamId,i=this.sourceName,s=t.sourceName,n=this.comObj,a=this,r=this.actionHandler[t.action],o={enqueue(t,a=1,r){if(this.isCancelled)return;const o=this.desiredSize;this.desiredSize-=a;if(o>0&&this.desiredSize<=0){this.sinkCapability=Promise.withResolvers();this.ready=this.sinkCapability.promise}n.postMessage({sourceName:i,targetName:s,stream:Lt,streamId:e,chunk:t},r)},close(){if(!this.isCancelled){this.isCancelled=!0;n.postMessage({sourceName:i,targetName:s,stream:It,streamId:e});delete a.streamSinks[e]}},error(t){assert(t instanceof Error,"error must have a valid reason");if(!this.isCancelled){this.isCancelled=!0;n.postMessage({sourceName:i,targetName:s,stream:Nt,streamId:e,reason:wrapReason(t)})}},sinkCapability:Promise.withResolvers(),onPull:null,onCancel:null,isCancelled:!1,desiredSize:t.desiredSize,ready:null};o.sinkCapability.resolve();o.ready=o.sinkCapability.promise;this.streamSinks[e]=o;new Promise((function(e){e(r(t.data,o))})).then((function(){n.postMessage({sourceName:i,targetName:s,stream:Ht,streamId:e,success:!0})}),(function(t){n.postMessage({sourceName:i,targetName:s,stream:Ht,streamId:e,reason:wrapReason(t)})}))}#Be(t){const e=t.streamId,i=this.sourceName,s=t.sourceName,n=this.comObj,a=this.streamControllers[e],r=this.streamSinks[e];switch(t.stream){case Ht:t.success?a.startCall.resolve():a.startCall.reject(wrapReason(t.reason));break;case Bt:t.success?a.pullCall.resolve():a.pullCall.reject(wrapReason(t.reason));break;case Ot:if(!r){n.postMessage({sourceName:i,targetName:s,stream:Bt,streamId:e,success:!0});break}r.desiredSize<=0&&t.desiredSize>0&&r.sinkCapability.resolve();r.desiredSize=t.desiredSize;new Promise((function(t){t(r.onPull?.())})).then((function(){n.postMessage({sourceName:i,targetName:s,stream:Bt,streamId:e,success:!0})}),(function(t){n.postMessage({sourceName:i,targetName:s,stream:Bt,streamId:e,reason:wrapReason(t)})}));break;case Lt:assert(a,"enqueue should have stream controller");if(a.isClosed)break;a.controller.enqueue(t.chunk);break;case It:assert(a,"close should have stream controller");if(a.isClosed)break;a.isClosed=!0;a.controller.close();this.#ze(a,e);break;case Nt:assert(a,"error should have stream controller");a.controller.error(wrapReason(t.reason));this.#ze(a,e);break;case Rt:t.success?a.cancelCall.resolve():a.cancelCall.reject(wrapReason(t.reason));this.#ze(a,e);break;case Dt:if(!r)break;new Promise((function(e){e(r.onCancel?.(wrapReason(t.reason)))})).then((function(){n.postMessage({sourceName:i,targetName:s,stream:Rt,streamId:e,success:!0})}),(function(t){n.postMessage({sourceName:i,targetName:s,stream:Rt,streamId:e,reason:wrapReason(t)})}));r.sinkCapability.reject(wrapReason(t.reason));r.isCancelled=!0;delete this.streamSinks[e];break;default:throw new Error("Unexpected stream case")}}async#ze(t,e){await Promise.allSettled([t.startCall?.promise,t.pullCall?.promise,t.cancelCall?.promise]);delete this.streamControllers[e]}destroy(){this.comObj.removeEventListener("message",this._onComObjOnMessage)}}class Metadata{#Ue;#je;constructor({parsedData:t,rawData:e}){this.#Ue=t;this.#je=e}getRaw(){return this.#je}get(t){return this.#Ue.get(t)??null}getAll(){return objectFromMap(this.#Ue)}has(t){return this.#Ue.has(t)}}const zt=Symbol("INTERNAL");class OptionalContentGroup{#We=!1;#Ge=!1;#$e=!1;#Ve=!0;constructor(t,{name:e,intent:i,usage:s}){this.#We=!!(t&r);this.#Ge=!!(t&o);this.name=e;this.intent=i;this.usage=s}get visible(){if(this.#$e)return this.#Ve;if(!this.#Ve)return!1;const{print:t,view:e}=this.usage;return this.#We?"OFF"!==e?.viewState:!this.#Ge||"OFF"!==t?.printState}_setVisible(t,e,i=!1){t!==zt&&unreachable("Internal method `_setVisible` called.");this.#$e=i;this.#Ve=e}}class OptionalContentConfig{#qe=null;#Xe=new Map;#Ke=null;#Ye=null;constructor(t,e=r){this.renderingIntent=e;this.name=null;this.creator=null;if(null!==t){this.name=t.name;this.creator=t.creator;this.#Ye=t.order;for(const i of t.groups)this.#Xe.set(i.id,new OptionalContentGroup(e,i));if("OFF"===t.baseState)for(const t of this.#Xe.values())t._setVisible(zt,!1);for(const e of t.on)this.#Xe.get(e)._setVisible(zt,!0);for(const e of t.off)this.#Xe.get(e)._setVisible(zt,!1);this.#Ke=this.getHash()}}#Qe(t){const e=t.length;if(e<2)return!0;const i=t[0];for(let s=1;s0?objectFromMap(this.#Xe):null}getGroup(t){return this.#Xe.get(t)||null}getHash(){if(null!==this.#qe)return this.#qe;const t=new MurmurHash3_64;for(const[e,i]of this.#Xe)t.update(`${e}:${i.visible}`);return this.#qe=t.hexdigest()}}class PDFDataTransportStream{constructor(t,{disableRange:e=!1,disableStream:i=!1}){assert(t,'PDFDataTransportStream - missing required "pdfDataRangeTransport" argument.');const{length:s,initialData:n,progressiveDone:a,contentDispositionFilename:r}=t;this._queuedChunks=[];this._progressiveDone=a;this._contentDispositionFilename=r;if(n?.length>0){const t=n instanceof Uint8Array&&n.byteLength===n.buffer.byteLength?n.buffer:new Uint8Array(n).buffer;this._queuedChunks.push(t)}this._pdfDataRangeTransport=t;this._isStreamingSupported=!i;this._isRangeSupported=!e;this._contentLength=s;this._fullRequestReader=null;this._rangeReaders=[];t.addRangeListener(((t,e)=>{this._onReceiveData({begin:t,chunk:e})}));t.addProgressListener(((t,e)=>{this._onProgress({loaded:t,total:e})}));t.addProgressiveReadListener((t=>{this._onReceiveData({chunk:t})}));t.addProgressiveDoneListener((()=>{this._onProgressiveDone()}));t.transportReady()}_onReceiveData({begin:t,chunk:e}){const i=e instanceof Uint8Array&&e.byteLength===e.buffer.byteLength?e.buffer:new Uint8Array(e).buffer;if(void 0===t)this._fullRequestReader?this._fullRequestReader._enqueue(i):this._queuedChunks.push(i);else{assert(this._rangeReaders.some((function(e){if(e._begin!==t)return!1;e._enqueue(i);return!0})),"_onReceiveData - no `PDFDataTransportStreamRangeReader` instance found.")}}get _progressiveDataLength(){return this._fullRequestReader?._loaded??0}_onProgress(t){void 0===t.total?this._rangeReaders[0]?.onProgress?.({loaded:t.loaded}):this._fullRequestReader?.onProgress?.({loaded:t.loaded,total:t.total})}_onProgressiveDone(){this._fullRequestReader?.progressiveDone();this._progressiveDone=!0}_removeRangeReader(t){const e=this._rangeReaders.indexOf(t);e>=0&&this._rangeReaders.splice(e,1)}getFullReader(){assert(!this._fullRequestReader,"PDFDataTransportStream.getFullReader can only be called once.");const t=this._queuedChunks;this._queuedChunks=null;return new PDFDataTransportStreamReader(this,t,this._progressiveDone,this._contentDispositionFilename)}getRangeReader(t,e){if(e<=this._progressiveDataLength)return null;const i=new PDFDataTransportStreamRangeReader(this,t,e);this._pdfDataRangeTransport.requestDataRange(t,e);this._rangeReaders.push(i);return i}cancelAllRequests(t){this._fullRequestReader?.cancel(t);for(const e of this._rangeReaders.slice(0))e.cancel(t);this._pdfDataRangeTransport.abort()}}class PDFDataTransportStreamReader{constructor(t,e,i=!1,s=null){this._stream=t;this._done=i||!1;this._filename=isPdfFile(s)?s:null;this._queuedChunks=e||[];this._loaded=0;for(const t of this._queuedChunks)this._loaded+=t.byteLength;this._requests=[];this._headersReady=Promise.resolve();t._fullRequestReader=this;this.onProgress=null}_enqueue(t){if(!this._done){if(this._requests.length>0){this._requests.shift().resolve({value:t,done:!1})}else this._queuedChunks.push(t);this._loaded+=t.byteLength}}get headersReady(){return this._headersReady}get filename(){return this._filename}get isRangeSupported(){return this._stream._isRangeSupported}get isStreamingSupported(){return this._stream._isStreamingSupported}get contentLength(){return this._stream._contentLength}async read(){if(this._queuedChunks.length>0){return{value:this._queuedChunks.shift(),done:!1}}if(this._done)return{value:void 0,done:!0};const t=Promise.withResolvers();this._requests.push(t);return t.promise}cancel(t){this._done=!0;for(const t of this._requests)t.resolve({value:void 0,done:!0});this._requests.length=0}progressiveDone(){this._done||(this._done=!0)}}class PDFDataTransportStreamRangeReader{constructor(t,e,i){this._stream=t;this._begin=e;this._end=i;this._queuedChunk=null;this._requests=[];this._done=!1;this.onProgress=null}_enqueue(t){if(!this._done){if(0===this._requests.length)this._queuedChunk=t;else{this._requests.shift().resolve({value:t,done:!1});for(const t of this._requests)t.resolve({value:void 0,done:!0});this._requests.length=0}this._done=!0;this._stream._removeRangeReader(this)}}get isStreamingSupported(){return!1}async read(){if(this._queuedChunk){const t=this._queuedChunk;this._queuedChunk=null;return{value:t,done:!1}}if(this._done)return{value:void 0,done:!0};const t=Promise.withResolvers();this._requests.push(t);return t.promise}cancel(t){this._done=!0;for(const t of this._requests)t.resolve({value:void 0,done:!0});this._requests.length=0;this._stream._removeRangeReader(this)}}function createHeaders(t,e){const i=new Headers;if(!t||!e||"object"!=typeof e)return i;for(const t in e){const s=e[t];void 0!==s&&i.append(t,s)}return i}function validateRangeRequestCapabilities({responseHeaders:t,isHttp:e,rangeChunkSize:i,disableRange:s}){const n={allowRangeRequests:!1,suggestedLength:void 0},a=parseInt(t.get("Content-Length"),10);if(!Number.isInteger(a))return n;n.suggestedLength=a;if(a<=2*i)return n;if(s||!e)return n;if("bytes"!==t.get("Accept-Ranges"))return n;if("identity"!==(t.get("Content-Encoding")||"identity"))return n;n.allowRangeRequests=!0;return n}function extractFilenameFromHeader(t){const e=t.get("Content-Disposition");if(e){let t=function getFilenameFromContentDispositionHeader(t){let e=!0,i=toParamRegExp("filename\\*","i").exec(t);if(i){i=i[1];let t=rfc2616unquote(i);t=unescape(t);t=rfc5987decode(t);t=rfc2047decode(t);return fixupEncoding(t)}i=function rfc2231getparam(t){const e=[];let i;const s=toParamRegExp("filename\\*((?!0\\d)\\d+)(\\*?)","ig");for(;null!==(i=s.exec(t));){let[,t,s,n]=i;t=parseInt(t,10);if(t in e){if(0===t)break}else e[t]=[s,n]}const n=[];for(let t=0;t{if(!validateResponseStatus(e.status))throw createResponseStatusError(e.status,s);this._reader=e.body.getReader();this._headersCapability.resolve();const i=e.headers,{allowRangeRequests:n,suggestedLength:a}=validateRangeRequestCapabilities({responseHeaders:i,isHttp:t.isHttp,rangeChunkSize:this._rangeChunkSize,disableRange:this._disableRange});this._isRangeSupported=n;this._contentLength=a||this._contentLength;this._filename=extractFilenameFromHeader(i);!this._isStreamingSupported&&this._isRangeSupported&&this.cancel(new AbortException("Streaming is disabled."))})).catch(this._headersCapability.reject);this.onProgress=null}get headersReady(){return this._headersCapability.promise}get filename(){return this._filename}get contentLength(){return this._contentLength}get isRangeSupported(){return this._isRangeSupported}get isStreamingSupported(){return this._isStreamingSupported}async read(){await this._headersCapability.promise;const{value:t,done:e}=await this._reader.read();if(e)return{value:t,done:e};this._loaded+=t.byteLength;this.onProgress?.({loaded:this._loaded,total:this._contentLength});return{value:getArrayBuffer(t),done:!1}}cancel(t){this._reader?.cancel(t);this._abortController.abort()}}class PDFFetchStreamRangeReader{constructor(t,e,i){this._stream=t;this._reader=null;this._loaded=0;const s=t.source;this._withCredentials=s.withCredentials||!1;this._readCapability=Promise.withResolvers();this._isStreamingSupported=!s.disableStream;this._abortController=new AbortController;const n=new Headers(t.headers);n.append("Range",`bytes=${e}-${i-1}`);const a=s.url;fetch(a,createFetchOptions(n,this._withCredentials,this._abortController)).then((t=>{if(!validateResponseStatus(t.status))throw createResponseStatusError(t.status,a);this._readCapability.resolve();this._reader=t.body.getReader()})).catch(this._readCapability.reject);this.onProgress=null}get isStreamingSupported(){return this._isStreamingSupported}async read(){await this._readCapability.promise;const{value:t,done:e}=await this._reader.read();if(e)return{value:t,done:e};this._loaded+=t.byteLength;this.onProgress?.({loaded:this._loaded});return{value:getArrayBuffer(t),done:!1}}cancel(t){this._reader?.cancel(t);this._abortController.abort()}}class NetworkManager{constructor({url:t,httpHeaders:e,withCredentials:i}){this.url=t;this.isHttp=/^https?:/i.test(t);this.headers=createHeaders(this.isHttp,e);this.withCredentials=i||!1;this.currXhrId=0;this.pendingRequests=Object.create(null)}requestRange(t,e,i){const s={begin:t,end:e};for(const t in i)s[t]=i[t];return this.request(s)}requestFull(t){return this.request(t)}request(t){const e=new XMLHttpRequest,i=this.currXhrId++,s=this.pendingRequests[i]={xhr:e};e.open("GET",this.url);e.withCredentials=this.withCredentials;for(const[t,i]of this.headers)e.setRequestHeader(t,i);if(this.isHttp&&"begin"in t&&"end"in t){e.setRequestHeader("Range",`bytes=${t.begin}-${t.end-1}`);s.expectedStatus=206}else s.expectedStatus=200;e.responseType="arraybuffer";t.onError&&(e.onerror=function(i){t.onError(e.status)});e.onreadystatechange=this.onStateChange.bind(this,i);e.onprogress=this.onProgress.bind(this,i);s.onHeadersReceived=t.onHeadersReceived;s.onDone=t.onDone;s.onError=t.onError;s.onProgress=t.onProgress;e.send(null);return i}onProgress(t,e){const i=this.pendingRequests[t];i&&i.onProgress?.(e)}onStateChange(t,e){const i=this.pendingRequests[t];if(!i)return;const s=i.xhr;if(s.readyState>=2&&i.onHeadersReceived){i.onHeadersReceived();delete i.onHeadersReceived}if(4!==s.readyState)return;if(!(t in this.pendingRequests))return;delete this.pendingRequests[t];if(0===s.status&&this.isHttp){i.onError?.(s.status);return}const n=s.status||200;if(!(200===n&&206===i.expectedStatus)&&n!==i.expectedStatus){i.onError?.(s.status);return}const a=function network_getArrayBuffer(t){const e=t.response;return"string"!=typeof e?e:stringToBytes(e).buffer}(s);if(206===n){const t=s.getResponseHeader("Content-Range"),e=/bytes (\d+)-(\d+)\/(\d+)/.exec(t);i.onDone({begin:parseInt(e[1],10),chunk:a})}else a?i.onDone({begin:0,chunk:a}):i.onError?.(s.status)}getRequestXhr(t){return this.pendingRequests[t].xhr}isPendingRequest(t){return t in this.pendingRequests}abortRequest(t){const e=this.pendingRequests[t].xhr;delete this.pendingRequests[t];e.abort()}}class PDFNetworkStream{constructor(t){this._source=t;this._manager=new NetworkManager(t);this._rangeChunkSize=t.rangeChunkSize;this._fullRequestReader=null;this._rangeRequestReaders=[]}_onRangeRequestReaderClosed(t){const e=this._rangeRequestReaders.indexOf(t);e>=0&&this._rangeRequestReaders.splice(e,1)}getFullReader(){assert(!this._fullRequestReader,"PDFNetworkStream.getFullReader can only be called once.");this._fullRequestReader=new PDFNetworkStreamFullRequestReader(this._manager,this._source);return this._fullRequestReader}getRangeReader(t,e){const i=new PDFNetworkStreamRangeRequestReader(this._manager,t,e);i.onClosed=this._onRangeRequestReaderClosed.bind(this);this._rangeRequestReaders.push(i);return i}cancelAllRequests(t){this._fullRequestReader?.cancel(t);for(const e of this._rangeRequestReaders.slice(0))e.cancel(t)}}class PDFNetworkStreamFullRequestReader{constructor(t,e){this._manager=t;const i={onHeadersReceived:this._onHeadersReceived.bind(this),onDone:this._onDone.bind(this),onError:this._onError.bind(this),onProgress:this._onProgress.bind(this)};this._url=e.url;this._fullRequestId=t.requestFull(i);this._headersCapability=Promise.withResolvers();this._disableRange=e.disableRange||!1;this._contentLength=e.length;this._rangeChunkSize=e.rangeChunkSize;this._rangeChunkSize||this._disableRange||(this._disableRange=!0);this._isStreamingSupported=!1;this._isRangeSupported=!1;this._cachedChunks=[];this._requests=[];this._done=!1;this._storedError=void 0;this._filename=null;this.onProgress=null}_onHeadersReceived(){const t=this._fullRequestId,e=this._manager.getRequestXhr(t),i=new Headers(e.getAllResponseHeaders().trim().split(/[\r\n]+/).map((t=>{const[e,...i]=t.split(": ");return[e,i.join(": ")]}))),{allowRangeRequests:s,suggestedLength:n}=validateRangeRequestCapabilities({responseHeaders:i,isHttp:this._manager.isHttp,rangeChunkSize:this._rangeChunkSize,disableRange:this._disableRange});s&&(this._isRangeSupported=!0);this._contentLength=n||this._contentLength;this._filename=extractFilenameFromHeader(i);this._isRangeSupported&&this._manager.abortRequest(t);this._headersCapability.resolve()}_onDone(t){if(t)if(this._requests.length>0){this._requests.shift().resolve({value:t.chunk,done:!1})}else this._cachedChunks.push(t.chunk);this._done=!0;if(!(this._cachedChunks.length>0)){for(const t of this._requests)t.resolve({value:void 0,done:!0});this._requests.length=0}}_onError(t){this._storedError=createResponseStatusError(t,this._url);this._headersCapability.reject(this._storedError);for(const t of this._requests)t.reject(this._storedError);this._requests.length=0;this._cachedChunks.length=0}_onProgress(t){this.onProgress?.({loaded:t.loaded,total:t.lengthComputable?t.total:this._contentLength})}get filename(){return this._filename}get isRangeSupported(){return this._isRangeSupported}get isStreamingSupported(){return this._isStreamingSupported}get contentLength(){return this._contentLength}get headersReady(){return this._headersCapability.promise}async read(){if(this._storedError)throw this._storedError;if(this._cachedChunks.length>0){return{value:this._cachedChunks.shift(),done:!1}}if(this._done)return{value:void 0,done:!0};const t=Promise.withResolvers();this._requests.push(t);return t.promise}cancel(t){this._done=!0;this._headersCapability.reject(t);for(const t of this._requests)t.resolve({value:void 0,done:!0});this._requests.length=0;this._manager.isPendingRequest(this._fullRequestId)&&this._manager.abortRequest(this._fullRequestId);this._fullRequestReader=null}}class PDFNetworkStreamRangeRequestReader{constructor(t,e,i){this._manager=t;const s={onDone:this._onDone.bind(this),onError:this._onError.bind(this),onProgress:this._onProgress.bind(this)};this._url=t.url;this._requestId=t.requestRange(e,i,s);this._requests=[];this._queuedChunk=null;this._done=!1;this._storedError=void 0;this.onProgress=null;this.onClosed=null}_close(){this.onClosed?.(this)}_onDone(t){const e=t.chunk;if(this._requests.length>0){this._requests.shift().resolve({value:e,done:!1})}else this._queuedChunk=e;this._done=!0;for(const t of this._requests)t.resolve({value:void 0,done:!0});this._requests.length=0;this._close()}_onError(t){this._storedError=createResponseStatusError(t,this._url);for(const t of this._requests)t.reject(this._storedError);this._requests.length=0;this._queuedChunk=null}_onProgress(t){this.isStreamingSupported||this.onProgress?.({loaded:t.loaded})}get isStreamingSupported(){return!1}async read(){if(this._storedError)throw this._storedError;if(null!==this._queuedChunk){const t=this._queuedChunk;this._queuedChunk=null;return{value:t,done:!1}}if(this._done)return{value:void 0,done:!0};const t=Promise.withResolvers();this._requests.push(t);return t.promise}cancel(t){this._done=!0;for(const t of this._requests)t.resolve({value:void 0,done:!0});this._requests.length=0;this._manager.isPendingRequest(this._requestId)&&this._manager.abortRequest(this._requestId);this._close()}}const Ut=/^[a-z][a-z0-9\-+.]+:/i;function createRequest(t,e,i){if("http:"===t.protocol){return NodePackages.get("http").request(t,{headers:e},i)}return NodePackages.get("https").request(t,{headers:e},i)}class PDFNodeStream{constructor(t){this.source=t;this.url=function parseUrlOrPath(t){if(Ut.test(t))return new URL(t);const e=NodePackages.get("url");return new URL(e.pathToFileURL(t))}(t.url);this.isHttp="http:"===this.url.protocol||"https:"===this.url.protocol;this.isFsUrl="file:"===this.url.protocol;this.headers=createHeaders(this.isHttp,t.httpHeaders);this._fullRequestReader=null;this._rangeRequestReaders=[]}get _progressiveDataLength(){return this._fullRequestReader?._loaded??0}getFullReader(){assert(!this._fullRequestReader,"PDFNodeStream.getFullReader can only be called once.");this._fullRequestReader=this.isFsUrl?new PDFNodeStreamFsFullReader(this):new PDFNodeStreamFullReader(this);return this._fullRequestReader}getRangeReader(t,e){if(e<=this._progressiveDataLength)return null;const i=this.isFsUrl?new PDFNodeStreamFsRangeReader(this,t,e):new PDFNodeStreamRangeReader(this,t,e);this._rangeRequestReaders.push(i);return i}cancelAllRequests(t){this._fullRequestReader?.cancel(t);for(const e of this._rangeRequestReaders.slice(0))e.cancel(t)}}class BaseFullReader{constructor(t){this._url=t.url;this._done=!1;this._storedError=null;this.onProgress=null;const e=t.source;this._contentLength=e.length;this._loaded=0;this._filename=null;this._disableRange=e.disableRange||!1;this._rangeChunkSize=e.rangeChunkSize;this._rangeChunkSize||this._disableRange||(this._disableRange=!0);this._isStreamingSupported=!e.disableStream;this._isRangeSupported=!e.disableRange;this._readableStream=null;this._readCapability=Promise.withResolvers();this._headersCapability=Promise.withResolvers()}get headersReady(){return this._headersCapability.promise}get filename(){return this._filename}get contentLength(){return this._contentLength}get isRangeSupported(){return this._isRangeSupported}get isStreamingSupported(){return this._isStreamingSupported}async read(){await this._readCapability.promise;if(this._done)return{value:void 0,done:!0};if(this._storedError)throw this._storedError;const t=this._readableStream.read();if(null===t){this._readCapability=Promise.withResolvers();return this.read()}this._loaded+=t.length;this.onProgress?.({loaded:this._loaded,total:this._contentLength});return{value:new Uint8Array(t).buffer,done:!1}}cancel(t){this._readableStream?this._readableStream.destroy(t):this._error(t)}_error(t){this._storedError=t;this._readCapability.resolve()}_setReadableStream(t){this._readableStream=t;t.on("readable",(()=>{this._readCapability.resolve()}));t.on("end",(()=>{t.destroy();this._done=!0;this._readCapability.resolve()}));t.on("error",(t=>{this._error(t)}));!this._isStreamingSupported&&this._isRangeSupported&&this._error(new AbortException("streaming is disabled"));this._storedError&&this._readableStream.destroy(this._storedError)}}class BaseRangeReader{constructor(t){this._url=t.url;this._done=!1;this._storedError=null;this.onProgress=null;this._loaded=0;this._readableStream=null;this._readCapability=Promise.withResolvers();const e=t.source;this._isStreamingSupported=!e.disableStream}get isStreamingSupported(){return this._isStreamingSupported}async read(){await this._readCapability.promise;if(this._done)return{value:void 0,done:!0};if(this._storedError)throw this._storedError;const t=this._readableStream.read();if(null===t){this._readCapability=Promise.withResolvers();return this.read()}this._loaded+=t.length;this.onProgress?.({loaded:this._loaded});return{value:new Uint8Array(t).buffer,done:!1}}cancel(t){this._readableStream?this._readableStream.destroy(t):this._error(t)}_error(t){this._storedError=t;this._readCapability.resolve()}_setReadableStream(t){this._readableStream=t;t.on("readable",(()=>{this._readCapability.resolve()}));t.on("end",(()=>{t.destroy();this._done=!0;this._readCapability.resolve()}));t.on("error",(t=>{this._error(t)}));this._storedError&&this._readableStream.destroy(this._storedError)}}class PDFNodeStreamFullReader extends BaseFullReader{constructor(t){super(t);const e=Object.fromEntries(t.headers);this._request=createRequest(this._url,e,(e=>{if(404===e.statusCode){const t=new MissingPDFException(`Missing PDF "${this._url}".`);this._storedError=t;this._headersCapability.reject(t);return}this._headersCapability.resolve();this._setReadableStream(e);const i=new Headers(this._readableStream.headers),{allowRangeRequests:s,suggestedLength:n}=validateRangeRequestCapabilities({responseHeaders:i,isHttp:t.isHttp,rangeChunkSize:this._rangeChunkSize,disableRange:this._disableRange});this._isRangeSupported=s;this._contentLength=n||this._contentLength;this._filename=extractFilenameFromHeader(i)}));this._request.on("error",(t=>{this._storedError=t;this._headersCapability.reject(t)}));this._request.end()}}class PDFNodeStreamRangeReader extends BaseRangeReader{constructor(t,e,i){super(t);const s=Object.fromEntries(t.headers);s.Range=`bytes=${e}-${i-1}`;this._request=createRequest(this._url,s,(t=>{if(404!==t.statusCode)this._setReadableStream(t);else{const t=new MissingPDFException(`Missing PDF "${this._url}".`);this._storedError=t}}));this._request.on("error",(t=>{this._storedError=t}));this._request.end()}}class PDFNodeStreamFsFullReader extends BaseFullReader{constructor(t){super(t);const e=NodePackages.get("fs");e.promises.lstat(this._url).then((t=>{this._contentLength=t.size;this._setReadableStream(e.createReadStream(this._url));this._headersCapability.resolve()}),(t=>{"ENOENT"===t.code&&(t=new MissingPDFException(`Missing PDF "${this._url}".`));this._storedError=t;this._headersCapability.reject(t)}))}}class PDFNodeStreamFsRangeReader extends BaseRangeReader{constructor(t,e,i){super(t);const s=NodePackages.get("fs");this._setReadableStream(s.createReadStream(this._url,{start:e,end:i-1}))}}const jt=30;class TextLayer{#Je=Promise.withResolvers();#ut=null;#Ze=!1;#ti=!!globalThis.FontInspector?.enabled;#ei=null;#ii=null;#si=0;#ni=0;#ai=null;#ri=null;#oi=0;#li=0;#hi=Object.create(null);#di=[];#ci=null;#ui=[];#pi=new WeakMap;#gi=null;static#mi=new Map;static#fi=new Map;static#bi=new WeakMap;static#Ai=null;static#vi=new Set;constructor({textContentSource:t,container:e,viewport:i}){if(t instanceof ReadableStream)this.#ci=t;else{if("object"!=typeof t)throw new Error('No "textContentSource" parameter specified.');this.#ci=new ReadableStream({start(e){e.enqueue(t);e.close()}})}this.#ut=this.#ri=e;this.#li=i.scale*(globalThis.devicePixelRatio||1);this.#oi=i.rotation;this.#ii={div:null,properties:null,ctx:null};const{pageWidth:s,pageHeight:n,pageX:a,pageY:r}=i.rawDims;this.#gi=[1,0,0,-1,-a,r+n];this.#ni=s;this.#si=n;TextLayer.#yi();setLayerDimensions(e,i);this.#Je.promise.finally((()=>{TextLayer.#vi.delete(this);this.#ii=null;this.#hi=null})).catch((()=>{}))}static get fontFamilyMap(){const{isWindows:t,isFirefox:e}=util_FeatureTest.platform;return shadow(this,"fontFamilyMap",new Map([["sans-serif",(t&&e?"Calibri, ":"")+"sans-serif"],["monospace",(t&&e?"Lucida Console, ":"")+"monospace"]]))}render(){const pump=()=>{this.#ai.read().then((({value:t,done:e})=>{if(e)this.#Je.resolve();else{this.#ei??=t.lang;Object.assign(this.#hi,t.styles);this.#wi(t.items);pump()}}),this.#Je.reject)};this.#ai=this.#ci.getReader();TextLayer.#vi.add(this);pump();return this.#Je.promise}update({viewport:t,onBefore:e=null}){const i=t.scale*(globalThis.devicePixelRatio||1),s=t.rotation;if(s!==this.#oi){e?.();this.#oi=s;setLayerDimensions(this.#ri,{rotation:s})}if(i!==this.#li){e?.();this.#li=i;const t={div:null,properties:null,ctx:TextLayer.#xi(this.#ei)};for(const e of this.#ui){t.properties=this.#pi.get(e);t.div=e;this.#_i(t)}}}cancel(){const t=new AbortException("TextLayer task cancelled.");this.#ai?.cancel(t).catch((()=>{}));this.#ai=null;this.#Je.reject(t)}get textDivs(){return this.#ui}get textContentItemsStr(){return this.#di}#wi(t){if(this.#Ze)return;this.#ii.ctx??=TextLayer.#xi(this.#ei);const e=this.#ui,i=this.#di;for(const s of t){if(e.length>1e5){warn("Ignoring additional textDivs for performance reasons.");this.#Ze=!0;return}if(void 0!==s.str){i.push(s.str);this.#Ei(s)}else if("beginMarkedContentProps"===s.type||"beginMarkedContent"===s.type){const t=this.#ut;this.#ut=document.createElement("span");this.#ut.classList.add("markedContent");null!==s.id&&this.#ut.setAttribute("id",`${s.id}`);t.append(this.#ut)}else"endMarkedContent"===s.type&&(this.#ut=this.#ut.parentNode)}}#Ei(t){const e=document.createElement("span"),i={angle:0,canvasWidth:0,hasText:""!==t.str,hasEOL:t.hasEOL,fontSize:0};this.#ui.push(e);const s=Util.transform(this.#gi,t.transform);let n=Math.atan2(s[1],s[0]);const a=this.#hi[t.fontName];a.vertical&&(n+=Math.PI/2);let r=this.#ti&&a.fontSubstitution||a.fontFamily;r=TextLayer.fontFamilyMap.get(r)||r;const o=Math.hypot(s[2],s[3]),l=o*TextLayer.#Ci(r,this.#ei);let h,d;if(0===n){h=s[4];d=s[5]-l}else{h=s[4]+l*Math.sin(n);d=s[5]-l*Math.cos(n)}const c="calc(var(--scale-factor)*",u=e.style;if(this.#ut===this.#ri){u.left=`${(100*h/this.#ni).toFixed(2)}%`;u.top=`${(100*d/this.#si).toFixed(2)}%`}else{u.left=`${c}${h.toFixed(2)}px)`;u.top=`${c}${d.toFixed(2)}px)`}u.fontSize=`${c}${(TextLayer.#Ai*o).toFixed(2)}px)`;u.fontFamily=r;i.fontSize=o;e.setAttribute("role","presentation");e.textContent=t.str;e.dir=t.dir;this.#ti&&(e.dataset.fontName=a.fontSubstitutionLoadedName||t.fontName);0!==n&&(i.angle=n*(180/Math.PI));let p=!1;if(t.str.length>1)p=!0;else if(" "!==t.str&&t.transform[0]!==t.transform[3]){const e=Math.abs(t.transform[0]),i=Math.abs(t.transform[3]);e!==i&&Math.max(e,i)/Math.min(e,i)>1.5&&(p=!0)}p&&(i.canvasWidth=a.vertical?t.height:t.width);this.#pi.set(e,i);this.#ii.div=e;this.#ii.properties=i;this.#_i(this.#ii);i.hasText&&this.#ut.append(e);if(i.hasEOL){const t=document.createElement("br");t.setAttribute("role","presentation");this.#ut.append(t)}}#_i(t){const{div:e,properties:i,ctx:s}=t,{style:n}=e;let a="";TextLayer.#Ai>1&&(a=`scale(${1/TextLayer.#Ai})`);if(0!==i.canvasWidth&&i.hasText){const{fontFamily:t}=n,{canvasWidth:r,fontSize:o}=i;TextLayer.#Si(s,o*this.#li,t);const{width:l}=s.measureText(e.textContent);l>0&&(a=`scaleX(${r*this.#li/l}) ${a}`)}0!==i.angle&&(a=`rotate(${i.angle}deg) ${a}`);a.length>0&&(n.transform=a)}static cleanup(){if(!(this.#vi.size>0)){this.#mi.clear();for(const{canvas:t}of this.#fi.values())t.remove();this.#fi.clear()}}static#xi(t=null){let e=this.#fi.get(t||="");if(!e){const i=document.createElement("canvas");i.className="hiddenCanvasElement";i.lang=t;document.body.append(i);e=i.getContext("2d",{alpha:!1,willReadFrequently:!0});this.#fi.set(t,e);this.#bi.set(e,{size:0,family:""})}return e}static#Si(t,e,i){const s=this.#bi.get(t);if(e!==s.size||i!==s.family){t.font=`${e}px ${i}`;s.size=e;s.family=i}}static#yi(){if(null!==this.#Ai)return;const t=document.createElement("div");t.style.opacity=0;t.style.lineHeight=1;t.style.fontSize="1px";t.style.position="absolute";t.textContent="X";document.body.append(t);this.#Ai=t.getBoundingClientRect().height;t.remove()}static#Ci(t,e){const i=this.#mi.get(t);if(i)return i;const s=this.#xi(e);s.canvas.width=s.canvas.height=jt;this.#Si(s,jt,t);const n=s.measureText("");let a=n.fontBoundingBoxAscent,r=Math.abs(n.fontBoundingBoxDescent);if(a){const e=a/(a+r);this.#mi.set(t,e);s.canvas.width=s.canvas.height=0;return e}s.strokeStyle="red";s.clearRect(0,0,jt,jt);s.strokeText("g",0,0);let o=s.getImageData(0,0,jt,jt).data;r=0;for(let t=o.length-1-3;t>=0;t-=4)if(o[t]>0){r=Math.ceil(t/4/jt);break}s.clearRect(0,0,jt,jt);s.strokeText("A",0,jt);o=s.getImageData(0,0,jt,jt).data;a=0;for(let t=0,e=o.length;t0){a=jt-Math.floor(t/4/jt);break}s.canvas.width=s.canvas.height=0;const l=a?a/(a+r):.8;this.#mi.set(t,l);return l}}class XfaText{static textContent(t){const e=[],i={items:e,styles:Object.create(null)};!function walk(t){if(!t)return;let i=null;const s=t.name;if("#text"===s)i=t.value;else{if(!XfaText.shouldBuildText(s))return;t?.attributes?.textContent?i=t.attributes.textContent:t.value&&(i=t.value)}null!==i&&e.push({str:i});if(t.children)for(const e of t.children)walk(e)}(t);return i}static shouldBuildText(t){return!("textarea"===t||"input"===t||"option"===t||"select"===t)}}const Wt=65536,Gt=e?class NodeCanvasFactory extends BaseCanvasFactory{_createCanvas(t,e){return NodePackages.get("canvas").createCanvas(t,e)}}:class DOMCanvasFactory extends BaseCanvasFactory{constructor({ownerDocument:t=globalThis.document,enableHWA:e=!1}){super({enableHWA:e});this._document=t}_createCanvas(t,e){const i=this._document.createElement("canvas");i.width=t;i.height=e;return i}},$t=e?class NodeCMapReaderFactory extends BaseCMapReaderFactory{_fetchData(t,e){return node_utils_fetchData(t).then((t=>({cMapData:t,compressionType:e})))}}:DOMCMapReaderFactory,Vt=e?class NodeFilterFactory extends BaseFilterFactory{}:class DOMFilterFactory extends BaseFilterFactory{#Ti;#Mi;#ki;#Pi;#Fi;#Di;#v=0;constructor({docId:t,ownerDocument:e=globalThis.document}){super();this.#Pi=t;this.#Fi=e}get#w(){return this.#Mi||=new Map}get#Ri(){return this.#Di||=new Map}get#Ii(){if(!this.#ki){const t=this.#Fi.createElement("div"),{style:e}=t;e.visibility="hidden";e.contain="strict";e.width=e.height=0;e.position="absolute";e.top=e.left=0;e.zIndex=-1;const i=this.#Fi.createElementNS(ut,"svg");i.setAttribute("width",0);i.setAttribute("height",0);this.#ki=this.#Fi.createElementNS(ut,"defs");t.append(i);i.append(this.#ki);this.#Fi.body.append(t)}return this.#ki}#Li(t){if(1===t.length){const e=t[0],i=new Array(256);for(let t=0;t<256;t++)i[t]=e[t]/255;const s=i.join(",");return[s,s,s]}const[e,i,s]=t,n=new Array(256),a=new Array(256),r=new Array(256);for(let t=0;t<256;t++){n[t]=e[t]/255;a[t]=i[t]/255;r[t]=s[t]/255}return[n.join(","),a.join(","),r.join(",")]}#Ni(t){if(void 0===this.#Ti){this.#Ti="";const t=this.#Fi.URL;t!==this.#Fi.baseURI&&(isDataScheme(t)?warn('#createUrl: ignore "data:"-URL for performance reasons.'):this.#Ti=t.split("#",1)[0])}return`url(${this.#Ti}#${t})`}addFilter(t){if(!t)return"none";let e=this.#w.get(t);if(e)return e;const[i,s,n]=this.#Li(t),a=1===t.length?i:`${i}${s}${n}`;e=this.#w.get(a);if(e){this.#w.set(t,e);return e}const r=`g_${this.#Pi}_transfer_map_${this.#v++}`,o=this.#Ni(r);this.#w.set(t,o);this.#w.set(a,o);const l=this.#Oi(r);this.#Bi(i,s,n,l);return o}addHCMFilter(t,e){const i=`${t}-${e}`,s="base";let n=this.#Ri.get(s);if(n?.key===i)return n.url;if(n){n.filter?.remove();n.key=i;n.url="none";n.filter=null}else{n={key:i,url:"none",filter:null};this.#Ri.set(s,n)}if(!t||!e)return n.url;const a=this.#Hi(t);t=Util.makeHexColor(...a);const r=this.#Hi(e);e=Util.makeHexColor(...r);this.#Ii.style.color="";if("#000000"===t&&"#ffffff"===e||t===e)return n.url;const o=new Array(256);for(let t=0;t<=255;t++){const e=t/255;o[t]=e<=.03928?e/12.92:((e+.055)/1.055)**2.4}const l=o.join(","),h=`g_${this.#Pi}_hcm_filter`,d=n.filter=this.#Oi(h);this.#Bi(l,l,l,d);this.#zi(d);const getSteps=(t,e)=>{const i=a[t]/255,s=r[t]/255,n=new Array(e+1);for(let t=0;t<=e;t++)n[t]=i+t/e*(s-i);return n.join(",")};this.#Bi(getSteps(0,5),getSteps(1,5),getSteps(2,5),d);n.url=this.#Ni(h);return n.url}addAlphaFilter(t){let e=this.#w.get(t);if(e)return e;const[i]=this.#Li([t]),s=`alpha_${i}`;e=this.#w.get(s);if(e){this.#w.set(t,e);return e}const n=`g_${this.#Pi}_alpha_map_${this.#v++}`,a=this.#Ni(n);this.#w.set(t,a);this.#w.set(s,a);const r=this.#Oi(n);this.#Ui(i,r);return a}addLuminosityFilter(t){let e,i,s=this.#w.get(t||"luminosity");if(s)return s;if(t){[e]=this.#Li([t]);i=`luminosity_${e}`}else i="luminosity";s=this.#w.get(i);if(s){this.#w.set(t,s);return s}const n=`g_${this.#Pi}_luminosity_map_${this.#v++}`,a=this.#Ni(n);this.#w.set(t,a);this.#w.set(i,a);const r=this.#Oi(n);this.#ji(r);t&&this.#Ui(e,r);return a}addHighlightHCMFilter(t,e,i,s,n){const a=`${e}-${i}-${s}-${n}`;let r=this.#Ri.get(t);if(r?.key===a)return r.url;if(r){r.filter?.remove();r.key=a;r.url="none";r.filter=null}else{r={key:a,url:"none",filter:null};this.#Ri.set(t,r)}if(!e||!i)return r.url;const[o,l]=[e,i].map(this.#Hi.bind(this));let h=Math.round(.2126*o[0]+.7152*o[1]+.0722*o[2]),d=Math.round(.2126*l[0]+.7152*l[1]+.0722*l[2]),[c,u]=[s,n].map(this.#Hi.bind(this));d{const s=new Array(256),n=(d-h)/i,a=t/255,r=(e-t)/(255*i);let o=0;for(let t=0;t<=i;t++){const e=Math.round(h+t*n),i=a+t*r;for(let t=o;t<=e;t++)s[t]=i;o=e+1}for(let t=o;t<256;t++)s[t]=s[o-1];return s.join(",")},p=`g_${this.#Pi}_hcm_${t}_filter`,g=r.filter=this.#Oi(p);this.#zi(g);this.#Bi(getSteps(c[0],u[0],5),getSteps(c[1],u[1],5),getSteps(c[2],u[2],5),g);r.url=this.#Ni(p);return r.url}destroy(t=!1){if(!t||0===this.#Ri.size){if(this.#ki){this.#ki.parentNode.parentNode.remove();this.#ki=null}if(this.#Mi){this.#Mi.clear();this.#Mi=null}this.#v=0}}#ji(t){const e=this.#Fi.createElementNS(ut,"feColorMatrix");e.setAttribute("type","matrix");e.setAttribute("values","0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.3 0.59 0.11 0 0");t.append(e)}#zi(t){const e=this.#Fi.createElementNS(ut,"feColorMatrix");e.setAttribute("type","matrix");e.setAttribute("values","0.2126 0.7152 0.0722 0 0 0.2126 0.7152 0.0722 0 0 0.2126 0.7152 0.0722 0 0 0 0 0 1 0");t.append(e)}#Oi(t){const e=this.#Fi.createElementNS(ut,"filter");e.setAttribute("color-interpolation-filters","sRGB");e.setAttribute("id",t);this.#Ii.append(e);return e}#Wi(t,e,i){const s=this.#Fi.createElementNS(ut,e);s.setAttribute("type","discrete");s.setAttribute("tableValues",i);t.append(s)}#Bi(t,e,i,s){const n=this.#Fi.createElementNS(ut,"feComponentTransfer");s.append(n);this.#Wi(n,"feFuncR",t);this.#Wi(n,"feFuncG",e);this.#Wi(n,"feFuncB",i)}#Ui(t,e){const i=this.#Fi.createElementNS(ut,"feComponentTransfer");e.append(i);this.#Wi(i,"feFuncA",t)}#Hi(t){this.#Ii.style.color=t;return getRGB(getComputedStyle(this.#Ii).getPropertyValue("color"))}},qt=e?class NodeStandardFontDataFactory extends BaseStandardFontDataFactory{_fetchData(t){return node_utils_fetchData(t)}}:DOMStandardFontDataFactory;function getDocument(t={}){"string"==typeof t||t instanceof URL?t={url:t}:(t instanceof ArrayBuffer||ArrayBuffer.isView(t))&&(t={data:t});const i=new PDFDocumentLoadingTask,{docId:s}=i,n=t.url?function getUrlProp(t){if(t instanceof URL)return t.href;try{return new URL(t,window.location).href}catch{if(e&&"string"==typeof t)return t}throw new Error("Invalid PDF url data: either string or URL-object is expected in the url property.")}(t.url):null,a=t.data?function getDataProp(t){if(e&&"undefined"!=typeof Buffer&&t instanceof Buffer)throw new Error("Please provide binary data as `Uint8Array`, rather than `Buffer`.");if(t instanceof Uint8Array&&t.byteLength===t.buffer.byteLength)return t;if("string"==typeof t)return stringToBytes(t);if(t instanceof ArrayBuffer||ArrayBuffer.isView(t)||"object"==typeof t&&!isNaN(t?.length))return new Uint8Array(t);throw new Error("Invalid PDF binary data: either TypedArray, string, or array-like object is expected in the data property.")}(t.data):null,r=t.httpHeaders||null,o=!0===t.withCredentials,l=t.password??null,h=t.range instanceof PDFDataRangeTransport?t.range:null,d=Number.isInteger(t.rangeChunkSize)&&t.rangeChunkSize>0?t.rangeChunkSize:Wt;let c=t.worker instanceof PDFWorker?t.worker:null;const u=t.verbosity,p="string"!=typeof t.docBaseUrl||isDataScheme(t.docBaseUrl)?null:t.docBaseUrl,g="string"==typeof t.cMapUrl?t.cMapUrl:null,m=!1!==t.cMapPacked,f=t.CMapReaderFactory||$t,b="string"==typeof t.standardFontDataUrl?t.standardFontDataUrl:null,A=t.StandardFontDataFactory||qt,v=!0!==t.stopAtErrors,y=Number.isInteger(t.maxImageSize)&&t.maxImageSize>-1?t.maxImageSize:-1,w=!1!==t.isEvalSupported,x="boolean"==typeof t.isOffscreenCanvasSupported?t.isOffscreenCanvasSupported:!e,_=Number.isInteger(t.canvasMaxAreaInBytes)?t.canvasMaxAreaInBytes:-1,E="boolean"==typeof t.disableFontFace?t.disableFontFace:e,C=!0===t.fontExtraProperties,S=!0===t.enableXfa,T=t.ownerDocument||globalThis.document,M=!0===t.disableRange,k=!0===t.disableStream,P=!0===t.disableAutoFetch,F=!0===t.pdfBug,D=t.CanvasFactory||Gt,R=t.FilterFactory||Vt,I=!0===t.enableHWA,L=h?h.length:t.length??NaN,N="boolean"==typeof t.useSystemFonts?t.useSystemFonts:!e&&!E,O="boolean"==typeof t.useWorkerFetch?t.useWorkerFetch:f===DOMCMapReaderFactory&&A===DOMStandardFontDataFactory&&g&&b&&isValidFetchUrl(g,document.baseURI)&&isValidFetchUrl(b,document.baseURI);t.canvasFactory&&deprecated("`canvasFactory`-instance option, please use `CanvasFactory` instead.");t.filterFactory&&deprecated("`filterFactory`-instance option, please use `FilterFactory` instead.");setVerbosityLevel(u);const B={canvasFactory:new D({ownerDocument:T,enableHWA:I}),filterFactory:new R({docId:s,ownerDocument:T}),cMapReaderFactory:O?null:new f({baseUrl:g,isCompressed:m}),standardFontDataFactory:O?null:new A({baseUrl:b})};if(!c){const t={verbosity:u,port:GlobalWorkerOptions.workerPort};c=t.port?PDFWorker.fromPort(t):new PDFWorker(t);i._worker=c}const H={docId:s,apiVersion:"4.7.76",data:a,password:l,disableAutoFetch:P,rangeChunkSize:d,length:L,docBaseUrl:p,enableXfa:S,evaluatorOptions:{maxImageSize:y,disableFontFace:E,ignoreErrors:v,isEvalSupported:w,isOffscreenCanvasSupported:x,canvasMaxAreaInBytes:_,fontExtraProperties:C,useSystemFonts:N,cMapUrl:O?g:null,standardFontDataUrl:O?b:null}},z={disableFontFace:E,fontExtraProperties:C,ownerDocument:T,pdfBug:F,styleElement:null,loadingParams:{disableAutoFetch:P,enableXfa:S}};c.promise.then((function(){if(i.destroyed)throw new Error("Loading aborted");if(c.destroyed)throw new Error("Worker was destroyed");const t=c.messageHandler.sendWithPromise("GetDocRequest",H,a?[a.buffer]:null);let l;if(h)l=new PDFDataTransportStream(h,{disableRange:M,disableStream:k});else if(!a){if(!n)throw new Error("getDocument - no `url` parameter provided.");let t;if(e){t="undefined"!=typeof fetch&&"undefined"!=typeof Response&&"body"in Response.prototype&&isValidFetchUrl(n)?PDFFetchStream:PDFNodeStream}else t=isValidFetchUrl(n)?PDFFetchStream:PDFNetworkStream;l=new t({url:n,length:L,httpHeaders:r,withCredentials:o,rangeChunkSize:d,disableRange:M,disableStream:k})}return t.then((t=>{if(i.destroyed)throw new Error("Loading aborted");if(c.destroyed)throw new Error("Worker was destroyed");const e=new MessageHandler(s,t,c.port),n=new WorkerTransport(e,i,l,z,B);i._transport=n;e.send("Ready",null)}))})).catch(i._capability.reject);return i}function isRefProxy(t){return"object"==typeof t&&Number.isInteger(t?.num)&&t.num>=0&&Number.isInteger(t?.gen)&&t.gen>=0}class PDFDocumentLoadingTask{static#Pi=0;constructor(){this._capability=Promise.withResolvers();this._transport=null;this._worker=null;this.docId="d"+PDFDocumentLoadingTask.#Pi++;this.destroyed=!1;this.onPassword=null;this.onProgress=null}get promise(){return this._capability.promise}async destroy(){this.destroyed=!0;try{this._worker?.port&&(this._worker._pendingDestroy=!0);await(this._transport?.destroy())}catch(t){this._worker?.port&&delete this._worker._pendingDestroy;throw t}this._transport=null;if(this._worker){this._worker.destroy();this._worker=null}}}class PDFDataRangeTransport{constructor(t,e,i=!1,s=null){this.length=t;this.initialData=e;this.progressiveDone=i;this.contentDispositionFilename=s;this._rangeListeners=[];this._progressListeners=[];this._progressiveReadListeners=[];this._progressiveDoneListeners=[];this._readyCapability=Promise.withResolvers()}addRangeListener(t){this._rangeListeners.push(t)}addProgressListener(t){this._progressListeners.push(t)}addProgressiveReadListener(t){this._progressiveReadListeners.push(t)}addProgressiveDoneListener(t){this._progressiveDoneListeners.push(t)}onDataRange(t,e){for(const i of this._rangeListeners)i(t,e)}onDataProgress(t,e){this._readyCapability.promise.then((()=>{for(const i of this._progressListeners)i(t,e)}))}onDataProgressiveRead(t){this._readyCapability.promise.then((()=>{for(const e of this._progressiveReadListeners)e(t)}))}onDataProgressiveDone(){this._readyCapability.promise.then((()=>{for(const t of this._progressiveDoneListeners)t()}))}transportReady(){this._readyCapability.resolve()}requestDataRange(t,e){unreachable("Abstract method PDFDataRangeTransport.requestDataRange")}abort(){}}class PDFDocumentProxy{constructor(t,e){this._pdfInfo=t;this._transport=e}get annotationStorage(){return this._transport.annotationStorage}get canvasFactory(){return this._transport.canvasFactory}get filterFactory(){return this._transport.filterFactory}get numPages(){return this._pdfInfo.numPages}get fingerprints(){return this._pdfInfo.fingerprints}get isPureXfa(){return shadow(this,"isPureXfa",!!this._transport._htmlForXfa)}get allXfaHtml(){return this._transport._htmlForXfa}getPage(t){return this._transport.getPage(t)}getPageIndex(t){return this._transport.getPageIndex(t)}getDestinations(){return this._transport.getDestinations()}getDestination(t){return this._transport.getDestination(t)}getPageLabels(){return this._transport.getPageLabels()}getPageLayout(){return this._transport.getPageLayout()}getPageMode(){return this._transport.getPageMode()}getViewerPreferences(){return this._transport.getViewerPreferences()}getOpenAction(){return this._transport.getOpenAction()}getAttachments(){return this._transport.getAttachments()}getJSActions(){return this._transport.getDocJSActions()}getOutline(){return this._transport.getOutline()}getOptionalContentConfig({intent:t="display"}={}){const{renderingIntent:e}=this._transport.getRenderingIntent(t);return this._transport.getOptionalContentConfig(e)}getPermissions(){return this._transport.getPermissions()}getMetadata(){return this._transport.getMetadata()}getMarkInfo(){return this._transport.getMarkInfo()}getData(){return this._transport.getData()}saveDocument(){return this._transport.saveDocument()}getDownloadInfo(){return this._transport.downloadInfoCapability.promise}cleanup(t=!1){return this._transport.startCleanup(t||this.isPureXfa)}destroy(){return this.loadingTask.destroy()}cachedPageNumber(t){return this._transport.cachedPageNumber(t)}get loadingParams(){return this._transport.loadingParams}get loadingTask(){return this._transport.loadingTask}getFieldObjects(){return this._transport.getFieldObjects()}hasJSActions(){return this._transport.hasJSActions()}getCalculationOrderIds(){return this._transport.getCalculationOrderIds()}}class PDFPageProxy{#Gi=null;#$i=!1;constructor(t,e,i,s=!1){this._pageIndex=t;this._pageInfo=e;this._transport=i;this._stats=s?new StatTimer:null;this._pdfBug=s;this.commonObjs=i.commonObjs;this.objs=new PDFObjects;this._maybeCleanupAfterRender=!1;this._intentStates=new Map;this.destroyed=!1}get pageNumber(){return this._pageIndex+1}get rotate(){return this._pageInfo.rotate}get ref(){return this._pageInfo.ref}get userUnit(){return this._pageInfo.userUnit}get view(){return this._pageInfo.view}getViewport({scale:t,rotation:e=this.rotate,offsetX:i=0,offsetY:s=0,dontFlip:n=!1}={}){return new PageViewport({viewBox:this.view,scale:t,rotation:e,offsetX:i,offsetY:s,dontFlip:n})}getAnnotations({intent:t="display"}={}){const{renderingIntent:e}=this._transport.getRenderingIntent(t);return this._transport.getAnnotations(this._pageIndex,e)}getJSActions(){return this._transport.getPageJSActions(this._pageIndex)}get filterFactory(){return this._transport.filterFactory}get isPureXfa(){return shadow(this,"isPureXfa",!!this._transport._htmlForXfa)}async getXfa(){return this._transport._htmlForXfa?.children[this._pageIndex]||null}render({canvasContext:t,viewport:e,intent:i="display",annotationMode:s=p.ENABLE,transform:n=null,background:a=null,optionalContentConfigPromise:r=null,annotationCanvasMap:l=null,pageColors:h=null,printAnnotationStorage:d=null,isEditing:c=!1}){this._stats?.time("Overall");const u=this._transport.getRenderingIntent(i,s,d,c),{renderingIntent:g,cacheKey:m}=u;this.#$i=!1;this.#Vi();r||=this._transport.getOptionalContentConfig(g);let f=this._intentStates.get(m);if(!f){f=Object.create(null);this._intentStates.set(m,f)}if(f.streamReaderCancelTimeout){clearTimeout(f.streamReaderCancelTimeout);f.streamReaderCancelTimeout=null}const b=!!(g&o);if(!f.displayReadyCapability){f.displayReadyCapability=Promise.withResolvers();f.operatorList={fnArray:[],argsArray:[],lastChunk:!1,separateAnnots:null};this._stats?.time("Page Request");this._pumpOperatorList(u)}const complete=t=>{f.renderTasks.delete(A);(this._maybeCleanupAfterRender||b)&&(this.#$i=!0);this.#qi(!b);if(t){A.capability.reject(t);this._abortOperatorList({intentState:f,reason:t instanceof Error?t:new Error(t)})}else A.capability.resolve();if(this._stats){this._stats.timeEnd("Rendering");this._stats.timeEnd("Overall");globalThis.Stats?.enabled&&globalThis.Stats.add(this.pageNumber,this._stats)}},A=new InternalRenderTask({callback:complete,params:{canvasContext:t,viewport:e,transform:n,background:a},objs:this.objs,commonObjs:this.commonObjs,annotationCanvasMap:l,operatorList:f.operatorList,pageIndex:this._pageIndex,canvasFactory:this._transport.canvasFactory,filterFactory:this._transport.filterFactory,useRequestAnimationFrame:!b,pdfBug:this._pdfBug,pageColors:h});(f.renderTasks||=new Set).add(A);const v=A.task;Promise.all([f.displayReadyCapability.promise,r]).then((([t,e])=>{if(this.destroyed)complete();else{this._stats?.time("Rendering");if(!(e.renderingIntent&g))throw new Error("Must use the same `intent`-argument when calling the `PDFPageProxy.render` and `PDFDocumentProxy.getOptionalContentConfig` methods.");A.initializeGraphics({transparency:t,optionalContentConfig:e});A.operatorListChanged()}})).catch(complete);return v}getOperatorList({intent:t="display",annotationMode:e=p.ENABLE,printAnnotationStorage:i=null,isEditing:s=!1}={}){const n=this._transport.getRenderingIntent(t,e,i,s,!0);let a,r=this._intentStates.get(n.cacheKey);if(!r){r=Object.create(null);this._intentStates.set(n.cacheKey,r)}if(!r.opListReadCapability){a=Object.create(null);a.operatorListChanged=function operatorListChanged(){if(r.operatorList.lastChunk){r.opListReadCapability.resolve(r.operatorList);r.renderTasks.delete(a)}};r.opListReadCapability=Promise.withResolvers();(r.renderTasks||=new Set).add(a);r.operatorList={fnArray:[],argsArray:[],lastChunk:!1,separateAnnots:null};this._stats?.time("Page Request");this._pumpOperatorList(n)}return r.opListReadCapability.promise}streamTextContent({includeMarkedContent:t=!1,disableNormalization:e=!1}={}){return this._transport.messageHandler.sendWithStream("GetTextContent",{pageIndex:this._pageIndex,includeMarkedContent:!0===t,disableNormalization:!0===e},{highWaterMark:100,size:t=>t.items.length})}getTextContent(t={}){if(this._transport._htmlForXfa)return this.getXfa().then((t=>XfaText.textContent(t)));const e=this.streamTextContent(t);return new Promise((function(t,i){const s=e.getReader(),n={items:[],styles:Object.create(null),lang:null};!function pump(){s.read().then((function({value:e,done:i}){if(i)t(n);else{n.lang??=e.lang;Object.assign(n.styles,e.styles);n.items.push(...e.items);pump()}}),i)}()}))}getStructTree(){return this._transport.getStructTree(this._pageIndex)}_destroy(){this.destroyed=!0;const t=[];for(const e of this._intentStates.values()){this._abortOperatorList({intentState:e,reason:new Error("Page was destroyed."),force:!0});if(!e.opListReadCapability)for(const i of e.renderTasks){t.push(i.completed);i.cancel()}}this.objs.clear();this.#$i=!1;this.#Vi();return Promise.all(t)}cleanup(t=!1){this.#$i=!0;const e=this.#qi(!1);t&&e&&(this._stats&&=new StatTimer);return e}#qi(t=!1){this.#Vi();if(!this.#$i||this.destroyed)return!1;if(t){this.#Gi=setTimeout((()=>{this.#Gi=null;this.#qi(!1)}),5e3);return!1}for(const{renderTasks:t,operatorList:e}of this._intentStates.values())if(t.size>0||!e.lastChunk)return!1;this._intentStates.clear();this.objs.clear();this.#$i=!1;return!0}#Vi(){if(this.#Gi){clearTimeout(this.#Gi);this.#Gi=null}}_startRenderPage(t,e){const i=this._intentStates.get(e);if(i){this._stats?.timeEnd("Page Request");i.displayReadyCapability?.resolve(t)}}_renderPageChunk(t,e){for(let i=0,s=t.length;i{r.read().then((({value:t,done:e})=>{if(e)o.streamReader=null;else if(!this._transport.destroyed){this._renderPageChunk(t,o);pump()}}),(t=>{o.streamReader=null;if(!this._transport.destroyed){if(o.operatorList){o.operatorList.lastChunk=!0;for(const t of o.renderTasks)t.operatorListChanged();this.#qi(!0)}if(o.displayReadyCapability)o.displayReadyCapability.reject(t);else{if(!o.opListReadCapability)throw t;o.opListReadCapability.reject(t)}}}))};pump()}_abortOperatorList({intentState:t,reason:e,force:i=!1}){if(t.streamReader){if(t.streamReaderCancelTimeout){clearTimeout(t.streamReaderCancelTimeout);t.streamReaderCancelTimeout=null}if(!i){if(t.renderTasks.size>0)return;if(e instanceof RenderingCancelledException){let i=100;e.extraDelay>0&&e.extraDelay<1e3&&(i+=e.extraDelay);t.streamReaderCancelTimeout=setTimeout((()=>{t.streamReaderCancelTimeout=null;this._abortOperatorList({intentState:t,reason:e,force:!0})}),i);return}}t.streamReader.cancel(new AbortException(e.message)).catch((()=>{}));t.streamReader=null;if(!this._transport.destroyed){for(const[e,i]of this._intentStates)if(i===t){this._intentStates.delete(e);break}this.cleanup()}}}get stats(){return this._stats}}class LoopbackPort{#Xi=new Set;#Ki=Promise.resolve();postMessage(t,e){const i={data:structuredClone(t,e?{transfer:e}:null)};this.#Ki.then((()=>{for(const t of this.#Xi)t.call(this,i)}))}addEventListener(t,e){this.#Xi.add(e)}removeEventListener(t,e){this.#Xi.delete(e)}terminate(){this.#Xi.clear()}}class PDFWorker{static#Yi=0;static#Qi=!1;static#Ji;static{if(e){this.#Qi=!0;GlobalWorkerOptions.workerSrc||="./pdf.worker.mjs"}this._isSameOrigin=(t,e)=>{let i;try{i=new URL(t);if(!i.origin||"null"===i.origin)return!1}catch{return!1}const s=new URL(e,i);return i.origin===s.origin};this._createCDNWrapper=t=>{const e=`await import("${t}");`;return URL.createObjectURL(new Blob([e],{type:"text/javascript"}))}}constructor({name:t=null,port:e=null,verbosity:i=getVerbosityLevel()}={}){this.name=t;this.destroyed=!1;this.verbosity=i;this._readyCapability=Promise.withResolvers();this._port=null;this._webWorker=null;this._messageHandler=null;if(e){if(PDFWorker.#Ji?.has(e))throw new Error("Cannot use more than one PDFWorker per port.");(PDFWorker.#Ji||=new WeakMap).set(e,this);this._initializeFromPort(e)}else this._initialize()}get promise(){return e?Promise.all([NodePackages.promise,this._readyCapability.promise]):this._readyCapability.promise}#Zi(){this._readyCapability.resolve();this._messageHandler.send("configure",{verbosity:this.verbosity})}get port(){return this._port}get messageHandler(){return this._messageHandler}_initializeFromPort(t){this._port=t;this._messageHandler=new MessageHandler("main","worker",t);this._messageHandler.on("ready",(function(){}));this.#Zi()}_initialize(){if(PDFWorker.#Qi||PDFWorker.#ts){this._setupFakeWorker();return}let{workerSrc:t}=PDFWorker;try{PDFWorker._isSameOrigin(window.location.href,t)||(t=PDFWorker._createCDNWrapper(new URL(t,window.location).href));const e=new Worker(t,{type:"module"}),i=new MessageHandler("main","worker",e),terminateEarly=()=>{s.abort();i.destroy();e.terminate();this.destroyed?this._readyCapability.reject(new Error("Worker was destroyed")):this._setupFakeWorker()},s=new AbortController;e.addEventListener("error",(()=>{this._webWorker||terminateEarly()}),{signal:s.signal});i.on("test",(t=>{s.abort();if(!this.destroyed&&t){this._messageHandler=i;this._port=e;this._webWorker=e;this.#Zi()}else terminateEarly()}));i.on("ready",(t=>{s.abort();if(this.destroyed)terminateEarly();else try{sendTest()}catch{this._setupFakeWorker()}}));const sendTest=()=>{const t=new Uint8Array;i.send("test",t,[t.buffer])};sendTest();return}catch{info("The worker has been disabled.")}this._setupFakeWorker()}_setupFakeWorker(){if(!PDFWorker.#Qi){warn("Setting up fake worker.");PDFWorker.#Qi=!0}PDFWorker._setupFakeWorkerGlobal.then((t=>{if(this.destroyed){this._readyCapability.reject(new Error("Worker was destroyed"));return}const e=new LoopbackPort;this._port=e;const i="fake"+PDFWorker.#Yi++,s=new MessageHandler(i+"_worker",i,e);t.setup(s,e);this._messageHandler=new MessageHandler(i,i+"_worker",e);this.#Zi()})).catch((t=>{this._readyCapability.reject(new Error(`Setting up fake worker failed: "${t.message}".`))}))}destroy(){this.destroyed=!0;if(this._webWorker){this._webWorker.terminate();this._webWorker=null}PDFWorker.#Ji?.delete(this._port);this._port=null;if(this._messageHandler){this._messageHandler.destroy();this._messageHandler=null}}static fromPort(t){if(!t?.port)throw new Error("PDFWorker.fromPort - invalid method signature.");const e=this.#Ji?.get(t.port);if(e){if(e._pendingDestroy)throw new Error("PDFWorker.fromPort - the worker is being destroyed.\nPlease remember to await `PDFDocumentLoadingTask.destroy()`-calls.");return e}return new PDFWorker(t)}static get workerSrc(){if(GlobalWorkerOptions.workerSrc)return GlobalWorkerOptions.workerSrc;throw new Error('No "GlobalWorkerOptions.workerSrc" specified.')}static get#ts(){try{return globalThis.pdfjsWorker?.WorkerMessageHandler||null}catch{return null}}static get _setupFakeWorkerGlobal(){return shadow(this,"_setupFakeWorkerGlobal",(async()=>{if(this.#ts)return this.#ts;return(await import(this.workerSrc)).WorkerMessageHandler})())}}class WorkerTransport{#es=new Map;#is=new Map;#ss=new Map;#ns=new Map;#as=null;constructor(t,e,i,s,n){this.messageHandler=t;this.loadingTask=e;this.commonObjs=new PDFObjects;this.fontLoader=new FontLoader({ownerDocument:s.ownerDocument,styleElement:s.styleElement});this.loadingParams=s.loadingParams;this._params=s;this.canvasFactory=n.canvasFactory;this.filterFactory=n.filterFactory;this.cMapReaderFactory=n.cMapReaderFactory;this.standardFontDataFactory=n.standardFontDataFactory;this.destroyed=!1;this.destroyCapability=null;this._networkStream=i;this._fullReader=null;this._lastProgress=null;this.downloadInfoCapability=Promise.withResolvers();this.setupMessageHandler()}#rs(t,e=null){const i=this.#es.get(t);if(i)return i;const s=this.messageHandler.sendWithPromise(t,e);this.#es.set(t,s);return s}get annotationStorage(){return shadow(this,"annotationStorage",new AnnotationStorage)}getRenderingIntent(t,e=p.ENABLE,i=null,s=!1,n=!1){let g=r,m=bt;switch(t){case"any":g=a;break;case"display":break;case"print":g=o;break;default:warn(`getRenderingIntent - invalid intent: ${t}`)}const f=g&o&&i instanceof PrintAnnotationStorage?i:this.annotationStorage;switch(e){case p.DISABLE:g+=d;break;case p.ENABLE:break;case p.ENABLE_FORMS:g+=l;break;case p.ENABLE_STORAGE:g+=h;m=f.serializable;break;default:warn(`getRenderingIntent - invalid annotationMode: ${e}`)}s&&(g+=c);n&&(g+=u);const{ids:b,hash:A}=f.modifiedIds;return{renderingIntent:g,cacheKey:[g,m.hash,A].join("_"),annotationStorageSerializable:m,modifiedIds:b}}destroy(){if(this.destroyCapability)return this.destroyCapability.promise;this.destroyed=!0;this.destroyCapability=Promise.withResolvers();this.#as?.reject(new Error("Worker was destroyed during onPassword callback"));const t=[];for(const e of this.#is.values())t.push(e._destroy());this.#is.clear();this.#ss.clear();this.#ns.clear();this.hasOwnProperty("annotationStorage")&&this.annotationStorage.resetModified();const e=this.messageHandler.sendWithPromise("Terminate",null);t.push(e);Promise.all(t).then((()=>{this.commonObjs.clear();this.fontLoader.clear();this.#es.clear();this.filterFactory.destroy();TextLayer.cleanup();this._networkStream?.cancelAllRequests(new AbortException("Worker was terminated."));if(this.messageHandler){this.messageHandler.destroy();this.messageHandler=null}this.destroyCapability.resolve()}),this.destroyCapability.reject);return this.destroyCapability.promise}setupMessageHandler(){const{messageHandler:t,loadingTask:e}=this;t.on("GetReader",((t,e)=>{assert(this._networkStream,"GetReader - no `IPDFStream` instance available.");this._fullReader=this._networkStream.getFullReader();this._fullReader.onProgress=t=>{this._lastProgress={loaded:t.loaded,total:t.total}};e.onPull=()=>{this._fullReader.read().then((function({value:t,done:i}){if(i)e.close();else{assert(t instanceof ArrayBuffer,"GetReader - expected an ArrayBuffer.");e.enqueue(new Uint8Array(t),1,[t])}})).catch((t=>{e.error(t)}))};e.onCancel=t=>{this._fullReader.cancel(t);e.ready.catch((t=>{if(!this.destroyed)throw t}))}}));t.on("ReaderHeadersReady",(t=>{const i=Promise.withResolvers(),s=this._fullReader;s.headersReady.then((()=>{if(!s.isStreamingSupported||!s.isRangeSupported){this._lastProgress&&e.onProgress?.(this._lastProgress);s.onProgress=t=>{e.onProgress?.({loaded:t.loaded,total:t.total})}}i.resolve({isStreamingSupported:s.isStreamingSupported,isRangeSupported:s.isRangeSupported,contentLength:s.contentLength})}),i.reject);return i.promise}));t.on("GetRangeReader",((t,e)=>{assert(this._networkStream,"GetRangeReader - no `IPDFStream` instance available.");const i=this._networkStream.getRangeReader(t.begin,t.end);if(i){e.onPull=()=>{i.read().then((function({value:t,done:i}){if(i)e.close();else{assert(t instanceof ArrayBuffer,"GetRangeReader - expected an ArrayBuffer.");e.enqueue(new Uint8Array(t),1,[t])}})).catch((t=>{e.error(t)}))};e.onCancel=t=>{i.cancel(t);e.ready.catch((t=>{if(!this.destroyed)throw t}))}}else e.close()}));t.on("GetDoc",(({pdfInfo:t})=>{this._numPages=t.numPages;this._htmlForXfa=t.htmlForXfa;delete t.htmlForXfa;e._capability.resolve(new PDFDocumentProxy(t,this))}));t.on("DocException",(function(t){let i;switch(t.name){case"PasswordException":i=new PasswordException(t.message,t.code);break;case"InvalidPDFException":i=new InvalidPDFException(t.message);break;case"MissingPDFException":i=new MissingPDFException(t.message);break;case"UnexpectedResponseException":i=new UnexpectedResponseException(t.message,t.status);break;case"UnknownErrorException":i=new UnknownErrorException(t.message,t.details);break;default:unreachable("DocException - expected a valid Error.")}e._capability.reject(i)}));t.on("PasswordRequest",(t=>{this.#as=Promise.withResolvers();if(e.onPassword){const updatePassword=t=>{t instanceof Error?this.#as.reject(t):this.#as.resolve({password:t})};try{e.onPassword(updatePassword,t.code)}catch(t){this.#as.reject(t)}}else this.#as.reject(new PasswordException(t.message,t.code));return this.#as.promise}));t.on("DataLoaded",(t=>{e.onProgress?.({loaded:t.length,total:t.length});this.downloadInfoCapability.resolve(t)}));t.on("StartRenderPage",(t=>{if(this.destroyed)return;this.#is.get(t.pageIndex)._startRenderPage(t.transparency,t.cacheKey)}));t.on("commonobj",(([e,i,s])=>{if(this.destroyed)return null;if(this.commonObjs.has(e))return null;switch(i){case"Font":const{disableFontFace:n,fontExtraProperties:a,pdfBug:r}=this._params;if("error"in s){const t=s.error;warn(`Error during font loading: ${t}`);this.commonObjs.resolve(e,t);break}const o=r&&globalThis.FontInspector?.enabled?(t,e)=>globalThis.FontInspector.fontAdded(t,e):null,l=new FontFaceObject(s,{disableFontFace:n,inspectFont:o});this.fontLoader.bind(l).catch((()=>t.sendWithPromise("FontFallback",{id:e}))).finally((()=>{!a&&l.data&&(l.data=null);this.commonObjs.resolve(e,l)}));break;case"CopyLocalImage":const{imageRef:h}=s;assert(h,"The imageRef must be defined.");for(const t of this.#is.values())for(const[,i]of t.objs)if(i?.ref===h){if(!i.dataLen)return null;this.commonObjs.resolve(e,structuredClone(i));return i.dataLen}break;case"FontPath":case"Image":case"Pattern":this.commonObjs.resolve(e,s);break;default:throw new Error(`Got unknown common object type ${i}`)}return null}));t.on("obj",(([t,e,i,s])=>{if(this.destroyed)return;const n=this.#is.get(e);if(!n.objs.has(t))if(0!==n._intentStates.size)switch(i){case"Image":n.objs.resolve(t,s);s?.dataLen>1e7&&(n._maybeCleanupAfterRender=!0);break;case"Pattern":n.objs.resolve(t,s);break;default:throw new Error(`Got unknown object type ${i}`)}else s?.bitmap?.close()}));t.on("DocProgress",(t=>{this.destroyed||e.onProgress?.({loaded:t.loaded,total:t.total})}));t.on("FetchBuiltInCMap",(t=>this.destroyed?Promise.reject(new Error("Worker was destroyed.")):this.cMapReaderFactory?this.cMapReaderFactory.fetch(t):Promise.reject(new Error("CMapReaderFactory not initialized, see the `useWorkerFetch` parameter."))));t.on("FetchStandardFontData",(t=>this.destroyed?Promise.reject(new Error("Worker was destroyed.")):this.standardFontDataFactory?this.standardFontDataFactory.fetch(t):Promise.reject(new Error("StandardFontDataFactory not initialized, see the `useWorkerFetch` parameter."))))}getData(){return this.messageHandler.sendWithPromise("GetData",null)}saveDocument(){this.annotationStorage.size<=0&&warn("saveDocument called while `annotationStorage` is empty, please use the getData-method instead.");const{map:t,transfer:e}=this.annotationStorage.serializable;return this.messageHandler.sendWithPromise("SaveDocument",{isPureXfa:!!this._htmlForXfa,numPages:this._numPages,annotationStorage:t,filename:this._fullReader?.filename??null},e).finally((()=>{this.annotationStorage.resetModified()}))}getPage(t){if(!Number.isInteger(t)||t<=0||t>this._numPages)return Promise.reject(new Error("Invalid page request."));const e=t-1,i=this.#ss.get(e);if(i)return i;const s=this.messageHandler.sendWithPromise("GetPage",{pageIndex:e}).then((i=>{if(this.destroyed)throw new Error("Transport destroyed");i.refStr&&this.#ns.set(i.refStr,t);const s=new PDFPageProxy(e,i,this,this._params.pdfBug);this.#is.set(e,s);return s}));this.#ss.set(e,s);return s}getPageIndex(t){return isRefProxy(t)?this.messageHandler.sendWithPromise("GetPageIndex",{num:t.num,gen:t.gen}):Promise.reject(new Error("Invalid pageIndex request."))}getAnnotations(t,e){return this.messageHandler.sendWithPromise("GetAnnotations",{pageIndex:t,intent:e})}getFieldObjects(){return this.#rs("GetFieldObjects")}hasJSActions(){return this.#rs("HasJSActions")}getCalculationOrderIds(){return this.messageHandler.sendWithPromise("GetCalculationOrderIds",null)}getDestinations(){return this.messageHandler.sendWithPromise("GetDestinations",null)}getDestination(t){return"string"!=typeof t?Promise.reject(new Error("Invalid destination request.")):this.messageHandler.sendWithPromise("GetDestination",{id:t})}getPageLabels(){return this.messageHandler.sendWithPromise("GetPageLabels",null)}getPageLayout(){return this.messageHandler.sendWithPromise("GetPageLayout",null)}getPageMode(){return this.messageHandler.sendWithPromise("GetPageMode",null)}getViewerPreferences(){return this.messageHandler.sendWithPromise("GetViewerPreferences",null)}getOpenAction(){return this.messageHandler.sendWithPromise("GetOpenAction",null)}getAttachments(){return this.messageHandler.sendWithPromise("GetAttachments",null)}getDocJSActions(){return this.#rs("GetDocJSActions")}getPageJSActions(t){return this.messageHandler.sendWithPromise("GetPageJSActions",{pageIndex:t})}getStructTree(t){return this.messageHandler.sendWithPromise("GetStructTree",{pageIndex:t})}getOutline(){return this.messageHandler.sendWithPromise("GetOutline",null)}getOptionalContentConfig(t){return this.#rs("GetOptionalContentConfig").then((e=>new OptionalContentConfig(e,t)))}getPermissions(){return this.messageHandler.sendWithPromise("GetPermissions",null)}getMetadata(){const t="GetMetadata",e=this.#es.get(t);if(e)return e;const i=this.messageHandler.sendWithPromise(t,null).then((t=>({info:t[0],metadata:t[1]?new Metadata(t[1]):null,contentDispositionFilename:this._fullReader?.filename??null,contentLength:this._fullReader?.contentLength??null})));this.#es.set(t,i);return i}getMarkInfo(){return this.messageHandler.sendWithPromise("GetMarkInfo",null)}async startCleanup(t=!1){if(!this.destroyed){await this.messageHandler.sendWithPromise("Cleanup",null);for(const t of this.#is.values()){if(!t.cleanup())throw new Error(`startCleanup: Page ${t.pageNumber} is currently rendering.`)}this.commonObjs.clear();t||this.fontLoader.clear();this.#es.clear();this.filterFactory.destroy(!0);TextLayer.cleanup()}}cachedPageNumber(t){if(!isRefProxy(t))return null;const e=0===t.gen?`${t.num}R`:`${t.num}R${t.gen}`;return this.#ns.get(e)??null}}const Xt=Symbol("INITIAL_DATA");class PDFObjects{#os=Object.create(null);#ls(t){return this.#os[t]||={...Promise.withResolvers(),data:Xt}}get(t,e=null){if(e){const i=this.#ls(t);i.promise.then((()=>e(i.data)));return null}const i=this.#os[t];if(!i||i.data===Xt)throw new Error(`Requesting object that isn't resolved yet ${t}.`);return i.data}has(t){const e=this.#os[t];return!!e&&e.data!==Xt}resolve(t,e=null){const i=this.#ls(t);i.data=e;i.resolve()}clear(){for(const t in this.#os){const{data:e}=this.#os[t];e?.bitmap?.close()}this.#os=Object.create(null)}*[Symbol.iterator](){for(const t in this.#os){const{data:e}=this.#os[t];e!==Xt&&(yield[t,e])}}}class RenderTask{#hs=null;constructor(t){this.#hs=t;this.onContinue=null}get promise(){return this.#hs.capability.promise}cancel(t=0){this.#hs.cancel(null,t)}get separateAnnots(){const{separateAnnots:t}=this.#hs.operatorList;if(!t)return!1;const{annotationCanvasMap:e}=this.#hs;return t.form||t.canvas&&e?.size>0}}class InternalRenderTask{#ds=null;static#cs=new WeakSet;constructor({callback:t,params:e,objs:i,commonObjs:s,annotationCanvasMap:n,operatorList:a,pageIndex:r,canvasFactory:o,filterFactory:l,useRequestAnimationFrame:h=!1,pdfBug:d=!1,pageColors:c=null}){this.callback=t;this.params=e;this.objs=i;this.commonObjs=s;this.annotationCanvasMap=n;this.operatorListIdx=null;this.operatorList=a;this._pageIndex=r;this.canvasFactory=o;this.filterFactory=l;this._pdfBug=d;this.pageColors=c;this.running=!1;this.graphicsReadyCallback=null;this.graphicsReady=!1;this._useRequestAnimationFrame=!0===h&&"undefined"!=typeof window;this.cancelled=!1;this.capability=Promise.withResolvers();this.task=new RenderTask(this);this._cancelBound=this.cancel.bind(this);this._continueBound=this._continue.bind(this);this._scheduleNextBound=this._scheduleNext.bind(this);this._nextBound=this._next.bind(this);this._canvas=e.canvasContext.canvas}get completed(){return this.capability.promise.catch((function(){}))}initializeGraphics({transparency:t=!1,optionalContentConfig:e}){if(this.cancelled)return;if(this._canvas){if(InternalRenderTask.#cs.has(this._canvas))throw new Error("Cannot use the same canvas during multiple render() operations. Use different canvas or ensure previous operations were cancelled or completed.");InternalRenderTask.#cs.add(this._canvas)}if(this._pdfBug&&globalThis.StepperManager?.enabled){this.stepper=globalThis.StepperManager.create(this._pageIndex);this.stepper.init(this.operatorList);this.stepper.nextBreakPoint=this.stepper.getNextBreakPoint()}const{canvasContext:i,viewport:s,transform:n,background:a}=this.params;this.gfx=new CanvasGraphics(i,this.commonObjs,this.objs,this.canvasFactory,this.filterFactory,{optionalContentConfig:e},this.annotationCanvasMap,this.pageColors);this.gfx.beginDrawing({transform:n,viewport:s,transparency:t,background:a});this.operatorListIdx=0;this.graphicsReady=!0;this.graphicsReadyCallback?.()}cancel(t=null,e=0){this.running=!1;this.cancelled=!0;this.gfx?.endDrawing();if(this.#ds){window.cancelAnimationFrame(this.#ds);this.#ds=null}InternalRenderTask.#cs.delete(this._canvas);this.callback(t||new RenderingCancelledException(`Rendering cancelled, page ${this._pageIndex+1}`,e))}operatorListChanged(){if(this.graphicsReady){this.stepper?.updateOperatorList(this.operatorList);this.running||this._continue()}else this.graphicsReadyCallback||=this._continueBound}_continue(){this.running=!0;this.cancelled||(this.task.onContinue?this.task.onContinue(this._scheduleNextBound):this._scheduleNext())}_scheduleNext(){this._useRequestAnimationFrame?this.#ds=window.requestAnimationFrame((()=>{this.#ds=null;this._nextBound().catch(this._cancelBound)})):Promise.resolve().then(this._nextBound).catch(this._cancelBound)}async _next(){if(!this.cancelled){this.operatorListIdx=this.gfx.executeOperatorList(this.operatorList,this.operatorListIdx,this._continueBound,this.stepper);if(this.operatorListIdx===this.operatorList.argsArray.length){this.running=!1;if(this.operatorList.lastChunk){this.gfx.endDrawing();InternalRenderTask.#cs.delete(this._canvas);this.callback()}}}}}const Kt="4.7.76",Yt="8b73b828b";function makeColorComp(t){return Math.floor(255*Math.max(0,Math.min(1,t))).toString(16).padStart(2,"0")}function scaleAndClamp(t){return Math.max(0,Math.min(255,255*t))}class ColorConverters{static CMYK_G([t,e,i,s]){return["G",1-Math.min(1,.3*t+.59*i+.11*e+s)]}static G_CMYK([t]){return["CMYK",0,0,0,1-t]}static G_RGB([t]){return["RGB",t,t,t]}static G_rgb([t]){return[t=scaleAndClamp(t),t,t]}static G_HTML([t]){const e=makeColorComp(t);return`#${e}${e}${e}`}static RGB_G([t,e,i]){return["G",.3*t+.59*e+.11*i]}static RGB_rgb(t){return t.map(scaleAndClamp)}static RGB_HTML(t){return`#${t.map(makeColorComp).join("")}`}static T_HTML(){return"#00000000"}static T_rgb(){return[null]}static CMYK_RGB([t,e,i,s]){return["RGB",1-Math.min(1,t+s),1-Math.min(1,i+s),1-Math.min(1,e+s)]}static CMYK_rgb([t,e,i,s]){return[scaleAndClamp(1-Math.min(1,t+s)),scaleAndClamp(1-Math.min(1,i+s)),scaleAndClamp(1-Math.min(1,e+s))]}static CMYK_HTML(t){const e=this.CMYK_RGB(t).slice(1);return this.RGB_HTML(e)}static RGB_CMYK([t,e,i]){const s=1-t,n=1-e,a=1-i;return["CMYK",s,n,a,Math.min(s,n,a)]}}class XfaLayer{static setupStorage(t,e,i,s,n){const a=s.getValue(e,{value:null});switch(i.name){case"textarea":null!==a.value&&(t.textContent=a.value);if("print"===n)break;t.addEventListener("input",(t=>{s.setValue(e,{value:t.target.value})}));break;case"input":if("radio"===i.attributes.type||"checkbox"===i.attributes.type){a.value===i.attributes.xfaOn?t.setAttribute("checked",!0):a.value===i.attributes.xfaOff&&t.removeAttribute("checked");if("print"===n)break;t.addEventListener("change",(t=>{s.setValue(e,{value:t.target.checked?t.target.getAttribute("xfaOn"):t.target.getAttribute("xfaOff")})}))}else{null!==a.value&&t.setAttribute("value",a.value);if("print"===n)break;t.addEventListener("input",(t=>{s.setValue(e,{value:t.target.value})}))}break;case"select":if(null!==a.value){t.setAttribute("value",a.value);for(const t of i.children)t.attributes.value===a.value?t.attributes.selected=!0:t.attributes.hasOwnProperty("selected")&&delete t.attributes.selected}t.addEventListener("input",(t=>{const i=t.target.options,n=-1===i.selectedIndex?"":i[i.selectedIndex].value;s.setValue(e,{value:n})}))}}static setAttributes({html:t,element:e,storage:i=null,intent:s,linkService:n}){const{attributes:a}=e,r=t instanceof HTMLAnchorElement;"radio"===a.type&&(a.name=`${a.name}-${s}`);for(const[e,i]of Object.entries(a))if(null!=i)switch(e){case"class":i.length&&t.setAttribute(e,i.join(" "));break;case"dataId":break;case"id":t.setAttribute("data-element-id",i);break;case"style":Object.assign(t.style,i);break;case"textContent":t.textContent=i;break;default:(!r||"href"!==e&&"newWindow"!==e)&&t.setAttribute(e,i)}r&&n.addLinkAttributes(t,a.href,a.newWindow);i&&a.dataId&&this.setupStorage(t,a.dataId,e,i)}static render(t){const e=t.annotationStorage,i=t.linkService,s=t.xfaHtml,n=t.intent||"display",a=document.createElement(s.name);s.attributes&&this.setAttributes({html:a,element:s,intent:n,linkService:i});const r="richText"!==n,o=t.div;o.append(a);if(t.viewport){const e=`matrix(${t.viewport.transform.join(",")})`;o.style.transform=e}r&&o.setAttribute("class","xfaLayer xfaFont");const l=[];if(0===s.children.length){if(s.value){const t=document.createTextNode(s.value);a.append(t);r&&XfaText.shouldBuildText(s.name)&&l.push(t)}return{textDivs:l}}const h=[[s,-1,a]];for(;h.length>0;){const[t,s,a]=h.at(-1);if(s+1===t.children.length){h.pop();continue}const o=t.children[++h.at(-1)[1]];if(null===o)continue;const{name:d}=o;if("#text"===d){const t=document.createTextNode(o.value);l.push(t);a.append(t);continue}const c=o?.attributes?.xmlns?document.createElementNS(o.attributes.xmlns,d):document.createElement(d);a.append(c);o.attributes&&this.setAttributes({html:c,element:o,storage:e,intent:n,linkService:i});if(o.children?.length>0)h.push([o,-1,c]);else if(o.value){const t=document.createTextNode(o.value);r&&XfaText.shouldBuildText(d)&&l.push(t);c.append(t)}}for(const t of o.querySelectorAll(".xfaNonInteractive input, .xfaNonInteractive textarea"))t.setAttribute("readOnly",!0);return{textDivs:l}}static update(t){const e=`matrix(${t.viewport.transform.join(",")})`;t.div.style.transform=e;t.div.hidden=!1}}const Qt=1e3,Jt=new WeakSet;function getRectDims(t){return{width:t[2]-t[0],height:t[3]-t[1]}}class AnnotationElementFactory{static create(t){switch(t.data.annotationType){case C:return new LinkAnnotationElement(t);case E:return new TextAnnotationElement(t);case U:switch(t.data.fieldType){case"Tx":return new TextWidgetAnnotationElement(t);case"Btn":return t.data.radioButton?new RadioButtonWidgetAnnotationElement(t):t.data.checkBox?new CheckboxWidgetAnnotationElement(t):new PushButtonWidgetAnnotationElement(t);case"Ch":return new ChoiceWidgetAnnotationElement(t);case"Sig":return new SignatureWidgetAnnotationElement(t)}return new WidgetAnnotationElement(t);case H:return new PopupAnnotationElement(t);case S:return new FreeTextAnnotationElement(t);case T:return new LineAnnotationElement(t);case M:return new SquareAnnotationElement(t);case k:return new CircleAnnotationElement(t);case F:return new PolylineAnnotationElement(t);case O:return new CaretAnnotationElement(t);case B:return new InkAnnotationElement(t);case P:return new PolygonAnnotationElement(t);case D:return new HighlightAnnotationElement(t);case R:return new UnderlineAnnotationElement(t);case I:return new SquigglyAnnotationElement(t);case L:return new StrikeOutAnnotationElement(t);case N:return new StampAnnotationElement(t);case z:return new FileAttachmentAnnotationElement(t);default:return new AnnotationElement(t)}}}class AnnotationElement{#us=null;#ps=!1;#gs=null;constructor(t,{isRenderable:e=!1,ignoreBorder:i=!1,createQuadrilaterals:s=!1}={}){this.isRenderable=e;this.data=t.data;this.layer=t.layer;this.linkService=t.linkService;this.downloadManager=t.downloadManager;this.imageResourcesPath=t.imageResourcesPath;this.renderForms=t.renderForms;this.svgFactory=t.svgFactory;this.annotationStorage=t.annotationStorage;this.enableScripting=t.enableScripting;this.hasJSActions=t.hasJSActions;this._fieldObjects=t.fieldObjects;this.parent=t.parent;e&&(this.container=this._createContainer(i));s&&this._createQuadrilaterals()}static _hasPopupData({titleObj:t,contentsObj:e,richText:i}){return!!(t?.str||e?.str||i?.str)}get _isEditable(){return this.data.isEditable}get hasPopupData(){return AnnotationElement._hasPopupData(this.data)}updateEdited(t){if(!this.container)return;this.#us||={rect:this.data.rect.slice(0)};const{rect:e}=t;e&&this.#ms(e);this.#gs?.popup.updateEdited(t)}resetEdited(){if(this.#us){this.#ms(this.#us.rect);this.#gs?.popup.resetEdited();this.#us=null}}#ms(t){const{container:{style:e},data:{rect:i,rotation:s},parent:{viewport:{rawDims:{pageWidth:n,pageHeight:a,pageX:r,pageY:o}}}}=this;i?.splice(0,4,...t);const{width:l,height:h}=getRectDims(t);e.left=100*(t[0]-r)/n+"%";e.top=100*(a-t[3]+o)/a+"%";if(0===s){e.width=100*l/n+"%";e.height=100*h/a+"%"}else this.setRotation(s)}_createContainer(t){const{data:e,parent:{page:i,viewport:s}}=this,n=document.createElement("section");n.setAttribute("data-annotation-id",e.id);this instanceof WidgetAnnotationElement||(n.tabIndex=Qt);const{style:a}=n;a.zIndex=this.parent.zIndex++;e.popupRef&&n.setAttribute("aria-haspopup","dialog");e.alternativeText&&(n.title=e.alternativeText);e.noRotate&&n.classList.add("norotate");if(!e.rect||this instanceof PopupAnnotationElement){const{rotation:t}=e;e.hasOwnCanvas||0===t||this.setRotation(t,n);return n}const{width:r,height:o}=getRectDims(e.rect);if(!t&&e.borderStyle.width>0){a.borderWidth=`${e.borderStyle.width}px`;const t=e.borderStyle.horizontalCornerRadius,i=e.borderStyle.verticalCornerRadius;if(t>0||i>0){const e=`calc(${t}px * var(--scale-factor)) / calc(${i}px * var(--scale-factor))`;a.borderRadius=e}else if(this instanceof RadioButtonWidgetAnnotationElement){const t=`calc(${r}px * var(--scale-factor)) / calc(${o}px * var(--scale-factor))`;a.borderRadius=t}switch(e.borderStyle.style){case j:a.borderStyle="solid";break;case W:a.borderStyle="dashed";break;case G:warn("Unimplemented border style: beveled");break;case $:warn("Unimplemented border style: inset");break;case V:a.borderBottomStyle="solid"}const s=e.borderColor||null;if(s){this.#ps=!0;a.borderColor=Util.makeHexColor(0|s[0],0|s[1],0|s[2])}else a.borderWidth=0}const l=Util.normalizeRect([e.rect[0],i.view[3]-e.rect[1]+i.view[1],e.rect[2],i.view[3]-e.rect[3]+i.view[1]]),{pageWidth:h,pageHeight:d,pageX:c,pageY:u}=s.rawDims;a.left=100*(l[0]-c)/h+"%";a.top=100*(l[1]-u)/d+"%";const{rotation:p}=e;if(e.hasOwnCanvas||0===p){a.width=100*r/h+"%";a.height=100*o/d+"%"}else this.setRotation(p,n);return n}setRotation(t,e=this.container){if(!this.data.rect)return;const{pageWidth:i,pageHeight:s}=this.parent.viewport.rawDims,{width:n,height:a}=getRectDims(this.data.rect);let r,o;if(t%180==0){r=100*n/i;o=100*a/s}else{r=100*a/i;o=100*n/s}e.style.width=`${r}%`;e.style.height=`${o}%`;e.setAttribute("data-main-rotation",(360-t)%360)}get _commonActions(){const setColor=(t,e,i)=>{const s=i.detail[t],n=s[0],a=s.slice(1);i.target.style[e]=ColorConverters[`${n}_HTML`](a);this.annotationStorage.setValue(this.data.id,{[e]:ColorConverters[`${n}_rgb`](a)})};return shadow(this,"_commonActions",{display:t=>{const{display:e}=t.detail,i=e%2==1;this.container.style.visibility=i?"hidden":"visible";this.annotationStorage.setValue(this.data.id,{noView:i,noPrint:1===e||2===e})},print:t=>{this.annotationStorage.setValue(this.data.id,{noPrint:!t.detail.print})},hidden:t=>{const{hidden:e}=t.detail;this.container.style.visibility=e?"hidden":"visible";this.annotationStorage.setValue(this.data.id,{noPrint:e,noView:e})},focus:t=>{setTimeout((()=>t.target.focus({preventScroll:!1})),0)},userName:t=>{t.target.title=t.detail.userName},readonly:t=>{t.target.disabled=t.detail.readonly},required:t=>{this._setRequired(t.target,t.detail.required)},bgColor:t=>{setColor("bgColor","backgroundColor",t)},fillColor:t=>{setColor("fillColor","backgroundColor",t)},fgColor:t=>{setColor("fgColor","color",t)},textColor:t=>{setColor("textColor","color",t)},borderColor:t=>{setColor("borderColor","borderColor",t)},strokeColor:t=>{setColor("strokeColor","borderColor",t)},rotation:t=>{const e=t.detail.rotation;this.setRotation(e);this.annotationStorage.setValue(this.data.id,{rotation:e})}})}_dispatchEventFromSandbox(t,e){const i=this._commonActions;for(const s of Object.keys(e.detail)){const n=t[s]||i[s];n?.(e)}}_setDefaultPropertiesFromJS(t){if(!this.enableScripting)return;const e=this.annotationStorage.getRawValue(this.data.id);if(!e)return;const i=this._commonActions;for(const[s,n]of Object.entries(e)){const a=i[s];if(a){a({detail:{[s]:n},target:t});delete e[s]}}}_createQuadrilaterals(){if(!this.container)return;const{quadPoints:t}=this.data;if(!t)return;const[e,i,s,n]=this.data.rect.map((t=>Math.fround(t)));if(8===t.length){const[a,r,o,l]=t.subarray(2,6);if(s===a&&n===r&&e===o&&i===l)return}const{style:a}=this.container;let r;if(this.#ps){const{borderColor:t,borderWidth:e}=a;a.borderWidth=0;r=["url('data:image/svg+xml;utf8,",'',``];this.container.classList.add("hasBorder")}const o=s-e,l=n-i,{svgFactory:h}=this,d=h.createElement("svg");d.classList.add("quadrilateralsContainer");d.setAttribute("width",0);d.setAttribute("height",0);const c=h.createElement("defs");d.append(c);const u=h.createElement("clipPath"),p=`clippath_${this.data.id}`;u.setAttribute("id",p);u.setAttribute("clipPathUnits","objectBoundingBox");c.append(u);for(let i=2,s=t.length;i`)}if(this.#ps){r.push("')");a.backgroundImage=r.join("")}this.container.append(d);this.container.style.clipPath=`url(#${p})`}_createPopup(){const{container:t,data:e}=this;t.setAttribute("aria-haspopup","dialog");const i=this.#gs=new PopupAnnotationElement({data:{color:e.color,titleObj:e.titleObj,modificationDate:e.modificationDate,contentsObj:e.contentsObj,richText:e.richText,parentRect:e.rect,borderStyle:0,id:`popup_${e.id}`,rotation:e.rotation},parent:this.parent,elements:[this]});this.parent.div.append(i.render())}render(){unreachable("Abstract method `AnnotationElement.render` called")}_getElementsByName(t,e=null){const i=[];if(this._fieldObjects){const s=this._fieldObjects[t];if(s)for(const{page:t,id:n,exportValues:a}of s){if(-1===t)continue;if(n===e)continue;const s="string"==typeof a?a:null,r=document.querySelector(`[data-element-id="${n}"]`);!r||Jt.has(r)?i.push({id:n,exportValue:s,domElement:r}):warn(`_getElementsByName - element not allowed: ${n}`)}return i}for(const s of document.getElementsByName(t)){const{exportValue:t}=s,n=s.getAttribute("data-element-id");n!==e&&(Jt.has(s)&&i.push({id:n,exportValue:t,domElement:s}))}return i}show(){this.container&&(this.container.hidden=!1);this.popup?.maybeShow()}hide(){this.container&&(this.container.hidden=!0);this.popup?.forceHide()}getElementsToTriggerPopup(){return this.container}addHighlightArea(){const t=this.getElementsToTriggerPopup();if(Array.isArray(t))for(const e of t)e.classList.add("highlightArea");else t.classList.add("highlightArea")}_editOnDoubleClick(){if(!this._isEditable)return;const{annotationEditorType:t,data:{id:e}}=this;this.container.addEventListener("dblclick",(()=>{this.linkService.eventBus?.dispatch("switchannotationeditormode",{source:this,mode:t,editId:e})}))}}class LinkAnnotationElement extends AnnotationElement{constructor(t,e=null){super(t,{isRenderable:!0,ignoreBorder:!!e?.ignoreBorder,createQuadrilaterals:!0});this.isTooltipOnly=t.data.isTooltipOnly}render(){const{data:t,linkService:e}=this,i=document.createElement("a");i.setAttribute("data-element-id",t.id);let s=!1;if(t.url){e.addLinkAttributes(i,t.url,t.newWindow);s=!0}else if(t.action){this._bindNamedAction(i,t.action);s=!0}else if(t.attachment){this.#fs(i,t.attachment,t.attachmentDest);s=!0}else if(t.setOCGState){this.#bs(i,t.setOCGState);s=!0}else if(t.dest){this._bindLink(i,t.dest);s=!0}else{if(t.actions&&(t.actions.Action||t.actions["Mouse Up"]||t.actions["Mouse Down"])&&this.enableScripting&&this.hasJSActions){this._bindJSAction(i,t);s=!0}if(t.resetForm){this._bindResetFormAction(i,t.resetForm);s=!0}else if(this.isTooltipOnly&&!s){this._bindLink(i,"");s=!0}}this.container.classList.add("linkAnnotation");s&&this.container.append(i);return this.container}#As(){this.container.setAttribute("data-internal-link","")}_bindLink(t,e){t.href=this.linkService.getDestinationHash(e);t.onclick=()=>{e&&this.linkService.goToDestination(e);return!1};(e||""===e)&&this.#As()}_bindNamedAction(t,e){t.href=this.linkService.getAnchorUrl("");t.onclick=()=>{this.linkService.executeNamedAction(e);return!1};this.#As()}#fs(t,e,i=null){t.href=this.linkService.getAnchorUrl("");e.description&&(t.title=e.description);t.onclick=()=>{this.downloadManager?.openOrDownloadData(e.content,e.filename,i);return!1};this.#As()}#bs(t,e){t.href=this.linkService.getAnchorUrl("");t.onclick=()=>{this.linkService.executeSetOCGState(e);return!1};this.#As()}_bindJSAction(t,e){t.href=this.linkService.getAnchorUrl("");const i=new Map([["Action","onclick"],["Mouse Up","onmouseup"],["Mouse Down","onmousedown"]]);for(const s of Object.keys(e.actions)){const n=i.get(s);n&&(t[n]=()=>{this.linkService.eventBus?.dispatch("dispatcheventinsandbox",{source:this,detail:{id:e.id,name:s}});return!1})}t.onclick||(t.onclick=()=>!1);this.#As()}_bindResetFormAction(t,e){const i=t.onclick;i||(t.href=this.linkService.getAnchorUrl(""));this.#As();if(this._fieldObjects)t.onclick=()=>{i?.();const{fields:t,refs:s,include:n}=e,a=[];if(0!==t.length||0!==s.length){const e=new Set(s);for(const i of t){const t=this._fieldObjects[i]||[];for(const{id:i}of t)e.add(i)}for(const t of Object.values(this._fieldObjects))for(const i of t)e.has(i.id)===n&&a.push(i)}else for(const t of Object.values(this._fieldObjects))a.push(...t);const r=this.annotationStorage,o=[];for(const t of a){const{id:e}=t;o.push(e);switch(t.type){case"text":{const i=t.defaultValue||"";r.setValue(e,{value:i});break}case"checkbox":case"radiobutton":{const i=t.defaultValue===t.exportValues;r.setValue(e,{value:i});break}case"combobox":case"listbox":{const i=t.defaultValue||"";r.setValue(e,{value:i});break}default:continue}const i=document.querySelector(`[data-element-id="${e}"]`);i&&(Jt.has(i)?i.dispatchEvent(new Event("resetform")):warn(`_bindResetFormAction - element not allowed: ${e}`))}this.enableScripting&&this.linkService.eventBus?.dispatch("dispatcheventinsandbox",{source:this,detail:{id:"app",ids:o,name:"ResetForm"}});return!1};else{warn('_bindResetFormAction - "resetForm" action not supported, ensure that the `fieldObjects` parameter is provided.');i||(t.onclick=()=>!1)}}}class TextAnnotationElement extends AnnotationElement{constructor(t){super(t,{isRenderable:!0})}render(){this.container.classList.add("textAnnotation");const t=document.createElement("img");t.src=this.imageResourcesPath+"annotation-"+this.data.name.toLowerCase()+".svg";t.setAttribute("data-l10n-id","pdfjs-text-annotation-type");t.setAttribute("data-l10n-args",JSON.stringify({type:this.data.name}));!this.data.popupRef&&this.hasPopupData&&this._createPopup();this.container.append(t);return this.container}}class WidgetAnnotationElement extends AnnotationElement{render(){return this.container}showElementAndHideCanvas(t){if(this.data.hasOwnCanvas){"CANVAS"===t.previousSibling?.nodeName&&(t.previousSibling.hidden=!0);t.hidden=!1}}_getKeyModifier(t){return util_FeatureTest.platform.isMac?t.metaKey:t.ctrlKey}_setEventListener(t,e,i,s,n){i.includes("mouse")?t.addEventListener(i,(t=>{this.linkService.eventBus?.dispatch("dispatcheventinsandbox",{source:this,detail:{id:this.data.id,name:s,value:n(t),shift:t.shiftKey,modifier:this._getKeyModifier(t)}})})):t.addEventListener(i,(t=>{if("blur"===i){if(!e.focused||!t.relatedTarget)return;e.focused=!1}else if("focus"===i){if(e.focused)return;e.focused=!0}n&&this.linkService.eventBus?.dispatch("dispatcheventinsandbox",{source:this,detail:{id:this.data.id,name:s,value:n(t)}})}))}_setEventListeners(t,e,i,s){for(const[n,a]of i)if("Action"===a||this.data.actions?.[a]){"Focus"!==a&&"Blur"!==a||(e||={focused:!1});this._setEventListener(t,e,n,a,s);"Focus"!==a||this.data.actions?.Blur?"Blur"!==a||this.data.actions?.Focus||this._setEventListener(t,e,"focus","Focus",null):this._setEventListener(t,e,"blur","Blur",null)}}_setBackgroundColor(t){const e=this.data.backgroundColor||null;t.style.backgroundColor=null===e?"transparent":Util.makeHexColor(e[0],e[1],e[2])}_setTextStyle(t){const e=["left","center","right"],{fontColor:i}=this.data.defaultAppearanceData,s=this.data.defaultAppearanceData.fontSize||9,a=t.style;let r;const roundToOneDecimal=t=>Math.round(10*t)/10;if(this.data.multiLine){const t=Math.abs(this.data.rect[3]-this.data.rect[1]-2),e=t/(Math.round(t/(n*s))||1);r=Math.min(s,roundToOneDecimal(e/n))}else{const t=Math.abs(this.data.rect[3]-this.data.rect[1]-2);r=Math.min(s,roundToOneDecimal(t/n))}a.fontSize=`calc(${r}px * var(--scale-factor))`;a.color=Util.makeHexColor(i[0],i[1],i[2]);null!==this.data.textAlignment&&(a.textAlign=e[this.data.textAlignment])}_setRequired(t,e){e?t.setAttribute("required",!0):t.removeAttribute("required");t.setAttribute("aria-required",e)}}class TextWidgetAnnotationElement extends WidgetAnnotationElement{constructor(t){super(t,{isRenderable:t.renderForms||t.data.hasOwnCanvas||!t.data.hasAppearance&&!!t.data.fieldValue})}setPropertyOnSiblings(t,e,i,s){const n=this.annotationStorage;for(const a of this._getElementsByName(t.name,t.id)){a.domElement&&(a.domElement[e]=i);n.setValue(a.id,{[s]:i})}}render(){const t=this.annotationStorage,e=this.data.id;this.container.classList.add("textWidgetAnnotation");let i=null;if(this.renderForms){const s=t.getValue(e,{value:this.data.fieldValue});let n=s.value||"";const a=t.getValue(e,{charLimit:this.data.maxLen}).charLimit;a&&n.length>a&&(n=n.slice(0,a));let r=s.formattedValue||this.data.textContent?.join("\n")||null;r&&this.data.comb&&(r=r.replaceAll(/\s+/g,""));const o={userValue:n,formattedValue:r,lastCommittedValue:null,commitKey:1,focused:!1};if(this.data.multiLine){i=document.createElement("textarea");i.textContent=r??n;this.data.doNotScroll&&(i.style.overflowY="hidden")}else{i=document.createElement("input");i.type="text";i.setAttribute("value",r??n);this.data.doNotScroll&&(i.style.overflowX="hidden")}this.data.hasOwnCanvas&&(i.hidden=!0);Jt.add(i);i.setAttribute("data-element-id",e);i.disabled=this.data.readOnly;i.name=this.data.fieldName;i.tabIndex=Qt;this._setRequired(i,this.data.required);a&&(i.maxLength=a);i.addEventListener("input",(s=>{t.setValue(e,{value:s.target.value});this.setPropertyOnSiblings(i,"value",s.target.value,"value");o.formattedValue=null}));i.addEventListener("resetform",(t=>{const e=this.data.defaultFieldValue??"";i.value=o.userValue=e;o.formattedValue=null}));let blurListener=t=>{const{formattedValue:e}=o;null!=e&&(t.target.value=e);t.target.scrollLeft=0};if(this.enableScripting&&this.hasJSActions){i.addEventListener("focus",(t=>{if(o.focused)return;const{target:e}=t;o.userValue&&(e.value=o.userValue);o.lastCommittedValue=e.value;o.commitKey=1;this.data.actions?.Focus||(o.focused=!0)}));i.addEventListener("updatefromsandbox",(i=>{this.showElementAndHideCanvas(i.target);const s={value(i){o.userValue=i.detail.value??"";t.setValue(e,{value:o.userValue.toString()});i.target.value=o.userValue},formattedValue(i){const{formattedValue:s}=i.detail;o.formattedValue=s;null!=s&&i.target!==document.activeElement&&(i.target.value=s);t.setValue(e,{formattedValue:s})},selRange(t){t.target.setSelectionRange(...t.detail.selRange)},charLimit:i=>{const{charLimit:s}=i.detail,{target:n}=i;if(0===s){n.removeAttribute("maxLength");return}n.setAttribute("maxLength",s);let a=o.userValue;if(a&&!(a.length<=s)){a=a.slice(0,s);n.value=o.userValue=a;t.setValue(e,{value:a});this.linkService.eventBus?.dispatch("dispatcheventinsandbox",{source:this,detail:{id:e,name:"Keystroke",value:a,willCommit:!0,commitKey:1,selStart:n.selectionStart,selEnd:n.selectionEnd}})}}};this._dispatchEventFromSandbox(s,i)}));i.addEventListener("keydown",(t=>{o.commitKey=1;let i=-1;"Escape"===t.key?i=0:"Enter"!==t.key||this.data.multiLine?"Tab"===t.key&&(o.commitKey=3):i=2;if(-1===i)return;const{value:s}=t.target;if(o.lastCommittedValue!==s){o.lastCommittedValue=s;o.userValue=s;this.linkService.eventBus?.dispatch("dispatcheventinsandbox",{source:this,detail:{id:e,name:"Keystroke",value:s,willCommit:!0,commitKey:i,selStart:t.target.selectionStart,selEnd:t.target.selectionEnd}})}}));const s=blurListener;blurListener=null;i.addEventListener("blur",(t=>{if(!o.focused||!t.relatedTarget)return;this.data.actions?.Blur||(o.focused=!1);const{value:i}=t.target;o.userValue=i;o.lastCommittedValue!==i&&this.linkService.eventBus?.dispatch("dispatcheventinsandbox",{source:this,detail:{id:e,name:"Keystroke",value:i,willCommit:!0,commitKey:o.commitKey,selStart:t.target.selectionStart,selEnd:t.target.selectionEnd}});s(t)}));this.data.actions?.Keystroke&&i.addEventListener("beforeinput",(t=>{o.lastCommittedValue=null;const{data:i,target:s}=t,{value:n,selectionStart:a,selectionEnd:r}=s;let l=a,h=r;switch(t.inputType){case"deleteWordBackward":{const t=n.substring(0,a).match(/\w*[^\w]*$/);t&&(l-=t[0].length);break}case"deleteWordForward":{const t=n.substring(a).match(/^[^\w]*\w*/);t&&(h+=t[0].length);break}case"deleteContentBackward":a===r&&(l-=1);break;case"deleteContentForward":a===r&&(h+=1)}t.preventDefault();this.linkService.eventBus?.dispatch("dispatcheventinsandbox",{source:this,detail:{id:e,name:"Keystroke",value:n,change:i||"",willCommit:!1,selStart:l,selEnd:h}})}));this._setEventListeners(i,o,[["focus","Focus"],["blur","Blur"],["mousedown","Mouse Down"],["mouseenter","Mouse Enter"],["mouseleave","Mouse Exit"],["mouseup","Mouse Up"]],(t=>t.target.value))}blurListener&&i.addEventListener("blur",blurListener);if(this.data.comb){const t=(this.data.rect[2]-this.data.rect[0])/a;i.classList.add("comb");i.style.letterSpacing=`calc(${t}px * var(--scale-factor) - 1ch)`}}else{i=document.createElement("div");i.textContent=this.data.fieldValue;i.style.verticalAlign="middle";i.style.display="table-cell";this.data.hasOwnCanvas&&(i.hidden=!0)}this._setTextStyle(i);this._setBackgroundColor(i);this._setDefaultPropertiesFromJS(i);this.container.append(i);return this.container}}class SignatureWidgetAnnotationElement extends WidgetAnnotationElement{constructor(t){super(t,{isRenderable:!!t.data.hasOwnCanvas})}}class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement{constructor(t){super(t,{isRenderable:t.renderForms})}render(){const t=this.annotationStorage,e=this.data,i=e.id;let s=t.getValue(i,{value:e.exportValue===e.fieldValue}).value;if("string"==typeof s){s="Off"!==s;t.setValue(i,{value:s})}this.container.classList.add("buttonWidgetAnnotation","checkBox");const n=document.createElement("input");Jt.add(n);n.setAttribute("data-element-id",i);n.disabled=e.readOnly;this._setRequired(n,this.data.required);n.type="checkbox";n.name=e.fieldName;s&&n.setAttribute("checked",!0);n.setAttribute("exportValue",e.exportValue);n.tabIndex=Qt;n.addEventListener("change",(s=>{const{name:n,checked:a}=s.target;for(const s of this._getElementsByName(n,i)){const i=a&&s.exportValue===e.exportValue;s.domElement&&(s.domElement.checked=i);t.setValue(s.id,{value:i})}t.setValue(i,{value:a})}));n.addEventListener("resetform",(t=>{const i=e.defaultFieldValue||"Off";t.target.checked=i===e.exportValue}));if(this.enableScripting&&this.hasJSActions){n.addEventListener("updatefromsandbox",(e=>{const s={value(e){e.target.checked="Off"!==e.detail.value;t.setValue(i,{value:e.target.checked})}};this._dispatchEventFromSandbox(s,e)}));this._setEventListeners(n,null,[["change","Validate"],["change","Action"],["focus","Focus"],["blur","Blur"],["mousedown","Mouse Down"],["mouseenter","Mouse Enter"],["mouseleave","Mouse Exit"],["mouseup","Mouse Up"]],(t=>t.target.checked))}this._setBackgroundColor(n);this._setDefaultPropertiesFromJS(n);this.container.append(n);return this.container}}class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement{constructor(t){super(t,{isRenderable:t.renderForms})}render(){this.container.classList.add("buttonWidgetAnnotation","radioButton");const t=this.annotationStorage,e=this.data,i=e.id;let s=t.getValue(i,{value:e.fieldValue===e.buttonValue}).value;if("string"==typeof s){s=s!==e.buttonValue;t.setValue(i,{value:s})}if(s)for(const s of this._getElementsByName(e.fieldName,i))t.setValue(s.id,{value:!1});const n=document.createElement("input");Jt.add(n);n.setAttribute("data-element-id",i);n.disabled=e.readOnly;this._setRequired(n,this.data.required);n.type="radio";n.name=e.fieldName;s&&n.setAttribute("checked",!0);n.tabIndex=Qt;n.addEventListener("change",(e=>{const{name:s,checked:n}=e.target;for(const e of this._getElementsByName(s,i))t.setValue(e.id,{value:!1});t.setValue(i,{value:n})}));n.addEventListener("resetform",(t=>{const i=e.defaultFieldValue;t.target.checked=null!=i&&i===e.buttonValue}));if(this.enableScripting&&this.hasJSActions){const s=e.buttonValue;n.addEventListener("updatefromsandbox",(e=>{const n={value:e=>{const n=s===e.detail.value;for(const s of this._getElementsByName(e.target.name)){const e=n&&s.id===i;s.domElement&&(s.domElement.checked=e);t.setValue(s.id,{value:e})}}};this._dispatchEventFromSandbox(n,e)}));this._setEventListeners(n,null,[["change","Validate"],["change","Action"],["focus","Focus"],["blur","Blur"],["mousedown","Mouse Down"],["mouseenter","Mouse Enter"],["mouseleave","Mouse Exit"],["mouseup","Mouse Up"]],(t=>t.target.checked))}this._setBackgroundColor(n);this._setDefaultPropertiesFromJS(n);this.container.append(n);return this.container}}class PushButtonWidgetAnnotationElement extends LinkAnnotationElement{constructor(t){super(t,{ignoreBorder:t.data.hasAppearance})}render(){const t=super.render();t.classList.add("buttonWidgetAnnotation","pushButton");const e=t.lastChild;if(this.enableScripting&&this.hasJSActions&&e){this._setDefaultPropertiesFromJS(e);e.addEventListener("updatefromsandbox",(t=>{this._dispatchEventFromSandbox({},t)}))}return t}}class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement{constructor(t){super(t,{isRenderable:t.renderForms})}render(){this.container.classList.add("choiceWidgetAnnotation");const t=this.annotationStorage,e=this.data.id,i=t.getValue(e,{value:this.data.fieldValue}),s=document.createElement("select");Jt.add(s);s.setAttribute("data-element-id",e);s.disabled=this.data.readOnly;this._setRequired(s,this.data.required);s.name=this.data.fieldName;s.tabIndex=Qt;let n=this.data.combo&&this.data.options.length>0;if(!this.data.combo){s.size=this.data.options.length;this.data.multiSelect&&(s.multiple=!0)}s.addEventListener("resetform",(t=>{const e=this.data.defaultFieldValue;for(const t of s.options)t.selected=t.value===e}));for(const t of this.data.options){const e=document.createElement("option");e.textContent=t.displayValue;e.value=t.exportValue;if(i.value.includes(t.exportValue)){e.setAttribute("selected",!0);n=!1}s.append(e)}let a=null;if(n){const t=document.createElement("option");t.value=" ";t.setAttribute("hidden",!0);t.setAttribute("selected",!0);s.prepend(t);a=()=>{t.remove();s.removeEventListener("input",a);a=null};s.addEventListener("input",a)}const getValue=t=>{const e=t?"value":"textContent",{options:i,multiple:n}=s;return n?Array.prototype.filter.call(i,(t=>t.selected)).map((t=>t[e])):-1===i.selectedIndex?null:i[i.selectedIndex][e]};let r=getValue(!1);const getItems=t=>{const e=t.target.options;return Array.prototype.map.call(e,(t=>({displayValue:t.textContent,exportValue:t.value})))};if(this.enableScripting&&this.hasJSActions){s.addEventListener("updatefromsandbox",(i=>{const n={value(i){a?.();const n=i.detail.value,o=new Set(Array.isArray(n)?n:[n]);for(const t of s.options)t.selected=o.has(t.value);t.setValue(e,{value:getValue(!0)});r=getValue(!1)},multipleSelection(t){s.multiple=!0},remove(i){const n=s.options,a=i.detail.remove;n[a].selected=!1;s.remove(a);if(n.length>0){-1===Array.prototype.findIndex.call(n,(t=>t.selected))&&(n[0].selected=!0)}t.setValue(e,{value:getValue(!0),items:getItems(i)});r=getValue(!1)},clear(i){for(;0!==s.length;)s.remove(0);t.setValue(e,{value:null,items:[]});r=getValue(!1)},insert(i){const{index:n,displayValue:a,exportValue:o}=i.detail.insert,l=s.children[n],h=document.createElement("option");h.textContent=a;h.value=o;l?l.before(h):s.append(h);t.setValue(e,{value:getValue(!0),items:getItems(i)});r=getValue(!1)},items(i){const{items:n}=i.detail;for(;0!==s.length;)s.remove(0);for(const t of n){const{displayValue:e,exportValue:i}=t,n=document.createElement("option");n.textContent=e;n.value=i;s.append(n)}s.options.length>0&&(s.options[0].selected=!0);t.setValue(e,{value:getValue(!0),items:getItems(i)});r=getValue(!1)},indices(i){const s=new Set(i.detail.indices);for(const t of i.target.options)t.selected=s.has(t.index);t.setValue(e,{value:getValue(!0)});r=getValue(!1)},editable(t){t.target.disabled=!t.detail.editable}};this._dispatchEventFromSandbox(n,i)}));s.addEventListener("input",(i=>{const s=getValue(!0),n=getValue(!1);t.setValue(e,{value:s});i.preventDefault();this.linkService.eventBus?.dispatch("dispatcheventinsandbox",{source:this,detail:{id:e,name:"Keystroke",value:r,change:n,changeEx:s,willCommit:!1,commitKey:1,keyDown:!1}})}));this._setEventListeners(s,null,[["focus","Focus"],["blur","Blur"],["mousedown","Mouse Down"],["mouseenter","Mouse Enter"],["mouseleave","Mouse Exit"],["mouseup","Mouse Up"],["input","Action"],["input","Validate"]],(t=>t.target.value))}else s.addEventListener("input",(function(i){t.setValue(e,{value:getValue(!0)})}));this.data.combo&&this._setTextStyle(s);this._setBackgroundColor(s);this._setDefaultPropertiesFromJS(s);this.container.append(s);return this.container}}class PopupAnnotationElement extends AnnotationElement{constructor(t){const{data:e,elements:i}=t;super(t,{isRenderable:AnnotationElement._hasPopupData(e)});this.elements=i;this.popup=null}render(){this.container.classList.add("popupAnnotation");const t=this.popup=new PopupElement({container:this.container,color:this.data.color,titleObj:this.data.titleObj,modificationDate:this.data.modificationDate,contentsObj:this.data.contentsObj,richText:this.data.richText,rect:this.data.rect,parentRect:this.data.parentRect||null,parent:this.parent,elements:this.elements,open:this.data.open}),e=[];for(const i of this.elements){i.popup=t;e.push(i.data.id);i.addHighlightArea()}this.container.setAttribute("aria-controls",e.map((t=>`${it}${t}`)).join(","));return this.container}}class PopupElement{#vs=this.#ys.bind(this);#ws=this.#xs.bind(this);#_s=this.#Es.bind(this);#Cs=this.#Ss.bind(this);#Ts=null;#ut=null;#Ms=null;#ks=null;#Ps=null;#Fs=null;#Ds=null;#Rs=!1;#Is=null;#S=null;#Ls=null;#Ns=null;#Os=null;#us=null;#Bs=!1;constructor({container:t,color:e,elements:i,titleObj:s,modificationDate:n,contentsObj:a,richText:r,parent:o,rect:l,parentRect:h,open:d}){this.#ut=t;this.#Os=s;this.#Ms=a;this.#Ns=r;this.#Fs=o;this.#Ts=e;this.#Ls=l;this.#Ds=h;this.#Ps=i;this.#ks=PDFDateString.toDateObject(n);this.trigger=i.flatMap((t=>t.getElementsToTriggerPopup()));for(const t of this.trigger){t.addEventListener("click",this.#Cs);t.addEventListener("mouseenter",this.#_s);t.addEventListener("mouseleave",this.#ws);t.classList.add("popupTriggerArea")}for(const t of i)t.container?.addEventListener("keydown",this.#vs);this.#ut.hidden=!0;d&&this.#Ss()}render(){if(this.#Is)return;const t=this.#Is=document.createElement("div");t.className="popup";if(this.#Ts){const e=t.style.outlineColor=Util.makeHexColor(...this.#Ts);if(CSS.supports("background-color","color-mix(in srgb, red 30%, white)"))t.style.backgroundColor=`color-mix(in srgb, ${e} 30%, white)`;else{const e=.7;t.style.backgroundColor=Util.makeHexColor(...this.#Ts.map((t=>Math.floor(e*(255-t)+t))))}}const e=document.createElement("span");e.className="header";const i=document.createElement("h1");e.append(i);({dir:i.dir,str:i.textContent}=this.#Os);t.append(e);if(this.#ks){const t=document.createElement("span");t.classList.add("popupDate");t.setAttribute("data-l10n-id","pdfjs-annotation-date-time-string");t.setAttribute("data-l10n-args",JSON.stringify({dateObj:this.#ks.valueOf()}));e.append(t)}const s=this.#Hs;if(s){XfaLayer.render({xfaHtml:s,intent:"richText",div:t});t.lastChild.classList.add("richText","popupContent")}else{const e=this._formatContents(this.#Ms);t.append(e)}this.#ut.append(t)}get#Hs(){const t=this.#Ns,e=this.#Ms;return!t?.str||e?.str&&e.str!==t.str?null:this.#Ns.html||null}get#zs(){return this.#Hs?.attributes?.style?.fontSize||0}get#Us(){return this.#Hs?.attributes?.style?.color||null}#js(t){const e=[],i={str:t,html:{name:"div",attributes:{dir:"auto"},children:[{name:"p",children:e}]}},s={style:{color:this.#Us,fontSize:this.#zs?`calc(${this.#zs}px * var(--scale-factor))`:""}};for(const i of t.split("\n"))e.push({name:"span",value:i,attributes:s});return i}_formatContents({str:t,dir:e}){const i=document.createElement("p");i.classList.add("popupContent");i.dir=e;const s=t.split(/(?:\r\n?|\n)/);for(let t=0,e=s.length;t{"Enter"===t.key&&(s?t.metaKey:t.ctrlKey)&&this.#Ys()}));!e.popupRef&&this.hasPopupData?this._createPopup():i.classList.add("popupTriggerArea");t.append(i);return t}getElementsToTriggerPopup(){return this.#Ks}addHighlightArea(){this.container.classList.add("highlightArea")}#Ys(){this.downloadManager?.openOrDownloadData(this.content,this.filename)}}class AnnotationLayer{#Qs=null;#Js=null;#Zs=new Map;#tn=null;constructor({div:t,accessibilityManager:e,annotationCanvasMap:i,annotationEditorUIManager:s,page:n,viewport:a,structTreeLayer:r}){this.div=t;this.#Qs=e;this.#Js=i;this.#tn=r||null;this.page=n;this.viewport=a;this.zIndex=0;this._annotationEditorUIManager=s}hasEditableAnnotations(){return this.#Zs.size>0}async#en(t,e){const i=t.firstChild||t,s=i.id=`${it}${e}`,n=await(this.#tn?.getAriaAttributes(s));if(n)for(const[t,e]of n)i.setAttribute(t,e);this.div.append(t);this.#Qs?.moveElementInDOM(this.div,t,i,!1)}async render(t){const{annotations:e}=t,i=this.div;setLayerDimensions(i,this.viewport);const s=new Map,n={data:null,layer:i,linkService:t.linkService,downloadManager:t.downloadManager,imageResourcesPath:t.imageResourcesPath||"",renderForms:!1!==t.renderForms,svgFactory:new DOMSVGFactory,annotationStorage:t.annotationStorage||new AnnotationStorage,enableScripting:!0===t.enableScripting,hasJSActions:t.hasJSActions,fieldObjects:t.fieldObjects,parent:this,elements:null};for(const t of e){if(t.noHTML)continue;const e=t.annotationType===H;if(e){const e=s.get(t.id);if(!e)continue;n.elements=e}else{const{width:e,height:i}=getRectDims(t.rect);if(e<=0||i<=0)continue}n.data=t;const i=AnnotationElementFactory.create(n);if(!i.isRenderable)continue;if(!e&&t.popupRef){const e=s.get(t.popupRef);e?e.push(i):s.set(t.popupRef,[i])}const a=i.render();t.hidden&&(a.style.visibility="hidden");await this.#en(a,t.id);if(i._isEditable){this.#Zs.set(i.data.id,i);this._annotationEditorUIManager?.renderAnnotationElement(i)}}this.#in()}update({viewport:t}){const e=this.div;this.viewport=t;setLayerDimensions(e,{rotation:t.rotation});this.#in();e.hidden=!1}#in(){if(!this.#Js)return;const t=this.div;for(const[e,i]of this.#Js){const s=t.querySelector(`[data-annotation-id="${e}"]`);if(!s)continue;i.className="annotationContent";const{firstChild:n}=s;n?"CANVAS"===n.nodeName?n.replaceWith(i):n.classList.contains("annotationContent")?n.after(i):n.before(i):s.append(i)}this.#Js.clear()}getEditableAnnotations(){return Array.from(this.#Zs.values())}getEditableAnnotation(t){return this.#Zs.get(t)}}const Zt=/\r\n?|\n/g;class FreeTextEditor extends AnnotationEditor{#Ts;#sn="";#nn=`${this.id}-editor`;#an=null;#zs;static _freeTextDefaultContent="";static _internalPadding=0;static _defaultColor=null;static _defaultFontSize=10;static get _keyboardManager(){const t=FreeTextEditor.prototype,arrowChecker=t=>t.isEmpty(),e=AnnotationEditorUIManager.TRANSLATE_SMALL,i=AnnotationEditorUIManager.TRANSLATE_BIG;return shadow(this,"_keyboardManager",new KeyboardManager([[["ctrl+s","mac+meta+s","ctrl+p","mac+meta+p"],t.commitOrRemove,{bubbles:!0}],[["ctrl+Enter","mac+meta+Enter","Escape","mac+Escape"],t.commitOrRemove],[["ArrowLeft","mac+ArrowLeft"],t._translateEmpty,{args:[-e,0],checker:arrowChecker}],[["ctrl+ArrowLeft","mac+shift+ArrowLeft"],t._translateEmpty,{args:[-i,0],checker:arrowChecker}],[["ArrowRight","mac+ArrowRight"],t._translateEmpty,{args:[e,0],checker:arrowChecker}],[["ctrl+ArrowRight","mac+shift+ArrowRight"],t._translateEmpty,{args:[i,0],checker:arrowChecker}],[["ArrowUp","mac+ArrowUp"],t._translateEmpty,{args:[0,-e],checker:arrowChecker}],[["ctrl+ArrowUp","mac+shift+ArrowUp"],t._translateEmpty,{args:[0,-i],checker:arrowChecker}],[["ArrowDown","mac+ArrowDown"],t._translateEmpty,{args:[0,e],checker:arrowChecker}],[["ctrl+ArrowDown","mac+shift+ArrowDown"],t._translateEmpty,{args:[0,i],checker:arrowChecker}]]))}static _type="freetext";static _editorType=g.FREETEXT;constructor(t){super({...t,name:"freeTextEditor"});this.#Ts=t.color||FreeTextEditor._defaultColor||AnnotationEditor._defaultLineColor;this.#zs=t.fontSize||FreeTextEditor._defaultFontSize}static initialize(t,e){AnnotationEditor.initialize(t,e,{strings:["pdfjs-free-text-default-content"]});const i=getComputedStyle(document.documentElement);this._internalPadding=parseFloat(i.getPropertyValue("--freetext-padding"))}static updateDefaultParams(t,e){switch(t){case m.FREETEXT_SIZE:FreeTextEditor._defaultFontSize=e;break;case m.FREETEXT_COLOR:FreeTextEditor._defaultColor=e}}updateParams(t,e){switch(t){case m.FREETEXT_SIZE:this.#rn(e);break;case m.FREETEXT_COLOR:this.#on(e)}}static get defaultPropertiesToUpdate(){return[[m.FREETEXT_SIZE,FreeTextEditor._defaultFontSize],[m.FREETEXT_COLOR,FreeTextEditor._defaultColor||AnnotationEditor._defaultLineColor]]}get propertiesToUpdate(){return[[m.FREETEXT_SIZE,this.#zs],[m.FREETEXT_COLOR,this.#Ts]]}#rn(t){const setFontsize=t=>{this.editorDiv.style.fontSize=`calc(${t}px * var(--scale-factor))`;this.translate(0,-(t-this.#zs)*this.parentScale);this.#zs=t;this.#ln()},e=this.#zs;this.addCommands({cmd:setFontsize.bind(this,t),undo:setFontsize.bind(this,e),post:this._uiManager.updateUI.bind(this._uiManager,this),mustExec:!0,type:m.FREETEXT_SIZE,overwriteIfSameType:!0,keepUndo:!0})}#on(t){const setColor=t=>{this.#Ts=this.editorDiv.style.color=t},e=this.#Ts;this.addCommands({cmd:setColor.bind(this,t),undo:setColor.bind(this,e),post:this._uiManager.updateUI.bind(this._uiManager,this),mustExec:!0,type:m.FREETEXT_COLOR,overwriteIfSameType:!0,keepUndo:!0})}_translateEmpty(t,e){this._uiManager.translateSelectedEditors(t,e,!0)}getInitialTranslation(){const t=this.parentScale;return[-FreeTextEditor._internalPadding*t,-(FreeTextEditor._internalPadding+this.#zs)*t]}rebuild(){if(this.parent){super.rebuild();null!==this.div&&(this.isAttachedToDOM||this.parent.add(this))}}enableEditMode(){if(this.isInEditMode())return;this.parent.setEditingState(!1);this.parent.updateToolbar(g.FREETEXT);super.enableEditMode();this.overlayDiv.classList.remove("enabled");this.editorDiv.contentEditable=!0;this._isDraggable=!1;this.div.removeAttribute("aria-activedescendant");this.#an=new AbortController;const t=this._uiManager.combinedSignal(this.#an);this.editorDiv.addEventListener("keydown",this.editorDivKeydown.bind(this),{signal:t});this.editorDiv.addEventListener("focus",this.editorDivFocus.bind(this),{signal:t});this.editorDiv.addEventListener("blur",this.editorDivBlur.bind(this),{signal:t});this.editorDiv.addEventListener("input",this.editorDivInput.bind(this),{signal:t});this.editorDiv.addEventListener("paste",this.editorDivPaste.bind(this),{signal:t})}disableEditMode(){if(this.isInEditMode()){this.parent.setEditingState(!0);super.disableEditMode();this.overlayDiv.classList.add("enabled");this.editorDiv.contentEditable=!1;this.div.setAttribute("aria-activedescendant",this.#nn);this._isDraggable=!0;this.#an?.abort();this.#an=null;this.div.focus({preventScroll:!0});this.isEditing=!1;this.parent.div.classList.add("freetextEditing")}}focusin(t){if(this._focusEventsAllowed){super.focusin(t);t.target!==this.editorDiv&&this.editorDiv.focus()}}onceAdded(){if(!this.width){this.enableEditMode();this.editorDiv.focus();this._initialOptions?.isCentered&&this.center();this._initialOptions=null}}isEmpty(){return!this.editorDiv||""===this.editorDiv.innerText.trim()}remove(){this.isEditing=!1;if(this.parent){this.parent.setEditingState(!0);this.parent.div.classList.add("freetextEditing")}super.remove()}#hn(){const t=[];this.editorDiv.normalize();let e=null;for(const i of this.editorDiv.childNodes)if(e?.nodeType!==Node.TEXT_NODE||"BR"!==i.nodeName){t.push(FreeTextEditor.#dn(i));e=i}return t.join("\n")}#ln(){const[t,e]=this.parentDimensions;let i;if(this.isAttachedToDOM)i=this.div.getBoundingClientRect();else{const{currentLayer:t,div:e}=this,s=e.style.display,n=e.classList.contains("hidden");e.classList.remove("hidden");e.style.display="hidden";t.div.append(this.div);i=e.getBoundingClientRect();e.remove();e.style.display=s;e.classList.toggle("hidden",n)}if(this.rotation%180==this.parentRotation%180){this.width=i.width/t;this.height=i.height/e}else{this.width=i.height/t;this.height=i.width/e}this.fixAndSetPosition()}commit(){if(!this.isInEditMode())return;super.commit();this.disableEditMode();const t=this.#sn,e=this.#sn=this.#hn().trimEnd();if(t===e)return;const setText=t=>{this.#sn=t;if(t){this.#cn();this._uiManager.rebuild(this);this.#ln()}else this.remove()};this.addCommands({cmd:()=>{setText(e)},undo:()=>{setText(t)},mustExec:!1});this.#ln()}shouldGetKeyboardEvents(){return this.isInEditMode()}enterInEditMode(){this.enableEditMode();this.editorDiv.focus()}dblclick(t){this.enterInEditMode()}keydown(t){if(t.target===this.div&&"Enter"===t.key){this.enterInEditMode();t.preventDefault()}}editorDivKeydown(t){FreeTextEditor._keyboardManager.exec(this,t)}editorDivFocus(t){this.isEditing=!0}editorDivBlur(t){this.isEditing=!1}editorDivInput(t){this.parent.div.classList.toggle("freetextEditing",this.isEmpty())}disableEditing(){this.editorDiv.setAttribute("role","comment");this.editorDiv.removeAttribute("aria-multiline")}enableEditing(){this.editorDiv.setAttribute("role","textbox");this.editorDiv.setAttribute("aria-multiline",!0)}render(){if(this.div)return this.div;let t,e;if(this.width){t=this.x;e=this.y}super.render();this.editorDiv=document.createElement("div");this.editorDiv.className="internal";this.editorDiv.setAttribute("id",this.#nn);this.editorDiv.setAttribute("data-l10n-id","pdfjs-free-text");this.enableEditing();AnnotationEditor._l10nPromise.get("pdfjs-free-text-default-content").then((t=>this.editorDiv?.setAttribute("default-content",t)));this.editorDiv.contentEditable=!0;const{style:i}=this.editorDiv;i.fontSize=`calc(${this.#zs}px * var(--scale-factor))`;i.color=this.#Ts;this.div.append(this.editorDiv);this.overlayDiv=document.createElement("div");this.overlayDiv.classList.add("overlay","enabled");this.div.append(this.overlayDiv);bindEvents(this,this.div,["dblclick","keydown"]);if(this.width){const[i,s]=this.parentDimensions;if(this.annotationElementId){const{position:n}=this._initialData;let[a,r]=this.getInitialTranslation();[a,r]=this.pageTranslationToScreen(a,r);const[o,l]=this.pageDimensions,[h,d]=this.pageTranslation;let c,u;switch(this.rotation){case 0:c=t+(n[0]-h)/o;u=e+this.height-(n[1]-d)/l;break;case 90:c=t+(n[0]-h)/o;u=e-(n[1]-d)/l;[a,r]=[r,-a];break;case 180:c=t-this.width+(n[0]-h)/o;u=e-(n[1]-d)/l;[a,r]=[-a,-r];break;case 270:c=t+(n[0]-h-this.height*l)/o;u=e+(n[1]-d-this.width*o)/l;[a,r]=[-r,a]}this.setAt(c*i,u*s,a,r)}else this.setAt(t*i,e*s,this.width*i,this.height*s);this.#cn();this._isDraggable=!0;this.editorDiv.contentEditable=!1}else{this._isDraggable=!1;this.editorDiv.contentEditable=!0}return this.div}static#dn(t){return(t.nodeType===Node.TEXT_NODE?t.nodeValue:t.innerText).replaceAll(Zt,"")}editorDivPaste(t){const e=t.clipboardData||window.clipboardData,{types:i}=e;if(1===i.length&&"text/plain"===i[0])return;t.preventDefault();const s=FreeTextEditor.#un(e.getData("text")||"").replaceAll(Zt,"\n");if(!s)return;const n=window.getSelection();if(!n.rangeCount)return;this.editorDiv.normalize();n.deleteFromDocument();const a=n.getRangeAt(0);if(!s.includes("\n")){a.insertNode(document.createTextNode(s));this.editorDiv.normalize();n.collapseToStart();return}const{startContainer:r,startOffset:o}=a,l=[],h=[];if(r.nodeType===Node.TEXT_NODE){const t=r.parentElement;h.push(r.nodeValue.slice(o).replaceAll(Zt,""));if(t!==this.editorDiv){let e=l;for(const i of this.editorDiv.childNodes)i!==t?e.push(FreeTextEditor.#dn(i)):e=h}l.push(r.nodeValue.slice(0,o).replaceAll(Zt,""))}else if(r===this.editorDiv){let t=l,e=0;for(const i of this.editorDiv.childNodes){e++===o&&(t=h);t.push(FreeTextEditor.#dn(i))}}this.#sn=`${l.join("\n")}${s}${h.join("\n")}`;this.#cn();const d=new Range;let c=l.reduce(((t,e)=>t+e.length),0);for(const{firstChild:t}of this.editorDiv.childNodes)if(t.nodeType===Node.TEXT_NODE){const e=t.nodeValue.length;if(c<=e){d.setStart(t,c);d.setEnd(t,c);break}c-=e}n.removeAllRanges();n.addRange(d)}#cn(){this.editorDiv.replaceChildren();if(this.#sn)for(const t of this.#sn.split("\n")){const e=document.createElement("div");e.append(t?document.createTextNode(t):document.createElement("br"));this.editorDiv.append(e)}}#pn(){return this.#sn.replaceAll(" "," ")}static#un(t){return t.replaceAll(" "," ")}get contentDiv(){return this.editorDiv}static async deserialize(t,e,i){let s=null;if(t instanceof FreeTextAnnotationElement){const{data:{defaultAppearanceData:{fontSize:e,fontColor:i},rect:n,rotation:a,id:r,popupRef:o},textContent:l,textPosition:h,parent:{page:{pageNumber:d}}}=t;if(!l||0===l.length)return null;s=t={annotationType:g.FREETEXT,color:Array.from(i),fontSize:e,value:l.join("\n"),position:h,pageIndex:d-1,rect:n.slice(0),rotation:a,id:r,deleted:!1,popupRef:o}}const n=await super.deserialize(t,e,i);n.#zs=t.fontSize;n.#Ts=Util.makeHexColor(...t.color);n.#sn=FreeTextEditor.#un(t.value);n.annotationElementId=t.id||null;n._initialData=s;return n}serialize(t=!1){if(this.isEmpty())return null;if(this.deleted)return this.serializeDeleted();const e=FreeTextEditor._internalPadding*this.parentScale,i=this.getRect(e,e),s=AnnotationEditor._colorManager.convert(this.isAttachedToDOM?getComputedStyle(this.editorDiv).color:this.#Ts),n={annotationType:g.FREETEXT,color:s,fontSize:this.#zs,value:this.#pn(),pageIndex:this.pageIndex,rect:i,rotation:this.rotation,structTreeParentId:this._structTreeParentId};if(t)return n;if(this.annotationElementId&&!this.#gn(n))return null;n.id=this.annotationElementId;return n}#gn(t){const{value:e,fontSize:i,color:s,pageIndex:n}=this._initialData;return this._hasBeenMoved||t.value!==e||t.fontSize!==i||t.color.some(((t,e)=>t!==s[e]))||t.pageIndex!==n}renderAnnotationElement(t){const e=super.renderAnnotationElement(t);if(this.deleted)return e;const{style:i}=e;i.fontSize=`calc(${this.#zs}px * var(--scale-factor))`;i.color=this.#Ts;e.replaceChildren();for(const t of this.#sn.split("\n")){const i=document.createElement("div");i.append(t?document.createTextNode(t):document.createElement("br"));e.append(i)}const s=FreeTextEditor._internalPadding*this.parentScale;t.updateEdited({rect:this.getRect(s,s),popupContent:this.#sn});return e}resetAnnotationElement(t){super.resetAnnotationElement(t);t.resetEdited()}}class Outliner{#mn;#fn=[];#bn=[];constructor(t,e=0,i=0,s=!0){let n=1/0,a=-1/0,r=1/0,o=-1/0;const l=10**-4;for(const{x:i,y:s,width:h,height:d}of t){const t=Math.floor((i-e)/l)*l,c=Math.ceil((i+h+e)/l)*l,u=Math.floor((s-e)/l)*l,p=Math.ceil((s+d+e)/l)*l,g=[t,u,p,!0],m=[c,u,p,!1];this.#fn.push(g,m);n=Math.min(n,t);a=Math.max(a,c);r=Math.min(r,u);o=Math.max(o,p)}const h=a-n+2*i,d=o-r+2*i,c=n-i,u=r-i,p=this.#fn.at(s?-1:-2),g=[p[0],p[2]];for(const t of this.#fn){const[e,i,s]=t;t[0]=(e-c)/h;t[1]=(i-u)/d;t[2]=(s-u)/d}this.#mn={x:c,y:u,width:h,height:d,lastPoint:g}}getOutlines(){this.#fn.sort(((t,e)=>t[0]-e[0]||t[1]-e[1]||t[2]-e[2]));const t=[];for(const e of this.#fn)if(e[3]){t.push(...this.#An(e));this.#vn(e)}else{this.#yn(e);t.push(...this.#An(e))}return this.#wn(t)}#wn(t){const e=[],i=new Set;for(const i of t){const[t,s,n]=i;e.push([t,s,i],[t,n,i])}e.sort(((t,e)=>t[1]-e[1]||t[0]-e[0]));for(let t=0,s=e.length;t0;){const t=i.values().next().value;let[e,a,r,o,l]=t;i.delete(t);let h=e,d=a;n=[e,r];s.push(n);for(;;){let t;if(i.has(o))t=o;else{if(!i.has(l))break;t=l}i.delete(t);[e,a,r,o,l]=t;if(h!==e){n.push(h,d,e,d===a?a:r);h=e}d=d===a?r:a}n.push(h,d)}return new HighlightOutline(s,this.#mn)}#xn(t){const e=this.#bn;let i=0,s=e.length-1;for(;i<=s;){const n=i+s>>1,a=e[n][0];if(a===t)return n;a=0;s--){const[i,n]=this.#bn[s];if(i!==t)break;if(i===t&&n===e){this.#bn.splice(s,1);return}}}#An(t){const[e,i,s]=t,n=[[e,i,s]],a=this.#xn(s);for(let t=0;t=i)if(o>s)n[t][1]=s;else{if(1===a)return[];n.splice(t,1);t--;a--}else{n[t][2]=i;o>s&&n.push([e,s,o])}}}return n}}class Outline{toSVGPath(){throw new Error("Abstract method `toSVGPath` must be implemented.")}get box(){throw new Error("Abstract getter `box` must be implemented.")}serialize(t,e){throw new Error("Abstract method `serialize` must be implemented.")}get free(){return this instanceof FreeHighlightOutline}}class HighlightOutline extends Outline{#mn;#_n;constructor(t,e){super();this.#_n=t;this.#mn=e}toSVGPath(){const t=[];for(const e of this.#_n){let[i,s]=e;t.push(`M${i} ${s}`);for(let n=2;n=6;t-=6)isNaN(e[t])?u.push(`L${e[t+4]} ${e[t+5]}`):u.push(`C${e[t]} ${e[t+1]} ${e[t+2]} ${e[t+3]} ${e[t+4]} ${e[t+5]}`);u.push(`L${e[4]} ${e[5]} Z`);return u.join(" ")}getOutlines(){const t=this.#Tn,e=this.#En,i=this.#Mn,s=i.subarray(4,6),n=i.subarray(16,18),[a,r,o,l]=this.#mn,h=new Float64Array((this.#Ln?.length??0)+2);for(let t=0,e=h.length-2;t=6;t-=6)for(let i=0;i<6;i+=2)if(isNaN(e[t+i])){g[m]=g[m+1]=NaN;m+=2}else{g[m]=e[t+i];g[m+1]=e[t+i+1];m+=2}g.set([NaN,NaN,NaN,NaN,e[4],e[5]],m);return new FreeHighlightOutline(g,h,this.#mn,this.#Rn,this.#Cn,this.#Sn)}}class FreeHighlightOutline extends Outline{#mn;#zn=null;#Cn;#Sn;#Ln;#Rn;#Un;constructor(t,e,i,s,n,a){super();this.#Un=t;this.#Ln=e;this.#mn=i;this.#Rn=s;this.#Cn=n;this.#Sn=a;this.#jn(a);const{x:r,y:o,width:l,height:h}=this.#zn;for(let e=0,i=t.length;e-1){this.#ga=!0;this.#ya(t);this.#wa()}else if(this.#oa){this.#aa=t.anchorNode;this.#ra=t.anchorOffset;this.#da=t.focusNode;this.#ca=t.focusOffset;this.#xa();this.#wa();this.rotate(this.rotation)}}get telemetryInitialData(){return{action:"added",type:this.#ga?"free_highlight":"highlight",color:this._uiManager.highlightColorNames.get(this.color),thickness:this.#In,methodOfCreation:this.#va}}get telemetryFinalData(){return{type:"highlight",color:this._uiManager.highlightColorNames.get(this.color)}}static computeTelemetryFinalData(t){return{numberOfColors:t.get("color").size}}#xa(){const t=new Outliner(this.#oa,.001);this.#pa=t.getOutlines();({x:this.x,y:this.y,width:this.width,height:this.height}=this.#pa.box);const e=new Outliner(this.#oa,.0025,.001,"ltr"===this._uiManager.direction);this.#ha=e.getOutlines();const{lastPoint:i}=this.#ha.box;this.#ma=[(i[0]-this.x)/this.width,(i[1]-this.y)/this.height]}#ya({highlightOutlines:t,highlightId:e,clipPathId:i}){this.#pa=t;this.#ha=t.getNewOutline(this.#In/2+1.5,.0025);if(e>=0){this.#v=e;this.#la=i;this.parent.drawLayer.finalizeLine(e,t);this.#ba=this.parent.drawLayer.highlightOutline(this.#ha)}else if(this.parent){const e=this.parent.viewport.rotation;this.parent.drawLayer.updateLine(this.#v,t);this.parent.drawLayer.updateBox(this.#v,HighlightEditor.#_a(this.#pa.box,(e-this.rotation+360)%360));this.parent.drawLayer.updateLine(this.#ba,this.#ha);this.parent.drawLayer.updateBox(this.#ba,HighlightEditor.#_a(this.#ha.box,e))}const{x:s,y:n,width:a,height:r}=t.box;switch(this.rotation){case 0:this.x=s;this.y=n;this.width=a;this.height=r;break;case 90:{const[t,e]=this.parentDimensions;this.x=n;this.y=1-s;this.width=a*e/t;this.height=r*t/e;break}case 180:this.x=1-s;this.y=1-n;this.width=a;this.height=r;break;case 270:{const[t,e]=this.parentDimensions;this.x=1-n;this.y=s;this.width=a*e/t;this.height=r*t/e;break}}const{lastPoint:o}=this.#ha.box;this.#ma=[(o[0]-s)/a,(o[1]-n)/r]}static initialize(t,e){AnnotationEditor.initialize(t,e);HighlightEditor._defaultColor||=e.highlightColors?.values().next().value||"#fff066"}static updateDefaultParams(t,e){switch(t){case m.HIGHLIGHT_DEFAULT_COLOR:HighlightEditor._defaultColor=e;break;case m.HIGHLIGHT_THICKNESS:HighlightEditor._defaultThickness=e}}translateInPage(t,e){}get toolbarPosition(){return this.#ma}updateParams(t,e){switch(t){case m.HIGHLIGHT_COLOR:this.#on(e);break;case m.HIGHLIGHT_THICKNESS:this.#Ea(e)}}static get defaultPropertiesToUpdate(){return[[m.HIGHLIGHT_DEFAULT_COLOR,HighlightEditor._defaultColor],[m.HIGHLIGHT_THICKNESS,HighlightEditor._defaultThickness]]}get propertiesToUpdate(){return[[m.HIGHLIGHT_COLOR,this.color||HighlightEditor._defaultColor],[m.HIGHLIGHT_THICKNESS,this.#In||HighlightEditor._defaultThickness],[m.HIGHLIGHT_FREE,this.#ga]]}#on(t){const setColorAndOpacity=(t,e)=>{this.color=t;this.parent?.drawLayer.changeColor(this.#v,t);this.#n?.updateColor(t);this.#fa=e;this.parent?.drawLayer.changeOpacity(this.#v,e)},e=this.color,i=this.#fa;this.addCommands({cmd:setColorAndOpacity.bind(this,t,HighlightEditor._defaultOpacity),undo:setColorAndOpacity.bind(this,e,i),post:this._uiManager.updateUI.bind(this._uiManager,this),mustExec:!0,type:m.HIGHLIGHT_COLOR,overwriteIfSameType:!0,keepUndo:!0});this._reportTelemetry({action:"color_changed",color:this._uiManager.highlightColorNames.get(t)},!0)}#Ea(t){const e=this.#In,setThickness=t=>{this.#In=t;this.#Ca(t)};this.addCommands({cmd:setThickness.bind(this,t),undo:setThickness.bind(this,e),post:this._uiManager.updateUI.bind(this._uiManager,this),mustExec:!0,type:m.INK_THICKNESS,overwriteIfSameType:!0,keepUndo:!0});this._reportTelemetry({action:"thickness_changed",thickness:t},!0)}async addEditToolbar(){const t=await super.addEditToolbar();if(!t)return null;if(this._uiManager.highlightColors){this.#n=new ColorPicker({editor:this});t.addColorPicker(this.#n)}return t}disableEditing(){super.disableEditing();this.div.classList.toggle("disabled",!0)}enableEditing(){super.enableEditing();this.div.classList.toggle("disabled",!1)}fixAndSetPosition(){return super.fixAndSetPosition(this.#Sa())}getBaseTranslation(){return[0,0]}getRect(t,e){return super.getRect(t,e,this.#Sa())}onceAdded(){this.annotationElementId||this.parent.addUndoableEditor(this);this.div.focus()}remove(){this.#Ta();this._reportTelemetry({action:"deleted"});super.remove()}rebuild(){if(this.parent){super.rebuild();if(null!==this.div){this.#wa();this.isAttachedToDOM||this.parent.add(this)}}}setParent(t){let e=!1;if(this.parent&&!t)this.#Ta();else if(t){this.#wa(t);e=!this.parent&&this.div?.classList.contains("selectedEditor")}super.setParent(t);this.show(this._isVisible);e&&this.select()}#Ca(t){if(!this.#ga)return;this.#ya({highlightOutlines:this.#pa.getNewOutline(t/2)});this.fixAndSetPosition();const[e,i]=this.parentDimensions;this.setDims(this.width*e,this.height*i)}#Ta(){if(null!==this.#v&&this.parent){this.parent.drawLayer.remove(this.#v);this.#v=null;this.parent.drawLayer.remove(this.#ba);this.#ba=null}}#wa(t=this.parent){if(null===this.#v){({id:this.#v,clipPathId:this.#la}=t.drawLayer.highlight(this.#pa,this.color,this.#fa));this.#ba=t.drawLayer.highlightOutline(this.#ha);this.#ua&&(this.#ua.style.clipPath=this.#la)}}static#_a({x:t,y:e,width:i,height:s},n){switch(n){case 90:return{x:1-e-s,y:t,width:s,height:i};case 180:return{x:1-t-i,y:1-e-s,width:i,height:s};case 270:return{x:e,y:1-t-i,width:s,height:i}}return{x:t,y:e,width:i,height:s}}rotate(t){const{drawLayer:e}=this.parent;let i;if(this.#ga){t=(t-this.rotation+360)%360;i=HighlightEditor.#_a(this.#pa.box,t)}else i=HighlightEditor.#_a(this,t);e.rotate(this.#v,t);e.rotate(this.#ba,t);e.updateBox(this.#v,i);e.updateBox(this.#ba,HighlightEditor.#_a(this.#ha.box,t))}render(){if(this.div)return this.div;const t=super.render();if(this.#Aa){t.setAttribute("aria-label",this.#Aa);t.setAttribute("role","mark")}this.#ga?t.classList.add("free"):this.div.addEventListener("keydown",this.#Ma.bind(this),{signal:this._uiManager._signal});const e=this.#ua=document.createElement("div");t.append(e);e.setAttribute("aria-hidden","true");e.className="internal";e.style.clipPath=this.#la;const[i,s]=this.parentDimensions;this.setDims(this.width*i,this.height*s);bindEvents(this,this.#ua,["pointerover","pointerleave"]);this.enableEditing();return t}pointerover(){this.parent.drawLayer.addClass(this.#ba,"hovered")}pointerleave(){this.parent.drawLayer.removeClass(this.#ba,"hovered")}#Ma(t){HighlightEditor._keyboardManager.exec(this,t)}_moveCaret(t){this.parent.unselect(this);switch(t){case 0:case 2:this.#ka(!0);break;case 1:case 3:this.#ka(!1)}}#ka(t){if(!this.#aa)return;const e=window.getSelection();t?e.setPosition(this.#aa,this.#ra):e.setPosition(this.#da,this.#ca)}select(){super.select();if(this.#ba){this.parent?.drawLayer.removeClass(this.#ba,"hovered");this.parent?.drawLayer.addClass(this.#ba,"selected")}}unselect(){super.unselect();if(this.#ba){this.parent?.drawLayer.removeClass(this.#ba,"selected");this.#ga||this.#ka(!1)}}get _mustFixPosition(){return!this.#ga}show(t=this._isVisible){super.show(t);if(this.parent){this.parent.drawLayer.show(this.#v,t);this.parent.drawLayer.show(this.#ba,t)}}#Sa(){return this.#ga?this.rotation:0}#Pa(){if(this.#ga)return null;const[t,e]=this.pageDimensions,[i,s]=this.pageTranslation,n=this.#oa,a=new Float32Array(8*n.length);let r=0;for(const{x:o,y:l,width:h,height:d}of n){const n=o*t+i,c=(1-l-d)*e+s;a[r]=a[r+4]=n;a[r+1]=a[r+3]=c;a[r+2]=a[r+6]=n+h*t;a[r+5]=a[r+7]=c+d*e;r+=8}return a}#Fa(t){return this.#pa.serialize(t,this.#Sa())}static startHighlighting(t,e,{target:i,x:s,y:n}){const{x:a,y:r,width:o,height:l}=i.getBoundingClientRect(),h=new AbortController,d=t.combinedSignal(h),pointerUpCallback=e=>{h.abort();this.#Da(t,e)};window.addEventListener("blur",pointerUpCallback,{signal:d});window.addEventListener("pointerup",pointerUpCallback,{signal:d});window.addEventListener("pointerdown",(t=>{t.preventDefault();t.stopPropagation()}),{capture:!0,passive:!1,signal:d});window.addEventListener("contextmenu",noContextMenu,{signal:d});i.addEventListener("pointermove",this.#Ra.bind(this,t),{signal:d});this._freeHighlight=new FreeOutliner({x:s,y:n},[a,r,o,l],t.scale,this._defaultThickness/2,e,.001);({id:this._freeHighlightId,clipPathId:this._freeHighlightClipId}=t.drawLayer.highlight(this._freeHighlight,this._defaultColor,this._defaultOpacity,!0))}static#Ra(t,e){this._freeHighlight.add(e)&&t.drawLayer.updatePath(this._freeHighlightId,this._freeHighlight)}static#Da(t,e){this._freeHighlight.isEmpty()?t.drawLayer.removeFreeHighlight(this._freeHighlightId):t.createAndAddNewEditor(e,!1,{highlightId:this._freeHighlightId,highlightOutlines:this._freeHighlight.getOutlines(),clipPathId:this._freeHighlightClipId,methodOfCreation:"main_toolbar"});this._freeHighlightId=-1;this._freeHighlight=null;this._freeHighlightClipId=""}static async deserialize(t,e,i){let s=null;if(t instanceof HighlightAnnotationElement){const{data:{quadPoints:e,rect:i,rotation:n,id:a,color:r,opacity:o,popupRef:l},parent:{page:{pageNumber:h}}}=t;s=t={annotationType:g.HIGHLIGHT,color:Array.from(r),opacity:o,quadPoints:e,boxes:null,pageIndex:h-1,rect:i.slice(0),rotation:n,id:a,deleted:!1,popupRef:l}}else if(t instanceof InkAnnotationElement){const{data:{inkLists:e,rect:i,rotation:n,id:a,color:r,borderStyle:{rawWidth:o},popupRef:l},parent:{page:{pageNumber:h}}}=t;s=t={annotationType:g.HIGHLIGHT,color:Array.from(r),thickness:o,inkLists:e,boxes:null,pageIndex:h-1,rect:i.slice(0),rotation:n,id:a,deleted:!1,popupRef:l}}const{color:n,quadPoints:a,inkLists:r,opacity:o}=t,l=await super.deserialize(t,e,i);l.color=Util.makeHexColor(...n);l.#fa=o||1;r&&(l.#In=t.thickness);l.annotationElementId=t.id||null;l._initialData=s;const[h,d]=l.pageDimensions,[c,u]=l.pageTranslation;if(a){const t=l.#oa=[];for(let e=0;et!==e[i]))}renderAnnotationElement(t){t.updateEdited({rect:this.getRect(0,0)});return null}static canCreateNewEmptyEditor(){return!1}}class InkEditor extends AnnotationEditor{#Ia=0;#La=0;#Na=null;#Oa=new Path2D;#Ba=!1;#Ha=null;#za=!1;#Ua=!1;#ja=null;#Wa=null;#Ga=0;#$a=0;#Va=null;static _defaultColor=null;static _defaultOpacity=1;static _defaultThickness=1;static _type="ink";static _editorType=g.INK;constructor(t){super({...t,name:"inkEditor"});this.color=t.color||null;this.thickness=t.thickness||null;this.opacity=t.opacity||null;this.paths=[];this.bezierPath2D=[];this.allRawPaths=[];this.currentPath=[];this.scaleFactor=1;this.translationX=this.translationY=0;this.x=0;this.y=0;this._willKeepAspectRatio=!0}static initialize(t,e){AnnotationEditor.initialize(t,e)}static updateDefaultParams(t,e){switch(t){case m.INK_THICKNESS:InkEditor._defaultThickness=e;break;case m.INK_COLOR:InkEditor._defaultColor=e;break;case m.INK_OPACITY:InkEditor._defaultOpacity=e/100}}updateParams(t,e){switch(t){case m.INK_THICKNESS:this.#Ea(e);break;case m.INK_COLOR:this.#on(e);break;case m.INK_OPACITY:this.#qa(e)}}static get defaultPropertiesToUpdate(){return[[m.INK_THICKNESS,InkEditor._defaultThickness],[m.INK_COLOR,InkEditor._defaultColor||AnnotationEditor._defaultLineColor],[m.INK_OPACITY,Math.round(100*InkEditor._defaultOpacity)]]}get propertiesToUpdate(){return[[m.INK_THICKNESS,this.thickness||InkEditor._defaultThickness],[m.INK_COLOR,this.color||InkEditor._defaultColor||AnnotationEditor._defaultLineColor],[m.INK_OPACITY,Math.round(100*(this.opacity??InkEditor._defaultOpacity))]]}#Ea(t){const setThickness=t=>{this.thickness=t;this.#Xa()},e=this.thickness;this.addCommands({cmd:setThickness.bind(this,t),undo:setThickness.bind(this,e),post:this._uiManager.updateUI.bind(this._uiManager,this),mustExec:!0,type:m.INK_THICKNESS,overwriteIfSameType:!0,keepUndo:!0})}#on(t){const setColor=t=>{this.color=t;this.#Ka()},e=this.color;this.addCommands({cmd:setColor.bind(this,t),undo:setColor.bind(this,e),post:this._uiManager.updateUI.bind(this._uiManager,this),mustExec:!0,type:m.INK_COLOR,overwriteIfSameType:!0,keepUndo:!0})}#qa(t){const setOpacity=t=>{this.opacity=t;this.#Ka()};t/=100;const e=this.opacity;this.addCommands({cmd:setOpacity.bind(this,t),undo:setOpacity.bind(this,e),post:this._uiManager.updateUI.bind(this._uiManager,this),mustExec:!0,type:m.INK_OPACITY,overwriteIfSameType:!0,keepUndo:!0})}rebuild(){if(this.parent){super.rebuild();if(null!==this.div){if(!this.canvas){this.#Ya();this.#Qa()}if(!this.isAttachedToDOM){this.parent.add(this);this.#Ja()}this.#Xa()}}}remove(){if(null!==this.canvas){this.isEmpty()||this.commit();this.canvas.width=this.canvas.height=0;this.canvas.remove();this.canvas=null;if(this.#Na){clearTimeout(this.#Na);this.#Na=null}this.#ja?.disconnect();this.#ja=null;super.remove()}}setParent(t){!this.parent&&t?this._uiManager.removeShouldRescale(this):this.parent&&null===t&&this._uiManager.addShouldRescale(this);super.setParent(t)}onScaleChanging(){const[t,e]=this.parentDimensions,i=this.width*t,s=this.height*e;this.setDimensions(i,s)}enableEditMode(){if(!this.#Ba&&null!==this.canvas){super.enableEditMode();this._isDraggable=!1;this.#Za()}}disableEditMode(){if(this.isInEditMode()&&null!==this.canvas){super.disableEditMode();this._isDraggable=!this.isEmpty();this.div.classList.remove("editing");this.#tr()}}onceAdded(){this._isDraggable=!this.isEmpty()}isEmpty(){return 0===this.paths.length||1===this.paths.length&&0===this.paths[0].length}#er(){const{parentRotation:t,parentDimensions:[e,i]}=this;switch(t){case 90:return[0,i,i,e];case 180:return[e,i,e,i];case 270:return[e,0,i,e];default:return[0,0,e,i]}}#ir(){const{ctx:t,color:e,opacity:i,thickness:s,parentScale:n,scaleFactor:a}=this;t.lineWidth=s*n/a;t.lineCap="round";t.lineJoin="round";t.miterLimit=10;t.strokeStyle=`${e}${function opacityToHex(t){return Math.round(Math.min(255,Math.max(1,255*t))).toString(16).padStart(2,"0")}(i)}`}#sr(t,e){this.canvas.addEventListener("contextmenu",noContextMenu,{signal:this._uiManager._signal});this.#tr();this.#Ha=new AbortController;const i=this._uiManager.combinedSignal(this.#Ha);this.canvas.addEventListener("pointerleave",this.canvasPointerleave.bind(this),{signal:i});this.canvas.addEventListener("pointermove",this.canvasPointermove.bind(this),{signal:i});this.canvas.addEventListener("pointerup",this.canvasPointerup.bind(this),{signal:i});this.isEditing=!0;if(!this.#Ua){this.#Ua=!0;this.#Ja();this.thickness||=InkEditor._defaultThickness;this.color||=InkEditor._defaultColor||AnnotationEditor._defaultLineColor;this.opacity??=InkEditor._defaultOpacity}this.currentPath.push([t,e]);this.#za=!1;this.#ir();this.#Va=()=>{this.#nr();this.#Va&&window.requestAnimationFrame(this.#Va)};window.requestAnimationFrame(this.#Va)}#ar(t,e){const[i,s]=this.currentPath.at(-1);if(this.currentPath.length>1&&t===i&&e===s)return;const n=this.currentPath;let a=this.#Oa;n.push([t,e]);this.#za=!0;if(n.length<=2){a.moveTo(...n[0]);a.lineTo(t,e)}else{if(3===n.length){this.#Oa=a=new Path2D;a.moveTo(...n[0])}this.#rr(a,...n.at(-3),...n.at(-2),t,e)}}#or(){if(0===this.currentPath.length)return;const t=this.currentPath.at(-1);this.#Oa.lineTo(...t)}#lr(t,e){this.#Va=null;t=Math.min(Math.max(t,0),this.canvas.width);e=Math.min(Math.max(e,0),this.canvas.height);this.#ar(t,e);this.#or();let i;if(1!==this.currentPath.length)i=this.#hr();else{const s=[t,e];i=[[s,s.slice(),s.slice(),s]]}const s=this.#Oa,n=this.currentPath;this.currentPath=[];this.#Oa=new Path2D;this.addCommands({cmd:()=>{this.allRawPaths.push(n);this.paths.push(i);this.bezierPath2D.push(s);this._uiManager.rebuild(this)},undo:()=>{this.allRawPaths.pop();this.paths.pop();this.bezierPath2D.pop();if(0===this.paths.length)this.remove();else{if(!this.canvas){this.#Ya();this.#Qa()}this.#Xa()}},mustExec:!0})}#nr(){if(!this.#za)return;this.#za=!1;const t=Math.ceil(this.thickness*this.parentScale),e=this.currentPath.slice(-3),i=e.map((t=>t[0])),s=e.map((t=>t[1])),{ctx:n}=(Math.min(...i),Math.max(...i),Math.min(...s),Math.max(...s),this);n.save();n.clearRect(0,0,this.canvas.width,this.canvas.height);for(const t of this.bezierPath2D)n.stroke(t);n.stroke(this.#Oa);n.restore()}#rr(t,e,i,s,n,a,r){const o=(e+s)/2,l=(i+n)/2,h=(s+a)/2,d=(n+r)/2;t.bezierCurveTo(o+2*(s-o)/3,l+2*(n-l)/3,h+2*(s-h)/3,d+2*(n-d)/3,h,d)}#hr(){const t=this.currentPath;if(t.length<=2)return[[t[0],t[0],t.at(-1),t.at(-1)]];const e=[];let i,[s,n]=t[0];for(i=1;i{this.#Na=null;this.canvas.removeEventListener("contextmenu",noContextMenu)}),10);this.#lr(t.offsetX,t.offsetY);this.addToAnnotationStorage();this.setInBackground()}#Ya(){this.canvas=document.createElement("canvas");this.canvas.width=this.canvas.height=0;this.canvas.className="inkEditorCanvas";this.canvas.setAttribute("data-l10n-id","pdfjs-ink-canvas");this.div.append(this.canvas);this.ctx=this.canvas.getContext("2d")}#Qa(){this.#ja=new ResizeObserver((t=>{const e=t[0].contentRect;e.width&&e.height&&this.setDimensions(e.width,e.height)}));this.#ja.observe(this.div);this._uiManager._signal.addEventListener("abort",(()=>{this.#ja?.disconnect();this.#ja=null}),{once:!0})}get isResizable(){return!this.isEmpty()&&this.#Ba}render(){if(this.div)return this.div;let t,e;if(this.width){t=this.x;e=this.y}super.render();this.div.setAttribute("data-l10n-id","pdfjs-ink");const[i,s,n,a]=this.#er();this.setAt(i,s,0,0);this.setDims(n,a);this.#Ya();if(this.width){const[i,s]=this.parentDimensions;this.setAspectRatio(this.width*i,this.height*s);this.setAt(t*i,e*s,this.width*i,this.height*s);this.#Ua=!0;this.#Ja();this.setDims(this.width*i,this.height*s);this.#Ka();this.div.classList.add("disabled")}else{this.div.classList.add("editing");this.enableEditMode()}this.#Qa();return this.div}#Ja(){if(!this.#Ua)return;const[t,e]=this.parentDimensions;this.canvas.width=Math.ceil(this.width*t);this.canvas.height=Math.ceil(this.height*e);this.#dr()}setDimensions(t,e){const i=Math.round(t),s=Math.round(e);if(this.#Ga===i&&this.#$a===s)return;this.#Ga=i;this.#$a=s;this.canvas.style.visibility="hidden";const[n,a]=this.parentDimensions;this.width=t/n;this.height=e/a;this.fixAndSetPosition();this.#Ba&&this.#ur(t,e);this.#Ja();this.#Ka();this.canvas.style.visibility="visible";this.fixDims()}#ur(t,e){const i=this.#pr(),s=(t-i)/this.#La,n=(e-i)/this.#Ia;this.scaleFactor=Math.min(s,n)}#dr(){const t=this.#pr()/2;this.ctx.setTransform(this.scaleFactor,0,0,this.scaleFactor,this.translationX*this.scaleFactor+t,this.translationY*this.scaleFactor+t)}static#gr(t){const e=new Path2D;for(let i=0,s=t.length;i`image/${t}`)))}static get supportedTypesStr(){return shadow(this,"supportedTypesStr",this.supportedTypes.join(","))}static isHandlingMimeForPasting(t){return this.supportedTypes.includes(t)}static paste(t,e){e.pasteEditor(g.STAMP,{bitmapFile:t.getAsFile()})}altTextFinish(){this._uiManager.useNewAltTextFlow&&(this.div.hidden=!1);super.altTextFinish()}get telemetryFinalData(){return{type:"stamp",hasAltText:!!this.altTextData?.altText}}static computeTelemetryFinalData(t){const e=t.get("hasAltText");return{hasAltText:e.get(!0)??0,hasNoAltText:e.get(!1)??0}}#kr(t,e=!1){if(t){this.#vr=t.bitmap;if(!e){this.#yr=t.id;this.#Tr=t.isSvg}t.file&&(this.#Er=t.file.name);this.#Ya()}else this.remove()}#Pr(){this.#wr=null;this._uiManager.enableWaiting(!1);if(this.#Cr)if(this._uiManager.useNewAltTextWhenAddingImage&&this._uiManager.useNewAltTextFlow&&this.#vr){this._editToolbar.hide();this._uiManager.editAltText(this,!0)}else{if(!this._uiManager.useNewAltTextWhenAddingImage&&this._uiManager.useNewAltTextFlow&&this.#vr){this._reportTelemetry({action:"pdfjs.image.image_added",data:{alt_text_modal:!1,alt_text_type:"empty"}});try{this.mlGuessAltText()}catch{}}this.div.focus()}}async mlGuessAltText(t=null,e=!0){if(this.hasAltTextData())return null;const{mlManager:i}=this._uiManager;if(!i)throw new Error("No ML.");if(!await i.isEnabledFor("altText"))throw new Error("ML isn't enabled for alt text.");const{data:s,width:n,height:a}=t||this.copyCanvas(null,null,!0).imageData,r=await i.guess({name:"altText",request:{data:s,width:n,height:a,channels:s.length/(n*a)}});if(!r)throw new Error("No response from the AI service.");if(r.error)throw new Error("Error from the AI service.");if(r.cancel)return null;if(!r.output)throw new Error("No valid response from the AI service.");const o=r.output;await this.setGuessedAltText(o);e&&!this.hasAltTextData()&&(this.altTextData={alt:o,decorative:!1});return o}#Fr(){if(this.#yr){this._uiManager.enableWaiting(!0);this._uiManager.imageManager.getFromId(this.#yr).then((t=>this.#kr(t,!0))).finally((()=>this.#Pr()));return}if(this.#xr){const t=this.#xr;this.#xr=null;this._uiManager.enableWaiting(!0);this.#wr=this._uiManager.imageManager.getFromUrl(t).then((t=>this.#kr(t))).finally((()=>this.#Pr()));return}if(this.#_r){const t=this.#_r;this.#_r=null;this._uiManager.enableWaiting(!0);this.#wr=this._uiManager.imageManager.getFromFile(t).then((t=>this.#kr(t))).finally((()=>this.#Pr()));return}const t=document.createElement("input");t.type="file";t.accept=StampEditor.supportedTypesStr;const e=this._uiManager._signal;this.#wr=new Promise((i=>{t.addEventListener("change",(async()=>{if(t.files&&0!==t.files.length){this._uiManager.enableWaiting(!0);const e=await this._uiManager.imageManager.getFromFile(t.files[0]);this._reportTelemetry({action:"pdfjs.image.image_selected",data:{alt_text_modal:this._uiManager.useNewAltTextFlow}});this.#kr(e)}else this.remove();i()}),{signal:e});t.addEventListener("cancel",(()=>{this.remove();i()}),{signal:e})})).finally((()=>this.#Pr()));t.click()}remove(){if(this.#yr){this.#vr=null;this._uiManager.imageManager.deleteId(this.#yr);this.#Cr?.remove();this.#Cr=null;this.#ja?.disconnect();this.#ja=null;if(this.#Sr){clearTimeout(this.#Sr);this.#Sr=null}}super.remove()}rebuild(){if(this.parent){super.rebuild();if(null!==this.div){this.#yr&&null===this.#Cr&&this.#Fr();this.isAttachedToDOM||this.parent.add(this)}}else this.#yr&&this.#Fr()}onceAdded(){this._isDraggable=!0;this.div.focus()}isEmpty(){return!(this.#wr||this.#vr||this.#xr||this.#_r||this.#yr)}get isResizable(){return!0}render(){if(this.div)return this.div;let t,e;if(this.width){t=this.x;e=this.y}super.render();this.div.hidden=!0;this.div.setAttribute("role","figure");this.addAltTextButton();this.#vr?this.#Ya():this.#Fr();if(this.width&&!this.annotationElementId){const[i,s]=this.parentDimensions;this.setAt(t*i,e*s,this.width*i,this.height*s)}return this.div}#Ya(){const{div:t}=this;let{width:e,height:i}=this.#vr;const[s,n]=this.pageDimensions,a=.75;if(this.width){e=this.width*s;i=this.height*n}else if(e>a*s||i>a*n){const t=Math.min(a*s/e,a*n/i);e*=t;i*=t}const[r,o]=this.parentDimensions;this.setDims(e*r/s,i*o/n);this._uiManager.enableWaiting(!1);const l=this.#Cr=document.createElement("canvas");l.setAttribute("role","img");this.addContainer(l);this._uiManager.useNewAltTextWhenAddingImage&&this._uiManager.useNewAltTextFlow&&!this.annotationElementId||(t.hidden=!1);this.#Dr(e,i);this.#Qa();if(!this.#Mr){this.parent.addUndoableEditor(this);this.#Mr=!0}this._reportTelemetry({action:"inserted_image"});this.#Er&&l.setAttribute("aria-label",this.#Er)}copyCanvas(t,e,i=!1){t||(t=224);const{width:s,height:n}=this.#vr,a=new OutputScale;let r=this.#vr,o=s,l=n,h=null;if(e){if(s>e||n>e){const t=Math.min(e/s,e/n);o=Math.floor(s*t);l=Math.floor(n*t)}h=document.createElement("canvas");const t=h.width=Math.ceil(o*a.sx),i=h.height=Math.ceil(l*a.sy);this.#Tr||(r=this.#Rr(t,i));const d=h.getContext("2d");d.filter=this._uiManager.hcmFilter;let c="white",u="#cfcfd8";if("none"!==this._uiManager.hcmFilter)u="black";else if(window.matchMedia?.("(prefers-color-scheme: dark)").matches){c="#8f8f9d";u="#42414d"}const p=15,g=p*a.sx,m=p*a.sy,f=new OffscreenCanvas(2*g,2*m),b=f.getContext("2d");b.fillStyle=c;b.fillRect(0,0,2*g,2*m);b.fillStyle=u;b.fillRect(0,0,g,m);b.fillRect(g,m,g,m);d.fillStyle=d.createPattern(f,"repeat");d.fillRect(0,0,t,i);d.drawImage(r,0,0,r.width,r.height,0,0,t,i)}let d=null;if(i){let e,i;if(a.symmetric&&r.widtht||n>t){const a=Math.min(t/s,t/n);e=Math.floor(s*a);i=Math.floor(n*a);this.#Tr||(r=this.#Rr(e,i))}}const o=new OffscreenCanvas(e,i).getContext("2d",{willReadFrequently:!0});o.drawImage(r,0,0,r.width,r.height,0,0,e,i);d={width:e,height:i,data:o.getImageData(0,0,e,i).data}}return{canvas:h,width:o,height:l,imageData:d}}#Ir(t,e){const[i,s]=this.parentDimensions;this.width=t/i;this.height=e/s;this._initialOptions?.isCentered?this.center():this.fixAndSetPosition();this._initialOptions=null;null!==this.#Sr&&clearTimeout(this.#Sr);this.#Sr=setTimeout((()=>{this.#Sr=null;this.#Dr(t,e)}),200)}#Rr(t,e){const{width:i,height:s}=this.#vr;let n=i,a=s,r=this.#vr;for(;n>2*t||a>2*e;){const i=n,s=a;n>2*t&&(n=n>=16384?Math.floor(n/2)-1:Math.ceil(n/2));a>2*e&&(a=a>=16384?Math.floor(a/2)-1:Math.ceil(a/2));const o=new OffscreenCanvas(n,a);o.getContext("2d").drawImage(r,0,0,i,s,0,0,n,a);r=o.transferToImageBitmap()}return r}#Dr(t,e){const i=new OutputScale,s=Math.ceil(t*i.sx),n=Math.ceil(e*i.sy),a=this.#Cr;if(!a||a.width===s&&a.height===n)return;a.width=s;a.height=n;const r=this.#Tr?this.#vr:this.#Rr(s,n),o=a.getContext("2d");o.filter=this._uiManager.hcmFilter;o.drawImage(r,0,0,r.width,r.height,0,0,s,n)}getImageForAltText(){return this.#Cr}#Lr(t){if(t){if(this.#Tr){const t=this._uiManager.imageManager.getSvgUrl(this.#yr);if(t)return t}const t=document.createElement("canvas");({width:t.width,height:t.height}=this.#vr);t.getContext("2d").drawImage(this.#vr,0,0);return t.toDataURL()}if(this.#Tr){const[t,e]=this.pageDimensions,i=Math.round(this.width*t*PixelsPerInch.PDF_TO_CSS_UNITS),s=Math.round(this.height*e*PixelsPerInch.PDF_TO_CSS_UNITS),n=new OffscreenCanvas(i,s);n.getContext("2d").drawImage(this.#vr,0,0,this.#vr.width,this.#vr.height,0,0,i,s);return n.transferToImageBitmap()}return structuredClone(this.#vr)}#Qa(){if(this._uiManager._signal){this.#ja=new ResizeObserver((t=>{const e=t[0].contentRect;e.width&&e.height&&this.#Ir(e.width,e.height)}));this.#ja.observe(this.div);this._uiManager._signal.addEventListener("abort",(()=>{this.#ja?.disconnect();this.#ja=null}),{once:!0})}}static async deserialize(t,e,i){let s=null;if(t instanceof StampAnnotationElement){const{data:{rect:n,rotation:a,id:r,structParent:o,popupRef:l},container:h,parent:{page:{pageNumber:d}}}=t,c=h.querySelector("canvas"),u=i.imageManager.getFromCanvas(h.id,c);c.remove();const p=(await e._structTree.getAriaAttributes(`${it}${r}`))?.get("aria-label")||"";s=t={annotationType:g.STAMP,bitmapId:u.id,bitmap:u.bitmap,pageIndex:d-1,rect:n.slice(0),rotation:a,id:r,deleted:!1,accessibilityData:{decorative:!1,altText:p},isSvg:!1,structParent:o,popupRef:l}}const n=await super.deserialize(t,e,i),{rect:a,bitmap:r,bitmapUrl:o,bitmapId:l,isSvg:h,accessibilityData:d}=t;if(l&&i.imageManager.isValidId(l)){n.#yr=l;r&&(n.#vr=r)}else n.#xr=o;n.#Tr=h;const[c,u]=n.pageDimensions;n.width=(a[2]-a[0])/c;n.height=(a[3]-a[1])/u;n.annotationElementId=t.id||null;d&&(n.altTextData=d);n._initialData=s;n.#Mr=!!s;return n}serialize(t=!1,e=null){if(this.isEmpty())return null;if(this.deleted)return this.serializeDeleted();const i={annotationType:g.STAMP,bitmapId:this.#yr,pageIndex:this.pageIndex,rect:this.getRect(0,0),rotation:this.rotation,isSvg:this.#Tr,structTreeParentId:this._structTreeParentId};if(t){i.bitmapUrl=this.#Lr(!0);i.accessibilityData=this.serializeAltText(!0);return i}const{decorative:s,altText:n}=this.serializeAltText(!1);!s&&n&&(i.accessibilityData={type:"Figure",alt:n});if(this.annotationElementId){const t=this.#gn(i);if(t.isSame)return null;t.isSameAltText?delete i.accessibilityData:i.accessibilityData.structParent=this._initialData.structParent??-1}i.id=this.annotationElementId;if(null===e)return i;e.stamps||=new Map;const a=this.#Tr?(i.rect[2]-i.rect[0])*(i.rect[3]-i.rect[1]):null;if(e.stamps.has(this.#yr)){if(this.#Tr){const t=e.stamps.get(this.#yr);if(a>t.area){t.area=a;t.serialized.bitmap.close();t.serialized.bitmap=this.#Lr(!1)}}}else{e.stamps.set(this.#yr,{area:a,serialized:i});i.bitmap=this.#Lr(!1)}return i}#gn(t){const{rect:e,pageIndex:i,accessibilityData:{altText:s}}=this._initialData,n=t.rect.every(((t,i)=>Math.abs(t-e[i])<1)),a=t.pageIndex===i,r=(t.accessibilityData?.alt||"")===s;return{isSame:n&&a&&r,isSameAltText:r}}renderAnnotationElement(t){t.updateEdited({rect:this.getRect(0,0)});return null}}class AnnotationEditorLayer{#Qs;#Nr=!1;#Or=null;#Br=null;#Hr=null;#zr=new Map;#Ur=!1;#jr=!1;#Wr=!1;#Gr=null;#$r=null;#m;static _initialized=!1;static#z=new Map([FreeTextEditor,InkEditor,StampEditor,HighlightEditor].map((t=>[t._editorType,t])));constructor({uiManager:t,pageIndex:e,div:i,structTreeLayer:s,accessibilityManager:n,annotationLayer:a,drawLayer:r,textLayer:o,viewport:l,l10n:h}){const d=[...AnnotationEditorLayer.#z.values()];if(!AnnotationEditorLayer._initialized){AnnotationEditorLayer._initialized=!0;for(const e of d)e.initialize(h,t)}t.registerEditorTypes(d);this.#m=t;this.pageIndex=e;this.div=i;this.#Qs=n;this.#Or=a;this.viewport=l;this.#Gr=o;this.drawLayer=r;this._structTree=s;this.#m.addLayer(this)}get isEmpty(){return 0===this.#zr.size}get isInvisible(){return this.isEmpty&&this.#m.getMode()===g.NONE}updateToolbar(t){this.#m.updateToolbar(t)}updateMode(t=this.#m.getMode()){this.#Vr();switch(t){case g.NONE:this.disableTextSelection();this.togglePointerEvents(!1);this.toggleAnnotationLayerPointerEvents(!0);this.disableClick();return;case g.INK:this.addInkEditorIfNeeded(!1);this.disableTextSelection();this.togglePointerEvents(!0);this.disableClick();break;case g.HIGHLIGHT:this.enableTextSelection();this.togglePointerEvents(!1);this.disableClick();break;default:this.disableTextSelection();this.togglePointerEvents(!0);this.enableClick()}this.toggleAnnotationLayerPointerEvents(!1);const{classList:e}=this.div;for(const i of AnnotationEditorLayer.#z.values())e.toggle(`${i._type}Editing`,t===i._editorType);this.div.hidden=!1}hasTextLayer(t){return t===this.#Gr?.div}addInkEditorIfNeeded(t){if(this.#m.getMode()!==g.INK)return;if(!t)for(const t of this.#zr.values())if(t.isEmpty()){t.setInBackground();return}this.createAndAddNewEditor({offsetX:0,offsetY:0},!1).setInBackground()}setEditingState(t){this.#m.setEditingState(t)}addCommands(t){this.#m.addCommands(t)}toggleDrawing(t=!1){this.div.classList.toggle("drawing",!t)}togglePointerEvents(t=!1){this.div.classList.toggle("disabled",!t)}toggleAnnotationLayerPointerEvents(t=!1){this.#Or?.div.classList.toggle("disabled",!t)}async enable(){this.div.tabIndex=0;this.togglePointerEvents(!0);const t=new Set;for(const e of this.#zr.values()){e.enableEditing();e.show(!0);if(e.annotationElementId){this.#m.removeChangedExistingAnnotation(e);t.add(e.annotationElementId)}}if(!this.#Or)return;const e=this.#Or.getEditableAnnotations();for(const i of e){i.hide();if(this.#m.isDeletedAnnotationElement(i.data.id))continue;if(t.has(i.data.id))continue;const e=await this.deserialize(i);if(e){this.addOrRebuild(e);e.enableEditing()}}}disable(){this.#Wr=!0;this.div.tabIndex=-1;this.togglePointerEvents(!1);const t=new Map,e=new Map;for(const i of this.#zr.values()){i.disableEditing();if(i.annotationElementId)if(null===i.serialize()){e.set(i.annotationElementId,i);this.getEditableAnnotation(i.annotationElementId)?.show();i.remove()}else t.set(i.annotationElementId,i)}if(this.#Or){const i=this.#Or.getEditableAnnotations();for(const s of i){const{id:i}=s.data;if(this.#m.isDeletedAnnotationElement(i))continue;let n=e.get(i);if(n){n.resetAnnotationElement(s);n.show(!1);s.show()}else{n=t.get(i);if(n){this.#m.addChangedExistingAnnotation(n);n.renderAnnotationElement(s)&&n.show(!1)}s.show()}}}this.#Vr();this.isEmpty&&(this.div.hidden=!0);const{classList:i}=this.div;for(const t of AnnotationEditorLayer.#z.values())i.remove(`${t._type}Editing`);this.disableTextSelection();this.toggleAnnotationLayerPointerEvents(!0);this.#Wr=!1}getEditableAnnotation(t){return this.#Or?.getEditableAnnotation(t)||null}setActiveEditor(t){this.#m.getActive()!==t&&this.#m.setActiveEditor(t)}enableTextSelection(){this.div.tabIndex=-1;if(this.#Gr?.div&&!this.#$r){this.#$r=new AbortController;const t=this.#m.combinedSignal(this.#$r);this.#Gr.div.addEventListener("pointerdown",this.#qr.bind(this),{signal:t});this.#Gr.div.classList.add("highlighting")}}disableTextSelection(){this.div.tabIndex=0;if(this.#Gr?.div&&this.#$r){this.#$r.abort();this.#$r=null;this.#Gr.div.classList.remove("highlighting")}}#qr(t){this.#m.unselectAll();const{target:e}=t;if(e===this.#Gr.div||("img"===e.getAttribute("role")||e.classList.contains("endOfContent"))&&this.#Gr.div.contains(e)){const{isMac:e}=util_FeatureTest.platform;if(0!==t.button||t.ctrlKey&&e)return;this.#m.showAllEditors("highlight",!0,!0);this.#Gr.div.classList.add("free");this.toggleDrawing();HighlightEditor.startHighlighting(this,"ltr"===this.#m.direction,{target:this.#Gr.div,x:t.x,y:t.y});this.#Gr.div.addEventListener("pointerup",(()=>{this.#Gr.div.classList.remove("free");this.toggleDrawing(!0)}),{once:!0,signal:this.#m._signal});t.preventDefault()}}enableClick(){if(this.#Br)return;this.#Br=new AbortController;const t=this.#m.combinedSignal(this.#Br);this.div.addEventListener("pointerdown",this.pointerdown.bind(this),{signal:t});this.div.addEventListener("pointerup",this.pointerup.bind(this),{signal:t})}disableClick(){this.#Br?.abort();this.#Br=null}attach(t){this.#zr.set(t.id,t);const{annotationElementId:e}=t;e&&this.#m.isDeletedAnnotationElement(e)&&this.#m.removeDeletedAnnotationElement(t)}detach(t){this.#zr.delete(t.id);this.#Qs?.removePointerInTextLayer(t.contentDiv);!this.#Wr&&t.annotationElementId&&this.#m.addDeletedAnnotationElement(t)}remove(t){this.detach(t);this.#m.removeEditor(t);t.div.remove();t.isAttachedToDOM=!1;this.#jr||this.addInkEditorIfNeeded(!1)}changeParent(t){if(t.parent!==this){if(t.parent&&t.annotationElementId){this.#m.addDeletedAnnotationElement(t.annotationElementId);AnnotationEditor.deleteAnnotationElement(t);t.annotationElementId=null}this.attach(t);t.parent?.detach(t);t.setParent(this);if(t.div&&t.isAttachedToDOM){t.div.remove();this.div.append(t.div)}}}add(t){if(t.parent!==this||!t.isAttachedToDOM){this.changeParent(t);this.#m.addEditor(t);this.attach(t);if(!t.isAttachedToDOM){const e=t.render();this.div.append(e);t.isAttachedToDOM=!0}t.fixAndSetPosition();t.onceAdded();this.#m.addToAnnotationStorage(t);t._reportTelemetry(t.telemetryInitialData)}}moveEditorInDOM(t){if(!t.isAttachedToDOM)return;const{activeElement:e}=document;if(t.div.contains(e)&&!this.#Hr){t._focusEventsAllowed=!1;this.#Hr=setTimeout((()=>{this.#Hr=null;if(t.div.contains(document.activeElement))t._focusEventsAllowed=!0;else{t.div.addEventListener("focusin",(()=>{t._focusEventsAllowed=!0}),{once:!0,signal:this.#m._signal});e.focus()}}),0)}t._structTreeParentId=this.#Qs?.moveElementInDOM(this.div,t.div,t.contentDiv,!0)}addOrRebuild(t){if(t.needsToBeRebuilt()){t.parent||=this;t.rebuild();t.show()}else this.add(t)}addUndoableEditor(t){this.addCommands({cmd:()=>t._uiManager.rebuild(t),undo:()=>{t.remove()},mustExec:!1})}getNextId(){return this.#m.getId()}get#Xr(){return AnnotationEditorLayer.#z.get(this.#m.getMode())}combinedSignal(t){return this.#m.combinedSignal(t)}#Kr(t){const e=this.#Xr;return e?new e.prototype.constructor(t):null}canCreateNewEmptyEditor(){return this.#Xr?.canCreateNewEmptyEditor()}pasteEditor(t,e){this.#m.updateToolbar(t);this.#m.updateMode(t);const{offsetX:i,offsetY:s}=this.#Yr(),n=this.getNextId(),a=this.#Kr({parent:this,id:n,x:i,y:s,uiManager:this.#m,isCentered:!0,...e});a&&this.add(a)}async deserialize(t){return await(AnnotationEditorLayer.#z.get(t.annotationType??t.annotationEditorType)?.deserialize(t,this,this.#m))||null}createAndAddNewEditor(t,e,i={}){const s=this.getNextId(),n=this.#Kr({parent:this,id:s,x:t.offsetX,y:t.offsetY,uiManager:this.#m,isCentered:e,...i});n&&this.add(n);return n}#Yr(){const{x:t,y:e,width:i,height:s}=this.div.getBoundingClientRect(),n=Math.max(0,t),a=Math.max(0,e),r=(n+Math.min(window.innerWidth,t+i))/2-t,o=(a+Math.min(window.innerHeight,e+s))/2-e,[l,h]=this.viewport.rotation%180==0?[r,o]:[o,r];return{offsetX:l,offsetY:h}}addNewEditor(){this.createAndAddNewEditor(this.#Yr(),!0)}setSelected(t){this.#m.setSelected(t)}toggleSelected(t){this.#m.toggleSelected(t)}isSelected(t){return this.#m.isSelected(t)}unselect(t){this.#m.unselect(t)}pointerup(t){const{isMac:e}=util_FeatureTest.platform;if(!(0!==t.button||t.ctrlKey&&e)&&t.target===this.div&&this.#Ur){this.#Ur=!1;this.#Nr?this.#m.getMode()!==g.STAMP?this.createAndAddNewEditor(t,!1):this.#m.unselectAll():this.#Nr=!0}}pointerdown(t){this.#m.getMode()===g.HIGHLIGHT&&this.enableTextSelection();if(this.#Ur){this.#Ur=!1;return}const{isMac:e}=util_FeatureTest.platform;if(0!==t.button||t.ctrlKey&&e)return;if(t.target!==this.div)return;this.#Ur=!0;const i=this.#m.getActive();this.#Nr=!i||i.isEmpty()}findNewParent(t,e,i){const s=this.#m.findParent(e,i);if(null===s||s===this)return!1;s.changeParent(t);return!0}destroy(){if(this.#m.getActive()?.parent===this){this.#m.commitOrRemove();this.#m.setActiveEditor(null)}if(this.#Hr){clearTimeout(this.#Hr);this.#Hr=null}for(const t of this.#zr.values()){this.#Qs?.removePointerInTextLayer(t.contentDiv);t.setParent(null);t.isAttachedToDOM=!1;t.div.remove()}this.div=null;this.#zr.clear();this.#m.removeLayer(this)}#Vr(){this.#jr=!0;for(const t of this.#zr.values())t.isEmpty()&&t.remove();this.#jr=!1}render({viewport:t}){this.viewport=t;setLayerDimensions(this.div,t);for(const t of this.#m.getEditors(this.pageIndex)){this.add(t);t.rebuild()}this.updateMode()}update({viewport:t}){this.#m.commitOrRemove();this.#Vr();const e=this.viewport.rotation,i=t.rotation;this.viewport=t;setLayerDimensions(this.div,{rotation:i});if(e!==i)for(const t of this.#zr.values())t.rotate(i);this.addInkEditorIfNeeded(!1)}get pageDimensions(){const{pageWidth:t,pageHeight:e}=this.viewport.rawDims;return[t,e]}get scale(){return this.#m.viewParameters.realScale}}class DrawLayer{#Fs=null;#v=0;#Qr=new Map;#Jr=new Map;constructor({pageIndex:t}){this.pageIndex=t}setParent(t){if(this.#Fs){if(this.#Fs!==t){if(this.#Qr.size>0)for(const e of this.#Qr.values()){e.remove();t.append(e)}this.#Fs=t}}else this.#Fs=t}static get _svgFactory(){return shadow(this,"_svgFactory",new DOMSVGFactory)}static#Zr(t,{x:e=0,y:i=0,width:s=1,height:n=1}={}){const{style:a}=t;a.top=100*i+"%";a.left=100*e+"%";a.width=100*s+"%";a.height=100*n+"%"}#to(t){const e=DrawLayer._svgFactory.create(1,1,!0);this.#Fs.append(e);e.setAttribute("aria-hidden",!0);DrawLayer.#Zr(e,t);return e}#eo(t,e){const i=DrawLayer._svgFactory.createElement("clipPath");t.append(i);const s=`clip_${e}`;i.setAttribute("id",s);i.setAttribute("clipPathUnits","objectBoundingBox");const n=DrawLayer._svgFactory.createElement("use");i.append(n);n.setAttribute("href",`#${e}`);n.classList.add("clip");return s}highlight(t,e,i,s=!1){const n=this.#v++,a=this.#to(t.box);a.classList.add("highlight");t.free&&a.classList.add("free");const r=DrawLayer._svgFactory.createElement("defs");a.append(r);const o=DrawLayer._svgFactory.createElement("path");r.append(o);const l=`path_p${this.pageIndex}_${n}`;o.setAttribute("id",l);o.setAttribute("d",t.toSVGPath());s&&this.#Jr.set(n,o);const h=this.#eo(r,l),d=DrawLayer._svgFactory.createElement("use");a.append(d);a.setAttribute("fill",e);a.setAttribute("fill-opacity",i);d.setAttribute("href",`#${l}`);this.#Qr.set(n,a);return{id:n,clipPathId:`url(#${h})`}}highlightOutline(t){const e=this.#v++,i=this.#to(t.box);i.classList.add("highlightOutline");const s=DrawLayer._svgFactory.createElement("defs");i.append(s);const n=DrawLayer._svgFactory.createElement("path");s.append(n);const a=`path_p${this.pageIndex}_${e}`;n.setAttribute("id",a);n.setAttribute("d",t.toSVGPath());n.setAttribute("vector-effect","non-scaling-stroke");let r;if(t.free){i.classList.add("free");const t=DrawLayer._svgFactory.createElement("mask");s.append(t);r=`mask_p${this.pageIndex}_${e}`;t.setAttribute("id",r);t.setAttribute("maskUnits","objectBoundingBox");const n=DrawLayer._svgFactory.createElement("rect");t.append(n);n.setAttribute("width","1");n.setAttribute("height","1");n.setAttribute("fill","white");const o=DrawLayer._svgFactory.createElement("use");t.append(o);o.setAttribute("href",`#${a}`);o.setAttribute("stroke","none");o.setAttribute("fill","black");o.setAttribute("fill-rule","nonzero");o.classList.add("mask")}const o=DrawLayer._svgFactory.createElement("use");i.append(o);o.setAttribute("href",`#${a}`);r&&o.setAttribute("mask",`url(#${r})`);const l=o.cloneNode();i.append(l);o.classList.add("mainOutline");l.classList.add("secondaryOutline");this.#Qr.set(e,i);return e}finalizeLine(t,e){const i=this.#Jr.get(t);this.#Jr.delete(t);this.updateBox(t,e.box);i.setAttribute("d",e.toSVGPath())}updateLine(t,e){this.#Qr.get(t).firstChild.firstChild.setAttribute("d",e.toSVGPath())}removeFreeHighlight(t){this.remove(t);this.#Jr.delete(t)}updatePath(t,e){this.#Jr.get(t).setAttribute("d",e.toSVGPath())}updateBox(t,e){DrawLayer.#Zr(this.#Qr.get(t),e)}show(t,e){this.#Qr.get(t).classList.toggle("hidden",!e)}rotate(t,e){this.#Qr.get(t).setAttribute("data-main-rotation",e)}changeColor(t,e){this.#Qr.get(t).setAttribute("fill",e)}changeOpacity(t,e){this.#Qr.get(t).setAttribute("fill-opacity",e)}addClass(t,e){this.#Qr.get(t).classList.add(e)}removeClass(t,e){this.#Qr.get(t).classList.remove(e)}getSVGRoot(t){return this.#Qr.get(t)}remove(t){if(null!==this.#Fs){this.#Qr.get(t).remove();this.#Qr.delete(t)}}destroy(){this.#Fs=null;for(const t of this.#Qr.values())t.remove();this.#Qr.clear()}}var te=__webpack_exports__.AbortException,ee=__webpack_exports__.AnnotationEditorLayer,ie=__webpack_exports__.AnnotationEditorParamsType,se=__webpack_exports__.AnnotationEditorType,ne=__webpack_exports__.AnnotationEditorUIManager,ae=__webpack_exports__.AnnotationLayer,re=__webpack_exports__.AnnotationMode,oe=__webpack_exports__.CMapCompressionType,le=__webpack_exports__.ColorPicker,he=__webpack_exports__.DOMSVGFactory,de=__webpack_exports__.DrawLayer,ce=__webpack_exports__.FeatureTest,ue=__webpack_exports__.GlobalWorkerOptions,pe=__webpack_exports__.ImageKind,ge=__webpack_exports__.InvalidPDFException,me=__webpack_exports__.MissingPDFException,fe=__webpack_exports__.OPS,be=__webpack_exports__.OutputScale,Ae=__webpack_exports__.PDFDataRangeTransport,ve=__webpack_exports__.PDFDateString,ye=__webpack_exports__.PDFWorker,we=__webpack_exports__.PasswordResponses,xe=__webpack_exports__.PermissionFlag,_e=__webpack_exports__.PixelsPerInch,Ee=__webpack_exports__.RenderingCancelledException,Ce=__webpack_exports__.TextLayer,Se=__webpack_exports__.UnexpectedResponseException,Te=__webpack_exports__.Util,Me=__webpack_exports__.VerbosityLevel,ke=__webpack_exports__.XfaLayer,Pe=__webpack_exports__.build,Fe=__webpack_exports__.createValidAbsoluteUrl,De=__webpack_exports__.fetchData,Re=__webpack_exports__.getDocument,Ie=__webpack_exports__.getFilenameFromUrl,Le=__webpack_exports__.getPdfFilenameFromUrl,Ne=__webpack_exports__.getXfaPageViewport,Oe=__webpack_exports__.isDataScheme,Be=__webpack_exports__.isPdfFile,He=__webpack_exports__.noContextMenu,ze=__webpack_exports__.normalizeUnicode,Ue=__webpack_exports__.setLayerDimensions,je=__webpack_exports__.shadow,We=__webpack_exports__.version;export{te as AbortException,ee as AnnotationEditorLayer,ie as AnnotationEditorParamsType,se as AnnotationEditorType,ne as AnnotationEditorUIManager,ae as AnnotationLayer,re as AnnotationMode,oe as CMapCompressionType,le as ColorPicker,he as DOMSVGFactory,de as DrawLayer,ce as FeatureTest,ue as GlobalWorkerOptions,pe as ImageKind,ge as InvalidPDFException,me as MissingPDFException,fe as OPS,be as OutputScale,Ae as PDFDataRangeTransport,ve as PDFDateString,ye as PDFWorker,we as PasswordResponses,xe as PermissionFlag,_e as PixelsPerInch,Ee as RenderingCancelledException,Ce as TextLayer,Se as UnexpectedResponseException,Te as Util,Me as VerbosityLevel,ke as XfaLayer,Pe as build,Fe as createValidAbsoluteUrl,De as fetchData,Re as getDocument,Ie as getFilenameFromUrl,Le as getPdfFilenameFromUrl,Ne as getXfaPageViewport,Oe as isDataScheme,Be as isPdfFile,He as noContextMenu,ze as normalizeUnicode,Ue as setLayerDimensions,je as shadow,We as version}; \ No newline at end of file diff --git a/jiuguan2025cc/public/lib/pdf.worker.min.mjs b/jiuguan2025cc/public/lib/pdf.worker.min.mjs new file mode 100644 index 0000000000000000000000000000000000000000..ba391b489b6742527663d143620bf7b75eb8bab6 --- /dev/null +++ b/jiuguan2025cc/public/lib/pdf.worker.min.mjs @@ -0,0 +1,21 @@ +/** + * @licstart The following is the entire license notice for the + * JavaScript code in this page + * + * Copyright 2024 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @licend The above is the entire license notice for the + * JavaScript code in this page + */var e={d:(t,i)=>{for(var a in i)e.o(i,a)&&!e.o(t,a)&&Object.defineProperty(t,a,{enumerable:!0,get:i[a]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)},__webpack_exports__ = globalThis.pdfjsWorker = {};e.d(__webpack_exports__,{WorkerMessageHandler:()=>WorkerMessageHandler});const t=!("object"!=typeof process||process+""!="[object process]"||process.versions.nw||process.versions.electron&&process.type&&"browser"!==process.type),i=[1,0,0,1,0,0],a=[.001,0,0,.001,0,0],s=1.35,r=.35,n=.25925925925925924,g=1,o=2,c=4,C=8,h=16,l=64,Q=128,E=256,u="pdfjs_internal_editor_",d=3,f=9,p=13,m=15,y={PRINT:4,MODIFY_CONTENTS:8,COPY:16,MODIFY_ANNOTATIONS:32,FILL_INTERACTIVE_FORMS:256,COPY_FOR_ACCESSIBILITY:512,ASSEMBLE:1024,PRINT_HIGH_QUALITY:2048},w=0,D=4,b=1,F=2,S=3,k=1,R=2,N=3,G=4,x=5,U=6,M=7,L=8,H=9,J=10,Y=11,v=12,K=13,T=14,q=15,O=16,W=17,j=20,X="Group",Z="R",V=1,z=2,_=4,$=16,AA=32,eA=128,tA=512,iA=1,aA=2,sA=4096,rA=8192,nA=32768,gA=65536,oA=131072,IA=1048576,cA=2097152,CA=8388608,hA=16777216,BA=1,lA=2,QA=3,EA=4,uA=5,dA={E:"Mouse Enter",X:"Mouse Exit",D:"Mouse Down",U:"Mouse Up",Fo:"Focus",Bl:"Blur",PO:"PageOpen",PC:"PageClose",PV:"PageVisible",PI:"PageInvisible",K:"Keystroke",F:"Format",V:"Validate",C:"Calculate"},fA={WC:"WillClose",WS:"WillSave",DS:"DidSave",WP:"WillPrint",DP:"DidPrint"},pA={O:"PageOpen",C:"PageClose"},mA={ERRORS:0,WARNINGS:1,INFOS:5},yA={NONE:0,BINARY:1},wA=1,DA=2,bA=3,FA=4,SA=5,kA=6,RA=7,NA=8,GA=9,xA=10,UA=11,MA=12,LA=13,HA=14,JA=15,YA=16,vA=17,KA=18,TA=19,qA=20,OA=21,PA=22,WA=23,jA=24,XA=25,ZA=26,VA=27,zA=28,_A=29,$A=30,Ae=31,ee=32,te=33,ie=34,ae=35,se=36,re=37,ne=38,ge=39,oe=40,Ie=41,ce=42,Ce=43,he=44,Be=45,le=46,Qe=47,Ee=48,ue=49,de=50,fe=51,pe=52,me=53,ye=54,we=55,De=56,be=57,Fe=58,Se=59,ke=60,Re=61,Ne=62,Ge=63,xe=64,Ue=65,Me=66,Le=67,He=68,Je=69,Ye=70,ve=71,Ke=72,Te=73,qe=74,Oe=75,Pe=76,We=77,je=80,Xe=81,Ze=83,Ve=84,ze=85,_e=86,$e=87,At=88,et=89,tt=90,it=91,at=92,st=93,rt=1,nt=2;let gt=mA.WARNINGS;function getVerbosityLevel(){return gt}function info(e){gt>=mA.INFOS&&console.log(`Info: ${e}`)}function warn(e){gt>=mA.WARNINGS&&console.log(`Warning: ${e}`)}function unreachable(e){throw new Error(e)}function assert(e,t){e||unreachable(t)}function createValidAbsoluteUrl(e,t=null,i=null){if(!e)return null;try{if(i&&"string"==typeof e){if(i.addDefaultProtocol&&e.startsWith("www.")){const t=e.match(/\./g);t?.length>=2&&(e=`http://${e}`)}if(i.tryConvertEncoding)try{e=stringToUTF8String(e)}catch{}}const a=t?new URL(e,t):new URL(e);if(function _isValidProtocol(e){switch(e?.protocol){case"http:":case"https:":case"ftp:":case"mailto:":case"tel:":return!0;default:return!1}}(a))return a}catch{}return null}function shadow(e,t,i,a=!1){Object.defineProperty(e,t,{value:i,enumerable:!a,configurable:!0,writable:!1});return i}const ot=function BaseExceptionClosure(){function BaseException(e,t){this.message=e;this.name=t}BaseException.prototype=new Error;BaseException.constructor=BaseException;return BaseException}();class PasswordException extends ot{constructor(e,t){super(e,"PasswordException");this.code=t}}class UnknownErrorException extends ot{constructor(e,t){super(e,"UnknownErrorException");this.details=t}}class InvalidPDFException extends ot{constructor(e){super(e,"InvalidPDFException")}}class MissingPDFException extends ot{constructor(e){super(e,"MissingPDFException")}}class UnexpectedResponseException extends ot{constructor(e,t){super(e,"UnexpectedResponseException");this.status=t}}class FormatError extends ot{constructor(e){super(e,"FormatError")}}class AbortException extends ot{constructor(e){super(e,"AbortException")}}function bytesToString(e){"object"==typeof e&&void 0!==e?.length||unreachable("Invalid argument for bytesToString");const t=e.length,i=8192;if(t>24&255,e>>16&255,e>>8&255,255&e)}function objectSize(e){return Object.keys(e).length}class FeatureTest{static get isLittleEndian(){return shadow(this,"isLittleEndian",function isLittleEndian(){const e=new Uint8Array(4);e[0]=1;return 1===new Uint32Array(e.buffer,0,1)[0]}())}static get isEvalSupported(){return shadow(this,"isEvalSupported",function isEvalSupported(){try{new Function("");return!0}catch{return!1}}())}static get isOffscreenCanvasSupported(){return shadow(this,"isOffscreenCanvasSupported","undefined"!=typeof OffscreenCanvas)}static get platform(){return"undefined"!=typeof navigator&&"string"==typeof navigator?.platform?shadow(this,"platform",{isMac:navigator.platform.includes("Mac"),isWindows:navigator.platform.includes("Win"),isFirefox:"string"==typeof navigator?.userAgent&&navigator.userAgent.includes("Firefox")}):shadow(this,"platform",{isMac:!1,isWindows:!1,isFirefox:!1})}static get isCSSRoundSupported(){return shadow(this,"isCSSRoundSupported",globalThis.CSS?.supports?.("width: round(1.5px, 1px)"))}}const It=Array.from(Array(256).keys(),(e=>e.toString(16).padStart(2,"0")));class Util{static makeHexColor(e,t,i){return`#${It[e]}${It[t]}${It[i]}`}static scaleMinMax(e,t){let i;if(e[0]){if(e[0]<0){i=t[0];t[0]=t[2];t[2]=i}t[0]*=e[0];t[2]*=e[0];if(e[3]<0){i=t[1];t[1]=t[3];t[3]=i}t[1]*=e[3];t[3]*=e[3]}else{i=t[0];t[0]=t[1];t[1]=i;i=t[2];t[2]=t[3];t[3]=i;if(e[1]<0){i=t[1];t[1]=t[3];t[3]=i}t[1]*=e[1];t[3]*=e[1];if(e[2]<0){i=t[0];t[0]=t[2];t[2]=i}t[0]*=e[2];t[2]*=e[2]}t[0]+=e[4];t[1]+=e[5];t[2]+=e[4];t[3]+=e[5]}static transform(e,t){return[e[0]*t[0]+e[2]*t[1],e[1]*t[0]+e[3]*t[1],e[0]*t[2]+e[2]*t[3],e[1]*t[2]+e[3]*t[3],e[0]*t[4]+e[2]*t[5]+e[4],e[1]*t[4]+e[3]*t[5]+e[5]]}static applyTransform(e,t){return[e[0]*t[0]+e[1]*t[2]+t[4],e[0]*t[1]+e[1]*t[3]+t[5]]}static applyInverseTransform(e,t){const i=t[0]*t[3]-t[1]*t[2];return[(e[0]*t[3]-e[1]*t[2]+t[2]*t[5]-t[4]*t[3])/i,(-e[0]*t[1]+e[1]*t[0]+t[4]*t[1]-t[5]*t[0])/i]}static getAxialAlignedBoundingBox(e,t){const i=this.applyTransform(e,t),a=this.applyTransform(e.slice(2,4),t),s=this.applyTransform([e[0],e[3]],t),r=this.applyTransform([e[2],e[1]],t);return[Math.min(i[0],a[0],s[0],r[0]),Math.min(i[1],a[1],s[1],r[1]),Math.max(i[0],a[0],s[0],r[0]),Math.max(i[1],a[1],s[1],r[1])]}static inverseTransform(e){const t=e[0]*e[3]-e[1]*e[2];return[e[3]/t,-e[1]/t,-e[2]/t,e[0]/t,(e[2]*e[5]-e[4]*e[3])/t,(e[4]*e[1]-e[5]*e[0])/t]}static singularValueDecompose2dScale(e){const t=[e[0],e[2],e[1],e[3]],i=e[0]*t[0]+e[1]*t[2],a=e[0]*t[1]+e[1]*t[3],s=e[2]*t[0]+e[3]*t[2],r=e[2]*t[1]+e[3]*t[3],n=(i+r)/2,g=Math.sqrt((i+r)**2-4*(i*r-s*a))/2,o=n+g||1,c=n-g||1;return[Math.sqrt(o),Math.sqrt(c)]}static normalizeRect(e){const t=e.slice(0);if(e[0]>e[2]){t[0]=e[2];t[2]=e[0]}if(e[1]>e[3]){t[1]=e[3];t[3]=e[1]}return t}static intersect(e,t){const i=Math.max(Math.min(e[0],e[2]),Math.min(t[0],t[2])),a=Math.min(Math.max(e[0],e[2]),Math.max(t[0],t[2]));if(i>a)return null;const s=Math.max(Math.min(e[1],e[3]),Math.min(t[1],t[3])),r=Math.min(Math.max(e[1],e[3]),Math.max(t[1],t[3]));return s>r?null:[i,s,a,r]}static#A(e,t,i,a,s,r,n,g,o,c){if(o<=0||o>=1)return;const C=1-o,h=o*o,l=h*o,Q=C*(C*(C*e+3*o*t)+3*h*i)+l*a,E=C*(C*(C*s+3*o*r)+3*h*n)+l*g;c[0]=Math.min(c[0],Q);c[1]=Math.min(c[1],E);c[2]=Math.max(c[2],Q);c[3]=Math.max(c[3],E)}static#e(e,t,i,a,s,r,n,g,o,c,C,h){if(Math.abs(o)<1e-12){Math.abs(c)>=1e-12&&this.#A(e,t,i,a,s,r,n,g,-C/c,h);return}const l=c**2-4*C*o;if(l<0)return;const Q=Math.sqrt(l),E=2*o;this.#A(e,t,i,a,s,r,n,g,(-c+Q)/E,h);this.#A(e,t,i,a,s,r,n,g,(-c-Q)/E,h)}static bezierBoundingBox(e,t,i,a,s,r,n,g,o){if(o){o[0]=Math.min(o[0],e,n);o[1]=Math.min(o[1],t,g);o[2]=Math.max(o[2],e,n);o[3]=Math.max(o[3],t,g)}else o=[Math.min(e,n),Math.min(t,g),Math.max(e,n),Math.max(t,g)];this.#e(e,i,s,n,t,a,r,g,3*(3*(i-s)-e+n),6*(e-2*i+s),3*(i-e),o);this.#e(e,i,s,n,t,a,r,g,3*(3*(a-r)-t+g),6*(t-2*a+r),3*(a-t),o);return o}}const ct=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,728,711,710,729,733,731,730,732,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8226,8224,8225,8230,8212,8211,402,8260,8249,8250,8722,8240,8222,8220,8221,8216,8217,8218,8482,64257,64258,321,338,352,376,381,305,322,339,353,382,0,8364];function stringToPDFString(e){if(e[0]>="ï"){let t;if("þ"===e[0]&&"ÿ"===e[1]){t="utf-16be";e.length%2==1&&(e=e.slice(0,-1))}else if("ÿ"===e[0]&&"þ"===e[1]){t="utf-16le";e.length%2==1&&(e=e.slice(0,-1))}else"ï"===e[0]&&"»"===e[1]&&"¿"===e[2]&&(t="utf-8");if(t)try{const i=new TextDecoder(t,{fatal:!0}),a=stringToBytes(e),s=i.decode(a);return s.includes("")?s.replaceAll(/\x1b[^\x1b]*(?:\x1b|$)/g,""):s}catch(e){warn(`stringToPDFString: "${e}".`)}}const t=[];for(let i=0,a=e.length;i{unreachable("Should not call `set` on the empty dictionary.")};return shadow(this,"empty",e)}static merge({xref:e,dictArray:t,mergeSubDicts:i=!1}){const a=new Dict(e),s=new Map;for(const e of t)if(e instanceof Dict)for(const[t,a]of Object.entries(e._map)){let e=s.get(t);if(void 0===e){e=[];s.set(t,e)}else if(!(i&&a instanceof Dict))continue;e.push(a)}for(const[t,i]of s){if(1===i.length||!(i[0]instanceof Dict)){a._map[t]=i[0];continue}const s=new Dict(e);for(const e of i)for(const[t,i]of Object.entries(e._map))void 0===s._map[t]&&(s._map[t]=i);s.size>0&&(a._map[t]=s)}s.clear();return a.size>0?a:Dict.empty}clone(){const e=new Dict(this.xref);for(const t of this.getKeys())e.set(t,this.getRaw(t));return e}delete(e){delete this._map[e]}}class Ref{constructor(e,t){this.num=e;this.gen=t}toString(){return 0===this.gen?`${this.num}R`:`${this.num}R${this.gen}`}static fromString(e){const t=Ft[e];if(t)return t;const i=/^(\d+)R(\d*)$/.exec(e);return i&&"0"!==i[1]?Ft[e]=new Ref(parseInt(i[1]),i[2]?parseInt(i[2]):0):null}static get(e,t){const i=0===t?`${e}R`:`${e}R${t}`;return Ft[i]||=new Ref(e,t)}}class RefSet{constructor(e=null){this._set=new Set(e?._set)}has(e){return this._set.has(e.toString())}put(e){this._set.add(e.toString())}remove(e){this._set.delete(e.toString())}[Symbol.iterator](){return this._set.values()}clear(){this._set.clear()}}class RefSetCache{constructor(){this._map=new Map}get size(){return this._map.size}get(e){return this._map.get(e.toString())}has(e){return this._map.has(e.toString())}put(e,t){this._map.set(e.toString(),t)}putAlias(e,t){this._map.set(e.toString(),this.get(t))}[Symbol.iterator](){return this._map.values()}clear(){this._map.clear()}*items(){for(const[e,t]of this._map)yield[Ref.fromString(e),t]}}function isName(e,t){return e instanceof Name&&(void 0===t||e.name===t)}function isCmd(e,t){return e instanceof Cmd&&(void 0===t||e.cmd===t)}function isDict(e,t){return e instanceof Dict&&(void 0===t||isName(e.get("Type"),t))}function isRefsEqual(e,t){return e.num===t.num&&e.gen===t.gen}class BaseStream{get length(){unreachable("Abstract getter `length` accessed")}get isEmpty(){unreachable("Abstract getter `isEmpty` accessed")}get isDataLoaded(){return shadow(this,"isDataLoaded",!0)}getByte(){unreachable("Abstract method `getByte` called")}getBytes(e){unreachable("Abstract method `getBytes` called")}async getImageData(e,t){return this.getBytes(e,t)}async asyncGetBytes(){unreachable("Abstract method `asyncGetBytes` called")}get isAsync(){return!1}get canAsyncDecodeImageFromBuffer(){return!1}peekByte(){const e=this.getByte();-1!==e&&this.pos--;return e}peekBytes(e){const t=this.getBytes(e);this.pos-=t.length;return t}getUint16(){const e=this.getByte(),t=this.getByte();return-1===e||-1===t?-1:(e<<8)+t}getInt32(){return(this.getByte()<<24)+(this.getByte()<<16)+(this.getByte()<<8)+this.getByte()}getByteRange(e,t){unreachable("Abstract method `getByteRange` called")}getString(e){return bytesToString(this.getBytes(e))}skip(e){this.pos+=e||1}reset(){unreachable("Abstract method `reset` called")}moveStart(){unreachable("Abstract method `moveStart` called")}makeSubStream(e,t,i=null){unreachable("Abstract method `makeSubStream` called")}getBaseStreams(){return null}}const kt=/^[1-9]\.\d$/;function getLookupTableFactory(e){let t;return function(){if(e){t=Object.create(null);e(t);e=null}return t}}class MissingDataException extends ot{constructor(e,t){super(`Missing data [${e}, ${t})`,"MissingDataException");this.begin=e;this.end=t}}class ParserEOFException extends ot{constructor(e){super(e,"ParserEOFException")}}class XRefEntryException extends ot{constructor(e){super(e,"XRefEntryException")}}class XRefParseException extends ot{constructor(e){super(e,"XRefParseException")}}function arrayBuffersToBytes(e){const t=e.length;if(0===t)return new Uint8Array(0);if(1===t)return new Uint8Array(e[0]);let i=0;for(let a=0;a0,"The number should be a positive integer.");const i=[];let a;for(;e>=1e3;){e-=1e3;i.push("M")}a=e/100|0;e%=100;i.push(Rt[a]);a=e/10|0;e%=10;i.push(Rt[10+a]);i.push(Rt[20+e]);const s=i.join("");return t?s.toLowerCase():s}function log2(e){return e<=0?0:Math.ceil(Math.log2(e))}function readInt8(e,t){return e[t]<<24>>24}function readUint16(e,t){return e[t]<<8|e[t+1]}function readUint32(e,t){return(e[t]<<24|e[t+1]<<16|e[t+2]<<8|e[t+3])>>>0}function isWhiteSpace(e){return 32===e||9===e||13===e||10===e}function isNumberArray(e,t){return Array.isArray(e)?(null===t||e.length===t)&&e.every((e=>"number"==typeof e)):ArrayBuffer.isView(e)&&(0===e.length||"number"==typeof e[0])&&(null===t||e.length===t)}function lookupMatrix(e,t){return isNumberArray(e,6)?e:t}function lookupRect(e,t){return isNumberArray(e,4)?e:t}function lookupNormalRect(e,t){return isNumberArray(e,4)?Util.normalizeRect(e):t}function parseXFAPath(e){const t=/(.+)\[(\d+)\]$/;return e.split(".").map((e=>{const i=e.match(t);return i?{name:i[1],pos:parseInt(i[2],10)}:{name:e,pos:0}}))}function escapePDFName(e){const t=[];let i=0;for(let a=0,s=e.length;a126||35===s||40===s||41===s||60===s||62===s||91===s||93===s||123===s||125===s||47===s||37===s){i"\n"===e?"\\n":"\r"===e?"\\r":`\\${e}`))}function _collectJS(e,t,i,a){if(!e)return;let s=null;if(e instanceof Ref){if(a.has(e))return;s=e;a.put(s);e=t.fetch(e)}if(Array.isArray(e))for(const s of e)_collectJS(s,t,i,a);else if(e instanceof Dict){if(isName(e.get("S"),"JavaScript")){const t=e.get("JS");let a;t instanceof BaseStream?a=t.getString():"string"==typeof t&&(a=t);a&&=stringToPDFString(a).replaceAll("\0","");a&&i.push(a)}_collectJS(e.getRaw("Next"),t,i,a)}s&&a.remove(s)}function collectActions(e,t,i){const a=Object.create(null),s=getInheritableProperty({dict:t,key:"AA",stopWhenFound:!1});if(s)for(let t=s.length-1;t>=0;t--){const r=s[t];if(r instanceof Dict)for(const t of r.getKeys()){const s=i[t];if(!s)continue;const n=[];_collectJS(r.getRaw(t),e,n,new RefSet);n.length>0&&(a[s]=n)}}if(t.has("A")){const i=[];_collectJS(t.get("A"),e,i,new RefSet);i.length>0&&(a.Action=i)}return objectSize(a)>0?a:null}const Nt={60:"<",62:">",38:"&",34:""",39:"'"};function*codePointIter(e){for(let t=0,i=e.length;t55295&&(i<57344||i>65533)&&t++;yield i}}function encodeToXmlString(e){const t=[];let i=0;for(let a=0,s=e.length;a55295&&(s<57344||s>65533)&&a++;i=a+1}}if(0===t.length)return e;i: ${e}.`);return!1}return!0}function validateCSSFont(e){const t=new Set(["100","200","300","400","500","600","700","800","900","1000","normal","bold","bolder","lighter"]),{fontFamily:i,fontWeight:a,italicAngle:s}=e;if(!validateFontName(i,!0))return!1;const r=a?a.toString():"";e.fontWeight=t.has(r)?r:"400";const n=parseFloat(s);e.italicAngle=isNaN(n)||n<-90||n>90?"14":s.toString();return!0}function recoverJsURL(e){const t=new RegExp("^\\s*("+["app.launchURL","window.open","xfa.host.gotoURL"].join("|").replaceAll(".","\\.")+")\\((?:'|\")([^'\"]*)(?:'|\")(?:,\\s*(\\w+)\\)|\\))","i").exec(e);if(t?.[2]){const e=t[2];let i=!1;"true"===t[3]&&"app.launchURL"===t[1]&&(i=!0);return{url:e,newWindow:i}}return null}function numberToString(e){if(Number.isInteger(e))return e.toString();const t=Math.round(100*e);return t%100==0?(t/100).toString():t%10==0?e.toFixed(1):e.toFixed(2)}function getNewAnnotationsMap(e){if(!e)return null;const t=new Map;for(const[i,a]of e){if(!i.startsWith(u))continue;let e=t.get(a.pageIndex);if(!e){e=[];t.set(a.pageIndex,e)}e.push(a)}return t.size>0?t:null}function stringToAsciiOrUTF16BE(e){return function isAscii(e){return/^[\x00-\x7F]*$/.test(e)}(e)?e:stringToUTF16String(e,!0)}function stringToUTF16HexString(e){const t=[];for(let i=0,a=e.length;i>8&255).toString(16).padStart(2,"0"),(255&a).toString(16).padStart(2,"0"))}return t.join("")}function stringToUTF16String(e,t=!1){const i=[];t&&i.push("þÿ");for(let t=0,a=e.length;t>8&255),String.fromCharCode(255&a))}return i.join("")}function getRotationMatrix(e,t,i){switch(e){case 90:return[0,1,-1,0,t,0];case 180:return[-1,0,0,-1,t,i];case 270:return[0,-1,1,0,0,i];default:throw new Error("Invalid rotation")}}function getSizeInBytes(e){return Math.ceil(Math.ceil(Math.log2(1+e))/8)}class Stream extends BaseStream{constructor(e,t,i,a){super();this.bytes=e instanceof Uint8Array?e:new Uint8Array(e);this.start=t||0;this.pos=this.start;this.end=t+i||this.bytes.length;this.dict=a}get length(){return this.end-this.start}get isEmpty(){return 0===this.length}getByte(){return this.pos>=this.end?-1:this.bytes[this.pos++]}getBytes(e){const t=this.bytes,i=this.pos,a=this.end;if(!e)return t.subarray(i,a);let s=i+e;s>a&&(s=a);this.pos=s;return t.subarray(i,s)}getByteRange(e,t){e<0&&(e=0);t>this.end&&(t=this.end);return this.bytes.subarray(e,t)}reset(){this.pos=this.start}moveStart(){this.start=this.pos}makeSubStream(e,t,i=null){return new Stream(this.bytes.buffer,e,t,i)}}class StringStream extends Stream{constructor(e){super(stringToBytes(e))}}class NullStream extends Stream{constructor(){super(new Uint8Array(0))}}class ChunkedStream extends Stream{constructor(e,t,i){super(new Uint8Array(e),0,e,null);this.chunkSize=t;this._loadedChunks=new Set;this.numChunks=Math.ceil(e/t);this.manager=i;this.progressiveDataLength=0;this.lastSuccessfulEnsureByteChunk=-1}getMissingChunks(){const e=[];for(let t=0,i=this.numChunks;t=this.end?this.numChunks:Math.floor(t/this.chunkSize);for(let e=i;ethis.numChunks)&&t!==this.lastSuccessfulEnsureByteChunk){if(!this._loadedChunks.has(t))throw new MissingDataException(e,e+1);this.lastSuccessfulEnsureByteChunk=t}}ensureRange(e,t){if(e>=t)return;if(t<=this.progressiveDataLength)return;const i=Math.floor(e/this.chunkSize);if(i>this.numChunks)return;const a=Math.min(Math.floor((t-1)/this.chunkSize)+1,this.numChunks);for(let s=i;s=this.end)return-1;e>=this.progressiveDataLength&&this.ensureByte(e);return this.bytes[this.pos++]}getBytes(e){const t=this.bytes,i=this.pos,a=this.end;if(!e){a>this.progressiveDataLength&&this.ensureRange(i,a);return t.subarray(i,a)}let s=i+e;s>a&&(s=a);s>this.progressiveDataLength&&this.ensureRange(i,s);this.pos=s;return t.subarray(i,s)}getByteRange(e,t){e<0&&(e=0);t>this.end&&(t=this.end);t>this.progressiveDataLength&&this.ensureRange(e,t);return this.bytes.subarray(e,t)}makeSubStream(e,t,i=null){t?e+t>this.progressiveDataLength&&this.ensureRange(e,e+t):e>=this.progressiveDataLength&&this.ensureByte(e);function ChunkedStreamSubstream(){}ChunkedStreamSubstream.prototype=Object.create(this);ChunkedStreamSubstream.prototype.getMissingChunks=function(){const e=this.chunkSize,t=Math.floor(this.start/e),i=Math.floor((this.end-1)/e)+1,a=[];for(let e=t;e{const readChunk=({value:r,done:n})=>{try{if(n){const t=arrayBuffersToBytes(a);a=null;e(t);return}s+=r.byteLength;i.isStreamingSupported&&this.onProgress({loaded:s});a.push(r);i.read().then(readChunk,t)}catch(e){t(e)}};i.read().then(readChunk,t)})).then((t=>{this.aborted||this.onReceiveData({chunk:t,begin:e})}))}requestAllChunks(e=!1){if(!e){const e=this.stream.getMissingChunks();this._requestChunks(e)}return this._loadedStreamCapability.promise}_requestChunks(e){const t=this.currRequestId++,i=new Set;this._chunksNeededByRequest.set(t,i);for(const t of e)this.stream.hasChunk(t)||i.add(t);if(0===i.size)return Promise.resolve();const a=Promise.withResolvers();this._promisesByRequest.set(t,a);const s=[];for(const e of i){let i=this._requestsByChunk.get(e);if(!i){i=[];this._requestsByChunk.set(e,i);s.push(e)}i.push(t)}if(s.length>0){const e=this.groupChunks(s);for(const t of e){const e=t.beginChunk*this.chunkSize,i=Math.min(t.endChunk*this.chunkSize,this.length);this.sendRequest(e,i).catch(a.reject)}}return a.promise.catch((e=>{if(!this.aborted)throw e}))}getStream(){return this.stream}requestRange(e,t){t=Math.min(t,this.length);const i=this.getBeginChunk(e),a=this.getEndChunk(t),s=[];for(let e=i;e=0&&a+1!==r){t.push({beginChunk:i,endChunk:a+1});i=r}s+1===e.length&&t.push({beginChunk:i,endChunk:r+1});a=r}return t}onProgress(e){this.msgHandler.send("DocProgress",{loaded:this.stream.numChunksLoaded*this.chunkSize+e.loaded,total:this.length})}onReceiveData(e){const t=e.chunk,i=void 0===e.begin,a=i?this.progressiveDataLength:e.begin,s=a+t.byteLength,r=Math.floor(a/this.chunkSize),n=s0||g.push(i)}}}if(!this.disableAutoFetch&&0===this._requestsByChunk.size){let e;if(1===this.stream.numChunksLoaded){const t=this.stream.numChunks-1;this.stream.hasChunk(t)||(e=t)}else e=this.stream.nextEmptyChunk(n);Number.isInteger(e)&&this._requestChunks([e])}for(const e of g){const t=this._promisesByRequest.get(e);this._promisesByRequest.delete(e);t.resolve()}this.msgHandler.send("DocProgress",{loaded:this.stream.numChunksLoaded*this.chunkSize,total:this.length})}onError(e){this._loadedStreamCapability.reject(e)}getBeginChunk(e){return Math.floor(e/this.chunkSize)}getEndChunk(e){return Math.floor((e-1)/this.chunkSize)+1}abort(e){this.aborted=!0;this.pdfNetworkStream?.cancelAllRequests(e);for(const t of this._promisesByRequest.values())t.reject(e)}}class ColorSpace{constructor(e,t){this.name=e;this.numComps=t}getRgb(e,t){const i=new Uint8ClampedArray(3);this.getRgbItem(e,t,i,0);return i}getRgbItem(e,t,i,a){unreachable("Should not call ColorSpace.getRgbItem")}getRgbBuffer(e,t,i,a,s,r,n){unreachable("Should not call ColorSpace.getRgbBuffer")}getOutputLength(e,t){unreachable("Should not call ColorSpace.getOutputLength")}isPassthrough(e){return!1}isDefaultDecode(e,t){return ColorSpace.isDefaultDecode(e,this.numComps)}fillRgb(e,t,i,a,s,r,n,g,o){const c=t*i;let C=null;const h=1<h&&"DeviceGray"!==this.name&&"DeviceRGB"!==this.name){const t=n<=8?new Uint8Array(h):new Uint16Array(h);for(let e=0;e=.99554525?1:this.#l(0,1,1.055*e**(1/2.4)-.055)}#l(e,t,i){return Math.max(e,Math.min(t,i))}#Q(e){return e<0?-this.#Q(-e):e>8?((e+16)/116)**3:e*CalRGBCS.#I}#E(e,t,i){if(0===e[0]&&0===e[1]&&0===e[2]){i[0]=t[0];i[1]=t[1];i[2]=t[2];return}const a=this.#Q(0),s=(1-a)/(1-this.#Q(e[0])),r=1-s,n=(1-a)/(1-this.#Q(e[1])),g=1-n,o=(1-a)/(1-this.#Q(e[2])),c=1-o;i[0]=t[0]*s+r;i[1]=t[1]*n+g;i[2]=t[2]*o+c}#u(e,t,i){if(1===e[0]&&1===e[2]){i[0]=t[0];i[1]=t[1];i[2]=t[2];return}const a=i;this.#c(CalRGBCS.#i,t,a);const s=CalRGBCS.#n;this.#C(e,a,s);this.#c(CalRGBCS.#a,s,i)}#d(e,t,i){const a=i;this.#c(CalRGBCS.#i,t,a);const s=CalRGBCS.#n;this.#h(e,a,s);this.#c(CalRGBCS.#a,s,i)}#t(e,t,i,a,s){const r=this.#l(0,1,e[t]*s),n=this.#l(0,1,e[t+1]*s),g=this.#l(0,1,e[t+2]*s),o=1===r?1:r**this.GR,c=1===n?1:n**this.GG,C=1===g?1:g**this.GB,h=this.MXA*o+this.MXB*c+this.MXC*C,l=this.MYA*o+this.MYB*c+this.MYC*C,Q=this.MZA*o+this.MZB*c+this.MZC*C,E=CalRGBCS.#g;E[0]=h;E[1]=l;E[2]=Q;const u=CalRGBCS.#o;this.#u(this.whitePoint,E,u);const d=CalRGBCS.#g;this.#E(this.blackPoint,u,d);const f=CalRGBCS.#o;this.#d(CalRGBCS.#r,d,f);const p=CalRGBCS.#g;this.#c(CalRGBCS.#s,f,p);i[a]=255*this.#B(p[0]);i[a+1]=255*this.#B(p[1]);i[a+2]=255*this.#B(p[2])}getRgbItem(e,t,i,a){this.#t(e,t,i,a,1)}getRgbBuffer(e,t,i,a,s,r,n){const g=1/((1<this.amax||this.bmin>this.bmax){info("Invalid Range, falling back to defaults");this.amin=-100;this.amax=100;this.bmin=-100;this.bmax=100}}#f(e){return e>=6/29?e**3:108/841*(e-4/29)}#p(e,t,i,a){return i+e*(a-i)/t}#t(e,t,i,a,s){let r=e[t],n=e[t+1],g=e[t+2];if(!1!==i){r=this.#p(r,i,0,100);n=this.#p(n,i,this.amin,this.amax);g=this.#p(g,i,this.bmin,this.bmax)}n>this.amax?n=this.amax:nthis.bmax?g=this.bmax:g>>0}function hexToStr(e,t){return 1===t?String.fromCharCode(e[0],e[1]):3===t?String.fromCharCode(e[0],e[1],e[2],e[3]):String.fromCharCode(...e.subarray(0,t+1))}function addHex(e,t,i){let a=0;for(let s=i;s>=0;s--){a+=e[s]+t[s];e[s]=255&a;a>>=8}}function incHex(e,t){let i=1;for(let a=t;a>=0&&i>0;a--){i+=e[a];e[a]=255&i;i>>=8}}const Gt=16;class BinaryCMapStream{constructor(e){this.buffer=e;this.pos=0;this.end=e.length;this.tmpBuf=new Uint8Array(19)}readByte(){return this.pos>=this.end?-1:this.buffer[this.pos++]}readNumber(){let e,t=0;do{const i=this.readByte();if(i<0)throw new FormatError("unexpected EOF in bcmap");e=!(128&i);t=t<<7|127&i}while(!e);return t}readSigned(){const e=this.readNumber();return 1&e?~(e>>>1):e>>>1}readHex(e,t){e.set(this.buffer.subarray(this.pos,this.pos+t+1));this.pos+=t+1}readHexNumber(e,t){let i;const a=this.tmpBuf;let s=0;do{const e=this.readByte();if(e<0)throw new FormatError("unexpected EOF in bcmap");i=!(128&e);a[s++]=127&e}while(!i);let r=t,n=0,g=0;for(;r>=0;){for(;g<8&&a.length>0;){n|=a[--s]<>=8;g-=8}}readHexSigned(e,t){this.readHexNumber(e,t);const i=1&e[t]?255:0;let a=0;for(let s=0;s<=t;s++){a=(1&a)<<8|e[s];e[s]=a>>1^i}}readString(){const e=this.readNumber(),t=new Array(e);for(let i=0;i=0;){const e=l>>5;if(7===e){switch(31&l){case 0:a.readString();break;case 1:r=a.readString()}continue}const i=!!(16&l),s=15&l;if(s+1>Gt)throw new Error("BinaryCMapReader.process: Invalid dataSize.");const Q=1,E=a.readNumber();switch(e){case 0:a.readHex(n,s);a.readHexNumber(g,s);addHex(g,n,s);t.addCodespaceRange(s+1,hexToInt(n,s),hexToInt(g,s));for(let e=1;es&&(a=s)}else{for(;!this.eof;)this.readBlock(t);a=this.bufferLength}this.pos=a;return this.buffer.subarray(i,a)}async getImageData(e,t=null){if(!this.canAsyncDecodeImageFromBuffer)return this.getBytes(e,t);const i=await this.stream.asyncGetBytes();return this.decodeImage(i,t)}reset(){this.pos=0}makeSubStream(e,t,i=null){if(void 0===t)for(;!this.eof;)this.readBlock();else{const i=e+t;for(;this.bufferLength<=i&&!this.eof;)this.readBlock()}return new Stream(this.buffer,e,t,i)}getBaseStreams(){return this.str?this.str.getBaseStreams():null}}class StreamsSequenceStream extends DecodeStream{constructor(e,t=null){let i=0;for(const t of e)i+=t instanceof DecodeStream?t._rawMinBufferLength:t.length;super(i);this.streams=e;this._onError=t}readBlock(){const e=this.streams;if(0===e.length){this.eof=!0;return}const t=e.shift();let i;try{i=t.getBytes()}catch(e){if(this._onError){this._onError(e,t.dict?.objId);return}throw e}const a=this.bufferLength,s=a+i.length;this.ensureBuffer(s).set(i,a);this.bufferLength=s}getBaseStreams(){const e=[];for(const t of this.streams){const i=t.getBaseStreams();i&&e.push(...i)}return e.length>0?e:null}}class Ascii85Stream extends DecodeStream{constructor(e,t){t&&(t*=.8);super(t);this.str=e;this.dict=e.dict;this.input=new Uint8Array(5)}readBlock(){const e=this.str;let t=e.getByte();for(;isWhiteSpace(t);)t=e.getByte();if(-1===t||126===t){this.eof=!0;return}const i=this.bufferLength;let a,s;if(122===t){a=this.ensureBuffer(i+4);for(s=0;s<4;++s)a[i+s]=0;this.bufferLength+=4}else{const r=this.input;r[0]=t;for(s=1;s<5;++s){t=e.getByte();for(;isWhiteSpace(t);)t=e.getByte();r[s]=t;if(-1===t||126===t)break}a=this.ensureBuffer(i+s-1);this.bufferLength+=s-1;if(s<5){for(;s<5;++s)r[s]=117;this.eof=!0}let n=0;for(s=0;s<5;++s)n=85*n+(r[s]-33);for(s=3;s>=0;--s){a[i+s]=255&n;n>>=8}}}}class AsciiHexStream extends DecodeStream{constructor(e,t){t&&(t*=.5);super(t);this.str=e;this.dict=e.dict;this.firstDigit=-1}readBlock(){const e=this.str.getBytes(8e3);if(!e.length){this.eof=!0;return}const t=e.length+1>>1,i=this.ensureBuffer(this.bufferLength+t);let a=this.bufferLength,s=this.firstDigit;for(const t of e){let e;if(t>=48&&t<=57)e=15&t;else{if(!(t>=65&&t<=70||t>=97&&t<=102)){if(62===t){this.eof=!0;break}continue}e=9+(15&t)}if(s<0)s=e;else{i[a++]=s<<4|e;s=-1}}if(s>=0&&this.eof){i[a++]=s<<4;s=-1}this.firstDigit=s;this.bufferLength=a}}const Ut=-1,Mt=[[-1,-1],[-1,-1],[7,8],[7,7],[6,6],[6,6],[6,5],[6,5],[4,0],[4,0],[4,0],[4,0],[4,0],[4,0],[4,0],[4,0],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,4],[3,4],[3,4],[3,4],[3,4],[3,4],[3,4],[3,4],[3,4],[3,4],[3,4],[3,4],[3,4],[3,4],[3,4],[3,4],[3,3],[3,3],[3,3],[3,3],[3,3],[3,3],[3,3],[3,3],[3,3],[3,3],[3,3],[3,3],[3,3],[3,3],[3,3],[3,3],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2]],Lt=[[-1,-1],[12,-2],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[11,1792],[11,1792],[12,1984],[12,2048],[12,2112],[12,2176],[12,2240],[12,2304],[11,1856],[11,1856],[11,1920],[11,1920],[12,2368],[12,2432],[12,2496],[12,2560]],Ht=[[-1,-1],[-1,-1],[-1,-1],[-1,-1],[8,29],[8,29],[8,30],[8,30],[8,45],[8,45],[8,46],[8,46],[7,22],[7,22],[7,22],[7,22],[7,23],[7,23],[7,23],[7,23],[8,47],[8,47],[8,48],[8,48],[6,13],[6,13],[6,13],[6,13],[6,13],[6,13],[6,13],[6,13],[7,20],[7,20],[7,20],[7,20],[8,33],[8,33],[8,34],[8,34],[8,35],[8,35],[8,36],[8,36],[8,37],[8,37],[8,38],[8,38],[7,19],[7,19],[7,19],[7,19],[8,31],[8,31],[8,32],[8,32],[6,1],[6,1],[6,1],[6,1],[6,1],[6,1],[6,1],[6,1],[6,12],[6,12],[6,12],[6,12],[6,12],[6,12],[6,12],[6,12],[8,53],[8,53],[8,54],[8,54],[7,26],[7,26],[7,26],[7,26],[8,39],[8,39],[8,40],[8,40],[8,41],[8,41],[8,42],[8,42],[8,43],[8,43],[8,44],[8,44],[7,21],[7,21],[7,21],[7,21],[7,28],[7,28],[7,28],[7,28],[8,61],[8,61],[8,62],[8,62],[8,63],[8,63],[8,0],[8,0],[8,320],[8,320],[8,384],[8,384],[5,10],[5,10],[5,10],[5,10],[5,10],[5,10],[5,10],[5,10],[5,10],[5,10],[5,10],[5,10],[5,10],[5,10],[5,10],[5,10],[5,11],[5,11],[5,11],[5,11],[5,11],[5,11],[5,11],[5,11],[5,11],[5,11],[5,11],[5,11],[5,11],[5,11],[5,11],[5,11],[7,27],[7,27],[7,27],[7,27],[8,59],[8,59],[8,60],[8,60],[9,1472],[9,1536],[9,1600],[9,1728],[7,18],[7,18],[7,18],[7,18],[7,24],[7,24],[7,24],[7,24],[8,49],[8,49],[8,50],[8,50],[8,51],[8,51],[8,52],[8,52],[7,25],[7,25],[7,25],[7,25],[8,55],[8,55],[8,56],[8,56],[8,57],[8,57],[8,58],[8,58],[6,192],[6,192],[6,192],[6,192],[6,192],[6,192],[6,192],[6,192],[6,1664],[6,1664],[6,1664],[6,1664],[6,1664],[6,1664],[6,1664],[6,1664],[8,448],[8,448],[8,512],[8,512],[9,704],[9,768],[8,640],[8,640],[8,576],[8,576],[9,832],[9,896],[9,960],[9,1024],[9,1088],[9,1152],[9,1216],[9,1280],[9,1344],[9,1408],[7,256],[7,256],[7,256],[7,256],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,2],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[5,128],[5,128],[5,128],[5,128],[5,128],[5,128],[5,128],[5,128],[5,128],[5,128],[5,128],[5,128],[5,128],[5,128],[5,128],[5,128],[5,8],[5,8],[5,8],[5,8],[5,8],[5,8],[5,8],[5,8],[5,8],[5,8],[5,8],[5,8],[5,8],[5,8],[5,8],[5,8],[5,9],[5,9],[5,9],[5,9],[5,9],[5,9],[5,9],[5,9],[5,9],[5,9],[5,9],[5,9],[5,9],[5,9],[5,9],[5,9],[6,16],[6,16],[6,16],[6,16],[6,16],[6,16],[6,16],[6,16],[6,17],[6,17],[6,17],[6,17],[6,17],[6,17],[6,17],[6,17],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,4],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[4,5],[6,14],[6,14],[6,14],[6,14],[6,14],[6,14],[6,14],[6,14],[6,15],[6,15],[6,15],[6,15],[6,15],[6,15],[6,15],[6,15],[5,64],[5,64],[5,64],[5,64],[5,64],[5,64],[5,64],[5,64],[5,64],[5,64],[5,64],[5,64],[5,64],[5,64],[5,64],[5,64],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,6],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7],[4,7]],Jt=[[-1,-1],[-1,-1],[12,-2],[12,-2],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[11,1792],[11,1792],[11,1792],[11,1792],[12,1984],[12,1984],[12,2048],[12,2048],[12,2112],[12,2112],[12,2176],[12,2176],[12,2240],[12,2240],[12,2304],[12,2304],[11,1856],[11,1856],[11,1856],[11,1856],[11,1920],[11,1920],[11,1920],[11,1920],[12,2368],[12,2368],[12,2432],[12,2432],[12,2496],[12,2496],[12,2560],[12,2560],[10,18],[10,18],[10,18],[10,18],[10,18],[10,18],[10,18],[10,18],[12,52],[12,52],[13,640],[13,704],[13,768],[13,832],[12,55],[12,55],[12,56],[12,56],[13,1280],[13,1344],[13,1408],[13,1472],[12,59],[12,59],[12,60],[12,60],[13,1536],[13,1600],[11,24],[11,24],[11,24],[11,24],[11,25],[11,25],[11,25],[11,25],[13,1664],[13,1728],[12,320],[12,320],[12,384],[12,384],[12,448],[12,448],[13,512],[13,576],[12,53],[12,53],[12,54],[12,54],[13,896],[13,960],[13,1024],[13,1088],[13,1152],[13,1216],[10,64],[10,64],[10,64],[10,64],[10,64],[10,64],[10,64],[10,64]],Yt=[[8,13],[8,13],[8,13],[8,13],[8,13],[8,13],[8,13],[8,13],[8,13],[8,13],[8,13],[8,13],[8,13],[8,13],[8,13],[8,13],[11,23],[11,23],[12,50],[12,51],[12,44],[12,45],[12,46],[12,47],[12,57],[12,58],[12,61],[12,256],[10,16],[10,16],[10,16],[10,16],[10,17],[10,17],[10,17],[10,17],[12,48],[12,49],[12,62],[12,63],[12,30],[12,31],[12,32],[12,33],[12,40],[12,41],[11,22],[11,22],[8,14],[8,14],[8,14],[8,14],[8,14],[8,14],[8,14],[8,14],[8,14],[8,14],[8,14],[8,14],[8,14],[8,14],[8,14],[8,14],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,10],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[7,11],[9,15],[9,15],[9,15],[9,15],[9,15],[9,15],[9,15],[9,15],[12,128],[12,192],[12,26],[12,27],[12,28],[12,29],[11,19],[11,19],[11,20],[11,20],[12,34],[12,35],[12,36],[12,37],[12,38],[12,39],[11,21],[11,21],[12,42],[12,43],[10,0],[10,0],[10,0],[10,0],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12],[7,12]],vt=[[-1,-1],[-1,-1],[-1,-1],[-1,-1],[6,9],[6,8],[5,7],[5,7],[4,6],[4,6],[4,6],[4,6],[4,5],[4,5],[4,5],[4,5],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,4],[3,4],[3,4],[3,4],[3,4],[3,4],[3,4],[3,4],[2,3],[2,3],[2,3],[2,3],[2,3],[2,3],[2,3],[2,3],[2,3],[2,3],[2,3],[2,3],[2,3],[2,3],[2,3],[2,3],[2,2],[2,2],[2,2],[2,2],[2,2],[2,2],[2,2],[2,2],[2,2],[2,2],[2,2],[2,2],[2,2],[2,2],[2,2],[2,2]];class CCITTFaxDecoder{constructor(e,t={}){if(!e||"function"!=typeof e.next)throw new Error('CCITTFaxDecoder - invalid "source" parameter.');this.source=e;this.eof=!1;this.encoding=t.K||0;this.eoline=t.EndOfLine||!1;this.byteAlign=t.EncodedByteAlign||!1;this.columns=t.Columns||1728;this.rows=t.Rows||0;this.eoblock=t.EndOfBlock??!0;this.black=t.BlackIs1||!1;this.codingLine=new Uint32Array(this.columns+1);this.refLine=new Uint32Array(this.columns+2);this.codingLine[0]=this.columns;this.codingPos=0;this.row=0;this.nextLine2D=this.encoding<0;this.inputBits=0;this.inputBuf=0;this.outputBits=0;this.rowsDone=!1;let i;for(;0===(i=this._lookBits(12));)this._eatBits(1);1===i&&this._eatBits(12);if(this.encoding>0){this.nextLine2D=!this._lookBits(1);this._eatBits(1)}}readNextChar(){if(this.eof)return-1;const e=this.refLine,t=this.codingLine,i=this.columns;let a,s,r,n,g;if(0===this.outputBits){this.rowsDone&&(this.eof=!0);if(this.eof)return-1;this.err=!1;let r,g,o;if(this.nextLine2D){for(n=0;t[n]=64);do{g+=o=this._getWhiteCode()}while(o>=64)}else{do{r+=o=this._getWhiteCode()}while(o>=64);do{g+=o=this._getBlackCode()}while(o>=64)}this._addPixels(t[this.codingPos]+r,s);t[this.codingPos]0?--a:++a;for(;e[a]<=t[this.codingPos]&&e[a]0?--a:++a;for(;e[a]<=t[this.codingPos]&&e[a]0?--a:++a;for(;e[a]<=t[this.codingPos]&&e[a]=64);else do{r+=o=this._getWhiteCode()}while(o>=64);this._addPixels(t[this.codingPos]+r,s);s^=1}}let c=!1;this.byteAlign&&(this.inputBits&=-8);if(this.eoblock||this.row!==this.rows-1){r=this._lookBits(12);if(this.eoline)for(;r!==Ut&&1!==r;){this._eatBits(1);r=this._lookBits(12)}else for(;0===r;){this._eatBits(1);r=this._lookBits(12)}if(1===r){this._eatBits(12);c=!0}else r===Ut&&(this.eof=!0)}else this.rowsDone=!0;if(!this.eof&&this.encoding>0&&!this.rowsDone){this.nextLine2D=!this._lookBits(1);this._eatBits(1)}if(this.eoblock&&c&&this.byteAlign){r=this._lookBits(12);if(1===r){this._eatBits(12);if(this.encoding>0){this._lookBits(1);this._eatBits(1)}if(this.encoding>=0)for(n=0;n<4;++n){r=this._lookBits(12);1!==r&&info("bad rtc code: "+r);this._eatBits(12);if(this.encoding>0){this._lookBits(1);this._eatBits(1)}}this.eof=!0}}else if(this.err&&this.eoline){for(;;){r=this._lookBits(13);if(r===Ut){this.eof=!0;return-1}if(r>>1==1)break;this._eatBits(1)}this._eatBits(12);if(this.encoding>0){this._eatBits(1);this.nextLine2D=!(1&r)}}this.outputBits=t[0]>0?t[this.codingPos=0]:t[this.codingPos=1];this.row++}if(this.outputBits>=8){g=1&this.codingPos?0:255;this.outputBits-=8;if(0===this.outputBits&&t[this.codingPos]r){g<<=r;1&this.codingPos||(g|=255>>8-r);this.outputBits-=r;r=0}else{g<<=this.outputBits;1&this.codingPos||(g|=255>>8-this.outputBits);r-=this.outputBits;this.outputBits=0;if(t[this.codingPos]0){g<<=r;r=0}}}while(r)}this.black&&(g^=255);return g}_addPixels(e,t){const i=this.codingLine;let a=this.codingPos;if(e>i[a]){if(e>this.columns){info("row is wrong length");this.err=!0;e=this.columns}1&a^t&&++a;i[a]=e}this.codingPos=a}_addPixelsNeg(e,t){const i=this.codingLine;let a=this.codingPos;if(e>i[a]){if(e>this.columns){info("row is wrong length");this.err=!0;e=this.columns}1&a^t&&++a;i[a]=e}else if(e0&&e=s){const t=i[e-s];if(t[0]===a){this._eatBits(a);return[!0,t[1],!0]}}}return[!1,0,!1]}_getTwoDimCode(){let e,t=0;if(this.eoblock){t=this._lookBits(7);e=Mt[t];if(e?.[0]>0){this._eatBits(e[0]);return e[1]}}else{const e=this._findTableCode(1,7,Mt);if(e[0]&&e[2])return e[1]}info("Bad two dim code");return Ut}_getWhiteCode(){let e,t=0;if(this.eoblock){t=this._lookBits(12);if(t===Ut)return 1;e=t>>5==0?Lt[t]:Ht[t>>3];if(e[0]>0){this._eatBits(e[0]);return e[1]}}else{let e=this._findTableCode(1,9,Ht);if(e[0])return e[1];e=this._findTableCode(11,12,Lt);if(e[0])return e[1]}info("bad white code");this._eatBits(1);return 1}_getBlackCode(){let e,t;if(this.eoblock){e=this._lookBits(13);if(e===Ut)return 1;t=e>>7==0?Jt[e]:e>>9==0&&e>>7!=0?Yt[(e>>1)-64]:vt[e>>7];if(t[0]>0){this._eatBits(t[0]);return t[1]}}else{let e=this._findTableCode(2,6,vt);if(e[0])return e[1];e=this._findTableCode(7,12,Yt,64);if(e[0])return e[1];e=this._findTableCode(10,13,Jt);if(e[0])return e[1]}info("bad black code");this._eatBits(1);return 1}_lookBits(e){let t;for(;this.inputBits>16-e;this.inputBuf=this.inputBuf<<8|t;this.inputBits+=8}return this.inputBuf>>this.inputBits-e&65535>>16-e}_eatBits(e){(this.inputBits-=e)<0&&(this.inputBits=0)}}class CCITTFaxStream extends DecodeStream{constructor(e,t,i){super(t);this.str=e;this.dict=e.dict;i instanceof Dict||(i=Dict.empty);const a={next:()=>e.getByte()};this.ccittFaxDecoder=new CCITTFaxDecoder(a,{K:i.get("K"),EndOfLine:i.get("EndOfLine"),EncodedByteAlign:i.get("EncodedByteAlign"),Columns:i.get("Columns"),Rows:i.get("Rows"),EndOfBlock:i.get("EndOfBlock"),BlackIs1:i.get("BlackIs1")})}readBlock(){for(;!this.eof;){const e=this.ccittFaxDecoder.readNextChar();if(-1===e){this.eof=!0;return}this.ensureBuffer(this.bufferLength+1);this.buffer[this.bufferLength++]=e}}}const Kt=new Int32Array([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),Tt=new Int32Array([3,4,5,6,7,8,9,10,65547,65549,65551,65553,131091,131095,131099,131103,196643,196651,196659,196667,262211,262227,262243,262259,327811,327843,327875,327907,258,258,258]),qt=new Int32Array([1,2,3,4,65541,65543,131081,131085,196625,196633,262177,262193,327745,327777,393345,393409,459009,459137,524801,525057,590849,591361,657409,658433,724993,727041,794625,798721,868353,876545]),Ot=[new Int32Array([459008,524368,524304,524568,459024,524400,524336,590016,459016,524384,524320,589984,524288,524416,524352,590048,459012,524376,524312,589968,459028,524408,524344,590032,459020,524392,524328,59e4,524296,524424,524360,590064,459010,524372,524308,524572,459026,524404,524340,590024,459018,524388,524324,589992,524292,524420,524356,590056,459014,524380,524316,589976,459030,524412,524348,590040,459022,524396,524332,590008,524300,524428,524364,590072,459009,524370,524306,524570,459025,524402,524338,590020,459017,524386,524322,589988,524290,524418,524354,590052,459013,524378,524314,589972,459029,524410,524346,590036,459021,524394,524330,590004,524298,524426,524362,590068,459011,524374,524310,524574,459027,524406,524342,590028,459019,524390,524326,589996,524294,524422,524358,590060,459015,524382,524318,589980,459031,524414,524350,590044,459023,524398,524334,590012,524302,524430,524366,590076,459008,524369,524305,524569,459024,524401,524337,590018,459016,524385,524321,589986,524289,524417,524353,590050,459012,524377,524313,589970,459028,524409,524345,590034,459020,524393,524329,590002,524297,524425,524361,590066,459010,524373,524309,524573,459026,524405,524341,590026,459018,524389,524325,589994,524293,524421,524357,590058,459014,524381,524317,589978,459030,524413,524349,590042,459022,524397,524333,590010,524301,524429,524365,590074,459009,524371,524307,524571,459025,524403,524339,590022,459017,524387,524323,589990,524291,524419,524355,590054,459013,524379,524315,589974,459029,524411,524347,590038,459021,524395,524331,590006,524299,524427,524363,590070,459011,524375,524311,524575,459027,524407,524343,590030,459019,524391,524327,589998,524295,524423,524359,590062,459015,524383,524319,589982,459031,524415,524351,590046,459023,524399,524335,590014,524303,524431,524367,590078,459008,524368,524304,524568,459024,524400,524336,590017,459016,524384,524320,589985,524288,524416,524352,590049,459012,524376,524312,589969,459028,524408,524344,590033,459020,524392,524328,590001,524296,524424,524360,590065,459010,524372,524308,524572,459026,524404,524340,590025,459018,524388,524324,589993,524292,524420,524356,590057,459014,524380,524316,589977,459030,524412,524348,590041,459022,524396,524332,590009,524300,524428,524364,590073,459009,524370,524306,524570,459025,524402,524338,590021,459017,524386,524322,589989,524290,524418,524354,590053,459013,524378,524314,589973,459029,524410,524346,590037,459021,524394,524330,590005,524298,524426,524362,590069,459011,524374,524310,524574,459027,524406,524342,590029,459019,524390,524326,589997,524294,524422,524358,590061,459015,524382,524318,589981,459031,524414,524350,590045,459023,524398,524334,590013,524302,524430,524366,590077,459008,524369,524305,524569,459024,524401,524337,590019,459016,524385,524321,589987,524289,524417,524353,590051,459012,524377,524313,589971,459028,524409,524345,590035,459020,524393,524329,590003,524297,524425,524361,590067,459010,524373,524309,524573,459026,524405,524341,590027,459018,524389,524325,589995,524293,524421,524357,590059,459014,524381,524317,589979,459030,524413,524349,590043,459022,524397,524333,590011,524301,524429,524365,590075,459009,524371,524307,524571,459025,524403,524339,590023,459017,524387,524323,589991,524291,524419,524355,590055,459013,524379,524315,589975,459029,524411,524347,590039,459021,524395,524331,590007,524299,524427,524363,590071,459011,524375,524311,524575,459027,524407,524343,590031,459019,524391,524327,589999,524295,524423,524359,590063,459015,524383,524319,589983,459031,524415,524351,590047,459023,524399,524335,590015,524303,524431,524367,590079]),9],Pt=[new Int32Array([327680,327696,327688,327704,327684,327700,327692,327708,327682,327698,327690,327706,327686,327702,327694,0,327681,327697,327689,327705,327685,327701,327693,327709,327683,327699,327691,327707,327687,327703,327695,0]),5];class FlateStream extends DecodeStream{constructor(e,t){super(t);this.str=e;this.dict=e.dict;const i=e.getByte(),a=e.getByte();if(-1===i||-1===a)throw new FormatError(`Invalid header in flate stream: ${i}, ${a}`);if(8!=(15&i))throw new FormatError(`Unknown compression method in flate stream: ${i}, ${a}`);if(((i<<8)+a)%31!=0)throw new FormatError(`Bad FCHECK in flate stream: ${i}, ${a}`);if(32&a)throw new FormatError(`FDICT bit set in flate stream: ${i}, ${a}`);this.codeSize=0;this.codeBuf=0}async getImageData(e,t){const i=await this.asyncGetBytes();return i?.subarray(0,e)||this.getBytes(e)}async asyncGetBytes(){this.str.reset();const e=this.str.getBytes();try{const{readable:t,writable:i}=new DecompressionStream("deflate"),a=i.getWriter();a.write(e);a.close();const s=[];let r=0;for await(const e of t){s.push(e);r+=e.byteLength}const n=new Uint8Array(r);let g=0;for(const e of s){n.set(e,g);g+=e.byteLength}return n}catch{this.str=new Stream(e,2,e.length,this.str.dict);this.reset();return null}}get isAsync(){return!0}getBits(e){const t=this.str;let i,a=this.codeSize,s=this.codeBuf;for(;a>e;this.codeSize=a-=e;return i}getCode(e){const t=this.str,i=e[0],a=e[1];let s,r=this.codeSize,n=this.codeBuf;for(;r>16,c=65535&g;if(o<1||r>o;this.codeSize=r-o;return c}generateHuffmanTable(e){const t=e.length;let i,a=0;for(i=0;ia&&(a=e[i]);const s=1<>=1}for(i=e;i>=1;if(0===t){let t;if(-1===(t=a.getByte())){this.#m("Bad block header in flate stream");return}let i=t;if(-1===(t=a.getByte())){this.#m("Bad block header in flate stream");return}i|=t<<8;if(-1===(t=a.getByte())){this.#m("Bad block header in flate stream");return}let s=t;if(-1===(t=a.getByte())){this.#m("Bad block header in flate stream");return}s|=t<<8;if(s!==(65535&~i)&&(0!==i||0!==s))throw new FormatError("Bad uncompressed block length in flate stream");this.codeBuf=0;this.codeSize=0;const r=this.bufferLength,n=r+i;e=this.ensureBuffer(n);this.bufferLength=n;if(0===i)-1===a.peekByte()&&(this.eof=!0);else{const t=a.getBytes(i);e.set(t,r);t.length0;)C[g++]=Q}s=this.generateHuffmanTable(C.subarray(0,e));r=this.generateHuffmanTable(C.subarray(e,c))}}e=this.buffer;let n=e?e.length:0,g=this.bufferLength;for(;;){let t=this.getCode(s);if(t<256){if(g+1>=n){e=this.ensureBuffer(g+1);n=e.length}e[g++]=t;continue}if(256===t){this.bufferLength=g;return}t-=257;t=Tt[t];let a=t>>16;a>0&&(a=this.getBits(a));i=(65535&t)+a;t=this.getCode(r);t=qt[t];a=t>>16;a>0&&(a=this.getBits(a));const o=(65535&t)+a;if(g+i>=n){e=this.ensureBuffer(g+i);n=e.length}for(let t=0;t>9&127;this.clow=this.clow<<7&65535;this.ct-=7;this.a=32768}byteIn(){const e=this.data;let t=this.bp;if(255===e[t])if(e[t+1]>143){this.clow+=65280;this.ct=8}else{t++;this.clow+=e[t]<<9;this.ct=7;this.bp=t}else{t++;this.clow+=t65535){this.chigh+=this.clow>>16;this.clow&=65535}}readBit(e,t){let i=e[t]>>1,a=1&e[t];const s=Wt[i],r=s.qe;let n,g=this.a-r;if(this.chigh>15&1;this.clow=this.clow<<1&65535;this.ct--}while(0==(32768&g));this.a=g;e[t]=i<<1|a;return n}}class Jbig2Error extends ot{constructor(e){super(e,"Jbig2Error")}}class ContextCache{getContexts(e){return e in this?this[e]:this[e]=new Int8Array(65536)}}class DecodingContext{constructor(e,t,i){this.data=e;this.start=t;this.end=i}get decoder(){return shadow(this,"decoder",new ArithmeticDecoder(this.data,this.start,this.end))}get contextCache(){return shadow(this,"contextCache",new ContextCache)}}const jt=2**31-1,Xt=-(2**31);function decodeInteger(e,t,i){const a=e.getContexts(t);let s=1;function readBits(e){let t=0;for(let r=0;r>>0}const r=readBits(1),n=readBits(1)?readBits(1)?readBits(1)?readBits(1)?readBits(1)?readBits(32)+4436:readBits(12)+340:readBits(8)+84:readBits(6)+20:readBits(4)+4:readBits(2);let g;0===r?g=n:n>0&&(g=-n);return g>=Xt&&g<=jt?g:null}function decodeIAID(e,t,i){const a=e.getContexts("IAID");let s=1;for(let e=0;e=F&&M=S){K=K<<1&d;for(u=0;u=0&&H=0){J=G[L][H];J&&(K|=J<=e?c<<=1:c=c<<1|w[g][o]}for(Q=0;Q=m||o<0||o>=p?c<<=1:c=c<<1|a[g][o]}const E=D.readBit(b,c);t[n]=E}}return w}function decodeTextRegion(e,t,i,a,s,r,n,g,o,c,C,h,l,Q,E,u,d,f,p){if(e&&t)throw new Jbig2Error("refinement with Huffman is not supported");const m=[];let y,w;for(y=0;y1&&(s=e?p.readBits(f):decodeInteger(b,"IAIT",D));const r=n*F+s,S=e?Q.symbolIDTable.decode(p):decodeIAID(b,D,o),k=t&&(e?p.readBit():decodeInteger(b,"IARI",D));let R=g[S],N=R[0].length,G=R.length;if(k){const e=decodeInteger(b,"IARDW",D),t=decodeInteger(b,"IARDH",D);N+=e;G+=t;R=decodeRefinement(N,G,E,R,(e>>1)+decodeInteger(b,"IARDX",D),(t>>1)+decodeInteger(b,"IARDY",D),!1,u,d)}let x=0;c?1&h?x=G-1:a+=G-1:h>1?a+=N-1:x=N-1;const U=r-(1&h?0:G-1),M=a-(2&h?N-1:0);let L,H,J;if(c)for(L=0;L>5&7;const o=[31&n];let c=t+6;if(7===n){g=536870911&readUint32(e,c-1);c+=3;let t=g+7>>3;o[0]=e[c++];for(;--t>0;)o.push(e[c++])}else if(5===n||6===n)throw new Jbig2Error("invalid referred-to flags");i.retainBits=o;let C=4;i.number<=256?C=1:i.number<=65536&&(C=2);const h=[];let l,Q;for(l=0;l>>24&255;r[3]=t.height>>16&255;r[4]=t.height>>8&255;r[5]=255&t.height;for(l=c,Q=e.length;l>2&3;e.huffmanDWSelector=t>>4&3;e.bitmapSizeSelector=t>>6&1;e.aggregationInstancesSelector=t>>7&1;e.bitmapCodingContextUsed=!!(256&t);e.bitmapCodingContextRetained=!!(512&t);e.template=t>>10&3;e.refinementTemplate=t>>12&1;c+=2;if(!e.huffman){o=0===e.template?4:1;n=[];for(g=0;g>2&3;C.stripSize=1<>4&3;C.transposed=!!(64&h);C.combinationOperator=h>>7&3;C.defaultPixelValue=h>>9&1;C.dsOffset=h<<17>>27;C.refinementTemplate=h>>15&1;if(C.huffman){const e=readUint16(a,c);c+=2;C.huffmanFS=3&e;C.huffmanDS=e>>2&3;C.huffmanDT=e>>4&3;C.huffmanRefinementDW=e>>6&3;C.huffmanRefinementDH=e>>8&3;C.huffmanRefinementDX=e>>10&3;C.huffmanRefinementDY=e>>12&3;C.huffmanRefinementSizeSelector=!!(16384&e)}if(C.refinement&&!C.refinementTemplate){n=[];for(g=0;g<2;g++){n.push({x:readInt8(a,c),y:readInt8(a,c+1)});c+=2}C.refinementAt=n}C.numberOfSymbolInstances=readUint32(a,c);c+=4;r=[C,i.referredTo,a,c,s];break;case 16:const l={},Q=a[c++];l.mmr=!!(1&Q);l.template=Q>>1&3;l.patternWidth=a[c++];l.patternHeight=a[c++];l.maxPatternIndex=readUint32(a,c);c+=4;r=[l,i.number,a,c,s];break;case 22:case 23:const E={};E.info=readRegionSegmentInformation(a,c);c+=Ai;const u=a[c++];E.mmr=!!(1&u);E.template=u>>1&3;E.enableSkip=!!(8&u);E.combinationOperator=u>>4&7;E.defaultPixelValue=u>>7&1;E.gridWidth=readUint32(a,c);c+=4;E.gridHeight=readUint32(a,c);c+=4;E.gridOffsetX=4294967295&readUint32(a,c);c+=4;E.gridOffsetY=4294967295&readUint32(a,c);c+=4;E.gridVectorX=readUint16(a,c);c+=2;E.gridVectorY=readUint16(a,c);c+=2;r=[E,i.referredTo,a,c,s];break;case 38:case 39:const d={};d.info=readRegionSegmentInformation(a,c);c+=Ai;const f=a[c++];d.mmr=!!(1&f);d.template=f>>1&3;d.prediction=!!(8&f);if(!d.mmr){o=0===d.template?4:1;n=[];for(g=0;g>2&1;p.combinationOperator=m>>3&3;p.requiresBuffer=!!(32&m);p.combinationOperatorOverride=!!(64&m);r=[p];break;case 49:case 50:case 51:case 62:break;case 53:r=[i.number,a,c,s];break;default:throw new Jbig2Error(`segment type ${i.typeName}(${i.type}) is not implemented`)}const C="on"+i.typeName;C in t&&t[C].apply(t,r)}function processSegments(e,t){for(let i=0,a=e.length;i>3,i=new Uint8ClampedArray(t*e.height);e.defaultPixelValue&&i.fill(255);this.buffer=i}drawBitmap(e,t){const i=this.currentPageInfo,a=e.width,s=e.height,r=i.width+7>>3,n=i.combinationOperatorOverride?e.combinationOperator:i.combinationOperator,g=this.buffer,o=128>>(7&e.x);let c,C,h,l,Q=e.y*r+(e.x>>3);switch(n){case 0:for(c=0;c>=1;if(!h){h=128;l++}}Q+=r}break;case 2:for(c=0;c>=1;if(!h){h=128;l++}}Q+=r}break;default:throw new Jbig2Error(`operator ${n} is not supported`)}}onImmediateGenericRegion(e,t,i,a){const s=e.info,r=new DecodingContext(t,i,a),n=decodeBitmap(e.mmr,s.width,s.height,e.template,e.prediction,null,e.at,r);this.drawBitmap(s,n)}onImmediateLosslessGenericRegion(){this.onImmediateGenericRegion(...arguments)}onSymbolDictionary(e,t,i,a,s,r){let n,g;if(e.huffman){n=function getSymbolDictionaryHuffmanTables(e,t,i){let a,s,r,n,g=0;switch(e.huffmanDHSelector){case 0:case 1:a=getStandardTable(e.huffmanDHSelector+4);break;case 3:a=getCustomHuffmanTable(g,t,i);g++;break;default:throw new Jbig2Error("invalid Huffman DH selector")}switch(e.huffmanDWSelector){case 0:case 1:s=getStandardTable(e.huffmanDWSelector+2);break;case 3:s=getCustomHuffmanTable(g,t,i);g++;break;default:throw new Jbig2Error("invalid Huffman DW selector")}if(e.bitmapSizeSelector){r=getCustomHuffmanTable(g,t,i);g++}else r=getStandardTable(1);n=e.aggregationInstancesSelector?getCustomHuffmanTable(g,t,i):getStandardTable(1);return{tableDeltaHeight:a,tableDeltaWidth:s,tableBitmapSize:r,tableAggregateInstances:n}}(e,i,this.customTables);g=new Reader(a,s,r)}let o=this.symbols;o||(this.symbols=o={});const c=[];for(const e of i){const t=o[e];t&&c.push(...t)}const C=new DecodingContext(a,s,r);o[t]=function decodeSymbolDictionary(e,t,i,a,s,r,n,g,o,c,C,h){if(e&&t)throw new Jbig2Error("symbol refinement with Huffman is not supported");const l=[];let Q=0,E=log2(i.length+a);const u=C.decoder,d=C.contextCache;let f,p;if(e){f=getStandardTable(1);p=[];E=Math.max(E,1)}for(;l.length1)m=decodeTextRegion(e,t,a,Q,0,s,1,i.concat(l),E,0,0,1,0,r,o,c,C,0,h);else{const e=decodeIAID(d,u,E),t=decodeInteger(d,"IARDX",u),s=decodeInteger(d,"IARDY",u);m=decodeRefinement(a,Q,o,e=32){let i,a,n;switch(t){case 32:if(0===e)throw new Jbig2Error("no previous value in symbol ID table");a=s.readBits(2)+3;i=r[e-1].prefixLength;break;case 33:a=s.readBits(3)+3;i=0;break;case 34:a=s.readBits(7)+11;i=0;break;default:throw new Jbig2Error("invalid code length in symbol ID table")}for(n=0;n=0;d--){R=e?decodeMMRBitmap(k,o,c,!0):decodeBitmap(!1,o,c,i,!1,null,F,E);S[d]=R}for(N=0;N=0;f--){x^=S[f][N][G];U|=x<>8;H=h+N*l-G*Q>>8;if(L>=0&&L+w<=a&&H>=0&&H+D<=s)for(d=0;d=s)){Y=u[t];J=M[d];for(f=0;f=0&&e>1&7),o=1+(a>>4&7),c=[];let C,h,l=s;do{C=n.readBits(g);h=n.readBits(o);c.push(new HuffmanLine([l,C,h,0]));l+=1<>t&1;if(t<=0)this.children[i]=new HuffmanTreeNode(e);else{let a=this.children[i];a||(this.children[i]=a=new HuffmanTreeNode(null));a.buildTree(e,t-1)}}decodeNode(e){if(this.isLeaf){if(this.isOOB)return null;const t=e.readBits(this.rangeLength);return this.rangeLow+(this.isLowerRange?-t:t)}const t=this.children[e.readBit()];if(!t)throw new Jbig2Error("invalid Huffman data");return t.decodeNode(e)}}class HuffmanTable{constructor(e,t){t||this.assignPrefixCodes(e);this.rootNode=new HuffmanTreeNode(null);for(let t=0,i=e.length;t0&&this.rootNode.buildTree(i,i.prefixLength-1)}}decode(e){return this.rootNode.decodeNode(e)}assignPrefixCodes(e){const t=e.length;let i=0;for(let a=0;a=this.end)throw new Jbig2Error("end of data while reading bit");this.currentByte=this.data[this.position++];this.shift=7}const e=this.currentByte>>this.shift&1;this.shift--;return e}readBits(e){let t,i=0;for(t=e-1;t>=0;t--)i|=this.readBit()<=this.end?-1:this.data[this.position++]}}function getCustomHuffmanTable(e,t,i){let a=0;for(let s=0,r=t.length;s>i&1;i--}}if(a&&!g){const e=5;for(let t=0;t>2,o=new Uint32Array(e.buffer,t,g);if(FeatureTest.isLittleEndian){for(;n>>24|t<<8|4278190080;i[a+2]=t>>>16|s<<16|4278190080;i[a+3]=s>>>8|4278190080}for(let t=4*n,s=e.length;t>>8|255;i[a+2]=t<<16|s>>>16|255;i[a+3]=s<<8|255}for(let t=4*n,s=e.length;t>3,h=7&a,l=e.length;i=new Uint32Array(i.buffer);let Q=0;for(let a=0;a0&&!e[r-1];)r--;const n=[{children:[],index:0}];let g,o=n[0];for(i=0;i0;)o=n.pop();o.index++;n.push(o);for(;n.length<=i;){n.push(g={children:[],index:0});o.children[o.index]=g.children;o=g}s++}if(i+10){E--;return Q>>E&1}Q=e[t++];if(255===Q){const a=e[t++];if(a){if(220===a&&c){const a=readUint16(e,t+=2);t+=2;if(a>0&&a!==i.scanLines)throw new DNLMarkerError("Found DNL marker (0xFFDC) while parsing scan data",a)}else if(217===a){if(c){const e=p*(8===i.precision?8:0);if(e>0&&Math.round(i.scanLines/e)>=5)throw new DNLMarkerError("Found EOI marker (0xFFD9) while parsing scan data, possibly caused by incorrect `scanLines` parameter",e)}throw new EOIMarkerError("Found EOI marker (0xFFD9) while parsing scan data")}throw new JpegError(`unexpected marker ${(Q<<8|a).toString(16)}`)}}E=7;return Q>>>7}function decodeHuffman(e){let t=e;for(;;){t=t[readBit()];switch(typeof t){case"number":return t;case"object":continue}throw new JpegError("invalid huffman sequence")}}function receive(e){let t=0;for(;e>0;){t=t<<1|readBit();e--}return t}function receiveAndExtend(e){if(1===e)return 1===readBit()?1:-1;const t=receive(e);return t>=1<0){u--;return}let i=r;const a=n;for(;i<=a;){const a=decodeHuffman(e.huffmanTableAC),s=15&a,r=a>>4;if(0===s){if(r<15){u=receive(r)+(1<>4;if(0===s)if(c<15){u=receive(c)+(1<>4;if(0===a){if(r<15)break;s+=16;continue}s+=r;const n=ti[s];e.blockData[t+n]=receiveAndExtend(a);s++}};let k,R=0;const N=1===m?a[0].blocksPerLine*a[0].blocksPerColumn:C*i.mcusPerColumn;let G,x;for(;R<=N;){const i=s?Math.min(N-R,s):N;if(i>0){for(w=0;w0?"unexpected":"excessive"} MCU data, current marker is: ${k.invalid}`);t=k.offset}if(!(k.marker>=65488&&k.marker<=65495))break;t+=2}return t-l}function quantizeAndInverse(e,t,i){const a=e.quantizationTable,s=e.blockData;let r,n,g,o,c,C,h,l,Q,E,u,d,f,p,m,y,w;if(!a)throw new JpegError("missing required Quantization Table.");for(let e=0;e<64;e+=8){Q=s[t+e];E=s[t+e+1];u=s[t+e+2];d=s[t+e+3];f=s[t+e+4];p=s[t+e+5];m=s[t+e+6];y=s[t+e+7];Q*=a[e];if(0!=(E|u|d|f|p|m|y)){E*=a[e+1];u*=a[e+2];d*=a[e+3];f*=a[e+4];p*=a[e+5];m*=a[e+6];y*=a[e+7];r=oi*Q+128>>8;n=oi*f+128>>8;g=u;o=m;c=Ii*(E-y)+128>>8;l=Ii*(E+y)+128>>8;C=d<<4;h=p<<4;r=r+n+1>>1;n=r-n;w=g*gi+o*ni+128>>8;g=g*ni-o*gi+128>>8;o=w;c=c+h+1>>1;h=c-h;l=l+C+1>>1;C=l-C;r=r+o+1>>1;o=r-o;n=n+g+1>>1;g=n-g;w=c*ri+l*si+2048>>12;c=c*si-l*ri+2048>>12;l=w;w=C*ai+h*ii+2048>>12;C=C*ii-h*ai+2048>>12;h=w;i[e]=r+l;i[e+7]=r-l;i[e+1]=n+h;i[e+6]=n-h;i[e+2]=g+C;i[e+5]=g-C;i[e+3]=o+c;i[e+4]=o-c}else{w=oi*Q+512>>10;i[e]=w;i[e+1]=w;i[e+2]=w;i[e+3]=w;i[e+4]=w;i[e+5]=w;i[e+6]=w;i[e+7]=w}}for(let e=0;e<8;++e){Q=i[e];E=i[e+8];u=i[e+16];d=i[e+24];f=i[e+32];p=i[e+40];m=i[e+48];y=i[e+56];if(0!=(E|u|d|f|p|m|y)){r=oi*Q+2048>>12;n=oi*f+2048>>12;g=u;o=m;c=Ii*(E-y)+2048>>12;l=Ii*(E+y)+2048>>12;C=d;h=p;r=4112+(r+n+1>>1);n=r-n;w=g*gi+o*ni+2048>>12;g=g*ni-o*gi+2048>>12;o=w;c=c+h+1>>1;h=c-h;l=l+C+1>>1;C=l-C;r=r+o+1>>1;o=r-o;n=n+g+1>>1;g=n-g;w=c*ri+l*si+2048>>12;c=c*si-l*ri+2048>>12;l=w;w=C*ai+h*ii+2048>>12;C=C*ii-h*ai+2048>>12;h=w;Q=r+l;y=r-l;E=n+h;m=n-h;u=g+C;p=g-C;d=o+c;f=o-c;Q<16?Q=0:Q>=4080?Q=255:Q>>=4;E<16?E=0:E>=4080?E=255:E>>=4;u<16?u=0:u>=4080?u=255:u>>=4;d<16?d=0:d>=4080?d=255:d>>=4;f<16?f=0:f>=4080?f=255:f>>=4;p<16?p=0:p>=4080?p=255:p>>=4;m<16?m=0:m>=4080?m=255:m>>=4;y<16?y=0:y>=4080?y=255:y>>=4;s[t+e]=Q;s[t+e+8]=E;s[t+e+16]=u;s[t+e+24]=d;s[t+e+32]=f;s[t+e+40]=p;s[t+e+48]=m;s[t+e+56]=y}else{w=oi*Q+8192>>14;w=w<-2040?0:w>=2024?255:w+2056>>4;s[t+e]=w;s[t+e+8]=w;s[t+e+16]=w;s[t+e+24]=w;s[t+e+32]=w;s[t+e+40]=w;s[t+e+48]=w;s[t+e+56]=w}}}function buildComponentData(e,t){const i=t.blocksPerLine,a=t.blocksPerColumn,s=new Int16Array(64);for(let e=0;e=a)return null;const r=readUint16(e,t);if(r>=65472&&r<=65534)return{invalid:null,marker:r,offset:t};let n=readUint16(e,s);for(;!(n>=65472&&n<=65534);){if(++s>=a)return null;n=readUint16(e,s)}return{invalid:r.toString(16),marker:n,offset:s}}class JpegImage{constructor({decodeTransform:e=null,colorTransform:t=-1}={}){this._decodeTransform=e;this._colorTransform=t}parse(e,{dnlScanLines:t=null}={}){function readDataBlock(){const t=readUint16(e,s);s+=2;let i=s+t-2;const a=findNextFileMarker(e,i,s);if(a?.invalid){warn("readDataBlock - incorrect length, current marker is: "+a.invalid);i=a.offset}const r=e.subarray(s,i);s+=r.length;return r}function prepareComponents(e){const t=Math.ceil(e.samplesPerLine/8/e.maxH),i=Math.ceil(e.scanLines/8/e.maxV);for(const a of e.components){const s=Math.ceil(Math.ceil(e.samplesPerLine/8)*a.h/e.maxH),r=Math.ceil(Math.ceil(e.scanLines/8)*a.v/e.maxV),n=t*a.h,g=64*(i*a.v)*(n+1);a.blockData=new Int16Array(g);a.blocksPerLine=s;a.blocksPerColumn=r}e.mcusPerLine=t;e.mcusPerColumn=i}let i,a,s=0,r=null,n=null,g=0;const o=[],c=[],C=[];let h=readUint16(e,s);s+=2;if(65496!==h)throw new JpegError("SOI not found");h=readUint16(e,s);s+=2;A:for(;65497!==h;){let l,Q,E;switch(h){case 65504:case 65505:case 65506:case 65507:case 65508:case 65509:case 65510:case 65511:case 65512:case 65513:case 65514:case 65515:case 65516:case 65517:case 65518:case 65519:case 65534:const u=readDataBlock();65504===h&&74===u[0]&&70===u[1]&&73===u[2]&&70===u[3]&&0===u[4]&&(r={version:{major:u[5],minor:u[6]},densityUnits:u[7],xDensity:u[8]<<8|u[9],yDensity:u[10]<<8|u[11],thumbWidth:u[12],thumbHeight:u[13],thumbData:u.subarray(14,14+3*u[12]*u[13])});65518===h&&65===u[0]&&100===u[1]&&111===u[2]&&98===u[3]&&101===u[4]&&(n={version:u[5]<<8|u[6],flags0:u[7]<<8|u[8],flags1:u[9]<<8|u[10],transformCode:u[11]});break;case 65499:const d=readUint16(e,s);s+=2;const f=d+s-2;let p;for(;s>4==0)for(Q=0;Q<64;Q++){p=ti[Q];i[p]=e[s++]}else{if(t>>4!=1)throw new JpegError("DQT - invalid table spec");for(Q=0;Q<64;Q++){p=ti[Q];i[p]=readUint16(e,s);s+=2}}o[15&t]=i}break;case 65472:case 65473:case 65474:if(i)throw new JpegError("Only single frame JPEGs supported");s+=2;i={};i.extended=65473===h;i.progressive=65474===h;i.precision=e[s++];const m=readUint16(e,s);s+=2;i.scanLines=t||m;i.samplesPerLine=readUint16(e,s);s+=2;i.components=[];i.componentIds={};const y=e[s++];let w=0,D=0;for(l=0;l>4,r=15&e[s+1];w>4==0?C:c)[15&t]=buildHuffmanTable(i,r)}break;case 65501:s+=2;a=readUint16(e,s);s+=2;break;case 65498:const F=1==++g&&!t;s+=2;const S=e[s++],k=[];for(l=0;l>4];r.huffmanTableAC=c[15&n];k.push(r)}const R=e[s++],N=e[s++],G=e[s++];try{const t=decodeScan(e,s,i,k,a,R,N,G>>4,15&G,F);s+=t}catch(t){if(t instanceof DNLMarkerError){warn(`${t.message} -- attempting to re-parse the JPEG image.`);return this.parse(e,{dnlScanLines:t.scanLines})}if(t instanceof EOIMarkerError){warn(`${t.message} -- ignoring the rest of the image data.`);break A}throw t}break;case 65500:s+=4;break;case 65535:255!==e[s]&&s--;break;default:const x=findNextFileMarker(e,s-2,s-3);if(x?.invalid){warn("JpegImage.parse - unexpected data, current marker is: "+x.invalid);s=x.offset;break}if(!x||s>=e.length-1){warn("JpegImage.parse - reached the end of the image data without finding an EOI marker (0xFFD9).");break A}throw new JpegError("JpegImage.parse - unknown marker: "+h.toString(16))}h=readUint16(e,s);s+=2}if(!i)throw new JpegError("JpegImage.parse - no frame data found.");this.width=i.samplesPerLine;this.height=i.scanLines;this.jfif=r;this.adobe=n;this.components=[];for(const e of i.components){const t=o[e.quantizationId];t&&(e.quantizationTable=t);this.components.push({index:e.index,output:buildComponentData(0,e),scaleX:e.h/i.maxH,scaleY:e.v/i.maxV,blocksPerLine:e.blocksPerLine,blocksPerColumn:e.blocksPerColumn})}this.numComponents=this.components.length}_getLinearizedBlockData(e,t,i=!1){const a=this.width/e,s=this.height/t;let r,n,g,o,c,C,h,l,Q,E,u,d=0;const f=this.components.length,p=e*t*f,m=new Uint8ClampedArray(p),y=new Uint32Array(e),w=4294967288;let D;for(h=0;h>8)+b[Q+1];return m}get _isColorConversionNeeded(){return this.adobe?!!this.adobe.transformCode:3===this.numComponents?0!==this._colorTransform&&(82!==this.components[0].index||71!==this.components[1].index||66!==this.components[2].index):1===this._colorTransform}_convertYccToRgb(e){let t,i,a;for(let s=0,r=e.length;s4)throw new JpegError("Unsupported color mode");const r=this._getLinearizedBlockData(e,t,s);if(1===this.numComponents&&(i||a)){const e=r.length*(i?4:3),t=new Uint8ClampedArray(e);let a=0;if(i)!function grayToRGBA(e,t){if(FeatureTest.isLittleEndian)for(let i=0,a=e.length;i0&&(e=e.subarray(t));break}const t={decodeTransform:void 0,colorTransform:void 0},i=this.dict.getArray("D","Decode");if((this.forceRGBA||this.forceRGB)&&Array.isArray(i)){const e=this.dict.get("BPC","BitsPerComponent")||8,a=i.length,s=new Int32Array(a);let r=!1;const n=(1<{t=e;i=a}));a.decode=function(e,{numComponents:t=4,isIndexedColormap:i=!1,smaskInData:s=!1}){const r=e.length,n=a._malloc(r);a.HEAPU8.set(e,n);const g=a._jp2_decode(n,r,t>0?t:0,!!i,!!s);a._free(n);if(g){const{errorMessages:e}=a;if(e){delete a.errorMessages;return e}return"Unknown error"}const{imageData:o}=a;a.imageData=null;return o};var s,r=Object.assign({},a),n="./this.program",g="";"undefined"!=typeof document&&document.currentScript&&(g=document.currentScript.src);ci&&(g=ci);g=g.startsWith("blob:")?"":g.substr(0,g.replace(/[?#].*/,"").lastIndexOf("/")+1);var o,c,C,h,l,Q=a.print||console.log.bind(console),E=a.printErr||console.error.bind(console);Object.assign(a,r);r=null;a.arguments&&a.arguments;a.thisProgram&&(n=a.thisProgram);a.quit&&a.quit;a.wasmBinary&&(o=a.wasmBinary);function tryParseAsDataURI(e){if(isDataURI(e))return function intArrayFromBase64(e){for(var t=atob(e),i=new Uint8Array(t.length),a=0;ae.startsWith(D);function instantiateSync(e,t){var i,a=function getBinarySync(e){if(e==u&&o)return new Uint8Array(o);var t=tryParseAsDataURI(e);if(t)return t;if(s)return s(e);throw'sync fetching of the wasm failed: you can preload it to Module["wasmBinary"] manually, or emcc.py will do that for you when generating HTML (but not JS)'}(e);i=new WebAssembly.Module(a);return[new WebAssembly.Instance(i,t),i]}var callRuntimeCallbacks=e=>{for(;e.length>0;)e.shift()(a)};a.noExitRuntime;var b,growMemory=e=>{var t=(e-c.buffer.byteLength+65535)/65536;try{c.grow(t);updateMemoryViews();return 1}catch(e){}},F={},getEnvStrings=()=>{if(!getEnvStrings.strings){var e={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"==typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:n||"./this.program"};for(var t in F)void 0===F[t]?delete e[t]:e[t]=F[t];var i=[];for(var t in e)i.push(`${t}=${e[t]}`);getEnvStrings.strings=i}return getEnvStrings.strings},S=[null,[],[]],k="undefined"!=typeof TextDecoder?new TextDecoder("utf8"):void 0,UTF8ArrayToString=(e,t,i)=>{for(var a=t+i,s=t;e[s]&&!(s>=a);)++s;if(s-t>16&&e.buffer&&k)return k.decode(e.subarray(t,s));for(var r="";t>10,56320|1023&c)}}else r+=String.fromCharCode((31&n)<<6|g)}else r+=String.fromCharCode(n)}return r},printChar=(e,t)=>{var i=S[e];if(0===t||10===t){(1===e?Q:E)(UTF8ArrayToString(i,0));i.length=0}else i.push(t)},UTF8ToString=(e,t)=>e?UTF8ArrayToString(h,e,t):"",R={c:(e,t,i)=>h.copyWithin(e,t,t+i),g:function _copy_pixels_1(e,t){e>>=2;const i=a.imageData=new Uint8ClampedArray(t),s=a.HEAP32.subarray(e,e+t);i.set(s)},f:function _copy_pixels_3(e,t,i,s){e>>=2;t>>=2;i>>=2;const r=a.imageData=new Uint8ClampedArray(3*s),n=a.HEAP32.subarray(e,e+s),g=a.HEAP32.subarray(t,t+s),o=a.HEAP32.subarray(i,i+s);for(let e=0;e>=2;t>>=2;i>>=2;s>>=2;const n=a.imageData=new Uint8ClampedArray(4*r),g=a.HEAP32.subarray(e,e+r),o=a.HEAP32.subarray(t,t+r),c=a.HEAP32.subarray(i,i+r),C=a.HEAP32.subarray(s,s+r);for(let e=0;e{var t=h.length,i=2147483648;if((e>>>=0)>i)return!1;for(var a,s,r=1;r<=4;r*=2){var n=t*(1+.2/r);n=Math.min(n,e+100663296);var g=Math.min(i,(a=Math.max(e,n))+((s=65536)-a%s)%s);if(growMemory(g))return!0}return!1},l:(e,t)=>{var i=0;getEnvStrings().forEach(((a,s)=>{var r=t+i;l[e+4*s>>2]=r;((e,t)=>{for(var i=0;i{var i=getEnvStrings();l[e>>2]=i.length;var a=0;i.forEach((e=>a+=e.length+1));l[t>>2]=a;return 0},n:e=>52,j:function _fd_seek(e,t,i,a,s){return 70},b:(e,t,i,a)=>{for(var s=0,r=0;r>2],g=l[t+4>>2];t+=8;for(var o=0;o>2]=s;return 0},o:function _gray_to_rgba(e,t){e>>=2;const i=a.imageData=new Uint8ClampedArray(4*t),s=a.HEAP32.subarray(e,e+t);for(let e=0;e>=2;t>>=2;const s=a.imageData=new Uint8ClampedArray(4*i),r=a.HEAP32.subarray(e,e+i),n=a.HEAP32.subarray(t,t+i);for(let e=0;e>=2;t>>=2;i>>=2;const r=a.imageData=new Uint8ClampedArray(4*s),n=a.HEAP32.subarray(e,e+s),g=a.HEAP32.subarray(t,t+s),o=a.HEAP32.subarray(i,i+s);for(let e=0;e0)){!function preRun(){if(a.preRun){"function"==typeof a.preRun&&(a.preRun=[a.preRun]);for(;a.preRun.length;)e=a.preRun.shift(),d.unshift(e)}var e;callRuntimeCallbacks(d)}();if(!(m>0))if(a.setStatus){a.setStatus("Running...");setTimeout((function(){setTimeout((function(){a.setStatus("")}),1);doRun()}),1)}else doRun()}function doRun(){if(!b){b=!0;a.calledRun=!0;!function initRuntime(){callRuntimeCallbacks(f)}();t(a);a.onRuntimeInitialized&&a.onRuntimeInitialized();!function postRun(){if(a.postRun){"function"==typeof a.postRun&&(a.postRun=[a.postRun]);for(;a.postRun.length;)e=a.postRun.shift(),p.unshift(e)}var e;callRuntimeCallbacks(p)}()}}}if(a.preInit){"function"==typeof a.preInit&&(a.preInit=[a.preInit]);for(;a.preInit.length>0;)a.preInit.pop()()}run();return a});const hi=Ci;class JpxError extends ot{constructor(e){super(e,"JpxError")}}class JpxImage{static#y=null;static decode(e,t){t||={};this.#y||=hi({warn});const i=this.#y.decode(e,t);if("string"==typeof i)throw new JpxError(i);return i}static cleanup(){this.#y=null}static parseImageProperties(e){let t=e.getByte();for(;t>=0;){const i=t;t=e.getByte();if(65361===(i<<8|t)){e.skip(4);const t=e.getInt32()>>>0,i=e.getInt32()>>>0,a=e.getInt32()>>>0,s=e.getInt32()>>>0;e.skip(16);return{width:t-a,height:i-s,bitsPerComponent:8,componentsCount:e.getUint16()}}}throw new JpxError("No size marker found in JPX stream")}}class JpxStream extends DecodeStream{constructor(e,t,i){super(t);this.stream=e;this.dict=e.dict;this.maybeLength=t;this.params=i}get bytes(){return shadow(this,"bytes",this.stream.getBytes(this.maybeLength))}ensureBuffer(e){}readBlock(e){this.decodeImage(null,e)}decodeImage(e,t){if(this.eof)return this.buffer;e||=this.bytes;this.buffer=JpxImage.decode(e,t);this.bufferLength=this.buffer.length;this.eof=!0;return this.buffer}get canAsyncDecodeImageFromBuffer(){return this.stream.isAsync}}class LZWStream extends DecodeStream{constructor(e,t,i){super(t);this.str=e;this.dict=e.dict;this.cachedData=0;this.bitsCached=0;const a=4096,s={earlyChange:i,codeLength:9,nextCode:258,dictionaryValues:new Uint8Array(a),dictionaryLengths:new Uint16Array(a),dictionaryPrevCodes:new Uint16Array(a),currentSequence:new Uint8Array(a),currentSequenceLength:0};for(let e=0;e<256;++e){s.dictionaryValues[e]=e;s.dictionaryLengths[e]=1}this.lzwState=s}readBits(e){let t=this.bitsCached,i=this.cachedData;for(;t>>t&(1<0;if(e<256){l[0]=e;Q=1}else{if(!(e>=258)){if(256===e){C=9;n=258;Q=0;continue}this.eof=!0;delete this.lzwState;break}if(e=0;t--){l[t]=g[i];i=c[i]}}else l[Q++]=l[0]}if(s){c[n]=h;o[n]=o[h]+1;g[n]=l[0];n++;C=n+r&n+r-1?C:0|Math.min(Math.log(n+r)/.6931471805599453+1,12)}h=e;E+=Q;if(a15))throw new FormatError(`Unsupported predictor: ${a}`);this.readBlock=2===a?this.readBlockTiff:this.readBlockPng;this.str=e;this.dict=e.dict;const s=this.colors=i.get("Colors")||1,r=this.bits=i.get("BPC","BitsPerComponent")||8,n=this.columns=i.get("Columns")||1;this.pixBytes=s*r+7>>3;this.rowBytes=n*s*r+7>>3;return this}readBlockTiff(){const e=this.rowBytes,t=this.bufferLength,i=this.ensureBuffer(t+e),a=this.bits,s=this.colors,r=this.str.getBytes(e);this.eof=!r.length;if(this.eof)return;let n,g=0,o=0,c=0,C=0,h=t;if(1===a&&1===s)for(n=0;n>1;e^=e>>2;e^=e>>4;g=(1&e)<<7;i[h++]=e}else if(8===a){for(n=0;n>8&255;i[h++]=255&e}}else{const e=new Uint8Array(s+1),h=(1<>c-a)&h;c-=a;o=o<=8){i[Q++]=o>>C-8&255;C-=8}}C>0&&(i[Q++]=(o<<8-C)+(g&(1<<8-C)-1))}this.bufferLength+=e}readBlockPng(){const e=this.rowBytes,t=this.pixBytes,i=this.str.getByte(),a=this.str.getBytes(e);this.eof=!a.length;if(this.eof)return;const s=this.bufferLength,r=this.ensureBuffer(s+e);let n=r.subarray(s-e,s);0===n.length&&(n=new Uint8Array(e));let g,o,c,C=s;switch(i){case 0:for(g=0;g>1)+a[g];for(;g>1)+a[g]&255;C++}break;case 4:for(g=0;g0){const e=this.str.getBytes(a);t.set(e,i);i+=a}}else{a=257-a;const s=e[1];t=this.ensureBuffer(i+a+1);for(let e=0;e>")&&this.buf1!==wt;){if(!(this.buf1 instanceof Name)){info("Malformed dictionary: key must be a name object");this.shift();continue}const t=this.buf1.name;this.shift();if(this.buf1===wt)break;a.set(t,this.getObj(e))}if(this.buf1===wt){if(this.recoveryMode)return a;throw new ParserEOFException("End of file inside dictionary.")}if(isCmd(this.buf2,"stream"))return this.allowStreams?this.makeStream(a,e):a;this.shift();return a;default:return t}if(Number.isInteger(t)){if(Number.isInteger(this.buf1)&&isCmd(this.buf2,"R")){const e=Ref.get(t,this.buf1);this.shift();this.shift();return e}return t}return"string"==typeof t&&e?e.decryptString(t):t}findDefaultInlineStreamEnd(e){const{knownCommands:t}=this.lexer,i=e.pos;let a,s,r=0;for(;-1!==(a=e.getByte());)if(0===r)r=69===a?1:0;else if(1===r)r=73===a?2:0;else if(32===a||10===a||13===a){s=e.pos;const i=e.peekBytes(15),n=i.length;if(0===n)break;for(let e=0;e127))){r=0;break}}if(2!==r)continue;if(!t){warn("findDefaultInlineStreamEnd - `lexer.knownCommands` is undefined.");continue}const g=new Lexer(new Stream(i.slice()),t);g._hexStringWarn=()=>{};let o=0;for(;;){const e=g.getObj();if(e===wt){r=0;break}if(e instanceof Cmd){const i=t[e.cmd];if(!i){r=0;break}if(i.variableArgs?o<=i.numArgs:o===i.numArgs)break;o=0}else o++}if(2===r)break}else r=0;if(-1===a){warn("findDefaultInlineStreamEnd: Reached the end of the stream without finding a valid EI marker");if(s){warn('... trying to recover by using the last "EI" occurrence.');e.skip(-(e.pos-s))}}let n=4;e.skip(-n);a=e.peekByte();e.skip(n);isWhiteSpace(a)||n--;return e.pos-n-i}findDCTDecodeInlineStreamEnd(e){const t=e.pos;let i,a,s=!1;for(;-1!==(i=e.getByte());)if(255===i){switch(e.getByte()){case 0:break;case 255:e.skip(-1);break;case 217:s=!0;break;case 192:case 193:case 194:case 195:case 197:case 198:case 199:case 201:case 202:case 203:case 205:case 206:case 207:case 196:case 204:case 218:case 219:case 220:case 221:case 222:case 223:case 224:case 225:case 226:case 227:case 228:case 229:case 230:case 231:case 232:case 233:case 234:case 235:case 236:case 237:case 238:case 239:case 254:a=e.getUint16();a>2?e.skip(a-2):e.skip(-2)}if(s)break}const r=e.pos-t;if(-1===i){warn("Inline DCTDecode image stream: EOI marker not found, searching for /EI/ instead.");e.skip(-r);return this.findDefaultInlineStreamEnd(e)}this.inlineStreamSkipEI(e);return r}findASCII85DecodeInlineStreamEnd(e){const t=e.pos;let i;for(;-1!==(i=e.getByte());)if(126===i){const t=e.pos;i=e.peekByte();for(;isWhiteSpace(i);){e.skip();i=e.peekByte()}if(62===i){e.skip();break}if(e.pos>t){const t=e.peekBytes(2);if(69===t[0]&&73===t[1])break}}const a=e.pos-t;if(-1===i){warn("Inline ASCII85Decode image stream: EOD marker not found, searching for /EI/ instead.");e.skip(-a);return this.findDefaultInlineStreamEnd(e)}this.inlineStreamSkipEI(e);return a}findASCIIHexDecodeInlineStreamEnd(e){const t=e.pos;let i;for(;-1!==(i=e.getByte())&&62!==i;);const a=e.pos-t;if(-1===i){warn("Inline ASCIIHexDecode image stream: EOD marker not found, searching for /EI/ instead.");e.skip(-a);return this.findDefaultInlineStreamEnd(e)}this.inlineStreamSkipEI(e);return a}inlineStreamSkipEI(e){let t,i=0;for(;-1!==(t=e.getByte());)if(0===i)i=69===t?1:0;else if(1===i)i=73===t?2:0;else if(2===i)break}makeInlineImage(e){const t=this.lexer,i=t.stream,a=Object.create(null);let s;for(;!isCmd(this.buf1,"ID")&&this.buf1!==wt;){if(!(this.buf1 instanceof Name))throw new FormatError("Dictionary key must be a name object");const t=this.buf1.name;this.shift();if(this.buf1===wt)break;a[t]=this.getObj(e)}-1!==t.beginInlineImagePos&&(s=i.pos-t.beginInlineImagePos);const r=this.xref.fetchIfRef(a.F||a.Filter);let n;if(r instanceof Name)n=r.name;else if(Array.isArray(r)){const e=this.xref.fetchIfRef(r[0]);e instanceof Name&&(n=e.name)}const g=i.pos;let o,c;switch(n){case"DCT":case"DCTDecode":o=this.findDCTDecodeInlineStreamEnd(i);break;case"A85":case"ASCII85Decode":o=this.findASCII85DecodeInlineStreamEnd(i);break;case"AHx":case"ASCIIHexDecode":o=this.findASCIIHexDecodeInlineStreamEnd(i);break;default:o=this.findDefaultInlineStreamEnd(i)}if(o<1e3&&s>0){const e=i.pos;i.pos=t.beginInlineImagePos;c=function getInlineImageCacheKey(e){const t=[],i=e.length;let a=0;for(;a=a){let a=!1;for(const e of s){const t=e.length;let s=0;for(;s=r){a=!0;break}if(s>=t){if(isWhiteSpace(n[o+g+s])){info(`Found "${bytesToString([...i,...e])}" when searching for endstream command.`);a=!0}break}}if(a){t.pos+=o;return t.pos-e}}o++}t.pos+=g}return-1}makeStream(e,t){const i=this.lexer;let a=i.stream;i.skipToNextLine();const s=a.pos-1;let r=e.get("Length");if(!Number.isInteger(r)){info(`Bad length "${r&&r.toString()}" in stream.`);r=0}a.pos=s+r;i.nextChar();if(this.tryShift()&&isCmd(this.buf2,"endstream"))this.shift();else{r=this.#w(s);if(r<0)throw new FormatError("Missing endstream command.");i.nextChar();this.shift();this.shift()}this.shift();a=a.makeSubStream(s,r,e);t&&(a=t.createStream(a,r));a=this.filter(a,e,r);a.dict=e;return a}filter(e,t,i){let a=t.get("F","Filter"),s=t.get("DP","DecodeParms");if(a instanceof Name){Array.isArray(s)&&warn("/DecodeParms should not be an Array, when /Filter is a Name.");return this.makeFilter(e,a.name,i,s)}let r=i;if(Array.isArray(a)){const t=a,i=s;for(let n=0,g=t.length;n=48&&e<=57?15&e:e>=65&&e<=70||e>=97&&e<=102?9+(15&e):-1}class Lexer{constructor(e,t=null){this.stream=e;this.nextChar();this.strBuf=[];this.knownCommands=t;this._hexStringNumWarn=0;this.beginInlineImagePos=-1}nextChar(){return this.currentChar=this.stream.getByte()}peekChar(){return this.stream.peekByte()}getNumber(){let e=this.currentChar,t=!1,i=0,a=1;if(45===e){a=-1;e=this.nextChar();45===e&&(e=this.nextChar())}else 43===e&&(e=this.nextChar());if(10===e||13===e)do{e=this.nextChar()}while(10===e||13===e);if(46===e){i=10;e=this.nextChar()}if(e<48||e>57){const t=`Invalid number: ${String.fromCharCode(e)} (charCode ${e})`;if(isWhiteSpace(e)||-1===e){info(`Lexer.getNumber - "${t}".`);return 0}throw new FormatError(t)}let s=e-48,r=0,n=1;for(;(e=this.nextChar())>=0;)if(e>=48&&e<=57){const a=e-48;if(t)r=10*r+a;else{0!==i&&(i*=10);s=10*s+a}}else if(46===e){if(0!==i)break;i=1}else if(45===e)warn("Badly formatted number: minus sign in the middle");else{if(69!==e&&101!==e)break;e=this.peekChar();if(43===e||45===e){n=45===e?-1:1;this.nextChar()}else if(e<48||e>57)break;t=!0}0!==i&&(s/=i);t&&(s*=10**(n*r));return a*s}getString(){let e=1,t=!1;const i=this.strBuf;i.length=0;let a=this.nextChar();for(;;){let s=!1;switch(0|a){case-1:warn("Unterminated string");t=!0;break;case 40:++e;i.push("(");break;case 41:if(0==--e){this.nextChar();t=!0}else i.push(")");break;case 92:a=this.nextChar();switch(a){case-1:warn("Unterminated string");t=!0;break;case 110:i.push("\n");break;case 114:i.push("\r");break;case 116:i.push("\t");break;case 98:i.push("\b");break;case 102:i.push("\f");break;case 92:case 40:case 41:i.push(String.fromCharCode(a));break;case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:let e=15&a;a=this.nextChar();s=!0;if(a>=48&&a<=55){e=(e<<3)+(15&a);a=this.nextChar();if(a>=48&&a<=55){s=!1;e=(e<<3)+(15&a)}}i.push(String.fromCharCode(e));break;case 13:10===this.peekChar()&&this.nextChar();break;case 10:break;default:i.push(String.fromCharCode(a))}break;default:i.push(String.fromCharCode(a))}if(t)break;s||(a=this.nextChar())}return i.join("")}getName(){let e,t;const i=this.strBuf;i.length=0;for(;(e=this.nextChar())>=0&&!Bi[e];)if(35===e){e=this.nextChar();if(Bi[e]){warn("Lexer_getName: NUMBER SIGN (#) should be followed by a hexadecimal number.");i.push("#");break}const a=toHexDigit(e);if(-1!==a){t=e;e=this.nextChar();const s=toHexDigit(e);if(-1===s){warn(`Lexer_getName: Illegal digit (${String.fromCharCode(e)}) in hexadecimal number.`);i.push("#",String.fromCharCode(t));if(Bi[e])break;i.push(String.fromCharCode(e));continue}i.push(String.fromCharCode(a<<4|s))}else i.push("#",String.fromCharCode(e))}else i.push(String.fromCharCode(e));i.length>127&&warn(`Name token is longer than allowed by the spec: ${i.length}`);return Name.get(i.join(""))}_hexStringWarn(e){5!=this._hexStringNumWarn++?this._hexStringNumWarn>5||warn(`getHexString - ignoring invalid character: ${e}`):warn("getHexString - ignoring additional invalid characters.")}getHexString(){const e=this.strBuf;e.length=0;let t=this.currentChar,i=-1,a=-1;this._hexStringNumWarn=0;for(;;){if(t<0){warn("Unterminated hex string");break}if(62===t){this.nextChar();break}if(1!==Bi[t]){a=toHexDigit(t);if(-1===a)this._hexStringWarn(t);else if(-1===i)i=a;else{e.push(String.fromCharCode(i<<4|a));i=-1}t=this.nextChar()}else t=this.nextChar()}-1!==i&&e.push(String.fromCharCode(i<<4));return e.join("")}getObj(){let e=!1,t=this.currentChar;for(;;){if(t<0)return wt;if(e)10!==t&&13!==t||(e=!1);else if(37===t)e=!0;else if(1!==Bi[t])break;t=this.nextChar()}switch(0|t){case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:case 43:case 45:case 46:return this.getNumber();case 40:return this.getString();case 47:return this.getName();case 91:this.nextChar();return Cmd.get("[");case 93:this.nextChar();return Cmd.get("]");case 60:t=this.nextChar();if(60===t){this.nextChar();return Cmd.get("<<")}return this.getHexString();case 62:t=this.nextChar();if(62===t){this.nextChar();return Cmd.get(">>")}return Cmd.get(">");case 123:this.nextChar();return Cmd.get("{");case 125:this.nextChar();return Cmd.get("}");case 41:this.nextChar();throw new FormatError(`Illegal character: ${t}`)}let i=String.fromCharCode(t);if(t<32||t>127){const e=this.peekChar();if(e>=32&&e<=127){this.nextChar();return Cmd.get(i)}}const a=this.knownCommands;let s=void 0!==a?.[i];for(;(t=this.nextChar())>=0&&!Bi[t];){const e=i+String.fromCharCode(t);if(s&&void 0===a[e])break;if(128===i.length)throw new FormatError(`Command token too long: ${i.length}`);i=e;s=void 0!==a?.[i]}if("true"===i)return!0;if("false"===i)return!1;if("null"===i)return null;"BI"===i&&(this.beginInlineImagePos=this.stream.pos);return Cmd.get(i)}skipToNextLine(){let e=this.currentChar;for(;e>=0;){if(13===e){e=this.nextChar();10===e&&this.nextChar();break}if(10===e){this.nextChar();break}e=this.nextChar()}}}class Linearization{static create(e){function getInt(e,t,i=!1){const a=e.get(t);if(Number.isInteger(a)&&(i?a>=0:a>0))return a;throw new Error(`The "${t}" parameter in the linearization dictionary is invalid.`)}const t=new Parser({lexer:new Lexer(e),xref:null}),i=t.getObj(),a=t.getObj(),s=t.getObj(),r=t.getObj();let n,g;if(!(Number.isInteger(i)&&Number.isInteger(a)&&isCmd(s,"obj")&&r instanceof Dict&&"number"==typeof(n=r.get("Linearized"))&&n>0))return null;if((g=getInt(r,"L"))!==e.length)throw new Error('The "L" parameter in the linearization dictionary does not equal the stream length.');return{length:g,hints:function getHints(e){const t=e.get("H");let i;if(Array.isArray(t)&&(2===(i=t.length)||4===i)){for(let e=0;e0))throw new Error(`Hint (${e}) in the linearization dictionary is invalid.`)}return t}throw new Error("Hint array in the linearization dictionary is invalid.")}(r),objectNumberFirst:getInt(r,"O"),endFirst:getInt(r,"E"),numPages:getInt(r,"N"),mainXRefEntriesOffset:getInt(r,"T"),pageFirst:r.has("P")?getInt(r,"P",!0):0}}}const li=["Adobe-GB1-UCS2","Adobe-CNS1-UCS2","Adobe-Japan1-UCS2","Adobe-Korea1-UCS2","78-EUC-H","78-EUC-V","78-H","78-RKSJ-H","78-RKSJ-V","78-V","78ms-RKSJ-H","78ms-RKSJ-V","83pv-RKSJ-H","90ms-RKSJ-H","90ms-RKSJ-V","90msp-RKSJ-H","90msp-RKSJ-V","90pv-RKSJ-H","90pv-RKSJ-V","Add-H","Add-RKSJ-H","Add-RKSJ-V","Add-V","Adobe-CNS1-0","Adobe-CNS1-1","Adobe-CNS1-2","Adobe-CNS1-3","Adobe-CNS1-4","Adobe-CNS1-5","Adobe-CNS1-6","Adobe-GB1-0","Adobe-GB1-1","Adobe-GB1-2","Adobe-GB1-3","Adobe-GB1-4","Adobe-GB1-5","Adobe-Japan1-0","Adobe-Japan1-1","Adobe-Japan1-2","Adobe-Japan1-3","Adobe-Japan1-4","Adobe-Japan1-5","Adobe-Japan1-6","Adobe-Korea1-0","Adobe-Korea1-1","Adobe-Korea1-2","B5-H","B5-V","B5pc-H","B5pc-V","CNS-EUC-H","CNS-EUC-V","CNS1-H","CNS1-V","CNS2-H","CNS2-V","ETHK-B5-H","ETHK-B5-V","ETen-B5-H","ETen-B5-V","ETenms-B5-H","ETenms-B5-V","EUC-H","EUC-V","Ext-H","Ext-RKSJ-H","Ext-RKSJ-V","Ext-V","GB-EUC-H","GB-EUC-V","GB-H","GB-V","GBK-EUC-H","GBK-EUC-V","GBK2K-H","GBK2K-V","GBKp-EUC-H","GBKp-EUC-V","GBT-EUC-H","GBT-EUC-V","GBT-H","GBT-V","GBTpc-EUC-H","GBTpc-EUC-V","GBpc-EUC-H","GBpc-EUC-V","H","HKdla-B5-H","HKdla-B5-V","HKdlb-B5-H","HKdlb-B5-V","HKgccs-B5-H","HKgccs-B5-V","HKm314-B5-H","HKm314-B5-V","HKm471-B5-H","HKm471-B5-V","HKscs-B5-H","HKscs-B5-V","Hankaku","Hiragana","KSC-EUC-H","KSC-EUC-V","KSC-H","KSC-Johab-H","KSC-Johab-V","KSC-V","KSCms-UHC-H","KSCms-UHC-HW-H","KSCms-UHC-HW-V","KSCms-UHC-V","KSCpc-EUC-H","KSCpc-EUC-V","Katakana","NWP-H","NWP-V","RKSJ-H","RKSJ-V","Roman","UniCNS-UCS2-H","UniCNS-UCS2-V","UniCNS-UTF16-H","UniCNS-UTF16-V","UniCNS-UTF32-H","UniCNS-UTF32-V","UniCNS-UTF8-H","UniCNS-UTF8-V","UniGB-UCS2-H","UniGB-UCS2-V","UniGB-UTF16-H","UniGB-UTF16-V","UniGB-UTF32-H","UniGB-UTF32-V","UniGB-UTF8-H","UniGB-UTF8-V","UniJIS-UCS2-H","UniJIS-UCS2-HW-H","UniJIS-UCS2-HW-V","UniJIS-UCS2-V","UniJIS-UTF16-H","UniJIS-UTF16-V","UniJIS-UTF32-H","UniJIS-UTF32-V","UniJIS-UTF8-H","UniJIS-UTF8-V","UniJIS2004-UTF16-H","UniJIS2004-UTF16-V","UniJIS2004-UTF32-H","UniJIS2004-UTF32-V","UniJIS2004-UTF8-H","UniJIS2004-UTF8-V","UniJISPro-UCS2-HW-V","UniJISPro-UCS2-V","UniJISPro-UTF8-V","UniJISX0213-UTF32-H","UniJISX0213-UTF32-V","UniJISX02132004-UTF32-H","UniJISX02132004-UTF32-V","UniKS-UCS2-H","UniKS-UCS2-V","UniKS-UTF16-H","UniKS-UTF16-V","UniKS-UTF32-H","UniKS-UTF32-V","UniKS-UTF8-H","UniKS-UTF8-V","V","WP-Symbol"],Qi=2**24-1;class CMap{constructor(e=!1){this.codespaceRanges=[[],[],[],[]];this.numCodespaceRanges=0;this._map=[];this.name="";this.vertical=!1;this.useCMap=null;this.builtInCMap=e}addCodespaceRange(e,t,i){this.codespaceRanges[e-1].push(t,i);this.numCodespaceRanges++}mapCidRange(e,t,i){if(t-e>Qi)throw new Error("mapCidRange - ignoring data above MAX_MAP_RANGE.");for(;e<=t;)this._map[e++]=i++}mapBfRange(e,t,i){if(t-e>Qi)throw new Error("mapBfRange - ignoring data above MAX_MAP_RANGE.");const a=i.length-1;for(;e<=t;){this._map[e++]=i;const t=i.charCodeAt(a)+1;t>255?i=i.substring(0,a-1)+String.fromCharCode(i.charCodeAt(a-1)+1)+"\0":i=i.substring(0,a)+String.fromCharCode(t)}}mapBfRangeToArray(e,t,i){if(t-e>Qi)throw new Error("mapBfRangeToArray - ignoring data above MAX_MAP_RANGE.");const a=i.length;let s=0;for(;e<=t&&s>>0;const n=s[r];for(let e=0,t=n.length;e=t&&a<=s){i.charcode=a;i.length=r+1;return}}}i.charcode=0;i.length=1}getCharCodeLength(e){const t=this.codespaceRanges;for(let i=0,a=t.length;i=s&&e<=r)return i+1}}return 1}get length(){return this._map.length}get isIdentityCMap(){if("Identity-H"!==this.name&&"Identity-V"!==this.name)return!1;if(65536!==this._map.length)return!1;for(let e=0;e<65536;e++)if(this._map[e]!==e)return!1;return!0}}class IdentityCMap extends CMap{constructor(e,t){super();this.vertical=e;this.addCodespaceRange(t,0,65535)}mapCidRange(e,t,i){unreachable("should not call mapCidRange")}mapBfRange(e,t,i){unreachable("should not call mapBfRange")}mapBfRangeToArray(e,t,i){unreachable("should not call mapBfRangeToArray")}mapOne(e,t){unreachable("should not call mapCidOne")}lookup(e){return Number.isInteger(e)&&e<=65535?e:void 0}contains(e){return Number.isInteger(e)&&e<=65535}forEach(e){for(let t=0;t<=65535;t++)e(t,t)}charCodeOf(e){return Number.isInteger(e)&&e<=65535?e:-1}getMap(){const e=new Array(65536);for(let t=0;t<=65535;t++)e[t]=t;return e}get length(){return 65536}get isIdentityCMap(){unreachable("should not access .isIdentityCMap")}}function strToInt(e){let t=0;for(let i=0;i>>0}function expectString(e){if("string"!=typeof e)throw new FormatError("Malformed CMap: expected string.")}function expectInt(e){if(!Number.isInteger(e))throw new FormatError("Malformed CMap: expected int.")}function parseBfChar(e,t){for(;;){let i=t.getObj();if(i===wt)break;if(isCmd(i,"endbfchar"))return;expectString(i);const a=strToInt(i);i=t.getObj();expectString(i);const s=i;e.mapOne(a,s)}}function parseBfRange(e,t){for(;;){let i=t.getObj();if(i===wt)break;if(isCmd(i,"endbfrange"))return;expectString(i);const a=strToInt(i);i=t.getObj();expectString(i);const s=strToInt(i);i=t.getObj();if(Number.isInteger(i)||"string"==typeof i){const t=Number.isInteger(i)?String.fromCharCode(i):i;e.mapBfRange(a,s,t)}else{if(!isCmd(i,"["))break;{i=t.getObj();const r=[];for(;!isCmd(i,"]")&&i!==wt;){r.push(i);i=t.getObj()}e.mapBfRangeToArray(a,s,r)}}}throw new FormatError("Invalid bf range.")}function parseCidChar(e,t){for(;;){let i=t.getObj();if(i===wt)break;if(isCmd(i,"endcidchar"))return;expectString(i);const a=strToInt(i);i=t.getObj();expectInt(i);const s=i;e.mapOne(a,s)}}function parseCidRange(e,t){for(;;){let i=t.getObj();if(i===wt)break;if(isCmd(i,"endcidrange"))return;expectString(i);const a=strToInt(i);i=t.getObj();expectString(i);const s=strToInt(i);i=t.getObj();expectInt(i);const r=i;e.mapCidRange(a,s,r)}}function parseCodespaceRange(e,t){for(;;){let i=t.getObj();if(i===wt)break;if(isCmd(i,"endcodespacerange"))return;if("string"!=typeof i)break;const a=strToInt(i);i=t.getObj();if("string"!=typeof i)break;const s=strToInt(i);e.addCodespaceRange(i.length,a,s)}throw new FormatError("Invalid codespace range.")}function parseWMode(e,t){const i=t.getObj();Number.isInteger(i)&&(e.vertical=!!i)}function parseCMapName(e,t){const i=t.getObj();i instanceof Name&&(e.name=i.name)}async function parseCMap(e,t,i,a){let s,r;A:for(;;)try{const i=t.getObj();if(i===wt)break;if(i instanceof Name){"WMode"===i.name?parseWMode(e,t):"CMapName"===i.name&&parseCMapName(e,t);s=i}else if(i instanceof Cmd)switch(i.cmd){case"endcmap":break A;case"usecmap":s instanceof Name&&(r=s.name);break;case"begincodespacerange":parseCodespaceRange(e,t);break;case"beginbfchar":parseBfChar(e,t);break;case"begincidchar":parseCidChar(e,t);break;case"beginbfrange":parseBfRange(e,t);break;case"begincidrange":parseCidRange(e,t)}}catch(e){if(e instanceof MissingDataException)throw e;warn("Invalid cMap data: "+e);continue}!a&&r&&(a=r);return a?extendCMap(e,i,a):e}async function extendCMap(e,t,i){e.useCMap=await createBuiltInCMap(i,t);if(0===e.numCodespaceRanges){const t=e.useCMap.codespaceRanges;for(let i=0;iextendCMap(s,t,e)));if(a===yA.NONE){const e=new Lexer(new Stream(i));return parseCMap(s,e,t,null)}throw new Error(`Invalid CMap "compressionType" value: ${a}`)}class CMapFactory{static async create({encoding:e,fetchBuiltInCMap:t,useCMap:i}){if(e instanceof Name)return createBuiltInCMap(e.name,t);if(e instanceof BaseStream){const a=await parseCMap(new CMap,new Lexer(e),t,i);return a.isIdentityCMap?createBuiltInCMap(a.name,t):a}throw new Error("Encoding required.")}}const Ei=[".notdef","space","exclam","quotedbl","numbersign","dollar","percent","ampersand","quoteright","parenleft","parenright","asterisk","plus","comma","hyphen","period","slash","zero","one","two","three","four","five","six","seven","eight","nine","colon","semicolon","less","equal","greater","question","at","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","bracketleft","backslash","bracketright","asciicircum","underscore","quoteleft","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","braceleft","bar","braceright","asciitilde","exclamdown","cent","sterling","fraction","yen","florin","section","currency","quotesingle","quotedblleft","guillemotleft","guilsinglleft","guilsinglright","fi","fl","endash","dagger","daggerdbl","periodcentered","paragraph","bullet","quotesinglbase","quotedblbase","quotedblright","guillemotright","ellipsis","perthousand","questiondown","grave","acute","circumflex","tilde","macron","breve","dotaccent","dieresis","ring","cedilla","hungarumlaut","ogonek","caron","emdash","AE","ordfeminine","Lslash","Oslash","OE","ordmasculine","ae","dotlessi","lslash","oslash","oe","germandbls","onesuperior","logicalnot","mu","trademark","Eth","onehalf","plusminus","Thorn","onequarter","divide","brokenbar","degree","thorn","threequarters","twosuperior","registered","minus","eth","multiply","threesuperior","copyright","Aacute","Acircumflex","Adieresis","Agrave","Aring","Atilde","Ccedilla","Eacute","Ecircumflex","Edieresis","Egrave","Iacute","Icircumflex","Idieresis","Igrave","Ntilde","Oacute","Ocircumflex","Odieresis","Ograve","Otilde","Scaron","Uacute","Ucircumflex","Udieresis","Ugrave","Yacute","Ydieresis","Zcaron","aacute","acircumflex","adieresis","agrave","aring","atilde","ccedilla","eacute","ecircumflex","edieresis","egrave","iacute","icircumflex","idieresis","igrave","ntilde","oacute","ocircumflex","odieresis","ograve","otilde","scaron","uacute","ucircumflex","udieresis","ugrave","yacute","ydieresis","zcaron"],ui=[".notdef","space","exclamsmall","Hungarumlautsmall","dollaroldstyle","dollarsuperior","ampersandsmall","Acutesmall","parenleftsuperior","parenrightsuperior","twodotenleader","onedotenleader","comma","hyphen","period","fraction","zerooldstyle","oneoldstyle","twooldstyle","threeoldstyle","fouroldstyle","fiveoldstyle","sixoldstyle","sevenoldstyle","eightoldstyle","nineoldstyle","colon","semicolon","commasuperior","threequartersemdash","periodsuperior","questionsmall","asuperior","bsuperior","centsuperior","dsuperior","esuperior","isuperior","lsuperior","msuperior","nsuperior","osuperior","rsuperior","ssuperior","tsuperior","ff","fi","fl","ffi","ffl","parenleftinferior","parenrightinferior","Circumflexsmall","hyphensuperior","Gravesmall","Asmall","Bsmall","Csmall","Dsmall","Esmall","Fsmall","Gsmall","Hsmall","Ismall","Jsmall","Ksmall","Lsmall","Msmall","Nsmall","Osmall","Psmall","Qsmall","Rsmall","Ssmall","Tsmall","Usmall","Vsmall","Wsmall","Xsmall","Ysmall","Zsmall","colonmonetary","onefitted","rupiah","Tildesmall","exclamdownsmall","centoldstyle","Lslashsmall","Scaronsmall","Zcaronsmall","Dieresissmall","Brevesmall","Caronsmall","Dotaccentsmall","Macronsmall","figuredash","hypheninferior","Ogoneksmall","Ringsmall","Cedillasmall","onequarter","onehalf","threequarters","questiondownsmall","oneeighth","threeeighths","fiveeighths","seveneighths","onethird","twothirds","zerosuperior","onesuperior","twosuperior","threesuperior","foursuperior","fivesuperior","sixsuperior","sevensuperior","eightsuperior","ninesuperior","zeroinferior","oneinferior","twoinferior","threeinferior","fourinferior","fiveinferior","sixinferior","seveninferior","eightinferior","nineinferior","centinferior","dollarinferior","periodinferior","commainferior","Agravesmall","Aacutesmall","Acircumflexsmall","Atildesmall","Adieresissmall","Aringsmall","AEsmall","Ccedillasmall","Egravesmall","Eacutesmall","Ecircumflexsmall","Edieresissmall","Igravesmall","Iacutesmall","Icircumflexsmall","Idieresissmall","Ethsmall","Ntildesmall","Ogravesmall","Oacutesmall","Ocircumflexsmall","Otildesmall","Odieresissmall","OEsmall","Oslashsmall","Ugravesmall","Uacutesmall","Ucircumflexsmall","Udieresissmall","Yacutesmall","Thornsmall","Ydieresissmall"],di=[".notdef","space","dollaroldstyle","dollarsuperior","parenleftsuperior","parenrightsuperior","twodotenleader","onedotenleader","comma","hyphen","period","fraction","zerooldstyle","oneoldstyle","twooldstyle","threeoldstyle","fouroldstyle","fiveoldstyle","sixoldstyle","sevenoldstyle","eightoldstyle","nineoldstyle","colon","semicolon","commasuperior","threequartersemdash","periodsuperior","asuperior","bsuperior","centsuperior","dsuperior","esuperior","isuperior","lsuperior","msuperior","nsuperior","osuperior","rsuperior","ssuperior","tsuperior","ff","fi","fl","ffi","ffl","parenleftinferior","parenrightinferior","hyphensuperior","colonmonetary","onefitted","rupiah","centoldstyle","figuredash","hypheninferior","onequarter","onehalf","threequarters","oneeighth","threeeighths","fiveeighths","seveneighths","onethird","twothirds","zerosuperior","onesuperior","twosuperior","threesuperior","foursuperior","fivesuperior","sixsuperior","sevensuperior","eightsuperior","ninesuperior","zeroinferior","oneinferior","twoinferior","threeinferior","fourinferior","fiveinferior","sixinferior","seveninferior","eightinferior","nineinferior","centinferior","dollarinferior","periodinferior","commainferior"],fi=["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","space","exclamsmall","Hungarumlautsmall","","dollaroldstyle","dollarsuperior","ampersandsmall","Acutesmall","parenleftsuperior","parenrightsuperior","twodotenleader","onedotenleader","comma","hyphen","period","fraction","zerooldstyle","oneoldstyle","twooldstyle","threeoldstyle","fouroldstyle","fiveoldstyle","sixoldstyle","sevenoldstyle","eightoldstyle","nineoldstyle","colon","semicolon","commasuperior","threequartersemdash","periodsuperior","questionsmall","","asuperior","bsuperior","centsuperior","dsuperior","esuperior","","","","isuperior","","","lsuperior","msuperior","nsuperior","osuperior","","","rsuperior","ssuperior","tsuperior","","ff","fi","fl","ffi","ffl","parenleftinferior","","parenrightinferior","Circumflexsmall","hyphensuperior","Gravesmall","Asmall","Bsmall","Csmall","Dsmall","Esmall","Fsmall","Gsmall","Hsmall","Ismall","Jsmall","Ksmall","Lsmall","Msmall","Nsmall","Osmall","Psmall","Qsmall","Rsmall","Ssmall","Tsmall","Usmall","Vsmall","Wsmall","Xsmall","Ysmall","Zsmall","colonmonetary","onefitted","rupiah","Tildesmall","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","exclamdownsmall","centoldstyle","Lslashsmall","","","Scaronsmall","Zcaronsmall","Dieresissmall","Brevesmall","Caronsmall","","Dotaccentsmall","","","Macronsmall","","","figuredash","hypheninferior","","","Ogoneksmall","Ringsmall","Cedillasmall","","","","onequarter","onehalf","threequarters","questiondownsmall","oneeighth","threeeighths","fiveeighths","seveneighths","onethird","twothirds","","","zerosuperior","onesuperior","twosuperior","threesuperior","foursuperior","fivesuperior","sixsuperior","sevensuperior","eightsuperior","ninesuperior","zeroinferior","oneinferior","twoinferior","threeinferior","fourinferior","fiveinferior","sixinferior","seveninferior","eightinferior","nineinferior","centinferior","dollarinferior","periodinferior","commainferior","Agravesmall","Aacutesmall","Acircumflexsmall","Atildesmall","Adieresissmall","Aringsmall","AEsmall","Ccedillasmall","Egravesmall","Eacutesmall","Ecircumflexsmall","Edieresissmall","Igravesmall","Iacutesmall","Icircumflexsmall","Idieresissmall","Ethsmall","Ntildesmall","Ogravesmall","Oacutesmall","Ocircumflexsmall","Otildesmall","Odieresissmall","OEsmall","Oslashsmall","Ugravesmall","Uacutesmall","Ucircumflexsmall","Udieresissmall","Yacutesmall","Thornsmall","Ydieresissmall"],pi=["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","space","exclamsmall","Hungarumlautsmall","centoldstyle","dollaroldstyle","dollarsuperior","ampersandsmall","Acutesmall","parenleftsuperior","parenrightsuperior","twodotenleader","onedotenleader","comma","hyphen","period","fraction","zerooldstyle","oneoldstyle","twooldstyle","threeoldstyle","fouroldstyle","fiveoldstyle","sixoldstyle","sevenoldstyle","eightoldstyle","nineoldstyle","colon","semicolon","","threequartersemdash","","questionsmall","","","","","Ethsmall","","","onequarter","onehalf","threequarters","oneeighth","threeeighths","fiveeighths","seveneighths","onethird","twothirds","","","","","","","ff","fi","fl","ffi","ffl","parenleftinferior","","parenrightinferior","Circumflexsmall","hypheninferior","Gravesmall","Asmall","Bsmall","Csmall","Dsmall","Esmall","Fsmall","Gsmall","Hsmall","Ismall","Jsmall","Ksmall","Lsmall","Msmall","Nsmall","Osmall","Psmall","Qsmall","Rsmall","Ssmall","Tsmall","Usmall","Vsmall","Wsmall","Xsmall","Ysmall","Zsmall","colonmonetary","onefitted","rupiah","Tildesmall","","","asuperior","centsuperior","","","","","Aacutesmall","Agravesmall","Acircumflexsmall","Adieresissmall","Atildesmall","Aringsmall","Ccedillasmall","Eacutesmall","Egravesmall","Ecircumflexsmall","Edieresissmall","Iacutesmall","Igravesmall","Icircumflexsmall","Idieresissmall","Ntildesmall","Oacutesmall","Ogravesmall","Ocircumflexsmall","Odieresissmall","Otildesmall","Uacutesmall","Ugravesmall","Ucircumflexsmall","Udieresissmall","","eightsuperior","fourinferior","threeinferior","sixinferior","eightinferior","seveninferior","Scaronsmall","","centinferior","twoinferior","","Dieresissmall","","Caronsmall","osuperior","fiveinferior","","commainferior","periodinferior","Yacutesmall","","dollarinferior","","","Thornsmall","","nineinferior","zeroinferior","Zcaronsmall","AEsmall","Oslashsmall","questiondownsmall","oneinferior","Lslashsmall","","","","","","","Cedillasmall","","","","","","OEsmall","figuredash","hyphensuperior","","","","","exclamdownsmall","","Ydieresissmall","","onesuperior","twosuperior","threesuperior","foursuperior","fivesuperior","sixsuperior","sevensuperior","ninesuperior","zerosuperior","","esuperior","rsuperior","tsuperior","","","isuperior","ssuperior","dsuperior","","","","","","lsuperior","Ogoneksmall","Brevesmall","Macronsmall","bsuperior","nsuperior","msuperior","commasuperior","periodsuperior","Dotaccentsmall","Ringsmall","","","",""],mi=["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","space","exclam","quotedbl","numbersign","dollar","percent","ampersand","quotesingle","parenleft","parenright","asterisk","plus","comma","hyphen","period","slash","zero","one","two","three","four","five","six","seven","eight","nine","colon","semicolon","less","equal","greater","question","at","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","bracketleft","backslash","bracketright","asciicircum","underscore","grave","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","braceleft","bar","braceright","asciitilde","","Adieresis","Aring","Ccedilla","Eacute","Ntilde","Odieresis","Udieresis","aacute","agrave","acircumflex","adieresis","atilde","aring","ccedilla","eacute","egrave","ecircumflex","edieresis","iacute","igrave","icircumflex","idieresis","ntilde","oacute","ograve","ocircumflex","odieresis","otilde","uacute","ugrave","ucircumflex","udieresis","dagger","degree","cent","sterling","section","bullet","paragraph","germandbls","registered","copyright","trademark","acute","dieresis","notequal","AE","Oslash","infinity","plusminus","lessequal","greaterequal","yen","mu","partialdiff","summation","product","pi","integral","ordfeminine","ordmasculine","Omega","ae","oslash","questiondown","exclamdown","logicalnot","radical","florin","approxequal","Delta","guillemotleft","guillemotright","ellipsis","space","Agrave","Atilde","Otilde","OE","oe","endash","emdash","quotedblleft","quotedblright","quoteleft","quoteright","divide","lozenge","ydieresis","Ydieresis","fraction","currency","guilsinglleft","guilsinglright","fi","fl","daggerdbl","periodcentered","quotesinglbase","quotedblbase","perthousand","Acircumflex","Ecircumflex","Aacute","Edieresis","Egrave","Iacute","Icircumflex","Idieresis","Igrave","Oacute","Ocircumflex","apple","Ograve","Uacute","Ucircumflex","Ugrave","dotlessi","circumflex","tilde","macron","breve","dotaccent","ring","cedilla","hungarumlaut","ogonek","caron"],yi=["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","space","exclam","quotedbl","numbersign","dollar","percent","ampersand","quoteright","parenleft","parenright","asterisk","plus","comma","hyphen","period","slash","zero","one","two","three","four","five","six","seven","eight","nine","colon","semicolon","less","equal","greater","question","at","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","bracketleft","backslash","bracketright","asciicircum","underscore","quoteleft","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","braceleft","bar","braceright","asciitilde","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","exclamdown","cent","sterling","fraction","yen","florin","section","currency","quotesingle","quotedblleft","guillemotleft","guilsinglleft","guilsinglright","fi","fl","","endash","dagger","daggerdbl","periodcentered","","paragraph","bullet","quotesinglbase","quotedblbase","quotedblright","guillemotright","ellipsis","perthousand","","questiondown","","grave","acute","circumflex","tilde","macron","breve","dotaccent","dieresis","","ring","cedilla","","hungarumlaut","ogonek","caron","emdash","","","","","","","","","","","","","","","","","AE","","ordfeminine","","","","","Lslash","Oslash","OE","ordmasculine","","","","","","ae","","","","dotlessi","","","lslash","oslash","oe","germandbls","","","",""],wi=["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","space","exclam","quotedbl","numbersign","dollar","percent","ampersand","quotesingle","parenleft","parenright","asterisk","plus","comma","hyphen","period","slash","zero","one","two","three","four","five","six","seven","eight","nine","colon","semicolon","less","equal","greater","question","at","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","bracketleft","backslash","bracketright","asciicircum","underscore","grave","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","braceleft","bar","braceright","asciitilde","bullet","Euro","bullet","quotesinglbase","florin","quotedblbase","ellipsis","dagger","daggerdbl","circumflex","perthousand","Scaron","guilsinglleft","OE","bullet","Zcaron","bullet","bullet","quoteleft","quoteright","quotedblleft","quotedblright","bullet","endash","emdash","tilde","trademark","scaron","guilsinglright","oe","bullet","zcaron","Ydieresis","space","exclamdown","cent","sterling","currency","yen","brokenbar","section","dieresis","copyright","ordfeminine","guillemotleft","logicalnot","hyphen","registered","macron","degree","plusminus","twosuperior","threesuperior","acute","mu","paragraph","periodcentered","cedilla","onesuperior","ordmasculine","guillemotright","onequarter","onehalf","threequarters","questiondown","Agrave","Aacute","Acircumflex","Atilde","Adieresis","Aring","AE","Ccedilla","Egrave","Eacute","Ecircumflex","Edieresis","Igrave","Iacute","Icircumflex","Idieresis","Eth","Ntilde","Ograve","Oacute","Ocircumflex","Otilde","Odieresis","multiply","Oslash","Ugrave","Uacute","Ucircumflex","Udieresis","Yacute","Thorn","germandbls","agrave","aacute","acircumflex","atilde","adieresis","aring","ae","ccedilla","egrave","eacute","ecircumflex","edieresis","igrave","iacute","icircumflex","idieresis","eth","ntilde","ograve","oacute","ocircumflex","otilde","odieresis","divide","oslash","ugrave","uacute","ucircumflex","udieresis","yacute","thorn","ydieresis"],Di=["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","space","exclam","universal","numbersign","existential","percent","ampersand","suchthat","parenleft","parenright","asteriskmath","plus","comma","minus","period","slash","zero","one","two","three","four","five","six","seven","eight","nine","colon","semicolon","less","equal","greater","question","congruent","Alpha","Beta","Chi","Delta","Epsilon","Phi","Gamma","Eta","Iota","theta1","Kappa","Lambda","Mu","Nu","Omicron","Pi","Theta","Rho","Sigma","Tau","Upsilon","sigma1","Omega","Xi","Psi","Zeta","bracketleft","therefore","bracketright","perpendicular","underscore","radicalex","alpha","beta","chi","delta","epsilon","phi","gamma","eta","iota","phi1","kappa","lambda","mu","nu","omicron","pi","theta","rho","sigma","tau","upsilon","omega1","omega","xi","psi","zeta","braceleft","bar","braceright","similar","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Euro","Upsilon1","minute","lessequal","fraction","infinity","florin","club","diamond","heart","spade","arrowboth","arrowleft","arrowup","arrowright","arrowdown","degree","plusminus","second","greaterequal","multiply","proportional","partialdiff","bullet","divide","notequal","equivalence","approxequal","ellipsis","arrowvertex","arrowhorizex","carriagereturn","aleph","Ifraktur","Rfraktur","weierstrass","circlemultiply","circleplus","emptyset","intersection","union","propersuperset","reflexsuperset","notsubset","propersubset","reflexsubset","element","notelement","angle","gradient","registerserif","copyrightserif","trademarkserif","product","radical","dotmath","logicalnot","logicaland","logicalor","arrowdblboth","arrowdblleft","arrowdblup","arrowdblright","arrowdbldown","lozenge","angleleft","registersans","copyrightsans","trademarksans","summation","parenlefttp","parenleftex","parenleftbt","bracketlefttp","bracketleftex","bracketleftbt","bracelefttp","braceleftmid","braceleftbt","braceex","","angleright","integral","integraltp","integralex","integralbt","parenrighttp","parenrightex","parenrightbt","bracketrighttp","bracketrightex","bracketrightbt","bracerighttp","bracerightmid","bracerightbt",""],bi=["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","space","a1","a2","a202","a3","a4","a5","a119","a118","a117","a11","a12","a13","a14","a15","a16","a105","a17","a18","a19","a20","a21","a22","a23","a24","a25","a26","a27","a28","a6","a7","a8","a9","a10","a29","a30","a31","a32","a33","a34","a35","a36","a37","a38","a39","a40","a41","a42","a43","a44","a45","a46","a47","a48","a49","a50","a51","a52","a53","a54","a55","a56","a57","a58","a59","a60","a61","a62","a63","a64","a65","a66","a67","a68","a69","a70","a71","a72","a73","a74","a203","a75","a204","a76","a77","a78","a79","a81","a82","a83","a84","a97","a98","a99","a100","","a89","a90","a93","a94","a91","a92","a205","a85","a206","a86","a87","a88","a95","a96","","","","","","","","","","","","","","","","","","","","a101","a102","a103","a104","a106","a107","a108","a112","a111","a110","a109","a120","a121","a122","a123","a124","a125","a126","a127","a128","a129","a130","a131","a132","a133","a134","a135","a136","a137","a138","a139","a140","a141","a142","a143","a144","a145","a146","a147","a148","a149","a150","a151","a152","a153","a154","a155","a156","a157","a158","a159","a160","a161","a163","a164","a196","a165","a192","a166","a167","a168","a169","a170","a171","a172","a173","a162","a174","a175","a176","a177","a178","a179","a193","a180","a199","a181","a200","a182","","a201","a183","a184","a197","a185","a194","a198","a186","a195","a187","a188","a189","a190","a191",""];function getEncoding(e){switch(e){case"WinAnsiEncoding":return wi;case"StandardEncoding":return yi;case"MacRomanEncoding":return mi;case"SymbolSetEncoding":return Di;case"ZapfDingbatsEncoding":return bi;case"ExpertEncoding":return fi;case"MacExpertEncoding":return pi;default:return null}}const Fi=[".notdef","space","exclam","quotedbl","numbersign","dollar","percent","ampersand","quoteright","parenleft","parenright","asterisk","plus","comma","hyphen","period","slash","zero","one","two","three","four","five","six","seven","eight","nine","colon","semicolon","less","equal","greater","question","at","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","bracketleft","backslash","bracketright","asciicircum","underscore","quoteleft","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","braceleft","bar","braceright","asciitilde","exclamdown","cent","sterling","fraction","yen","florin","section","currency","quotesingle","quotedblleft","guillemotleft","guilsinglleft","guilsinglright","fi","fl","endash","dagger","daggerdbl","periodcentered","paragraph","bullet","quotesinglbase","quotedblbase","quotedblright","guillemotright","ellipsis","perthousand","questiondown","grave","acute","circumflex","tilde","macron","breve","dotaccent","dieresis","ring","cedilla","hungarumlaut","ogonek","caron","emdash","AE","ordfeminine","Lslash","Oslash","OE","ordmasculine","ae","dotlessi","lslash","oslash","oe","germandbls","onesuperior","logicalnot","mu","trademark","Eth","onehalf","plusminus","Thorn","onequarter","divide","brokenbar","degree","thorn","threequarters","twosuperior","registered","minus","eth","multiply","threesuperior","copyright","Aacute","Acircumflex","Adieresis","Agrave","Aring","Atilde","Ccedilla","Eacute","Ecircumflex","Edieresis","Egrave","Iacute","Icircumflex","Idieresis","Igrave","Ntilde","Oacute","Ocircumflex","Odieresis","Ograve","Otilde","Scaron","Uacute","Ucircumflex","Udieresis","Ugrave","Yacute","Ydieresis","Zcaron","aacute","acircumflex","adieresis","agrave","aring","atilde","ccedilla","eacute","ecircumflex","edieresis","egrave","iacute","icircumflex","idieresis","igrave","ntilde","oacute","ocircumflex","odieresis","ograve","otilde","scaron","uacute","ucircumflex","udieresis","ugrave","yacute","ydieresis","zcaron","exclamsmall","Hungarumlautsmall","dollaroldstyle","dollarsuperior","ampersandsmall","Acutesmall","parenleftsuperior","parenrightsuperior","twodotenleader","onedotenleader","zerooldstyle","oneoldstyle","twooldstyle","threeoldstyle","fouroldstyle","fiveoldstyle","sixoldstyle","sevenoldstyle","eightoldstyle","nineoldstyle","commasuperior","threequartersemdash","periodsuperior","questionsmall","asuperior","bsuperior","centsuperior","dsuperior","esuperior","isuperior","lsuperior","msuperior","nsuperior","osuperior","rsuperior","ssuperior","tsuperior","ff","ffi","ffl","parenleftinferior","parenrightinferior","Circumflexsmall","hyphensuperior","Gravesmall","Asmall","Bsmall","Csmall","Dsmall","Esmall","Fsmall","Gsmall","Hsmall","Ismall","Jsmall","Ksmall","Lsmall","Msmall","Nsmall","Osmall","Psmall","Qsmall","Rsmall","Ssmall","Tsmall","Usmall","Vsmall","Wsmall","Xsmall","Ysmall","Zsmall","colonmonetary","onefitted","rupiah","Tildesmall","exclamdownsmall","centoldstyle","Lslashsmall","Scaronsmall","Zcaronsmall","Dieresissmall","Brevesmall","Caronsmall","Dotaccentsmall","Macronsmall","figuredash","hypheninferior","Ogoneksmall","Ringsmall","Cedillasmall","questiondownsmall","oneeighth","threeeighths","fiveeighths","seveneighths","onethird","twothirds","zerosuperior","foursuperior","fivesuperior","sixsuperior","sevensuperior","eightsuperior","ninesuperior","zeroinferior","oneinferior","twoinferior","threeinferior","fourinferior","fiveinferior","sixinferior","seveninferior","eightinferior","nineinferior","centinferior","dollarinferior","periodinferior","commainferior","Agravesmall","Aacutesmall","Acircumflexsmall","Atildesmall","Adieresissmall","Aringsmall","AEsmall","Ccedillasmall","Egravesmall","Eacutesmall","Ecircumflexsmall","Edieresissmall","Igravesmall","Iacutesmall","Icircumflexsmall","Idieresissmall","Ethsmall","Ntildesmall","Ogravesmall","Oacutesmall","Ocircumflexsmall","Otildesmall","Odieresissmall","OEsmall","Oslashsmall","Ugravesmall","Uacutesmall","Ucircumflexsmall","Udieresissmall","Yacutesmall","Thornsmall","Ydieresissmall","001.000","001.001","001.002","001.003","Black","Bold","Book","Light","Medium","Regular","Roman","Semibold"],Si=391,ki=[null,{id:"hstem",min:2,stackClearing:!0,stem:!0},null,{id:"vstem",min:2,stackClearing:!0,stem:!0},{id:"vmoveto",min:1,stackClearing:!0},{id:"rlineto",min:2,resetStack:!0},{id:"hlineto",min:1,resetStack:!0},{id:"vlineto",min:1,resetStack:!0},{id:"rrcurveto",min:6,resetStack:!0},null,{id:"callsubr",min:1,undefStack:!0},{id:"return",min:0,undefStack:!0},null,null,{id:"endchar",min:0,stackClearing:!0},null,null,null,{id:"hstemhm",min:2,stackClearing:!0,stem:!0},{id:"hintmask",min:0,stackClearing:!0},{id:"cntrmask",min:0,stackClearing:!0},{id:"rmoveto",min:2,stackClearing:!0},{id:"hmoveto",min:1,stackClearing:!0},{id:"vstemhm",min:2,stackClearing:!0,stem:!0},{id:"rcurveline",min:8,resetStack:!0},{id:"rlinecurve",min:8,resetStack:!0},{id:"vvcurveto",min:4,resetStack:!0},{id:"hhcurveto",min:4,resetStack:!0},null,{id:"callgsubr",min:1,undefStack:!0},{id:"vhcurveto",min:4,resetStack:!0},{id:"hvcurveto",min:4,resetStack:!0}],Ri=[null,null,null,{id:"and",min:2,stackDelta:-1},{id:"or",min:2,stackDelta:-1},{id:"not",min:1,stackDelta:0},null,null,null,{id:"abs",min:1,stackDelta:0},{id:"add",min:2,stackDelta:-1,stackFn(e,t){e[t-2]=e[t-2]+e[t-1]}},{id:"sub",min:2,stackDelta:-1,stackFn(e,t){e[t-2]=e[t-2]-e[t-1]}},{id:"div",min:2,stackDelta:-1,stackFn(e,t){e[t-2]=e[t-2]/e[t-1]}},null,{id:"neg",min:1,stackDelta:0,stackFn(e,t){e[t-1]=-e[t-1]}},{id:"eq",min:2,stackDelta:-1},null,null,{id:"drop",min:1,stackDelta:-1},null,{id:"put",min:2,stackDelta:-2},{id:"get",min:1,stackDelta:0},{id:"ifelse",min:4,stackDelta:-3},{id:"random",min:0,stackDelta:1},{id:"mul",min:2,stackDelta:-1,stackFn(e,t){e[t-2]=e[t-2]*e[t-1]}},null,{id:"sqrt",min:1,stackDelta:0},{id:"dup",min:1,stackDelta:1},{id:"exch",min:2,stackDelta:0},{id:"index",min:2,stackDelta:0},{id:"roll",min:3,stackDelta:-2},null,null,null,{id:"hflex",min:7,resetStack:!0},{id:"flex",min:13,resetStack:!0},{id:"hflex1",min:9,resetStack:!0},{id:"flex1",min:11,resetStack:!0}];class CFFParser{constructor(e,t,i){this.bytes=e.getBytes();this.properties=t;this.seacAnalysisEnabled=!!i}parse(){const e=this.properties,t=new CFF;this.cff=t;const i=this.parseHeader(),a=this.parseIndex(i.endPos),s=this.parseIndex(a.endPos),r=this.parseIndex(s.endPos),n=this.parseIndex(r.endPos),g=this.parseDict(s.obj.get(0)),o=this.createDict(CFFTopDict,g,t.strings);t.header=i.obj;t.names=this.parseNameIndex(a.obj);t.strings=this.parseStringIndex(r.obj);t.topDict=o;t.globalSubrIndex=n.obj;this.parsePrivateDict(t.topDict);t.isCIDFont=o.hasName("ROS");const c=o.getByName("CharStrings"),C=this.parseIndex(c).obj,h=o.getByName("FontMatrix");h&&(e.fontMatrix=h);const l=o.getByName("FontBBox");if(l){e.ascent=Math.max(l[3],l[1]);e.descent=Math.min(l[1],l[3]);e.ascentScaled=!0}let Q,E;if(t.isCIDFont){const e=this.parseIndex(o.getByName("FDArray")).obj;for(let i=0,a=e.count;i=t)throw new FormatError("Invalid CFF header");if(0!==i){info("cff data is shifted");e=e.subarray(i);this.bytes=e}const a=e[0],s=e[1],r=e[2],n=e[3];return{obj:new CFFHeader(a,s,r,n),endPos:r}}parseDict(e){let t=0;function parseOperand(){let i=e[t++];if(30===i)return function parseFloatOperand(){let i="";const a=15,s=["0","1","2","3","4","5","6","7","8","9",".","E","E-",null,"-"],r=e.length;for(;t>4,g=15&r;if(n===a)break;i+=s[n];if(g===a)break;i+=s[g]}return parseFloat(i)}();if(28===i){i=e[t++];i=(i<<24|e[t++]<<16)>>16;return i}if(29===i){i=e[t++];i=i<<8|e[t++];i=i<<8|e[t++];i=i<<8|e[t++];return i}if(i>=32&&i<=246)return i-139;if(i>=247&&i<=250)return 256*(i-247)+e[t++]+108;if(i>=251&&i<=254)return-256*(i-251)-e[t++]-108;warn('CFFParser_parseDict: "'+i+'" is a reserved command.');return NaN}let i=[];const a=[];t=0;const s=e.length;for(;t10)return!1;let s=e.stackSize;const r=e.stack;let n=t.length;for(let g=0;g>16;g+=2;s++}else if(14===o){if(s>=4){s-=4;if(this.seacAnalysisEnabled){e.seac=r.slice(s,s+4);return!1}}c=ki[o]}else if(o>=32&&o<=246){r[s]=o-139;s++}else if(o>=247&&o<=254){r[s]=o<251?(o-247<<8)+t[g]+108:-(o-251<<8)-t[g]-108;g++;s++}else if(255===o){r[s]=(t[g]<<24|t[g+1]<<16|t[g+2]<<8|t[g+3])/65536;g+=4;s++}else if(19===o||20===o){e.hints+=s>>1;if(0===e.hints){t.copyWithin(g-1,g,-1);g-=1;n-=1;continue}g+=e.hints+7>>3;s%=2;c=ki[o]}else{if(10===o||29===o){const t=10===o?i:a;if(!t){c=ki[o];warn("Missing subrsIndex for "+c.id);return!1}let n=32768;t.count<1240?n=107:t.count<33900&&(n=1131);const g=r[--s]+n;if(g<0||g>=t.count||isNaN(g)){c=ki[o];warn("Out of bounds subrIndex for "+c.id);return!1}e.stackSize=s;e.callDepth++;if(!this.parseCharString(e,t.get(g),i,a))return!1;e.callDepth--;s=e.stackSize;continue}if(11===o){e.stackSize=s;return!0}if(0===o&&g===t.length){t[g-1]=14;c=ki[14]}else{if(9===o){t.copyWithin(g-1,g,-1);g-=1;n-=1;continue}c=ki[o]}}if(c){if(c.stem){e.hints+=s>>1;if(3===o||23===o)e.hasVStems=!0;else if(e.hasVStems&&(1===o||18===o)){warn("CFF stem hints are in wrong order");t[g-1]=1===o?3:23}}if("min"in c&&!e.undefStack&&s=2&&c.stem?s%=2:s>1&&warn("Found too many parameters for stack-clearing command");s>0&&(e.width=r[s-1])}if("stackDelta"in c){"stackFn"in c&&c.stackFn(r,s);s+=c.stackDelta}else if(c.stackClearing)s=0;else if(c.resetStack){s=0;e.undefStack=!1}else if(c.undefStack){s=0;e.undefStack=!0;e.firstStackClearing=!1}}}n=s.length){warn("Invalid fd index for glyph index.");h=!1}if(h){Q=s[e].privateDict;l=Q.subrsIndex}}else t&&(l=t);h&&(h=this.parseCharString(C,o,l,i));if(null!==C.width){const e=Q.getByName("nominalWidthX");g[c]=e+C.width}else{const e=Q.getByName("defaultWidthX");g[c]=e}null!==C.seac&&(n[c]=C.seac);h||e.set(c,new Uint8Array([14]))}return{charStrings:e,seacs:n,widths:g}}emptyPrivateDictionary(e){const t=this.createDict(CFFPrivateDict,[],e.strings);e.setByKey(18,[0,0]);e.privateDict=t}parsePrivateDict(e){if(!e.hasName("Private")){this.emptyPrivateDictionary(e);return}const t=e.getByName("Private");if(!Array.isArray(t)||2!==t.length){e.removeByName("Private");return}const i=t[0],a=t[1];if(0===i||a>=this.bytes.length){this.emptyPrivateDictionary(e);return}const s=a+i,r=this.bytes.subarray(a,s),n=this.parseDict(r),g=this.createDict(CFFPrivateDict,n,e.strings);e.privateDict=g;0===g.getByName("ExpansionFactor")&&g.setByName("ExpansionFactor",.06);if(!g.getByName("Subrs"))return;const o=g.getByName("Subrs"),c=a+o;if(0===o||c>=this.bytes.length){this.emptyPrivateDictionary(e);return}const C=this.parseIndex(c);g.subrsIndex=C.obj}parseCharsets(e,t,i,a){if(0===e)return new CFFCharset(!0,xi.ISO_ADOBE,Ei);if(1===e)return new CFFCharset(!0,xi.EXPERT,ui);if(2===e)return new CFFCharset(!0,xi.EXPERT_SUBSET,di);const s=this.bytes,r=e,n=s[e++],g=[a?0:".notdef"];let o,c,C;t-=1;switch(n){case 0:for(C=0;C=65535){warn("Not enough space in charstrings to duplicate first glyph.");return}const e=this.charStrings.get(0);this.charStrings.add(e);this.isCIDFont&&this.fdSelect.fdSelect.push(this.fdSelect.fdSelect[0])}hasGlyphId(e){if(e<0||e>=this.charStrings.count)return!1;return this.charStrings.get(e).length>0}}class CFFHeader{constructor(e,t,i,a){this.major=e;this.minor=t;this.hdrSize=i;this.offSize=a}}class CFFStrings{constructor(){this.strings=[]}get(e){return e>=0&&e<=390?Fi[e]:e-Si<=this.strings.length?this.strings[e-Si]:Fi[0]}getSID(e){let t=Fi.indexOf(e);if(-1!==t)return t;t=this.strings.indexOf(e);return-1!==t?t+Si:-1}add(e){this.strings.push(e)}get count(){return this.strings.length}}class CFFIndex{constructor(){this.objects=[];this.length=0}add(e){this.length+=e.length;this.objects.push(e)}set(e,t){this.length+=t.length-this.objects[e].length;this.objects[e]=t}get(e){return this.objects[e]}get count(){return this.objects.length}}class CFFDict{constructor(e,t){this.keyToNameMap=e.keyToNameMap;this.nameToKeyMap=e.nameToKeyMap;this.defaults=e.defaults;this.types=e.types;this.opcodes=e.opcodes;this.order=e.order;this.strings=t;this.values=Object.create(null)}setByKey(e,t){if(!(e in this.keyToNameMap))return!1;if(0===t.length)return!0;for(const i of t)if(isNaN(i)){warn(`Invalid CFFDict value: "${t}" for key "${e}".`);return!0}const i=this.types[e];"num"!==i&&"sid"!==i&&"offset"!==i||(t=t[0]);this.values[e]=t;return!0}setByName(e,t){if(!(e in this.nameToKeyMap))throw new FormatError(`Invalid dictionary name "${e}"`);this.values[this.nameToKeyMap[e]]=t}hasName(e){return this.nameToKeyMap[e]in this.values}getByName(e){if(!(e in this.nameToKeyMap))throw new FormatError(`Invalid dictionary name ${e}"`);const t=this.nameToKeyMap[e];return t in this.values?this.values[t]:this.defaults[t]}removeByName(e){delete this.values[this.nameToKeyMap[e]]}static createTables(e){const t={keyToNameMap:{},nameToKeyMap:{},defaults:{},types:{},opcodes:{},order:[]};for(const i of e){const e=Array.isArray(i[0])?(i[0][0]<<8)+i[0][1]:i[0];t.keyToNameMap[e]=i[1];t.nameToKeyMap[i[1]]=e;t.types[e]=i[2];t.defaults[e]=i[3];t.opcodes[e]=Array.isArray(i[0])?i[0]:[i[0]];t.order.push(e)}return t}}const Ni=[[[12,30],"ROS",["sid","sid","num"],null],[[12,20],"SyntheticBase","num",null],[0,"version","sid",null],[1,"Notice","sid",null],[[12,0],"Copyright","sid",null],[2,"FullName","sid",null],[3,"FamilyName","sid",null],[4,"Weight","sid",null],[[12,1],"isFixedPitch","num",0],[[12,2],"ItalicAngle","num",0],[[12,3],"UnderlinePosition","num",-100],[[12,4],"UnderlineThickness","num",50],[[12,5],"PaintType","num",0],[[12,6],"CharstringType","num",2],[[12,7],"FontMatrix",["num","num","num","num","num","num"],[.001,0,0,.001,0,0]],[13,"UniqueID","num",null],[5,"FontBBox",["num","num","num","num"],[0,0,0,0]],[[12,8],"StrokeWidth","num",0],[14,"XUID","array",null],[15,"charset","offset",0],[16,"Encoding","offset",0],[17,"CharStrings","offset",0],[18,"Private",["offset","offset"],null],[[12,21],"PostScript","sid",null],[[12,22],"BaseFontName","sid",null],[[12,23],"BaseFontBlend","delta",null],[[12,31],"CIDFontVersion","num",0],[[12,32],"CIDFontRevision","num",0],[[12,33],"CIDFontType","num",0],[[12,34],"CIDCount","num",8720],[[12,35],"UIDBase","num",null],[[12,37],"FDSelect","offset",null],[[12,36],"FDArray","offset",null],[[12,38],"FontName","sid",null]];class CFFTopDict extends CFFDict{static get tables(){return shadow(this,"tables",this.createTables(Ni))}constructor(e){super(CFFTopDict.tables,e);this.privateDict=null}}const Gi=[[6,"BlueValues","delta",null],[7,"OtherBlues","delta",null],[8,"FamilyBlues","delta",null],[9,"FamilyOtherBlues","delta",null],[[12,9],"BlueScale","num",.039625],[[12,10],"BlueShift","num",7],[[12,11],"BlueFuzz","num",1],[10,"StdHW","num",null],[11,"StdVW","num",null],[[12,12],"StemSnapH","delta",null],[[12,13],"StemSnapV","delta",null],[[12,14],"ForceBold","num",0],[[12,17],"LanguageGroup","num",0],[[12,18],"ExpansionFactor","num",.06],[[12,19],"initialRandomSeed","num",0],[20,"defaultWidthX","num",0],[21,"nominalWidthX","num",0],[19,"Subrs","offset",null]];class CFFPrivateDict extends CFFDict{static get tables(){return shadow(this,"tables",this.createTables(Gi))}constructor(e){super(CFFPrivateDict.tables,e);this.subrsIndex=null}}const xi={ISO_ADOBE:0,EXPERT:1,EXPERT_SUBSET:2};class CFFCharset{constructor(e,t,i,a){this.predefined=e;this.format=t;this.charset=i;this.raw=a}}class CFFEncoding{constructor(e,t,i,a){this.predefined=e;this.format=t;this.encoding=i;this.raw=a}}class CFFFDSelect{constructor(e,t){this.format=e;this.fdSelect=t}getFDIndex(e){return e<0||e>=this.fdSelect.length?-1:this.fdSelect[e]}}class CFFOffsetTracker{constructor(){this.offsets=Object.create(null)}isTracking(e){return e in this.offsets}track(e,t){if(e in this.offsets)throw new FormatError(`Already tracking location of ${e}`);this.offsets[e]=t}offset(e){for(const t in this.offsets)this.offsets[t]+=e}setEntryLocation(e,t,i){if(!(e in this.offsets))throw new FormatError(`Not tracking location of ${e}`);const a=i.data,s=this.offsets[e];for(let e=0,i=t.length;e>24&255;a[n]=c>>16&255;a[g]=c>>8&255;a[o]=255&c}}}class CFFCompiler{constructor(e){this.cff=e}compile(){const e=this.cff,t={data:[],length:0,add(e){try{this.data.push(...e)}catch{this.data=this.data.concat(e)}this.length=this.data.length}},i=this.compileHeader(e.header);t.add(i);const a=this.compileNameIndex(e.names);t.add(a);if(e.isCIDFont&&e.topDict.hasName("FontMatrix")){const t=e.topDict.getByName("FontMatrix");e.topDict.removeByName("FontMatrix");for(const i of e.fdArray){let e=t.slice(0);i.hasName("FontMatrix")&&(e=Util.transform(e,i.getByName("FontMatrix")));i.setByName("FontMatrix",e)}}const s=e.topDict.getByName("XUID");s?.length>16&&e.topDict.removeByName("XUID");e.topDict.setByName("charset",0);let r=this.compileTopDicts([e.topDict],t.length,e.isCIDFont);t.add(r.output);const n=r.trackers[0],g=this.compileStringIndex(e.strings.strings);t.add(g);const o=this.compileIndex(e.globalSubrIndex);t.add(o);if(e.encoding&&e.topDict.hasName("Encoding"))if(e.encoding.predefined)n.setEntryLocation("Encoding",[e.encoding.format],t);else{const i=this.compileEncoding(e.encoding);n.setEntryLocation("Encoding",[t.length],t);t.add(i)}const c=this.compileCharset(e.charset,e.charStrings.count,e.strings,e.isCIDFont);n.setEntryLocation("charset",[t.length],t);t.add(c);const C=this.compileCharStrings(e.charStrings);n.setEntryLocation("CharStrings",[t.length],t);t.add(C);if(e.isCIDFont){n.setEntryLocation("FDSelect",[t.length],t);const i=this.compileFDSelect(e.fdSelect);t.add(i);r=this.compileTopDicts(e.fdArray,t.length,!0);n.setEntryLocation("FDArray",[t.length],t);t.add(r.output);const a=r.trackers;this.compilePrivateDicts(e.fdArray,a,t)}this.compilePrivateDicts([e.topDict],[n],t);t.add([0]);return t.data}encodeNumber(e){return Number.isInteger(e)?this.encodeInteger(e):this.encodeFloat(e)}static get EncodeFloatRegExp(){return shadow(this,"EncodeFloatRegExp",/\.(\d*?)(?:9{5,20}|0{5,20})\d{0,2}(?:e(.+)|$)/)}encodeFloat(e){let t=e.toString();const i=CFFCompiler.EncodeFloatRegExp.exec(t);if(i){const a=parseFloat("1e"+((i[2]?+i[2]:0)+i[1].length));t=(Math.round(e*a)/a).toString()}let a,s,r="";for(a=0,s=t.length;a=-107&&e<=107?[e+139]:e>=108&&e<=1131?[247+((e-=108)>>8),255&e]:e>=-1131&&e<=-108?[251+((e=-e-108)>>8),255&e]:e>=-32768&&e<=32767?[28,e>>8&255,255&e]:[29,e>>24&255,e>>16&255,e>>8&255,255&e];return t}compileHeader(e){return[e.major,e.minor,4,e.offSize]}compileNameIndex(e){const t=new CFFIndex;for(const i of e){const e=Math.min(i.length,127);let a=new Array(e);for(let t=0;t"~"||"["===e||"]"===e||"("===e||")"===e||"{"===e||"}"===e||"<"===e||">"===e||"/"===e||"%"===e)&&(e="_");a[t]=e}a=a.join("");""===a&&(a="Bad_Font_Name");t.add(stringToBytes(a))}return this.compileIndex(t)}compileTopDicts(e,t,i){const a=[];let s=new CFFIndex;for(const r of e){if(i){r.removeByName("CIDFontVersion");r.removeByName("CIDFontRevision");r.removeByName("CIDFontType");r.removeByName("CIDCount");r.removeByName("UIDBase")}const e=new CFFOffsetTracker,n=this.compileDict(r,e);a.push(e);s.add(n);e.offset(t)}s=this.compileIndex(s,a);return{trackers:a,output:s}}compilePrivateDicts(e,t,i){for(let a=0,s=e.length;a>8&255,255&r]);else{s=new Uint8Array(1+2*r);s[0]=0;let t=0;const a=e.charset.length;let n=!1;for(let r=1;r>8&255;s[r+1]=255&g}}return this.compileTypedArray(s)}compileEncoding(e){return this.compileTypedArray(e.raw)}compileFDSelect(e){const t=e.format;let i,a;switch(t){case 0:i=new Uint8Array(1+e.fdSelect.length);i[0]=t;for(a=0;a>8&255,255&s,r];for(a=1;a>8&255,255&a,t);r=t}}const g=(n.length-3)/3;n[1]=g>>8&255;n[2]=255&g;n.push(a>>8&255,255&a);i=new Uint8Array(n)}return this.compileTypedArray(i)}compileTypedArray(e){return Array.from(e)}compileIndex(e,t=[]){const i=e.objects,a=i.length;if(0===a)return[0,0];const s=[a>>8&255,255&a];let r,n,g=1;for(r=0;r>8&255,255&o):3===n?s.push(o>>16&255,o>>8&255,255&o):s.push(o>>>24&255,o>>16&255,o>>8&255,255&o);i[r]&&(o+=i[r].length)}for(r=0;r=5&&t<=7))return-1;a=e.substring(1)}if(a===a.toUpperCase()){i=parseInt(a,16);if(i>=0)return i}}return-1}const Yi=[[0,127],[128,255],[256,383],[384,591],[592,687,7424,7551,7552,7615],[688,767,42752,42783],[768,879,7616,7679],[880,1023],[11392,11519],[1024,1279,1280,1327,11744,11775,42560,42655],[1328,1423],[1424,1535],[42240,42559],[1536,1791,1872,1919],[1984,2047],[2304,2431],[2432,2559],[2560,2687],[2688,2815],[2816,2943],[2944,3071],[3072,3199],[3200,3327],[3328,3455],[3584,3711],[3712,3839],[4256,4351,11520,11567],[6912,7039],[4352,4607],[7680,7935,11360,11391,42784,43007],[7936,8191],[8192,8303,11776,11903],[8304,8351],[8352,8399],[8400,8447],[8448,8527],[8528,8591],[8592,8703,10224,10239,10496,10623,11008,11263],[8704,8959,10752,11007,10176,10223,10624,10751],[8960,9215],[9216,9279],[9280,9311],[9312,9471],[9472,9599],[9600,9631],[9632,9727],[9728,9983],[9984,10175],[12288,12351],[12352,12447],[12448,12543,12784,12799],[12544,12591,12704,12735],[12592,12687],[43072,43135],[12800,13055],[13056,13311],[44032,55215],[55296,57343],[67840,67871],[19968,40959,11904,12031,12032,12255,12272,12287,13312,19903,131072,173791,12688,12703],[57344,63743],[12736,12783,63744,64255,194560,195103],[64256,64335],[64336,65023],[65056,65071],[65040,65055],[65104,65135],[65136,65279],[65280,65519],[65520,65535],[3840,4095],[1792,1871],[1920,1983],[3456,3583],[4096,4255],[4608,4991,4992,5023,11648,11743],[5024,5119],[5120,5759],[5760,5791],[5792,5887],[6016,6143],[6144,6319],[10240,10495],[40960,42127],[5888,5919,5920,5951,5952,5983,5984,6015],[66304,66351],[66352,66383],[66560,66639],[118784,119039,119040,119295,119296,119375],[119808,120831],[1044480,1048573],[65024,65039,917760,917999],[917504,917631],[6400,6479],[6480,6527],[6528,6623],[6656,6687],[11264,11359],[11568,11647],[19904,19967],[43008,43055],[65536,65663,65664,65791,65792,65855],[65856,65935],[66432,66463],[66464,66527],[66640,66687],[66688,66735],[67584,67647],[68096,68191],[119552,119647],[73728,74751,74752,74879],[119648,119679],[7040,7103],[7168,7247],[7248,7295],[43136,43231],[43264,43311],[43312,43359],[43520,43615],[65936,65999],[66e3,66047],[66208,66271,66176,66207,67872,67903],[127024,127135,126976,127023]];function getUnicodeRangeFor(e,t=-1){if(-1!==t){const i=Yi[t];for(let a=0,s=i.length;a=i[a]&&e<=i[a+1])return t}for(let t=0,i=Yi.length;t=i[a]&&e<=i[a+1])return t}return-1}const vi=new RegExp("^(\\s)|(\\p{Mn})|(\\p{Cf})$","u"),Ki=new Map;const Ti=!0,qi=1,Oi=2,Pi=4,Wi=32,ji=[".notdef",".null","nonmarkingreturn","space","exclam","quotedbl","numbersign","dollar","percent","ampersand","quotesingle","parenleft","parenright","asterisk","plus","comma","hyphen","period","slash","zero","one","two","three","four","five","six","seven","eight","nine","colon","semicolon","less","equal","greater","question","at","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","bracketleft","backslash","bracketright","asciicircum","underscore","grave","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","braceleft","bar","braceright","asciitilde","Adieresis","Aring","Ccedilla","Eacute","Ntilde","Odieresis","Udieresis","aacute","agrave","acircumflex","adieresis","atilde","aring","ccedilla","eacute","egrave","ecircumflex","edieresis","iacute","igrave","icircumflex","idieresis","ntilde","oacute","ograve","ocircumflex","odieresis","otilde","uacute","ugrave","ucircumflex","udieresis","dagger","degree","cent","sterling","section","bullet","paragraph","germandbls","registered","copyright","trademark","acute","dieresis","notequal","AE","Oslash","infinity","plusminus","lessequal","greaterequal","yen","mu","partialdiff","summation","product","pi","integral","ordfeminine","ordmasculine","Omega","ae","oslash","questiondown","exclamdown","logicalnot","radical","florin","approxequal","Delta","guillemotleft","guillemotright","ellipsis","nonbreakingspace","Agrave","Atilde","Otilde","OE","oe","endash","emdash","quotedblleft","quotedblright","quoteleft","quoteright","divide","lozenge","ydieresis","Ydieresis","fraction","currency","guilsinglleft","guilsinglright","fi","fl","daggerdbl","periodcentered","quotesinglbase","quotedblbase","perthousand","Acircumflex","Ecircumflex","Aacute","Edieresis","Egrave","Iacute","Icircumflex","Idieresis","Igrave","Oacute","Ocircumflex","apple","Ograve","Uacute","Ucircumflex","Ugrave","dotlessi","circumflex","tilde","macron","breve","dotaccent","ring","cedilla","hungarumlaut","ogonek","caron","Lslash","lslash","Scaron","scaron","Zcaron","zcaron","brokenbar","Eth","eth","Yacute","yacute","Thorn","thorn","minus","multiply","onesuperior","twosuperior","threesuperior","onehalf","onequarter","threequarters","franc","Gbreve","gbreve","Idotaccent","Scedilla","scedilla","Cacute","cacute","Ccaron","ccaron","dcroat"];function recoverGlyphName(e,t){if(void 0!==t[e])return e;const i=getUnicodeForGlyph(e,t);if(-1!==i)for(const e in t)if(t[e]===i)return e;info("Unable to recover a standard glyph name for: "+e);return e}function type1FontGlyphMapping(e,t,i){const a=Object.create(null);let s,r,n;const g=!!(e.flags&Pi);if(e.isInternalFont){n=t;for(r=0;r=0?s:0}}else if(e.baseEncodingName){n=getEncoding(e.baseEncodingName);for(r=0;r=0?s:0}}else if(g)for(r in t)a[r]=t[r];else{n=yi;for(r=0;r=0?s:0}}const o=e.differences;let c;if(o)for(r in o){const e=o[r];s=i.indexOf(e);if(-1===s){c||(c=Mi());const t=recoverGlyphName(e,c);t!==e&&(s=i.indexOf(t))}a[r]=s>=0?s:0}return a}function normalizeFontName(e){return e.replaceAll(/[,_]/g,"-").replaceAll(/\s/g,"")}const Xi=getLookupTableFactory((e=>{e[8211]=65074;e[8212]=65073;e[8229]=65072;e[8230]=65049;e[12289]=65041;e[12290]=65042;e[12296]=65087;e[12297]=65088;e[12298]=65085;e[12299]=65086;e[12300]=65089;e[12301]=65090;e[12302]=65091;e[12303]=65092;e[12304]=65083;e[12305]=65084;e[12308]=65081;e[12309]=65082;e[12310]=65047;e[12311]=65048;e[65103]=65076;e[65281]=65045;e[65288]=65077;e[65289]=65078;e[65292]=65040;e[65306]=65043;e[65307]=65044;e[65311]=65046;e[65339]=65095;e[65341]=65096;e[65343]=65075;e[65371]=65079;e[65373]=65080})),Zi=getLookupTableFactory((function(e){e["Times-Roman"]="Times-Roman";e.Helvetica="Helvetica";e.Courier="Courier";e.Symbol="Symbol";e["Times-Bold"]="Times-Bold";e["Helvetica-Bold"]="Helvetica-Bold";e["Courier-Bold"]="Courier-Bold";e.ZapfDingbats="ZapfDingbats";e["Times-Italic"]="Times-Italic";e["Helvetica-Oblique"]="Helvetica-Oblique";e["Courier-Oblique"]="Courier-Oblique";e["Times-BoldItalic"]="Times-BoldItalic";e["Helvetica-BoldOblique"]="Helvetica-BoldOblique";e["Courier-BoldOblique"]="Courier-BoldOblique";e.ArialNarrow="Helvetica";e["ArialNarrow-Bold"]="Helvetica-Bold";e["ArialNarrow-BoldItalic"]="Helvetica-BoldOblique";e["ArialNarrow-Italic"]="Helvetica-Oblique";e.ArialBlack="Helvetica";e["ArialBlack-Bold"]="Helvetica-Bold";e["ArialBlack-BoldItalic"]="Helvetica-BoldOblique";e["ArialBlack-Italic"]="Helvetica-Oblique";e["Arial-Black"]="Helvetica";e["Arial-Black-Bold"]="Helvetica-Bold";e["Arial-Black-BoldItalic"]="Helvetica-BoldOblique";e["Arial-Black-Italic"]="Helvetica-Oblique";e.Arial="Helvetica";e["Arial-Bold"]="Helvetica-Bold";e["Arial-BoldItalic"]="Helvetica-BoldOblique";e["Arial-Italic"]="Helvetica-Oblique";e.ArialMT="Helvetica";e["Arial-BoldItalicMT"]="Helvetica-BoldOblique";e["Arial-BoldMT"]="Helvetica-Bold";e["Arial-ItalicMT"]="Helvetica-Oblique";e["Arial-BoldItalicMT-BoldItalic"]="Helvetica-BoldOblique";e["Arial-BoldMT-Bold"]="Helvetica-Bold";e["Arial-ItalicMT-Italic"]="Helvetica-Oblique";e.ArialUnicodeMS="Helvetica";e["ArialUnicodeMS-Bold"]="Helvetica-Bold";e["ArialUnicodeMS-BoldItalic"]="Helvetica-BoldOblique";e["ArialUnicodeMS-Italic"]="Helvetica-Oblique";e["Courier-BoldItalic"]="Courier-BoldOblique";e["Courier-Italic"]="Courier-Oblique";e.CourierNew="Courier";e["CourierNew-Bold"]="Courier-Bold";e["CourierNew-BoldItalic"]="Courier-BoldOblique";e["CourierNew-Italic"]="Courier-Oblique";e["CourierNewPS-BoldItalicMT"]="Courier-BoldOblique";e["CourierNewPS-BoldMT"]="Courier-Bold";e["CourierNewPS-ItalicMT"]="Courier-Oblique";e.CourierNewPSMT="Courier";e["Helvetica-BoldItalic"]="Helvetica-BoldOblique";e["Helvetica-Italic"]="Helvetica-Oblique";e["Symbol-Bold"]="Symbol";e["Symbol-BoldItalic"]="Symbol";e["Symbol-Italic"]="Symbol";e.TimesNewRoman="Times-Roman";e["TimesNewRoman-Bold"]="Times-Bold";e["TimesNewRoman-BoldItalic"]="Times-BoldItalic";e["TimesNewRoman-Italic"]="Times-Italic";e.TimesNewRomanPS="Times-Roman";e["TimesNewRomanPS-Bold"]="Times-Bold";e["TimesNewRomanPS-BoldItalic"]="Times-BoldItalic";e["TimesNewRomanPS-BoldItalicMT"]="Times-BoldItalic";e["TimesNewRomanPS-BoldMT"]="Times-Bold";e["TimesNewRomanPS-Italic"]="Times-Italic";e["TimesNewRomanPS-ItalicMT"]="Times-Italic";e.TimesNewRomanPSMT="Times-Roman";e["TimesNewRomanPSMT-Bold"]="Times-Bold";e["TimesNewRomanPSMT-BoldItalic"]="Times-BoldItalic";e["TimesNewRomanPSMT-Italic"]="Times-Italic"})),Vi=getLookupTableFactory((function(e){e.Courier="FoxitFixed.pfb";e["Courier-Bold"]="FoxitFixedBold.pfb";e["Courier-BoldOblique"]="FoxitFixedBoldItalic.pfb";e["Courier-Oblique"]="FoxitFixedItalic.pfb";e.Helvetica="LiberationSans-Regular.ttf";e["Helvetica-Bold"]="LiberationSans-Bold.ttf";e["Helvetica-BoldOblique"]="LiberationSans-BoldItalic.ttf";e["Helvetica-Oblique"]="LiberationSans-Italic.ttf";e["Times-Roman"]="FoxitSerif.pfb";e["Times-Bold"]="FoxitSerifBold.pfb";e["Times-BoldItalic"]="FoxitSerifBoldItalic.pfb";e["Times-Italic"]="FoxitSerifItalic.pfb";e.Symbol="FoxitSymbol.pfb";e.ZapfDingbats="FoxitDingbats.pfb";e["LiberationSans-Regular"]="LiberationSans-Regular.ttf";e["LiberationSans-Bold"]="LiberationSans-Bold.ttf";e["LiberationSans-Italic"]="LiberationSans-Italic.ttf";e["LiberationSans-BoldItalic"]="LiberationSans-BoldItalic.ttf"})),zi=getLookupTableFactory((function(e){e.Calibri="Helvetica";e["Calibri-Bold"]="Helvetica-Bold";e["Calibri-BoldItalic"]="Helvetica-BoldOblique";e["Calibri-Italic"]="Helvetica-Oblique";e.CenturyGothic="Helvetica";e["CenturyGothic-Bold"]="Helvetica-Bold";e["CenturyGothic-BoldItalic"]="Helvetica-BoldOblique";e["CenturyGothic-Italic"]="Helvetica-Oblique";e.ComicSansMS="Comic Sans MS";e["ComicSansMS-Bold"]="Comic Sans MS-Bold";e["ComicSansMS-BoldItalic"]="Comic Sans MS-BoldItalic";e["ComicSansMS-Italic"]="Comic Sans MS-Italic";e.GillSansMT="Helvetica";e["GillSansMT-Bold"]="Helvetica-Bold";e["GillSansMT-BoldItalic"]="Helvetica-BoldOblique";e["GillSansMT-Italic"]="Helvetica-Oblique";e.Impact="Helvetica";e["ItcSymbol-Bold"]="Helvetica-Bold";e["ItcSymbol-BoldItalic"]="Helvetica-BoldOblique";e["ItcSymbol-Book"]="Helvetica";e["ItcSymbol-BookItalic"]="Helvetica-Oblique";e["ItcSymbol-Medium"]="Helvetica";e["ItcSymbol-MediumItalic"]="Helvetica-Oblique";e.LucidaConsole="Courier";e["LucidaConsole-Bold"]="Courier-Bold";e["LucidaConsole-BoldItalic"]="Courier-BoldOblique";e["LucidaConsole-Italic"]="Courier-Oblique";e["LucidaSans-Demi"]="Helvetica-Bold";e["MS-Gothic"]="MS Gothic";e["MS-Gothic-Bold"]="MS Gothic-Bold";e["MS-Gothic-BoldItalic"]="MS Gothic-BoldItalic";e["MS-Gothic-Italic"]="MS Gothic-Italic";e["MS-Mincho"]="MS Mincho";e["MS-Mincho-Bold"]="MS Mincho-Bold";e["MS-Mincho-BoldItalic"]="MS Mincho-BoldItalic";e["MS-Mincho-Italic"]="MS Mincho-Italic";e["MS-PGothic"]="MS PGothic";e["MS-PGothic-Bold"]="MS PGothic-Bold";e["MS-PGothic-BoldItalic"]="MS PGothic-BoldItalic";e["MS-PGothic-Italic"]="MS PGothic-Italic";e["MS-PMincho"]="MS PMincho";e["MS-PMincho-Bold"]="MS PMincho-Bold";e["MS-PMincho-BoldItalic"]="MS PMincho-BoldItalic";e["MS-PMincho-Italic"]="MS PMincho-Italic";e.NuptialScript="Times-Italic";e.SegoeUISymbol="Helvetica"})),_i=getLookupTableFactory((function(e){e["Adobe Jenson"]=!0;e["Adobe Text"]=!0;e.Albertus=!0;e.Aldus=!0;e.Alexandria=!0;e.Algerian=!0;e["American Typewriter"]=!0;e.Antiqua=!0;e.Apex=!0;e.Arno=!0;e.Aster=!0;e.Aurora=!0;e.Baskerville=!0;e.Bell=!0;e.Bembo=!0;e["Bembo Schoolbook"]=!0;e.Benguiat=!0;e["Berkeley Old Style"]=!0;e["Bernhard Modern"]=!0;e["Berthold City"]=!0;e.Bodoni=!0;e["Bauer Bodoni"]=!0;e["Book Antiqua"]=!0;e.Bookman=!0;e["Bordeaux Roman"]=!0;e["Californian FB"]=!0;e.Calisto=!0;e.Calvert=!0;e.Capitals=!0;e.Cambria=!0;e.Cartier=!0;e.Caslon=!0;e.Catull=!0;e.Centaur=!0;e["Century Old Style"]=!0;e["Century Schoolbook"]=!0;e.Chaparral=!0;e["Charis SIL"]=!0;e.Cheltenham=!0;e["Cholla Slab"]=!0;e.Clarendon=!0;e.Clearface=!0;e.Cochin=!0;e.Colonna=!0;e["Computer Modern"]=!0;e["Concrete Roman"]=!0;e.Constantia=!0;e["Cooper Black"]=!0;e.Corona=!0;e.Ecotype=!0;e.Egyptienne=!0;e.Elephant=!0;e.Excelsior=!0;e.Fairfield=!0;e["FF Scala"]=!0;e.Folkard=!0;e.Footlight=!0;e.FreeSerif=!0;e["Friz Quadrata"]=!0;e.Garamond=!0;e.Gentium=!0;e.Georgia=!0;e.Gloucester=!0;e["Goudy Old Style"]=!0;e["Goudy Schoolbook"]=!0;e["Goudy Pro Font"]=!0;e.Granjon=!0;e["Guardian Egyptian"]=!0;e.Heather=!0;e.Hercules=!0;e["High Tower Text"]=!0;e.Hiroshige=!0;e["Hoefler Text"]=!0;e["Humana Serif"]=!0;e.Imprint=!0;e["Ionic No. 5"]=!0;e.Janson=!0;e.Joanna=!0;e.Korinna=!0;e.Lexicon=!0;e.LiberationSerif=!0;e["Liberation Serif"]=!0;e["Linux Libertine"]=!0;e.Literaturnaya=!0;e.Lucida=!0;e["Lucida Bright"]=!0;e.Melior=!0;e.Memphis=!0;e.Miller=!0;e.Minion=!0;e.Modern=!0;e["Mona Lisa"]=!0;e["Mrs Eaves"]=!0;e["MS Serif"]=!0;e["Museo Slab"]=!0;e["New York"]=!0;e["Nimbus Roman"]=!0;e["NPS Rawlinson Roadway"]=!0;e.NuptialScript=!0;e.Palatino=!0;e.Perpetua=!0;e.Plantin=!0;e["Plantin Schoolbook"]=!0;e.Playbill=!0;e["Poor Richard"]=!0;e["Rawlinson Roadway"]=!0;e.Renault=!0;e.Requiem=!0;e.Rockwell=!0;e.Roman=!0;e["Rotis Serif"]=!0;e.Sabon=!0;e.Scala=!0;e.Seagull=!0;e.Sistina=!0;e.Souvenir=!0;e.STIX=!0;e["Stone Informal"]=!0;e["Stone Serif"]=!0;e.Sylfaen=!0;e.Times=!0;e.Trajan=!0;e["Trinité"]=!0;e["Trump Mediaeval"]=!0;e.Utopia=!0;e["Vale Type"]=!0;e["Bitstream Vera"]=!0;e["Vera Serif"]=!0;e.Versailles=!0;e.Wanted=!0;e.Weiss=!0;e["Wide Latin"]=!0;e.Windsor=!0;e.XITS=!0})),$i=getLookupTableFactory((function(e){e.Dingbats=!0;e.Symbol=!0;e.ZapfDingbats=!0;e.Wingdings=!0;e["Wingdings-Bold"]=!0;e["Wingdings-Regular"]=!0})),Aa=getLookupTableFactory((function(e){e[2]=10;e[3]=32;e[4]=33;e[5]=34;e[6]=35;e[7]=36;e[8]=37;e[9]=38;e[10]=39;e[11]=40;e[12]=41;e[13]=42;e[14]=43;e[15]=44;e[16]=45;e[17]=46;e[18]=47;e[19]=48;e[20]=49;e[21]=50;e[22]=51;e[23]=52;e[24]=53;e[25]=54;e[26]=55;e[27]=56;e[28]=57;e[29]=58;e[30]=894;e[31]=60;e[32]=61;e[33]=62;e[34]=63;e[35]=64;e[36]=65;e[37]=66;e[38]=67;e[39]=68;e[40]=69;e[41]=70;e[42]=71;e[43]=72;e[44]=73;e[45]=74;e[46]=75;e[47]=76;e[48]=77;e[49]=78;e[50]=79;e[51]=80;e[52]=81;e[53]=82;e[54]=83;e[55]=84;e[56]=85;e[57]=86;e[58]=87;e[59]=88;e[60]=89;e[61]=90;e[62]=91;e[63]=92;e[64]=93;e[65]=94;e[66]=95;e[67]=96;e[68]=97;e[69]=98;e[70]=99;e[71]=100;e[72]=101;e[73]=102;e[74]=103;e[75]=104;e[76]=105;e[77]=106;e[78]=107;e[79]=108;e[80]=109;e[81]=110;e[82]=111;e[83]=112;e[84]=113;e[85]=114;e[86]=115;e[87]=116;e[88]=117;e[89]=118;e[90]=119;e[91]=120;e[92]=121;e[93]=122;e[94]=123;e[95]=124;e[96]=125;e[97]=126;e[98]=196;e[99]=197;e[100]=199;e[101]=201;e[102]=209;e[103]=214;e[104]=220;e[105]=225;e[106]=224;e[107]=226;e[108]=228;e[109]=227;e[110]=229;e[111]=231;e[112]=233;e[113]=232;e[114]=234;e[115]=235;e[116]=237;e[117]=236;e[118]=238;e[119]=239;e[120]=241;e[121]=243;e[122]=242;e[123]=244;e[124]=246;e[125]=245;e[126]=250;e[127]=249;e[128]=251;e[129]=252;e[130]=8224;e[131]=176;e[132]=162;e[133]=163;e[134]=167;e[135]=8226;e[136]=182;e[137]=223;e[138]=174;e[139]=169;e[140]=8482;e[141]=180;e[142]=168;e[143]=8800;e[144]=198;e[145]=216;e[146]=8734;e[147]=177;e[148]=8804;e[149]=8805;e[150]=165;e[151]=181;e[152]=8706;e[153]=8721;e[154]=8719;e[156]=8747;e[157]=170;e[158]=186;e[159]=8486;e[160]=230;e[161]=248;e[162]=191;e[163]=161;e[164]=172;e[165]=8730;e[166]=402;e[167]=8776;e[168]=8710;e[169]=171;e[170]=187;e[171]=8230;e[179]=8220;e[180]=8221;e[181]=8216;e[182]=8217;e[200]=193;e[203]=205;e[207]=211;e[210]=218;e[223]=711;e[224]=321;e[225]=322;e[226]=352;e[227]=353;e[228]=381;e[229]=382;e[233]=221;e[234]=253;e[252]=263;e[253]=268;e[254]=269;e[258]=258;e[260]=260;e[261]=261;e[265]=280;e[266]=281;e[267]=282;e[268]=283;e[269]=313;e[275]=323;e[276]=324;e[278]=328;e[283]=344;e[284]=345;e[285]=346;e[286]=347;e[292]=367;e[295]=377;e[296]=378;e[298]=380;e[305]=963;e[306]=964;e[307]=966;e[308]=8215;e[309]=8252;e[310]=8319;e[311]=8359;e[312]=8592;e[313]=8593;e[337]=9552;e[493]=1039;e[494]=1040;e[672]=1488;e[673]=1489;e[674]=1490;e[675]=1491;e[676]=1492;e[677]=1493;e[678]=1494;e[679]=1495;e[680]=1496;e[681]=1497;e[682]=1498;e[683]=1499;e[684]=1500;e[685]=1501;e[686]=1502;e[687]=1503;e[688]=1504;e[689]=1505;e[690]=1506;e[691]=1507;e[692]=1508;e[693]=1509;e[694]=1510;e[695]=1511;e[696]=1512;e[697]=1513;e[698]=1514;e[705]=1524;e[706]=8362;e[710]=64288;e[711]=64298;e[759]=1617;e[761]=1776;e[763]=1778;e[775]=1652;e[777]=1764;e[778]=1780;e[779]=1781;e[780]=1782;e[782]=771;e[783]=64726;e[786]=8363;e[788]=8532;e[790]=768;e[791]=769;e[792]=768;e[795]=803;e[797]=64336;e[798]=64337;e[799]=64342;e[800]=64343;e[801]=64344;e[802]=64345;e[803]=64362;e[804]=64363;e[805]=64364;e[2424]=7821;e[2425]=7822;e[2426]=7823;e[2427]=7824;e[2428]=7825;e[2429]=7826;e[2430]=7827;e[2433]=7682;e[2678]=8045;e[2679]=8046;e[2830]=1552;e[2838]=686;e[2840]=751;e[2842]=753;e[2843]=754;e[2844]=755;e[2846]=757;e[2856]=767;e[2857]=848;e[2858]=849;e[2862]=853;e[2863]=854;e[2864]=855;e[2865]=861;e[2866]=862;e[2906]=7460;e[2908]=7462;e[2909]=7463;e[2910]=7464;e[2912]=7466;e[2913]=7467;e[2914]=7468;e[2916]=7470;e[2917]=7471;e[2918]=7472;e[2920]=7474;e[2921]=7475;e[2922]=7476;e[2924]=7478;e[2925]=7479;e[2926]=7480;e[2928]=7482;e[2929]=7483;e[2930]=7484;e[2932]=7486;e[2933]=7487;e[2934]=7488;e[2936]=7490;e[2937]=7491;e[2938]=7492;e[2940]=7494;e[2941]=7495;e[2942]=7496;e[2944]=7498;e[2946]=7500;e[2948]=7502;e[2950]=7504;e[2951]=7505;e[2952]=7506;e[2954]=7508;e[2955]=7509;e[2956]=7510;e[2958]=7512;e[2959]=7513;e[2960]=7514;e[2962]=7516;e[2963]=7517;e[2964]=7518;e[2966]=7520;e[2967]=7521;e[2968]=7522;e[2970]=7524;e[2971]=7525;e[2972]=7526;e[2974]=7528;e[2975]=7529;e[2976]=7530;e[2978]=1537;e[2979]=1538;e[2980]=1539;e[2982]=1549;e[2983]=1551;e[2984]=1552;e[2986]=1554;e[2987]=1555;e[2988]=1556;e[2990]=1623;e[2991]=1624;e[2995]=1775;e[2999]=1791;e[3002]=64290;e[3003]=64291;e[3004]=64292;e[3006]=64294;e[3007]=64295;e[3008]=64296;e[3011]=1900;e[3014]=8223;e[3015]=8244;e[3017]=7532;e[3018]=7533;e[3019]=7534;e[3075]=7590;e[3076]=7591;e[3079]=7594;e[3080]=7595;e[3083]=7598;e[3084]=7599;e[3087]=7602;e[3088]=7603;e[3091]=7606;e[3092]=7607;e[3095]=7610;e[3096]=7611;e[3099]=7614;e[3100]=7615;e[3103]=7618;e[3104]=7619;e[3107]=8337;e[3108]=8338;e[3116]=1884;e[3119]=1885;e[3120]=1885;e[3123]=1886;e[3124]=1886;e[3127]=1887;e[3128]=1887;e[3131]=1888;e[3132]=1888;e[3135]=1889;e[3136]=1889;e[3139]=1890;e[3140]=1890;e[3143]=1891;e[3144]=1891;e[3147]=1892;e[3148]=1892;e[3153]=580;e[3154]=581;e[3157]=584;e[3158]=585;e[3161]=588;e[3162]=589;e[3165]=891;e[3166]=892;e[3169]=1274;e[3170]=1275;e[3173]=1278;e[3174]=1279;e[3181]=7622;e[3182]=7623;e[3282]=11799;e[3316]=578;e[3379]=42785;e[3393]=1159;e[3416]=8377})),ea=getLookupTableFactory((function(e){e[227]=322;e[264]=261;e[291]=346})),ta=getLookupTableFactory((function(e){e[1]=32;e[4]=65;e[5]=192;e[6]=193;e[9]=196;e[17]=66;e[18]=67;e[21]=268;e[24]=68;e[28]=69;e[29]=200;e[30]=201;e[32]=282;e[38]=70;e[39]=71;e[44]=72;e[47]=73;e[48]=204;e[49]=205;e[58]=74;e[60]=75;e[62]=76;e[68]=77;e[69]=78;e[75]=79;e[76]=210;e[80]=214;e[87]=80;e[89]=81;e[90]=82;e[92]=344;e[94]=83;e[97]=352;e[100]=84;e[104]=85;e[109]=220;e[115]=86;e[116]=87;e[121]=88;e[122]=89;e[124]=221;e[127]=90;e[129]=381;e[258]=97;e[259]=224;e[260]=225;e[263]=228;e[268]=261;e[271]=98;e[272]=99;e[273]=263;e[275]=269;e[282]=100;e[286]=101;e[287]=232;e[288]=233;e[290]=283;e[295]=281;e[296]=102;e[336]=103;e[346]=104;e[349]=105;e[350]=236;e[351]=237;e[361]=106;e[364]=107;e[367]=108;e[371]=322;e[373]=109;e[374]=110;e[381]=111;e[382]=242;e[383]=243;e[386]=246;e[393]=112;e[395]=113;e[396]=114;e[398]=345;e[400]=115;e[401]=347;e[403]=353;e[410]=116;e[437]=117;e[442]=252;e[448]=118;e[449]=119;e[454]=120;e[455]=121;e[457]=253;e[460]=122;e[462]=382;e[463]=380;e[853]=44;e[855]=58;e[856]=46;e[876]=47;e[878]=45;e[882]=45;e[894]=40;e[895]=41;e[896]=91;e[897]=93;e[923]=64;e[1004]=48;e[1005]=49;e[1006]=50;e[1007]=51;e[1008]=52;e[1009]=53;e[1010]=54;e[1011]=55;e[1012]=56;e[1013]=57;e[1081]=37;e[1085]=43;e[1086]=45}));function getStandardFontName(e){const t=normalizeFontName(e);return Zi()[t]}function isKnownFontName(e){const t=normalizeFontName(e);return!!(Zi()[t]||zi()[t]||_i()[t]||$i()[t])}class ToUnicodeMap{constructor(e=[]){this._map=e}get length(){return this._map.length}forEach(e){for(const t in this._map)e(t,this._map[t].charCodeAt(0))}has(e){return void 0!==this._map[e]}get(e){return this._map[e]}charCodeOf(e){const t=this._map;if(t.length<=65536)return t.indexOf(e);for(const i in t)if(t[i]===e)return 0|i;return-1}amend(e){for(const t in e)this._map[t]=e[t]}}class IdentityToUnicodeMap{constructor(e,t){this.firstChar=e;this.lastChar=t}get length(){return this.lastChar+1-this.firstChar}forEach(e){for(let t=this.firstChar,i=this.lastChar;t<=i;t++)e(t,t)}has(e){return this.firstChar<=e&&e<=this.lastChar}get(e){if(this.firstChar<=e&&e<=this.lastChar)return String.fromCharCode(e)}charCodeOf(e){return Number.isInteger(e)&&e>=this.firstChar&&e<=this.lastChar?e:-1}amend(e){unreachable("Should not call amend()")}}class CFFFont{constructor(e,t){this.properties=t;const i=new CFFParser(e,t,Ti);this.cff=i.parse();this.cff.duplicateFirstGlyph();const a=new CFFCompiler(this.cff);this.seacs=this.cff.seacs;try{this.data=a.compile()}catch{warn("Failed to compile font "+t.loadedName);this.data=e}this._createBuiltInEncoding()}get numGlyphs(){return this.cff.charStrings.count}getCharset(){return this.cff.charset.charset}getGlyphMapping(){const e=this.cff,t=this.properties,{cidToGidMap:i,cMap:a}=t,s=e.charset.charset;let r,n;if(t.composite){let t,g;if(i?.length>0){t=Object.create(null);for(let e=0,a=i.length;e=0){const a=i[t];a&&(s[e]=a)}}s.length>0&&(this.properties.builtInEncoding=s)}}function getUint32(e,t){return(e[t]<<24|e[t+1]<<16|e[t+2]<<8|e[t+3])>>>0}function getUint16(e,t){return e[t]<<8|e[t+1]}function getInt16(e,t){return(e[t]<<24|e[t+1]<<16)>>16}function getInt8(e,t){return e[t]<<24>>24}function getFloat214(e,t){return getInt16(e,t)/16384}function getSubroutineBias(e){const t=e.length;let i=32768;t<1240?i=107:t<33900&&(i=1131);return i}function parseCmap(e,t,i){const a=1===getUint16(e,t+2)?getUint32(e,t+8):getUint32(e,t+16),s=getUint16(e,t+a);let r,n,g;if(4===s){getUint16(e,t+a+2);const i=getUint16(e,t+a+6)>>1;n=t+a+14;r=[];for(g=0;g>1;i0;)C.push({flags:r})}for(i=0;i>1;p=!0;break;case 4:n+=s.pop();moveTo(r,n);p=!0;break;case 5:for(;s.length>0;){r+=s.shift();n+=s.shift();lineTo(r,n)}break;case 6:for(;s.length>0;){r+=s.shift();lineTo(r,n);if(0===s.length)break;n+=s.shift();lineTo(r,n)}break;case 7:for(;s.length>0;){n+=s.shift();lineTo(r,n);if(0===s.length)break;r+=s.shift();lineTo(r,n)}break;case 8:for(;s.length>0;){c=r+s.shift();h=n+s.shift();C=c+s.shift();l=h+s.shift();r=C+s.shift();n=l+s.shift();bezierCurveTo(c,h,C,l,r,n)}break;case 10:d=s.pop();f=null;if(i.isCFFCIDFont){const e=i.fdSelect.getFDIndex(a);if(e>=0&&eMath.abs(n-t)?r+=s.shift():n+=s.shift();bezierCurveTo(c,h,C,l,r,n);break;default:throw new FormatError(`unknown operator: 12 ${m}`)}break;case 14:if(s.length>=4){const e=s.pop(),a=s.pop();n=s.pop();r=s.pop();t.add(dt);t.add(mt,[r,n]);let g=lookupCmap(i.cmap,String.fromCharCode(i.glyphNameMap[yi[e]]));compileCharString(i.glyphs[g.glyphId],t,i,g.glyphId);t.add(ut);g=lookupCmap(i.cmap,String.fromCharCode(i.glyphNameMap[yi[a]]));compileCharString(i.glyphs[g.glyphId],t,i,g.glyphId)}return;case 19:case 20:g+=s.length>>1;o+=g+7>>3;p=!0;break;case 21:n+=s.pop();r+=s.pop();moveTo(r,n);p=!0;break;case 22:r+=s.pop();moveTo(r,n);p=!0;break;case 24:for(;s.length>2;){c=r+s.shift();h=n+s.shift();C=c+s.shift();l=h+s.shift();r=C+s.shift();n=l+s.shift();bezierCurveTo(c,h,C,l,r,n)}r+=s.shift();n+=s.shift();lineTo(r,n);break;case 25:for(;s.length>6;){r+=s.shift();n+=s.shift();lineTo(r,n)}c=r+s.shift();h=n+s.shift();C=c+s.shift();l=h+s.shift();r=C+s.shift();n=l+s.shift();bezierCurveTo(c,h,C,l,r,n);break;case 26:s.length%2&&(r+=s.shift());for(;s.length>0;){c=r;h=n+s.shift();C=c+s.shift();l=h+s.shift();r=C;n=l+s.shift();bezierCurveTo(c,h,C,l,r,n)}break;case 27:s.length%2&&(n+=s.shift());for(;s.length>0;){c=r+s.shift();h=n;C=c+s.shift();l=h+s.shift();r=C+s.shift();n=l;bezierCurveTo(c,h,C,l,r,n)}break;case 28:s.push((e[o]<<24|e[o+1]<<16)>>16);o+=2;break;case 29:d=s.pop()+i.gsubrsBias;f=i.gsubrs[d];f&&parse(f);break;case 30:for(;s.length>0;){c=r;h=n+s.shift();C=c+s.shift();l=h+s.shift();r=C+s.shift();n=l+(1===s.length?s.shift():0);bezierCurveTo(c,h,C,l,r,n);if(0===s.length)break;c=r+s.shift();h=n;C=c+s.shift();l=h+s.shift();n=l+s.shift();r=C+(1===s.length?s.shift():0);bezierCurveTo(c,h,C,l,r,n)}break;case 31:for(;s.length>0;){c=r+s.shift();h=n;C=c+s.shift();l=h+s.shift();n=l+s.shift();r=C+(1===s.length?s.shift():0);bezierCurveTo(c,h,C,l,r,n);if(0===s.length)break;c=r;h=n+s.shift();C=c+s.shift();l=h+s.shift();r=C+s.shift();n=l+(1===s.length?s.shift():0);bezierCurveTo(c,h,C,l,r,n)}break;default:if(m<32)throw new FormatError(`unknown operator: ${m}`);if(m<247)s.push(m-139);else if(m<251)s.push(256*(m-247)+e[o++]+108);else if(m<255)s.push(256*-(m-251)-e[o++]-108);else{s.push((e[o]<<24|e[o+1]<<16|e[o+2]<<8|e[o+3])/65536);o+=4}}p&&(s.length=0)}}(e)}const ia=[];class Commands{cmds=[];add(e,t){if(t)if(isNumberArray(t,null))this.cmds.push(e,...t);else{warn(`Commands.add - "${e}" has at least one non-number arg: "${t}".`);const i=t.map((e=>"number"==typeof e?e:0));this.cmds.push(e,...i)}else this.cmds.push(e)}}class CompiledFont{constructor(e){this.fontMatrix=e;this.compiledGlyphs=Object.create(null);this.compiledCharCodeToGlyphId=Object.create(null)}getPathJs(e){const{charCode:t,glyphId:i}=lookupCmap(this.cmap,e);let a,s=this.compiledGlyphs[i];if(!s){try{s=this.compileGlyph(this.glyphs[i],i)}catch(e){s=ia;a=e}this.compiledGlyphs[i]=s}this.compiledCharCodeToGlyphId[t]??=i;if(a)throw a;return s}compileGlyph(e,t){if(!e||0===e.length||14===e[0])return ia;let i=this.fontMatrix;if(this.isCFFCIDFont){const e=this.fdSelect.getFDIndex(t);if(e>=0&&e2*getUint16(e,t)}const r=[];let n=s(t,0);for(let i=a;ie+(t.getSize()+3&-4)),0)}write(){const e=this.getSize(),t=new DataView(new ArrayBuffer(e)),i=e>131070,a=i?4:2,s=new DataView(new ArrayBuffer((this.glyphs.length+1)*a));i?s.setUint32(0,0):s.setUint16(0,0);let r=0,n=0;for(const e of this.glyphs){r+=e.write(r,t);r=r+3&-4;n+=a;i?s.setUint32(n,r):s.setUint16(n,r>>1)}return{isLocationLong:i,loca:new Uint8Array(s.buffer),glyf:new Uint8Array(t.buffer)}}scale(e){for(let t=0,i=this.glyphs.length;te+t.getSize()),0);return this.header.getSize()+e}write(e,t){if(!this.header)return 0;const i=e;e+=this.header.write(e,t);if(this.simple)e+=this.simple.write(e,t);else for(const i of this.composites)e+=i.write(e,t);return e-i}scale(e){if(!this.header)return;const t=(this.header.xMin+this.header.xMax)/2;this.header.scale(t,e);if(this.simple)this.simple.scale(t,e);else for(const i of this.composites)i.scale(t,e)}}class GlyphHeader{constructor({numberOfContours:e,xMin:t,yMin:i,xMax:a,yMax:s}){this.numberOfContours=e;this.xMin=t;this.yMin=i;this.xMax=a;this.yMax=s}static parse(e,t){return[10,new GlyphHeader({numberOfContours:t.getInt16(e),xMin:t.getInt16(e+2),yMin:t.getInt16(e+4),xMax:t.getInt16(e+6),yMax:t.getInt16(e+8)})]}getSize(){return 10}write(e,t){t.setInt16(e,this.numberOfContours);t.setInt16(e+2,this.xMin);t.setInt16(e+4,this.yMin);t.setInt16(e+6,this.xMax);t.setInt16(e+8,this.yMax);return 10}scale(e,t){this.xMin=Math.round(e+(this.xMin-e)*t);this.xMax=Math.round(e+(this.xMax-e)*t)}}class Contour{constructor({flags:e,xCoordinates:t,yCoordinates:i}){this.xCoordinates=t;this.yCoordinates=i;this.flags=e}}class SimpleGlyph{constructor({contours:e,instructions:t}){this.contours=e;this.instructions=t}static parse(e,t,i){const a=[];for(let s=0;s255?e+=2:g>0&&(e+=1);t=r;g=Math.abs(n-i);g>255?e+=2:g>0&&(e+=1);i=n}}return e}write(e,t){const i=e,a=[],s=[],r=[];let n=0,g=0;for(const i of this.contours){for(let e=0,t=i.xCoordinates.length;e=0?18:2;a.push(e)}else a.push(c)}n=o;const C=i.yCoordinates[e];c=C-g;if(0===c){t|=32;s.push(0)}else{const e=Math.abs(c);if(e<=255){t|=c>=0?36:4;s.push(e)}else s.push(c)}g=C;r.push(t)}t.setUint16(e,a.length-1);e+=2}t.setUint16(e,this.instructions.length);e+=2;if(this.instructions.length){new Uint8Array(t.buffer,0,t.buffer.byteLength).set(this.instructions,e);e+=this.instructions.length}for(const i of r)t.setUint8(e++,i);for(let i=0,s=a.length;i=-128&&this.argument1<=127&&this.argument2>=-128&&this.argument2<=127||(e+=2):this.argument1>=0&&this.argument1<=255&&this.argument2>=0&&this.argument2<=255||(e+=2);return e}write(e,t){const i=e;2&this.flags?this.argument1>=-128&&this.argument1<=127&&this.argument2>=-128&&this.argument2<=127||(this.flags|=1):this.argument1>=0&&this.argument1<=255&&this.argument2>=0&&this.argument2<=255||(this.flags|=1);t.setUint16(e,this.flags);t.setUint16(e+2,this.glyphIndex);e+=4;if(1&this.flags){if(2&this.flags){t.setInt16(e,this.argument1);t.setInt16(e+2,this.argument2)}else{t.setUint16(e,this.argument1);t.setUint16(e+2,this.argument2)}e+=4}else{t.setUint8(e,this.argument1);t.setUint8(e+1,this.argument2);e+=2}if(256&this.flags){t.setUint16(e,this.instructions.length);e+=2;if(this.instructions.length){new Uint8Array(t.buffer,0,t.buffer.byteLength).set(this.instructions,e);e+=this.instructions.length}}return e-i}scale(e,t){}}function writeInt16(e,t,i){e[t]=i>>8&255;e[t+1]=255&i}function writeInt32(e,t,i){e[t]=i>>24&255;e[t+1]=i>>16&255;e[t+2]=i>>8&255;e[t+3]=255&i}function writeData(e,t,i){if(i instanceof Uint8Array)e.set(i,t);else if("string"==typeof i)for(let a=0,s=i.length;ai;){i<<=1;a++}const s=i*t;return{range:s,entry:a,rangeShift:t*e-s}}toArray(){let e=this.sfnt;const t=this.tables,i=Object.keys(t);i.sort();const a=i.length;let s,r,n,g,o,c=12+16*a;const C=[c];for(s=0;s>>0;C.push(c)}const h=new Uint8Array(c);for(s=0;s>>0}writeInt32(h,c+4,e);writeInt32(h,c+8,C[s]);writeInt32(h,c+12,t[o].length);c+=16}return h}addTable(e,t){if(e in this.tables)throw new Error("Table "+e+" already exists");this.tables[e]=t}}const ra=[4],na=[5],ga=[6],oa=[7],Ia=[8],ca=[12,35],Ca=[14],ha=[21],Ba=[22],la=[30],Qa=[31];class Type1CharString{constructor(){this.width=0;this.lsb=0;this.flexing=!1;this.output=[];this.stack=[]}convert(e,t,i){const a=e.length;let s,r,n,g=!1;for(let o=0;oa)return!0;const s=a-e;for(let e=s;e>8&255,255&t);else{t=65536*t|0;this.output.push(255,t>>24&255,t>>16&255,t>>8&255,255&t)}}this.output.push(...t);i?this.stack.splice(s,e):this.stack.length=0;return!1}}function isHexDigit(e){return e>=48&&e<=57||e>=65&&e<=70||e>=97&&e<=102}function decrypt(e,t,i){if(i>=e.length)return new Uint8Array(0);let a,s,r=0|t;for(a=0;a>8;r=52845*(t+r)+22719&65535}return g}function isSpecial(e){return 47===e||91===e||93===e||123===e||125===e||40===e||41===e}class Type1Parser{constructor(e,t,i){if(t){const t=e.getBytes(),i=!((isHexDigit(t[0])||isWhiteSpace(t[0]))&&isHexDigit(t[1])&&isHexDigit(t[2])&&isHexDigit(t[3])&&isHexDigit(t[4])&&isHexDigit(t[5])&&isHexDigit(t[6])&&isHexDigit(t[7]));e=new Stream(i?decrypt(t,55665,4):function decryptAscii(e,t,i){let a=0|t;const s=e.length,r=new Uint8Array(s>>>1);let n,g;for(n=0,g=0;n>8;a=52845*(e+a)+22719&65535}}return r.slice(i,g)}(t,55665,4))}this.seacAnalysisEnabled=!!i;this.stream=e;this.nextChar()}readNumberArray(){this.getToken();const e=[];for(;;){const t=this.getToken();if(null===t||"]"===t||"}"===t)break;e.push(parseFloat(t||0))}return e}readNumber(){const e=this.getToken();return parseFloat(e||0)}readInt(){const e=this.getToken();return 0|parseInt(e||0,10)}readBoolean(){return"true"===this.getToken()?1:0}nextChar(){return this.currentChar=this.stream.getByte()}prevChar(){this.stream.skip(-2);return this.currentChar=this.stream.getByte()}getToken(){let e=!1,t=this.currentChar;for(;;){if(-1===t)return null;if(e)10!==t&&13!==t||(e=!1);else if(37===t)e=!0;else if(!isWhiteSpace(t))break;t=this.nextChar()}if(isSpecial(t)){this.nextChar();return String.fromCharCode(t)}let i="";do{i+=String.fromCharCode(t);t=this.nextChar()}while(t>=0&&!isWhiteSpace(t)&&!isSpecial(t));return i}readCharStrings(e,t){return-1===t?e:decrypt(e,4330,t)}extractFontProgram(e){const t=this.stream,i=[],a=[],s=Object.create(null);s.lenIV=4;const r={subrs:[],charstrings:[],properties:{privateData:s}};let n,g,o,c;for(;null!==(n=this.getToken());)if("/"===n){n=this.getToken();switch(n){case"CharStrings":this.getToken();this.getToken();this.getToken();this.getToken();for(;;){n=this.getToken();if(null===n||"end"===n)break;if("/"!==n)continue;const e=this.getToken();g=this.readInt();this.getToken();o=g>0?t.getBytes(g):new Uint8Array(0);c=r.properties.privateData.lenIV;const i=this.readCharStrings(o,c);this.nextChar();n=this.getToken();"noaccess"===n?this.getToken():"/"===n&&this.prevChar();a.push({glyph:e,encoded:i})}break;case"Subrs":this.readInt();this.getToken();for(;"dup"===this.getToken();){const e=this.readInt();g=this.readInt();this.getToken();o=g>0?t.getBytes(g):new Uint8Array(0);c=r.properties.privateData.lenIV;const a=this.readCharStrings(o,c);this.nextChar();n=this.getToken();"noaccess"===n&&this.getToken();i[e]=a}break;case"BlueValues":case"OtherBlues":case"FamilyBlues":case"FamilyOtherBlues":const e=this.readNumberArray();e.length>0&&e.length,0;break;case"StemSnapH":case"StemSnapV":r.properties.privateData[n]=this.readNumberArray();break;case"StdHW":case"StdVW":r.properties.privateData[n]=this.readNumberArray()[0];break;case"BlueShift":case"lenIV":case"BlueFuzz":case"BlueScale":case"LanguageGroup":r.properties.privateData[n]=this.readNumber();break;case"ExpansionFactor":r.properties.privateData[n]=this.readNumber()||.06;break;case"ForceBold":r.properties.privateData[n]=this.readBoolean()}}for(const{encoded:t,glyph:s}of a){const a=new Type1CharString,n=a.convert(t,i,this.seacAnalysisEnabled);let g=a.output;n&&(g=[14]);const o={glyphName:s,charstring:g,width:a.width,lsb:a.lsb,seac:a.seac};".notdef"===s?r.charstrings.unshift(o):r.charstrings.push(o);if(e.builtInEncoding){const t=e.builtInEncoding.indexOf(s);t>-1&&void 0===e.widths[t]&&t>=e.firstChar&&t<=e.lastChar&&(e.widths[t]=a.width)}}return r}extractFontHeader(e){let t;for(;null!==(t=this.getToken());)if("/"===t){t=this.getToken();switch(t){case"FontMatrix":const i=this.readNumberArray();e.fontMatrix=i;break;case"Encoding":const a=this.getToken();let s;if(/^\d+$/.test(a)){s=[];const e=0|parseInt(a,10);this.getToken();for(let i=0;i=s){n+=i;for(;n=0&&(a[e]=s)}}return type1FontGlyphMapping(e,a,i)}hasGlyphId(e){if(e<0||e>=this.numGlyphs)return!1;if(0===e)return!0;return this.charstrings[e-1].charstring.length>0}getSeacs(e){const t=[];for(let i=0,a=e.length;i0;e--)t[e]-=t[e-1];Q.setByName(e,t)}r.topDict.privateDict=Q;const u=new CFFIndex;for(C=0,h=a.length;C0&&e.toUnicode.amend(t)}class fonts_Glyph{constructor(e,t,i,a,s,r,n,g,o){this.originalCharCode=e;this.fontChar=t;this.unicode=i;this.accent=a;this.width=s;this.vmetric=r;this.operatorListId=n;this.isSpace=g;this.isInFont=o}get category(){return shadow(this,"category",function getCharUnicodeCategory(e){const t=Ki.get(e);if(t)return t;const i=e.match(vi),a={isWhitespace:!!i?.[1],isZeroWidthDiacritic:!!i?.[2],isInvisibleFormatMark:!!i?.[3]};Ki.set(e,a);return a}(this.unicode),!0)}}function int16(e,t){return(e<<8)+t}function writeSignedInt16(e,t,i){e[t+1]=i;e[t]=i>>>8}function signedInt16(e,t){const i=(e<<8)+t;return 32768&i?i-65536:i}function string16(e){return String.fromCharCode(e>>8&255,255&e)}function safeString16(e){e>32767?e=32767:e<-32768&&(e=-32768);return String.fromCharCode(e>>8&255,255&e)}function isTrueTypeCollectionFile(e){return"ttcf"===bytesToString(e.peekBytes(4))}function getFontFileType(e,{type:t,subtype:i,composite:a}){let s,r;if(function isTrueTypeFile(e){const t=e.peekBytes(4);return 65536===readUint32(t,0)||"true"===bytesToString(t)}(e)||isTrueTypeCollectionFile(e))s=a?"CIDFontType2":"TrueType";else if(function isOpenTypeFile(e){return"OTTO"===bytesToString(e.peekBytes(4))}(e))s=a?"CIDFontType2":"OpenType";else if(function isType1File(e){const t=e.peekBytes(2);return 37===t[0]&&33===t[1]||128===t[0]&&1===t[1]}(e))s=a?"CIDFontType0":"MMType1"===t?"MMType1":"Type1";else if(function isCFFFile(e){const t=e.peekBytes(4);return t[0]>=1&&t[3]>=1&&t[3]<=4}(e))if(a){s="CIDFontType0";r="CIDFontType0C"}else{s="MMType1"===t?"MMType1":"Type1";r="Type1C"}else{warn("getFontFileType: Unable to detect correct font file Type/Subtype.");s=t;r=i}return[s,r]}function applyStandardFontGlyphMap(e,t){for(const i in t)e[+i]=t[i]}function buildToFontChar(e,t,i){const a=[];let s;for(let i=0,r=e.length;iC){o++;if(o>=Ea.length){warn("Ran out of space in font private use area.");break}c=Ea[o][0];C=Ea[o][1]}const E=c++;0===Q&&(Q=i);let u=a.get(l);"string"==typeof u&&(u=u.codePointAt(0));if(u&&!(h=u,Ea[0][0]<=h&&h<=Ea[0][1]||Ea[1][0]<=h&&h<=Ea[1][1])&&!g.has(Q)){r.set(u,Q);g.add(Q)}s[E]=Q;n[l]=E}var h;return{toFontChar:n,charCodeToGlyphId:s,toUnicodeExtraMap:r,nextAvailableFontCharCode:c}}function createCmapTable(e,t,i){const a=function getRanges(e,t,i){const a=[];for(const t in e)e[t]>=i||a.push({fontCharCode:0|t,glyphId:e[t]});if(t)for(const[e,s]of t)s>=i||a.push({fontCharCode:e,glyphId:s});0===a.length&&a.push({fontCharCode:0,glyphId:0});a.sort((function fontGetRangesSort(e,t){return e.fontCharCode-t.fontCharCode}));const s=[],r=a.length;for(let e=0;e65535?2:1;let r,n,g,o,c="\0\0"+string16(s)+"\0\0"+string32(4+8*s);for(r=a.length-1;r>=0&&!(a[r][0]<=65535);--r);const C=r+1;a[r][0]<65535&&65535===a[r][1]&&(a[r][1]=65534);const h=a[r][1]<65535?1:0,l=C+h,Q=OpenTypeFileBuilder.getSearchParams(l,2);let E,u,d,f,p="",m="",y="",w="",D="",b=0;for(r=0,n=C;r0){m+="ÿÿ";p+="ÿÿ";y+="\0";w+="\0\0"}const F="\0\0"+string16(2*l)+string16(Q.range)+string16(Q.entry)+string16(Q.rangeShift)+m+"\0\0"+p+y+w+D;let S="",k="";if(s>1){c+="\0\0\n"+string32(4+8*s+4+F.length);S="";for(r=0,n=a.length;re||!g)&&(g=e);o 123 are reserved for internal usage");n|=1<65535&&(o=65535)}else{g=0;o=255}const C=e.bbox||[0,0,0,0],h=i.unitsPerEm||(e.fontMatrix?1/Math.max(...e.fontMatrix.slice(0,4).map(Math.abs)):1e3),l=e.ascentScaled?1:h/ua,Q=i.ascent||Math.round(l*(e.ascent||C[3]));let E=i.descent||Math.round(l*(e.descent||C[1]));E>0&&e.descent>0&&C[1]<0&&(E=-E);const u=i.yMax||Q,d=-i.yMin||-E;return"\0$ô\0\0\0Š»\0\0\0ŒŠ»\0\0ß\x001\0\0\0\0"+String.fromCharCode(e.fixedPitch?9:0)+"\0\0\0\0\0\0"+string32(a)+string32(s)+string32(r)+string32(n)+"*21*"+string16(e.italicAngle?1:0)+string16(g||e.firstChar)+string16(o||e.lastChar)+string16(Q)+string16(E)+"\0d"+string16(u)+string16(d)+"\0\0\0\0\0\0\0\0"+string16(e.xHeight)+string16(e.capHeight)+string16(0)+string16(g||e.firstChar)+"\0"}function createPostTable(e){return"\0\0\0"+string32(Math.floor(65536*e.italicAngle))+"\0\0\0\0"+string32(e.fixedPitch?1:0)+"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"}function createPostscriptName(e){return e.replaceAll(/[^\x21-\x7E]|[[\](){}<>/%]/g,"").slice(0,63)}function createNameTable(e,t){t||(t=[[],[]]);const i=[t[0][0]||"Original licence",t[0][1]||e,t[0][2]||"Unknown",t[0][3]||"uniqueID",t[0][4]||e,t[0][5]||"Version 0.11",t[0][6]||createPostscriptName(e),t[0][7]||"Unknown",t[0][8]||"Unknown",t[0][9]||"Unknown"],a=[];let s,r,n,g,o;for(s=0,r=i.length;s0;if((n||g)&&"CIDFontType2"===i&&this.cidEncoding.startsWith("Identity-")){const i=e.cidToGidMap,a=[];applyStandardFontGlyphMap(a,Aa());/Arial-?Black/i.test(t)?applyStandardFontGlyphMap(a,ea()):/Calibri/i.test(t)&&applyStandardFontGlyphMap(a,ta());if(i){for(const e in a){const t=a[e];void 0!==i[t]&&(a[+e]=i[t])}i.length!==this.toUnicode.length&&e.hasIncludedToUnicodeMap&&this.toUnicode instanceof IdentityToUnicodeMap&&this.toUnicode.forEach((function(e,t){const s=a[e];void 0===i[s]&&(a[+e]=t)}))}this.toUnicode instanceof IdentityToUnicodeMap||this.toUnicode.forEach((function(e,t){a[+e]=t}));this.toFontChar=a;this.toUnicode=new ToUnicodeMap(a)}else if(/Symbol/i.test(a))this.toFontChar=buildToFontChar(Di,Mi(),this.differences);else if(/Dingbats/i.test(a))this.toFontChar=buildToFontChar(bi,Hi(),this.differences);else if(n||g){const e=buildToFontChar(this.defaultEncoding,Mi(),this.differences);"CIDFontType2"!==i||this.cidEncoding.startsWith("Identity-")||this.toUnicode instanceof IdentityToUnicodeMap||this.toUnicode.forEach((function(t,i){e[+t]=i}));this.toFontChar=e}else{const e=Mi(),i=[];this.toUnicode.forEach(((t,a)=>{if(!this.composite){const i=getUnicodeForGlyph(this.differences[t]||this.defaultEncoding[t],e);-1!==i&&(a=i)}i[+t]=a}));this.composite&&this.toUnicode instanceof IdentityToUnicodeMap&&/Tahoma|Verdana/i.test(t)&&applyStandardFontGlyphMap(i,Aa());this.toFontChar=i}amendFallbackToUnicode(e);this.loadedName=a.split("-",1)[0]}checkAndRepair(e,t,i){const a=["OS/2","cmap","head","hhea","hmtx","maxp","name","post","loca","glyf","fpgm","prep","cvt ","CFF "];function readTables(e,t){const i=Object.create(null);i["OS/2"]=null;i.cmap=null;i.head=null;i.hhea=null;i.hmtx=null;i.maxp=null;i.name=null;i.post=null;for(let s=0;s>>0,a=e.getInt32()>>>0,s=e.getInt32()>>>0,r=e.pos;e.pos=e.start||0;e.skip(a);const n=e.getBytes(s);e.pos=r;if("head"===t){n[8]=n[9]=n[10]=n[11]=0;n[17]|=32}return{tag:t,checksum:i,length:s,offset:a,data:n}}function readOpenTypeHeader(e){return{version:e.getString(4),numTables:e.getUint16(),searchRange:e.getUint16(),entrySelector:e.getUint16(),rangeShift:e.getUint16()}}function sanitizeGlyph(e,t,i,a,s,r){const n={length:0,sizeOfInstructions:0};if(t<0||t>=e.length||i>e.length||i-t<=12)return n;const g=e.subarray(t,i),o=signedInt16(g[2],g[3]),c=signedInt16(g[4],g[5]),C=signedInt16(g[6],g[7]),h=signedInt16(g[8],g[9]);if(o>C){writeSignedInt16(g,2,C);writeSignedInt16(g,6,o)}if(c>h){writeSignedInt16(g,4,h);writeSignedInt16(g,8,c)}const l=signedInt16(g[0],g[1]);if(l<0){if(l<-1)return n;a.set(g,s);n.length=g.length;return n}let Q,E=10,u=0;for(Q=0;Qg.length)return n;if(!r&&f>0){a.set(g.subarray(0,d),s);a.set([0,0],s+d);a.set(g.subarray(p,y),s+d+2);y-=f;g.length-y>3&&(y=y+3&-4);n.length=y;return n}if(g.length-y>3){y=y+3&-4;a.set(g.subarray(0,y),s);n.length=y;return n}a.set(g,s);n.length=g.length;return n}function readNameTable(e){const i=(t.start||0)+e.offset;t.pos=i;const a=[[],[]],s=[],r=e.length,n=i+r;if(0!==t.getUint16()||r<6)return[a,s];const g=t.getUint16(),o=t.getUint16();let c,C;for(c=0;cn)continue;t.pos=r;const g=e.name;if(e.encoding){let i="";for(let a=0,s=e.length;a0&&(c+=e-1)}}else{if(d||p){warn("TT: nested FDEFs not allowed");u=!0}d=!0;h=c;n=l.pop();t.functionsDefined[n]={data:o,i:c}}else if(!d&&!p){n=l.at(-1);if(isNaN(n))info("TT: CALL empty stack (or invalid entry).");else{t.functionsUsed[n]=!0;if(n in t.functionsStackDeltas){const e=l.length+t.functionsStackDeltas[n];if(e<0){warn("TT: CALL invalid functions stack delta.");t.hintsValid=!1;return}l.length=e}else if(n in t.functionsDefined&&!E.includes(n)){Q.push({data:o,i:c,stackTop:l.length-1});E.push(n);g=t.functionsDefined[n];if(!g){warn("TT: CALL non-existent function");t.hintsValid=!1;return}o=g.data;c=g.i}}}if(!d&&!p){let t=0;e<=142?t=s[e]:e>=192&&e<=223?t=-1:e>=224&&(t=-2);if(e>=113&&e<=117){a=l.pop();isNaN(a)||(t=2*-a)}for(;t<0&&l.length>0;){l.pop();t++}for(;t>0;){l.push(NaN);t--}}}t.tooComplexToFollowFunctions=u;const m=[o];c>o.length&&m.push(new Uint8Array(c-o.length));if(h>C){warn("TT: complementing a missing function tail");m.push(new Uint8Array([34,45]))}!function foldTTTable(e,t){if(t.length>1){let i,a,s=0;for(i=0,a=t.length;i>>0,r=[];for(let t=0;t>>0);const n={ttcTag:t,majorVersion:i,minorVersion:a,numFonts:s,offsetTable:r};switch(i){case 1:return n;case 2:n.dsigTag=e.getInt32()>>>0;n.dsigLength=e.getInt32()>>>0;n.dsigOffset=e.getInt32()>>>0;return n}throw new FormatError(`Invalid TrueType Collection majorVersion: ${i}.`)}(e),s=t.split("+");let r;for(let n=0;n0||!(i.cMap instanceof IdentityCMap));if("OTTO"===r.version&&!t||!n.head||!n.hhea||!n.maxp||!n.post){o=new Stream(n["CFF "].data);g=new CFFFont(o,i);adjustWidths(i);return this.convert(e,g,i)}delete n.glyf;delete n.loca;delete n.fpgm;delete n.prep;delete n["cvt "];this.isOpenType=!0}if(!n.maxp)throw new FormatError('Required "maxp" table is not found');t.pos=(t.start||0)+n.maxp.offset;let C=t.getInt32();const h=t.getUint16();if(65536!==C&&20480!==C){if(6===n.maxp.length)C=20480;else{if(!(n.maxp.length>=32))throw new FormatError('"maxp" table has a wrong version number');C=65536}!function writeUint32(e,t,i){e[t+3]=255&i;e[t+2]=i>>>8;e[t+1]=i>>>16;e[t]=i>>>24}(n.maxp.data,0,C)}if(i.scaleFactors?.length===h&&c){const{scaleFactors:e}=i,t=int16(n.head.data[50],n.head.data[51]),a=new GlyfTable({glyfTable:n.glyf.data,isGlyphLocationsLong:t,locaTable:n.loca.data,numGlyphs:h});a.scale(e);const{glyf:s,loca:r,isLocationLong:g}=a.write();n.glyf.data=s;n.loca.data=r;if(g!==!!t){n.head.data[50]=0;n.head.data[51]=g?1:0}const o=n.hmtx.data;for(let t=0;t>8&255;o[i+1]=255&a;writeSignedInt16(o,i+2,Math.round(e[t]*signedInt16(o[i+2],o[i+3])))}}let l=h+1,Q=!0;if(l>65535){Q=!1;l=h;warn("Not enough space in glyfs to duplicate first glyph.")}let E=0,u=0;if(C>=65536&&n.maxp.length>=32){t.pos+=8;if(t.getUint16()>2){n.maxp.data[14]=0;n.maxp.data[15]=2}t.pos+=4;E=t.getUint16();t.pos+=4;u=t.getUint16()}n.maxp.data[4]=l>>8;n.maxp.data[5]=255&l;const d=function sanitizeTTPrograms(e,t,i,a){const s={functionsDefined:[],functionsUsed:[],functionsStackDeltas:[],tooComplexToFollowFunctions:!1,hintsValid:!0};e&&sanitizeTTProgram(e,s);t&&sanitizeTTProgram(t,s);e&&function checkInvalidFunctions(e,t){if(!e.tooComplexToFollowFunctions)if(e.functionsDefined.length>t){warn("TT: more functions defined than expected");e.hintsValid=!1}else for(let i=0,a=e.functionsUsed.length;it){warn("TT: invalid function id: "+i);e.hintsValid=!1;return}if(e.functionsUsed[i]&&!e.functionsDefined[i]){warn("TT: undefined function: "+i);e.hintsValid=!1;return}}}(s,a);if(i&&1&i.length){const e=new Uint8Array(i.length+1);e.set(i.data);i.data=e}return s.hintsValid}(n.fpgm,n.prep,n["cvt "],E);if(!d){delete n.fpgm;delete n.prep;delete n["cvt "]}!function sanitizeMetrics(e,t,i,a,s,r){if(!t){i&&(i.data=null);return}e.pos=(e.start||0)+t.offset;e.pos+=4;e.pos+=2;e.pos+=2;e.pos+=2;e.pos+=2;e.pos+=2;e.pos+=2;e.pos+=2;e.pos+=2;e.pos+=2;const n=e.getUint16();e.pos+=8;e.pos+=2;let g=e.getUint16();if(0!==n){if(!(2&int16(a.data[44],a.data[45]))){t.data[22]=0;t.data[23]=0}}if(g>s){info(`The numOfMetrics (${g}) should not be greater than the numGlyphs (${s}).`);g=s;t.data[34]=(65280&g)>>8;t.data[35]=255&g}const o=s-g-(i.length-4*g>>1);if(o>0){const e=new Uint8Array(i.length+2*o);e.set(i.data);if(r){e[i.length]=i.data[2];e[i.length+1]=i.data[3]}i.data=e}}(t,n.hhea,n.hmtx,n.head,l,Q);if(!n.head)throw new FormatError('Required "head" table is not found');!function sanitizeHead(e,t,i){const a=e.data,s=function int32(e,t,i,a){return(e<<24)+(t<<16)+(i<<8)+a}(a[0],a[1],a[2],a[3]);if(s>>16!=1){info("Attempting to fix invalid version in head table: "+s);a[0]=0;a[1]=1;a[2]=0;a[3]=0}const r=int16(a[50],a[51]);if(r<0||r>1){info("Attempting to fix invalid indexToLocFormat in head table: "+r);const e=t+1;if(i===e<<1){a[50]=0;a[51]=0}else{if(i!==e<<2)throw new FormatError("Could not fix indexToLocFormat: "+r);a[50]=0;a[51]=1}}}(n.head,h,c?n.loca.length:0);let f=Object.create(null);if(c){const e=int16(n.head.data[50],n.head.data[51]),t=function sanitizeGlyphLocations(e,t,i,a,s,r,n){let g,o,c;if(a){g=4;o=function fontItemDecodeLong(e,t){return e[t]<<24|e[t+1]<<16|e[t+2]<<8|e[t+3]};c=function fontItemEncodeLong(e,t,i){e[t]=i>>>24&255;e[t+1]=i>>16&255;e[t+2]=i>>8&255;e[t+3]=255&i}}else{g=2;o=function fontItemDecode(e,t){return e[t]<<9|e[t+1]<<1};c=function fontItemEncode(e,t,i){e[t]=i>>9&255;e[t+1]=i>>1&255}}const C=r?i+1:i,h=g*(1+C),l=new Uint8Array(h);l.set(e.data.subarray(0,h));e.data=l;const Q=t.data,E=Q.length,u=new Uint8Array(E);let d,f;const p=[];for(d=0,f=0;dE&&(e=E);p.push({index:d,offset:e,endOffset:0})}p.sort(((e,t)=>e.offset-t.offset));for(d=0;de.index-t.index));for(d=0;dn&&(n=e.sizeOfInstructions);w+=t;c(l,f,w)}if(0===w){const e=new Uint8Array([0,1,0,0,0,0,0,0,0,0,0,0,0,0,49,0]);for(d=0,f=g;di+w)t.data=u.subarray(0,i+w);else{t.data=new Uint8Array(i+w);t.data.set(u.subarray(0,w))}t.data.set(u.subarray(0,i),w);c(e.data,l.length-g,w+i)}else t.data=u.subarray(0,w);return{missingGlyphs:y,maxSizeOfInstructions:n}}(n.loca,n.glyf,h,e,d,Q,u);f=t.missingGlyphs;if(C>=65536&&n.maxp.length>=32){n.maxp.data[26]=t.maxSizeOfInstructions>>8;n.maxp.data[27]=255&t.maxSizeOfInstructions}}if(!n.hhea)throw new FormatError('Required "hhea" table is not found');if(0===n.hhea.data[10]&&0===n.hhea.data[11]){n.hhea.data[10]=255;n.hhea.data[11]=255}const p={unitsPerEm:int16(n.head.data[18],n.head.data[19]),yMax:signedInt16(n.head.data[42],n.head.data[43]),yMin:signedInt16(n.head.data[38],n.head.data[39]),ascent:signedInt16(n.hhea.data[4],n.hhea.data[5]),descent:signedInt16(n.hhea.data[6],n.hhea.data[7]),lineGap:signedInt16(n.hhea.data[8],n.hhea.data[9])};this.ascent=p.ascent/p.unitsPerEm;this.descent=p.descent/p.unitsPerEm;this.lineGap=p.lineGap/p.unitsPerEm;if(this.cssFontInfo?.lineHeight){this.lineHeight=this.cssFontInfo.metrics.lineHeight;this.lineGap=this.cssFontInfo.metrics.lineGap}else this.lineHeight=this.ascent-this.descent+this.lineGap;n.post&&function readPostScriptTable(e,i,a){const s=(t.start||0)+e.offset;t.pos=s;const r=s+e.length,n=t.getInt32();t.skip(28);let g,o,c=!0;switch(n){case 65536:g=ji;break;case 131072:const e=t.getUint16();if(e!==a){c=!1;break}const s=[];for(o=0;o=32768){c=!1;break}s.push(e)}if(!c)break;const C=[],h=[];for(;t.pos65535)throw new FormatError("Max size of CID is 65,535");let s=-1;t?s=a:void 0!==e[a]&&(s=e[a]);s>=0&&s>>0;let C=!1;if(g?.platformId!==s||g?.encodingId!==r){if(0!==s||0!==r&&1!==r&&3!==r)if(1===s&&0===r)C=!0;else if(3!==s||1!==r||!a&&g){if(i&&3===s&&0===r){C=!0;let i=!0;if(e>3;e.push(a);i=Math.max(a,i)}const a=[];for(let e=0;e<=i;e++)a.push({firstCode:t.getUint16(),entryCount:t.getUint16(),idDelta:signedInt16(t.getByte(),t.getByte()),idRangePos:t.pos+t.getUint16()});for(let i=0;i<256;i++)if(0===e[i]){t.pos=a[0].idRangePos+2*i;Q=t.getUint16();h.push({charCode:i,glyphId:Q})}else{const s=a[e[i]];for(l=0;l>1;t.skip(6);const i=[];let a;for(a=0;a>1)-(e-a);s.offsetIndex=n;g=Math.max(g,n+s.end-s.start+1)}else s.offsetIndex=-1}const o=[];for(l=0;l>>0;for(l=0;l>>0,i=t.getInt32()>>>0;let a=t.getInt32()>>>0;for(let t=e;t<=i;t++)h.push({charCode:t,glyphId:a++})}}}h.sort((function(e,t){return e.charCode-t.charCode}));for(let e=1;e=61440&&t<=61695&&(t&=255);m[t]=e.glyphId}else for(const e of r)m[e.charCode]=e.glyphId;if(i.glyphNames&&(g.length||this.differences.length))for(let e=0;e<256;++e){if(!o&&void 0!==m[e])continue;const t=this.differences[e]||g[e];if(!t)continue;const a=i.glyphNames.indexOf(t);a>0&&hasGlyph(a)&&(m[e]=a)}}0===m.length&&(m[0]=0);let y=l-1;Q||(y=0);if(!i.cssFontInfo){const e=adjustMapping(m,hasGlyph,y,this.toUnicode);this.toFontChar=e.toFontChar;n.cmap={tag:"cmap",data:createCmapTable(e.charCodeToGlyphId,e.toUnicodeExtraMap,l)};n["OS/2"]&&function validateOS2Table(e,t){t.pos=(t.start||0)+e.offset;const i=t.getUint16();t.skip(60);const a=t.getUint16();if(i<4&&768&a)return!1;if(t.getUint16()>t.getUint16())return!1;t.skip(6);if(0===t.getUint16())return!1;e.data[8]=e.data[9]=0;return!0}(n["OS/2"],t)||(n["OS/2"]={tag:"OS/2",data:createOS2Table(i,e.charCodeToGlyphId,p)})}if(!c)try{o=new Stream(n["CFF "].data);g=new CFFParser(o,i,Ti).parse();g.duplicateFirstGlyph();const e=new CFFCompiler(g);n["CFF "].data=e.compile()}catch{warn("Failed to compile font "+i.loadedName)}if(n.name){const[t,a]=readNameTable(n.name);n.name.data=createNameTable(e,t);this.psName=t[0][6]||null;i.composite||function adjustTrueTypeToUnicode(e,t,i){if(e.isInternalFont)return;if(e.hasIncludedToUnicodeMap)return;if(e.hasEncoding)return;if(e.toUnicode instanceof IdentityToUnicodeMap)return;if(!t)return;if(0===i.length)return;if(e.defaultEncoding===wi)return;for(const e of i)if(!isWinNameRecord(e))return;const a=wi,s=[],r=Mi();for(const e in a){const t=a[e];if(""===t)continue;const i=r[t];void 0!==i&&(s[e]=String.fromCharCode(i))}s.length>0&&e.toUnicode.amend(s)}(i,this.isSymbolicFont,a)}else n.name={tag:"name",data:createNameTable(this.name)};const w=new OpenTypeFileBuilder(r.version);for(const e in n)w.addTable(e,n[e].data);return w.toArray()}convert(e,t,i){i.fixedPitch=!1;i.builtInEncoding&&function adjustType1ToUnicode(e,t){if(e.isInternalFont)return;if(e.hasIncludedToUnicodeMap)return;if(t===e.defaultEncoding)return;if(e.toUnicode instanceof IdentityToUnicodeMap)return;const i=[],a=Mi();for(const s in t){if(e.hasEncoding&&(e.baseEncodingName||void 0!==e.differences[s]))continue;const r=getUnicodeForGlyph(t[s],a);-1!==r&&(i[s]=String.fromCharCode(r))}i.length>0&&e.toUnicode.amend(i)}(i,i.builtInEncoding);let s=1;t instanceof CFFFont&&(s=t.numGlyphs-1);const r=t.getGlyphMapping(i);let n=null,g=r,o=null;if(!i.cssFontInfo){n=adjustMapping(r,t.hasGlyphId.bind(t),s,this.toUnicode);this.toFontChar=n.toFontChar;g=n.charCodeToGlyphId;o=n.toUnicodeExtraMap}const c=t.numGlyphs;function getCharCodes(e,t){let i=null;for(const a in e)t===e[a]&&(i||=[]).push(0|a);return i}function createCharCode(e,t){for(const i in e)if(t===e[i])return 0|i;n.charCodeToGlyphId[n.nextAvailableFontCharCode]=t;return n.nextAvailableFontCharCode++}const C=t.seacs;if(n&&C?.length){const e=i.fontMatrix||a,s=t.getCharset(),g=Object.create(null);for(let t in C){t|=0;const i=C[t],a=yi[i[2]],o=yi[i[3]],c=s.indexOf(a),h=s.indexOf(o);if(c<0||h<0)continue;const l={x:i[0]*e[0]+i[1]*e[2]+e[4],y:i[0]*e[1]+i[1]*e[3]+e[5]},Q=getCharCodes(r,t);if(Q)for(const e of Q){const t=n.charCodeToGlyphId,i=createCharCode(t,c),a=createCharCode(t,h);g[e]={baseFontCharCode:i,accentFontCharCode:a,accentOffset:l}}}i.seacMap=g}const h=i.fontMatrix?1/Math.max(...i.fontMatrix.slice(0,4).map(Math.abs)):1e3,l=new OpenTypeFileBuilder("OTTO");l.addTable("CFF ",t.data);l.addTable("OS/2",createOS2Table(i,g));l.addTable("cmap",createCmapTable(g,o,c));l.addTable("head","\0\0\0\0\0\0\0\0\0\0_<õ\0\0"+safeString16(h)+"\0\0\0\0ž\v~'\0\0\0\0ž\v~'\0\0"+safeString16(i.descent)+"ÿ"+safeString16(i.ascent)+string16(i.italicAngle?2:0)+"\0\0\0\0\0\0\0");l.addTable("hhea","\0\0\0"+safeString16(i.ascent)+safeString16(i.descent)+"\0\0ÿÿ\0\0\0\0\0\0"+safeString16(i.capHeight)+safeString16(Math.tan(i.italicAngle)*i.xHeight)+"\0\0\0\0\0\0\0\0\0\0\0\0"+string16(c));l.addTable("hmtx",function fontFieldsHmtx(){const e=t.charstrings,i=t.cff?t.cff.widths:null;let a="\0\0\0\0";for(let t=1,s=c;t=65520&&e<=65535?0:e>=62976&&e<=63743?Ji()[e]||e:173===e?45:e}(i)}this.isType3Font&&(s=i);let C=null;if(this.seacMap?.[e]){c=!0;const t=this.seacMap[e];i=t.baseFontCharCode;C={fontChar:String.fromCodePoint(t.accentFontCharCode),offset:t.accentOffset}}let h="";"number"==typeof i&&(i<=1114111?h=String.fromCodePoint(i):warn(`charToGlyph - invalid fontCharCode: ${i}`));if(this.missingFile&&this.vertical&&1===h.length){const e=Xi()[h.charCodeAt(0)];e&&(h=o=String.fromCharCode(e))}r=new fonts_Glyph(e,h,o,C,a,g,s,t,c);return this._glyphCache[e]=r}charsToGlyphs(e){let t=this._charsCache[e];if(t)return t;t=[];if(this.cMap){const i=Object.create(null),a=e.length;let s=0;for(;st.length%2==1,a=this.toUnicode instanceof IdentityToUnicodeMap?e=>this.toUnicode.charCodeOf(e):e=>this.toUnicode.charCodeOf(String.fromCodePoint(e));for(let s=0,r=e.length;s55295&&(r<57344||r>65533)&&s++;if(this.toUnicode){const e=a(r);if(-1!==e){if(hasCurrentBufErrors()){t.push(i.join(""));i.length=0}for(let t=(this.cMap?this.cMap.getCharCodeLength(e):1)-1;t>=0;t--)i.push(String.fromCharCode(e>>8*t&255));continue}}if(!hasCurrentBufErrors()){t.push(i.join(""));i.length=0}i.push(String.fromCodePoint(r))}t.push(i.join(""));return t}}class ErrorFont{constructor(e){this.error=e;this.loadedName="g_font_error";this.missingFile=!0}charsToGlyphs(){return[]}encodeString(e){return[e]}exportData(e=!1){return{error:this.error}}}const pa=2,ma=3,ya=4,wa=5,Da=6,ba=7;class Pattern{constructor(){unreachable("Cannot initialize Pattern.")}static parseShading(e,t,i,a,s){const r=e instanceof BaseStream?e.dict:e,n=r.get("ShadingType");try{switch(n){case pa:case ma:return new RadialAxialShading(r,t,i,a,s);case ya:case wa:case Da:case ba:return new MeshShading(e,t,i,a,s);default:throw new FormatError("Unsupported ShadingType: "+n)}}catch(e){if(e instanceof MissingDataException)throw e;warn(e);return new DummyShading}}}class BaseShading{static SMALL_NUMBER=1e-6;getIR(){unreachable("Abstract method `getIR` called.")}}class RadialAxialShading extends BaseShading{constructor(e,t,i,a,s){super();this.shadingType=e.get("ShadingType");let r=0;this.shadingType===pa?r=4:this.shadingType===ma&&(r=6);this.coordsArr=e.getArray("Coords");if(!isNumberArray(this.coordsArr,r))throw new FormatError("RadialAxialShading: Invalid /Coords array.");const n=ColorSpace.parse({cs:e.getRaw("CS")||e.getRaw("ColorSpace"),xref:t,resources:i,pdfFunctionFactory:a,localColorSpaceCache:s});this.bbox=lookupNormalRect(e.getArray("BBox"),null);let g=0,o=1;const c=e.getArray("Domain");isNumberArray(c,2)&&([g,o]=c);let C=!1,h=!1;const l=e.getArray("Extend");(function isBooleanArray(e,t){return Array.isArray(e)&&(null===t||e.length===t)&&e.every((e=>"boolean"==typeof e))})(l,2)&&([C,h]=l);if(!(this.shadingType!==ma||C&&h)){const[e,t,i,a,s,r]=this.coordsArr,n=Math.hypot(e-a,t-s);i<=r+n&&r<=i+n&&warn("Unsupported radial gradient.")}this.extendStart=C;this.extendEnd=h;const Q=e.getRaw("Function"),E=a.createFromArray(Q),u=(o-g)/840,d=this.colorStops=[];if(g>=o||u<=0){info("Bad shading domain.");return}const f=new Float32Array(n.numComps),p=new Float32Array(1);let m,y=0;p[0]=g;E(p,0,f,0);let w=n.getRgb(f,0);const D=Util.makeHexColor(w[0],w[1],w[2]);d.push([0,D]);let b=1;p[0]=g+u;E(p,0,f,0);let F=n.getRgb(f,0),S=F[0]-w[0]+1,k=F[1]-w[1]+1,R=F[2]-w[2]+1,N=F[0]-w[0]-1,G=F[1]-w[1]-1,x=F[2]-w[2]-1;for(let e=2;e<840;e++){p[0]=g+e*u;E(p,0,f,0);m=n.getRgb(f,0);const t=e-y;S=Math.min(S,(m[0]-w[0]+1)/t);k=Math.min(k,(m[1]-w[1]+1)/t);R=Math.min(R,(m[2]-w[2]+1)/t);N=Math.max(N,(m[0]-w[0]-1)/t);G=Math.max(G,(m[1]-w[1]-1)/t);x=Math.max(x,(m[2]-w[2]-1)/t);if(!(N<=S&&G<=k&&x<=R)){const e=Util.makeHexColor(F[0],F[1],F[2]);d.push([b/840,e]);S=m[0]-F[0]+1;k=m[1]-F[1]+1;R=m[2]-F[2]+1;N=m[0]-F[0]-1;G=m[1]-F[1]-1;x=m[2]-F[2]-1;y=b;w=F}b=e;F=m}const U=Util.makeHexColor(F[0],F[1],F[2]);d.push([1,U]);let M="transparent";if(e.has("Background")){m=n.getRgb(e.get("Background"),0);M=Util.makeHexColor(m[0],m[1],m[2])}if(!C){d.unshift([0,M]);d[1][0]+=BaseShading.SMALL_NUMBER}if(!h){d.at(-1)[0]-=BaseShading.SMALL_NUMBER;d.push([1,M])}this.colorStops=d}getIR(){const{coordsArr:e,shadingType:t}=this;let i,a,s,r,n;if(t===pa){a=[e[0],e[1]];s=[e[2],e[3]];r=null;n=null;i="axial"}else if(t===ma){a=[e[0],e[1]];s=[e[3],e[4]];r=e[2];n=e[5];i="radial"}else unreachable(`getPattern type unknown: ${t}`);return["RadialAxial",i,this.bbox,this.colorStops,a,s,r,n]}}class MeshStreamReader{constructor(e,t){this.stream=e;this.context=t;this.buffer=0;this.bufferLength=0;const i=t.numComps;this.tmpCompsBuf=new Float32Array(i);const a=t.colorSpace.numComps;this.tmpCsCompsBuf=t.colorFn?new Float32Array(a):this.tmpCompsBuf}get hasData(){if(this.stream.end)return this.stream.pos0)return!0;const e=this.stream.getByte();if(e<0)return!1;this.buffer=e;this.bufferLength=8;return!0}readBits(e){let t=this.buffer,i=this.bufferLength;if(32===e){if(0===i)return(this.stream.getByte()<<24|this.stream.getByte()<<16|this.stream.getByte()<<8|this.stream.getByte())>>>0;t=t<<24|this.stream.getByte()<<16|this.stream.getByte()<<8|this.stream.getByte();const e=this.stream.getByte();this.buffer=e&(1<>i)>>>0}if(8===e&&0===i)return this.stream.getByte();for(;i>i}align(){this.buffer=0;this.bufferLength=0}readFlag(){return this.readBits(this.context.bitsPerFlag)}readCoordinate(){const e=this.context.bitsPerCoordinate,t=this.readBits(e),i=this.readBits(e),a=this.context.decode,s=e<32?1/((1<r?r:e;t=t>n?n:t;i=ie*s[t])):i;let n,g=-2;const o=[];for(const[e,t]of a.map(((e,t)=>[e,t])).sort((([e],[t])=>e-t)))if(-1!==e)if(e===g+1){n.push(r[t]);g+=1}else{g=e;n=[r[t]];o.push(e,n)}return o}(e),i=new Dict(null);i.set("BaseFont",Name.get(e));i.set("Type",Name.get("Font"));i.set("Subtype",Name.get("CIDFontType2"));i.set("Encoding",Name.get("Identity-H"));i.set("CIDToGIDMap",Name.get("Identity"));i.set("W",t);i.set("FirstChar",t[0]);i.set("LastChar",t.at(-2)+t.at(-1).length-1);const a=new Dict(null);i.set("FontDescriptor",a);const s=new Dict(null);s.set("Ordering","Identity");s.set("Registry","Adobe");s.set("Supplement",0);i.set("CIDSystemInfo",s);return i}class PostScriptParser{constructor(e){this.lexer=e;this.operators=[];this.token=null;this.prev=null}nextToken(){this.prev=this.token;this.token=this.lexer.getToken()}accept(e){if(this.token.type===e){this.nextToken();return!0}return!1}expect(e){if(this.accept(e))return!0;throw new FormatError(`Unexpected symbol: found ${this.token.type} expected ${e}.`)}parse(){this.nextToken();this.expect(ls.LBRACE);this.parseBlock();this.expect(ls.RBRACE);return this.operators}parseBlock(){for(;;)if(this.accept(ls.NUMBER))this.operators.push(this.prev.value);else if(this.accept(ls.OPERATOR))this.operators.push(this.prev.value);else{if(!this.accept(ls.LBRACE))return;this.parseCondition()}}parseCondition(){const e=this.operators.length;this.operators.push(null,null);this.parseBlock();this.expect(ls.RBRACE);if(this.accept(ls.IF)){this.operators[e]=this.operators.length;this.operators[e+1]="jz"}else{if(!this.accept(ls.LBRACE))throw new FormatError("PS Function: error parsing conditional.");{const t=this.operators.length;this.operators.push(null,null);const i=this.operators.length;this.parseBlock();this.expect(ls.RBRACE);this.expect(ls.IFELSE);this.operators[t]=this.operators.length;this.operators[t+1]="j";this.operators[e]=i;this.operators[e+1]="jz"}}}}const ls={LBRACE:0,RBRACE:1,NUMBER:2,OPERATOR:3,IF:4,IFELSE:5};class PostScriptToken{static get opCache(){return shadow(this,"opCache",Object.create(null))}constructor(e,t){this.type=e;this.value=t}static getOperator(e){return PostScriptToken.opCache[e]||=new PostScriptToken(ls.OPERATOR,e)}static get LBRACE(){return shadow(this,"LBRACE",new PostScriptToken(ls.LBRACE,"{"))}static get RBRACE(){return shadow(this,"RBRACE",new PostScriptToken(ls.RBRACE,"}"))}static get IF(){return shadow(this,"IF",new PostScriptToken(ls.IF,"IF"))}static get IFELSE(){return shadow(this,"IFELSE",new PostScriptToken(ls.IFELSE,"IFELSE"))}}class PostScriptLexer{constructor(e){this.stream=e;this.nextChar();this.strBuf=[]}nextChar(){return this.currentChar=this.stream.getByte()}getToken(){let e=!1,t=this.currentChar;for(;;){if(t<0)return wt;if(e)10!==t&&13!==t||(e=!1);else if(37===t)e=!0;else if(!isWhiteSpace(t))break;t=this.nextChar()}switch(0|t){case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:case 43:case 45:case 46:return new PostScriptToken(ls.NUMBER,this.getNumber());case 123:this.nextChar();return PostScriptToken.LBRACE;case 125:this.nextChar();return PostScriptToken.RBRACE}const i=this.strBuf;i.length=0;i[0]=String.fromCharCode(t);for(;(t=this.nextChar())>=0&&(t>=65&&t<=90||t>=97&&t<=122);)i.push(String.fromCharCode(t));const a=i.join("");switch(a.toLowerCase()){case"if":return PostScriptToken.IF;case"ifelse":return PostScriptToken.IFELSE;default:return PostScriptToken.getOperator(a)}}getNumber(){let e=this.currentChar;const t=this.strBuf;t.length=0;t[0]=String.fromCharCode(e);for(;(e=this.nextChar())>=0&&(e>=48&&e<=57||45===e||46===e);)t.push(String.fromCharCode(e));const i=parseFloat(t.join(""));if(isNaN(i))throw new FormatError(`Invalid floating point number: ${i}`);return i}}class BaseLocalCache{constructor(e){this._onlyRefs=!0===e?.onlyRefs;if(!this._onlyRefs){this._nameRefMap=new Map;this._imageMap=new Map}this._imageCache=new RefSetCache}getByName(e){this._onlyRefs&&unreachable("Should not call `getByName` method.");const t=this._nameRefMap.get(e);return t?this.getByRef(t):this._imageMap.get(e)||null}getByRef(e){return this._imageCache.get(e)||null}set(e,t,i){unreachable("Abstract method `set` called.")}}class LocalImageCache extends BaseLocalCache{set(e,t=null,i){if("string"!=typeof e)throw new Error('LocalImageCache.set - expected "name" argument.');if(t){if(this._imageCache.has(t))return;this._nameRefMap.set(e,t);this._imageCache.put(t,i)}else this._imageMap.has(e)||this._imageMap.set(e,i)}}class LocalColorSpaceCache extends BaseLocalCache{set(e=null,t=null,i){if("string"!=typeof e&&!t)throw new Error('LocalColorSpaceCache.set - expected "name" and/or "ref" argument.');if(t){if(this._imageCache.has(t))return;null!==e&&this._nameRefMap.set(e,t);this._imageCache.put(t,i)}else this._imageMap.has(e)||this._imageMap.set(e,i)}}class LocalFunctionCache extends BaseLocalCache{constructor(e){super({onlyRefs:!0})}set(e=null,t,i){if(!t)throw new Error('LocalFunctionCache.set - expected "ref" argument.');this._imageCache.has(t)||this._imageCache.put(t,i)}}class LocalGStateCache extends BaseLocalCache{set(e,t=null,i){if("string"!=typeof e)throw new Error('LocalGStateCache.set - expected "name" argument.');if(t){if(this._imageCache.has(t))return;this._nameRefMap.set(e,t);this._imageCache.put(t,i)}else this._imageMap.has(e)||this._imageMap.set(e,i)}}class LocalTilingPatternCache extends BaseLocalCache{constructor(e){super({onlyRefs:!0})}set(e=null,t,i){if(!t)throw new Error('LocalTilingPatternCache.set - expected "ref" argument.');this._imageCache.has(t)||this._imageCache.put(t,i)}}class RegionalImageCache extends BaseLocalCache{constructor(e){super({onlyRefs:!0})}set(e=null,t,i){if(!t)throw new Error('RegionalImageCache.set - expected "ref" argument.');this._imageCache.has(t)||this._imageCache.put(t,i)}}class GlobalImageCache{static NUM_PAGES_THRESHOLD=2;static MIN_IMAGES_TO_CACHE=10;static MAX_BYTE_SIZE=5e7;#D=new RefSet;constructor(){this._refCache=new RefSetCache;this._imageCache=new RefSetCache}get#b(){let e=0;for(const t of this._imageCache)e+=t.byteSize;return e}get#F(){return!(this._imageCache.size+e)):null}class PDFFunction{static getSampleArray(e,t,i,a){let s,r,n=1;for(s=0,r=e.length;s>o)*C;c&=(1<i?e=i:e0&&(l=r[h-1]);let Q=a[1];h>1,c=s.length>>1,C=new PostScriptEvaluator(g),h=Object.create(null);let l=8192;const Q=new Float32Array(c);return function constructPostScriptFn(e,t,i,a){let s,n,g="";const E=Q;for(s=0;se&&(n=e)}d[s]=n}if(l>0){l--;h[g]=d}i.set(d,a)}}}function isPDFFunction(e){let t;if(e instanceof Dict)t=e;else{if(!(e instanceof BaseStream))return!1;t=e.dict}return t.has("FunctionType")}class PostScriptStack{static MAX_STACK_SIZE=100;constructor(e){this.stack=e?Array.from(e):[]}push(e){if(this.stack.length>=PostScriptStack.MAX_STACK_SIZE)throw new Error("PostScript function stack overflow.");this.stack.push(e)}pop(){if(this.stack.length<=0)throw new Error("PostScript function stack underflow.");return this.stack.pop()}copy(e){if(this.stack.length+e>=PostScriptStack.MAX_STACK_SIZE)throw new Error("PostScript function stack overflow.");const t=this.stack;for(let i=t.length-e,a=e-1;a>=0;a--,i++)t.push(t[i])}index(e){this.push(this.stack[this.stack.length-e-1])}roll(e,t){const i=this.stack,a=i.length-e,s=i.length-1,r=a+(t-Math.floor(t/e)*e);for(let e=a,t=s;e0?t.push(n<>g);break;case"ceiling":n=t.pop();t.push(Math.ceil(n));break;case"copy":n=t.pop();t.copy(n);break;case"cos":n=t.pop();t.push(Math.cos(n%360/180*Math.PI));break;case"cvi":n=0|t.pop();t.push(n);break;case"cvr":break;case"div":g=t.pop();n=t.pop();t.push(n/g);break;case"dup":t.copy(1);break;case"eq":g=t.pop();n=t.pop();t.push(n===g);break;case"exch":t.roll(2,1);break;case"exp":g=t.pop();n=t.pop();t.push(n**g);break;case"false":t.push(!1);break;case"floor":n=t.pop();t.push(Math.floor(n));break;case"ge":g=t.pop();n=t.pop();t.push(n>=g);break;case"gt":g=t.pop();n=t.pop();t.push(n>g);break;case"idiv":g=t.pop();n=t.pop();t.push(n/g|0);break;case"index":n=t.pop();t.index(n);break;case"le":g=t.pop();n=t.pop();t.push(n<=g);break;case"ln":n=t.pop();t.push(Math.log(n));break;case"log":n=t.pop();t.push(Math.log10(n));break;case"lt":g=t.pop();n=t.pop();t.push(n=t?new AstLiteral(t):e.max<=t?e:new AstMin(e,t)}class PostScriptCompiler{compile(e,t,i){const a=[],s=[],r=t.length>>1,n=i.length>>1;let g,o,c,C,h,l,Q,E,u=0;for(let e=0;et.min){g.unshift("Math.max(",r,", ");g.push(")")}if(n4){a=!0;t=0}else{a=!1;t=1}const o=[];for(r=0;r=0&&"ET"===ds[e];--e)ds[e]="EN";for(let e=r+1;e0&&(t=ds[r-1]);let i=h;e+1E&&isOdd(E)&&(d=E)}for(E=u;E>=d;--E){let e=-1;for(r=0,n=o.length;r=0){reverseValues(us,e,r);e=-1}}else e<0&&(e=r);e>=0&&reverseValues(us,e,o.length)}for(r=0,n=us.length;r"!==e||(us[r]="")}return createBidiText(us.join(""),a)}const fs={style:"normal",weight:"normal"},ps={style:"normal",weight:"bold"},ms={style:"italic",weight:"normal"},ys={style:"italic",weight:"bold"},ws=new Map([["Times-Roman",{local:["Times New Roman","Times-Roman","Times","Liberation Serif","Nimbus Roman","Nimbus Roman L","Tinos","Thorndale","TeX Gyre Termes","FreeSerif","Linux Libertine O","Libertinus Serif","DejaVu Serif","Bitstream Vera Serif","Ubuntu"],style:fs,ultimate:"serif"}],["Times-Bold",{alias:"Times-Roman",style:ps,ultimate:"serif"}],["Times-Italic",{alias:"Times-Roman",style:ms,ultimate:"serif"}],["Times-BoldItalic",{alias:"Times-Roman",style:ys,ultimate:"serif"}],["Helvetica",{local:["Helvetica","Helvetica Neue","Arial","Arial Nova","Liberation Sans","Arimo","Nimbus Sans","Nimbus Sans L","A030","TeX Gyre Heros","FreeSans","DejaVu Sans","Albany","Bitstream Vera Sans","Arial Unicode MS","Microsoft Sans Serif","Apple Symbols","Cantarell"],path:"LiberationSans-Regular.ttf",style:fs,ultimate:"sans-serif"}],["Helvetica-Bold",{alias:"Helvetica",path:"LiberationSans-Bold.ttf",style:ps,ultimate:"sans-serif"}],["Helvetica-Oblique",{alias:"Helvetica",path:"LiberationSans-Italic.ttf",style:ms,ultimate:"sans-serif"}],["Helvetica-BoldOblique",{alias:"Helvetica",path:"LiberationSans-BoldItalic.ttf",style:ys,ultimate:"sans-serif"}],["Courier",{local:["Courier","Courier New","Liberation Mono","Nimbus Mono","Nimbus Mono L","Cousine","Cumberland","TeX Gyre Cursor","FreeMono","Linux Libertine Mono O","Libertinus Mono"],style:fs,ultimate:"monospace"}],["Courier-Bold",{alias:"Courier",style:ps,ultimate:"monospace"}],["Courier-Oblique",{alias:"Courier",style:ms,ultimate:"monospace"}],["Courier-BoldOblique",{alias:"Courier",style:ys,ultimate:"monospace"}],["ArialBlack",{local:["Arial Black"],style:{style:"normal",weight:"900"},fallback:"Helvetica-Bold"}],["ArialBlack-Bold",{alias:"ArialBlack"}],["ArialBlack-Italic",{alias:"ArialBlack",style:{style:"italic",weight:"900"},fallback:"Helvetica-BoldOblique"}],["ArialBlack-BoldItalic",{alias:"ArialBlack-Italic"}],["ArialNarrow",{local:["Arial Narrow","Liberation Sans Narrow","Helvetica Condensed","Nimbus Sans Narrow","TeX Gyre Heros Cn"],style:fs,fallback:"Helvetica"}],["ArialNarrow-Bold",{alias:"ArialNarrow",style:ps,fallback:"Helvetica-Bold"}],["ArialNarrow-Italic",{alias:"ArialNarrow",style:ms,fallback:"Helvetica-Oblique"}],["ArialNarrow-BoldItalic",{alias:"ArialNarrow",style:ys,fallback:"Helvetica-BoldOblique"}],["Calibri",{local:["Calibri","Carlito"],style:fs,fallback:"Helvetica"}],["Calibri-Bold",{alias:"Calibri",style:ps,fallback:"Helvetica-Bold"}],["Calibri-Italic",{alias:"Calibri",style:ms,fallback:"Helvetica-Oblique"}],["Calibri-BoldItalic",{alias:"Calibri",style:ys,fallback:"Helvetica-BoldOblique"}],["Wingdings",{local:["Wingdings","URW Dingbats"],style:fs}],["Wingdings-Regular",{alias:"Wingdings"}],["Wingdings-Bold",{alias:"Wingdings"}]]),Ds=new Map([["Arial-Black","ArialBlack"]]);function getFamilyName(e){const t=new Set(["thin","extralight","ultralight","demilight","semilight","light","book","regular","normal","medium","demibold","semibold","bold","extrabold","ultrabold","black","heavy","extrablack","ultrablack","roman","italic","oblique","ultracondensed","extracondensed","condensed","semicondensed","normal","semiexpanded","expanded","extraexpanded","ultraexpanded","bolditalic"]);return e.split(/[- ,+]+/g).filter((e=>!t.has(e.toLowerCase()))).join(" ")}function generateFont({alias:e,local:t,path:i,fallback:a,style:s,ultimate:r},n,g,o=!0,c=!0,C=""){const h={style:null,ultimate:null};if(t){const e=C?` ${C}`:"";for(const i of t)n.push(`local(${i}${e})`)}if(e){const t=ws.get(e),r=C||function getStyleToAppend(e){switch(e){case ps:return"Bold";case ms:return"Italic";case ys:return"Bold Italic";default:if("bold"===e?.weight)return"Bold";if("italic"===e?.style)return"Italic"}return""}(s);Object.assign(h,generateFont(t,n,g,o&&!a,c&&!i,r))}s&&(h.style=s);r&&(h.ultimate=r);if(o&&a){const e=ws.get(a),{ultimate:t}=generateFont(e,n,g,o,c&&!i,C);h.ultimate||=t}c&&i&&g&&n.push(`url(${g}${i})`);return h}function getFontSubstitution(e,t,i,a,s,r){if(a.startsWith("InvalidPDFjsFont_"))return null;"TrueType"!==r&&"Type1"!==r||!/^[A-Z]{6}\+/.test(a)||(a=a.slice(7));const n=a=normalizeFontName(a);let g=e.get(n);if(g)return g;let o=ws.get(a);if(!o)for(const[e,t]of Ds)if(a.startsWith(e)){a=`${t}${a.substring(e.length)}`;o=ws.get(a);break}let c=!1;if(!o){o=ws.get(s);c=!0}const C=`${t.getDocId()}_s${t.createFontId()}`;if(!o){if(!validateFontName(a)){warn(`Cannot substitute the font because of its name: ${a}`);e.set(n,null);return null}const t=/bold/gi.test(a),i=/oblique|italic/gi.test(a),s=t&&i&&ys||t&&ps||i&&ms||fs;g={css:`"${getFamilyName(a)}",${C}`,guessFallback:!0,loadedName:C,baseFontName:a,src:`local(${a})`,style:s};e.set(n,g);return g}const h=[];c&&validateFontName(a)&&h.push(`local(${a})`);const{style:l,ultimate:Q}=generateFont(o,h,i),E=null===Q,u=E?"":`,${Q}`;g={css:`"${getFamilyName(a)}",${C}${u}`,guessFallback:E,loadedName:C,baseFontName:a,src:h.join(","),style:l};e.set(n,g);return g}class ImageResizer{constructor(e,t){this._imgData=e;this._isMask=t}static needsToBeResized(e,t){if(e<=this._goodSquareLength&&t<=this._goodSquareLength)return!1;const{MAX_DIM:i}=this;if(e>i||t>i)return!0;const a=e*t;if(this._hasMaxArea)return a>this.MAX_AREA;if(a(this.MAX_AREA=this._goodSquareLength**2)}static get MAX_DIM(){return shadow(this,"MAX_DIM",this._guessMax(2048,65537,0,1))}static get MAX_AREA(){this._hasMaxArea=!0;return shadow(this,"MAX_AREA",this._guessMax(ImageResizer._goodSquareLength,this.MAX_DIM,128,0)**2)}static set MAX_AREA(e){if(e>=0){this._hasMaxArea=!0;shadow(this,"MAX_AREA",e)}}static setMaxArea(e){this._hasMaxArea||(this.MAX_AREA=e>>2)}static _areGoodDims(e,t){try{const i=new OffscreenCanvas(e,t),a=i.getContext("2d");a.fillRect(0,0,1,1);const s=a.getImageData(0,0,1,1).data[3];i.width=i.height=1;return 0!==s}catch{return!1}}static _guessMax(e,t,i,a){for(;e+i+1>3,n=i+3&-4;if(i!==n){const e=new Uint8Array(n*t);let a=0;for(let r=0,g=t*i;r>>8;t[i++]=255&s}}}else{if(!ArrayBuffer.isView(e))throw new Error("Invalid data format, must be a string or TypedArray.");t=e.slice();i=t.byteLength}const a=i>>2,s=i-4*a,r=new Uint32Array(t.buffer,0,a);let n=0,g=0,o=this.h1,c=this.h2;const C=3432918353,h=461845907,l=11601,Q=13715;for(let e=0;e>>17;n=n*h&Fs|n*Q&Ss;o^=n;o=o<<13|o>>>19;o=5*o+3864292196}else{g=r[e];g=g*C&Fs|g*l&Ss;g=g<<15|g>>>17;g=g*h&Fs|g*Q&Ss;c^=g;c=c<<13|c>>>19;c=5*c+3864292196}n=0;switch(s){case 3:n^=t[4*a+2]<<16;case 2:n^=t[4*a+1]<<8;case 1:n^=t[4*a];n=n*C&Fs|n*l&Ss;n=n<<15|n>>>17;n=n*h&Fs|n*Q&Ss;1&a?o^=n:c^=n}this.h1=o;this.h2=c}hexdigest(){let e=this.h1,t=this.h2;e^=t>>>1;e=3981806797*e&Fs|36045*e&Ss;t=4283543511*t&Fs|(2950163797*(t<<16|e>>>16)&Fs)>>>16;e^=t>>>1;e=444984403*e&Fs|60499*e&Ss;t=3301882366*t&Fs|(3120437893*(t<<16|e>>>16)&Fs)>>>16;e^=t>>>1;return(e>>>0).toString(16).padStart(8,"0")+(t>>>0).toString(16).padStart(8,"0")}}function addState(e,t,i,a,s){let r=e;for(let e=0,i=t.length-1;e1e3){c=Math.max(c,l);Q+=h+2;l=0;h=0}C.push({transform:t,x:l,y:Q,w:i.width,h:i.height});l+=i.width+2;h=Math.max(h,i.height)}const E=Math.max(c,l)+1,u=Q+h+1,d=new Uint8Array(E*u*4),f=E<<2;for(let e=0;e=0;){t[r-4]=t[r];t[r-3]=t[r+1];t[r-2]=t[r+2];t[r-1]=t[r+3];t[r+i]=t[r+i-4];t[r+i+1]=t[r+i-3];t[r+i+2]=t[r+i-2];t[r+i+3]=t[r+i-1];r-=f}}const p={width:E,height:u};if(e.isOffscreenCanvasSupported){const e=new OffscreenCanvas(E,u);e.getContext("2d").putImageData(new ImageData(new Uint8ClampedArray(d.buffer),E,u),0,0);p.bitmap=e.transferToImageBitmap();p.data=null}else{p.kind=S;p.data=d}i.splice(r,4*o,$e);a.splice(r,4*o,[p,C]);return r+1}));addState(ks,[xA,MA,Ze,UA],null,(function iterateImageMaskGroup(e,t){const i=e.fnArray,a=(t-(e.iCurr-3))%4;switch(a){case 0:return i[t]===xA;case 1:return i[t]===MA;case 2:return i[t]===Ze;case 3:return i[t]===UA}throw new Error(`iterateImageMaskGroup - invalid pos: ${a}`)}),(function foundImageMaskGroup(e,t){const i=e.fnArray,a=e.argsArray,s=e.iCurr,r=s-3,n=s-2,g=s-1;let o=Math.floor((t-r)/4);if(o<10)return t-(t-r)%4;let c,C,h=!1;const l=a[g][0],Q=a[n][0],E=a[n][1],u=a[n][2],d=a[n][3];if(E===u){h=!0;c=n+4;let e=g+4;for(let t=1;t=4&&i[r-4]===i[n]&&i[r-3]===i[g]&&i[r-2]===i[o]&&i[r-1]===i[c]&&a[r-4][0]===C&&a[r-4][1]===h){l++;Q-=5}let E=Q+4;for(let e=1;e=i)break}a=(a||ks)[e[t]];if(a&&!Array.isArray(a)){r.iCurr=t;t++;if(!a.checkFn||(0,a.checkFn)(r)){s=a;a=null}else a=null}else t++}this.state=a;this.match=s;this.lastProcessed=t}flush(){for(;this.match;){const e=this.queue.fnArray.length;this.lastProcessed=(0,this.match.processFn)(this.context,e);this.match=null;this.state=null;this._optimize()}}reset(){this.state=null;this.match=null;this.lastProcessed=0}}class OperatorList{static CHUNK_SIZE=1e3;static CHUNK_SIZE_ABOUT=this.CHUNK_SIZE-5;constructor(e=0,t){this._streamSink=t;this.fnArray=[];this.argsArray=[];this.optimizer=!t||e&E?new NullOptimizer(this):new QueueOptimizer(this);this.dependencies=new Set;this._totalLength=0;this.weight=0;this._resolved=t?null:Promise.resolve()}set isOffscreenCanvasSupported(e){this.optimizer.isOffscreenCanvasSupported=e}get length(){return this.argsArray.length}get ready(){return this._resolved||this._streamSink.ready}get totalLength(){return this._totalLength+this.length}addOp(e,t){this.optimizer.push(e,t);this.weight++;this._streamSink&&(this.weight>=OperatorList.CHUNK_SIZE||this.weight>=OperatorList.CHUNK_SIZE_ABOUT&&(e===UA||e===ee))&&this.flush()}addImageOps(e,t,i){void 0!==i&&this.addOp(Ye,["OC",i]);this.addOp(e,t);void 0!==i&&this.addOp(ve,[])}addDependency(e){if(!this.dependencies.has(e)){this.dependencies.add(e);this.addOp(wA,[e])}}addDependencies(e){for(const t of e)this.addDependency(t)}addOpList(e){if(e instanceof OperatorList){for(const t of e.dependencies)this.dependencies.add(t);for(let t=0,i=e.length;ta&&(e=a);return e}function resizeImageMask(e,t,i,a,s,r){const n=s*r;let g;g=t<=8?new Uint8Array(n):t<=16?new Uint16Array(n):new Uint32Array(n);const o=i/s,c=a/r;let C,h,l,Q,E=0;const u=new Uint16Array(s),d=i;for(C=0;C0&&Number.isInteger(i.height)&&i.height>0&&(i.width!==l||i.height!==Q)){warn("PDFImage - using the Width/Height of the image data, rather than the image dictionary.");l=i.width;Q=i.height}if(l<1||Q<1)throw new FormatError(`Invalid image width: ${l} or height: ${Q}`);this.width=l;this.height=Q;this.interpolate=c.get("I","Interpolate");this.imageMask=c.get("IM","ImageMask")||!1;this.matte=c.get("Matte")||!1;let E=i.bitsPerComponent;if(!E){E=c.get("BPC","BitsPerComponent");if(!E){if(!this.imageMask)throw new FormatError(`Bits per component missing in image: ${this.imageMask}`);E=1}}this.bpc=E;if(!this.imageMask){let s=c.getRaw("CS")||c.getRaw("ColorSpace");const r=!!s;if(r)this.jpxDecoderOptions?.smaskInData&&(s=Name.get("DeviceRGBA"));else if(this.jpxDecoderOptions)s=Name.get("DeviceRGBA");else switch(i.numComps){case 1:s=Name.get("DeviceGray");break;case 3:s=Name.get("DeviceRGB");break;case 4:s=Name.get("DeviceCMYK");break;default:throw new Error(`Images with ${i.numComps} color components not supported.`)}this.colorSpace=ColorSpace.parse({cs:s,xref:e,resources:a?t:null,pdfFunctionFactory:g,localColorSpaceCache:o});this.numComps=this.colorSpace.numComps;if(this.jpxDecoderOptions){this.jpxDecoderOptions.numComponents=r?this.numComp:0;this.jpxDecoderOptions.isIndexedColormap="Indexed"===this.colorSpace.name}}this.decode=c.getArray("D","Decode");this.needsDecode=!1;if(this.decode&&(this.colorSpace&&!this.colorSpace.isDefaultDecode(this.decode,E)||n&&!ColorSpace.isDefaultDecode(this.decode,1))){this.needsDecode=!0;const e=(1<>3)*i,g=e.byteLength;let o,c;if(!a||s&&!(n===g))if(s){o=new Uint8Array(n);o.set(e);o.fill(255,g)}else o=new Uint8Array(e);else o=e;if(s)for(c=0;c>7&1;n[l+1]=h>>6&1;n[l+2]=h>>5&1;n[l+3]=h>>4&1;n[l+4]=h>>3&1;n[l+5]=h>>2&1;n[l+6]=h>>1&1;n[l+7]=1&h;l+=8}if(l>=1}}}}else{let i=0;h=0;for(l=0,C=r;l>a;s<0?s=0:s>c&&(s=c);n[l]=s;h&=(1<n[a+1]){t=255;break}}g[C]=t}}}if(g)for(C=0,l=3,h=t*a;C>3,C=t&&ImageResizer.needsToBeResized(i,a);if("DeviceRGBA"===this.colorSpace.name){s.kind=S;const e=s.data=await this.getImageBytes(g*n*4,{});return t?C?ImageResizer.createImage(s,!1):this.createBitmap(S,i,a,e):s}if(!e){let e;"DeviceGray"===this.colorSpace.name&&1===o?e=b:"DeviceRGB"!==this.colorSpace.name||8!==o||this.needsDecode||(e=F);if(e&&!this.smask&&!this.mask&&i===n&&a===g){const r=await this.getImageBytes(g*c,{});if(t)return C?ImageResizer.createImage({data:r,kind:e,width:i,height:a,interpolate:this.interpolate},this.needsDecode):this.createBitmap(e,n,g,r);s.kind=e;s.data=r;if(this.needsDecode){assert(e===b,"PDFImage.createImageData: The image must be grayscale.");const t=s.data;for(let e=0,i=t.length;e>3,n=await this.getImageBytes(a*r,{internal:!0}),g=this.getComponents(n);let o,c;if(1===s){c=i*a;if(this.needsDecode)for(o=0;o0&&t.args[0].count++}class TimeSlotManager{static TIME_SLOT_DURATION_MS=20;static CHECK_TIME_EVERY=100;constructor(){this.reset()}check(){if(++this.checkedh){const e="Image exceeded maximum allowed size and was removed.";if(this.options.ignoreErrors){warn(e);return}throw new Error(e)}let l;g.has("OC")&&(l=await this.parseMarkedContentProps(g.get("OC"),e));let Q,E;if(g.get("IM","ImageMask")||!1){const e=g.get("I","Interpolate"),i=c+7>>3,n=t.getBytes(i*C),h=g.getArray("D","Decode");if(this.parsingType3Font){Q=PDFImage.createRawMask({imgArray:n,width:c,height:C,imageIsFromDecodeStream:t instanceof DecodeStream,inverseDecode:h?.[0]>0,interpolate:e});Q.cached=!!s;E=[Q];a.addImageOps(Ze,E,l);if(s){const e={fn:Ze,args:E,optionalContent:l};r.set(s,o,e);o&&this._regionalImageCache.set(null,o,e)}return}Q=await PDFImage.createMask({imgArray:n,width:c,height:C,imageIsFromDecodeStream:t instanceof DecodeStream,inverseDecode:h?.[0]>0,interpolate:e,isOffscreenCanvasSupported:this.options.isOffscreenCanvasSupported});if(Q.isSingleOpaquePixel){a.addImageOps(tt,[],l);if(s){const e={fn:tt,args:[],optionalContent:l};r.set(s,o,e);o&&this._regionalImageCache.set(null,o,e)}return}const u=`mask_${this.idFactory.createObjId()}`;a.addDependency(u);Q.dataLen=Q.bitmap?Q.width*Q.height*4:Q.data.length;this._sendImgData(u,Q);E=[{data:u,width:Q.width,height:Q.height,interpolate:Q.interpolate,count:1}];a.addImageOps(Ze,E,l);if(s){const e={objId:u,fn:Ze,args:E,optionalContent:l};r.set(s,o,e);o&&this._regionalImageCache.set(null,o,e)}return}if(i&&c+C<200&&!g.has("SMask")&&!g.has("Mask")){try{const s=new PDFImage({xref:this.xref,res:e,image:t,isInline:i,pdfFunctionFactory:this._pdfFunctionFactory,localColorSpaceCache:n});Q=await s.createImageData(!0,!1);a.isOffscreenCanvasSupported=this.options.isOffscreenCanvasSupported;a.addImageOps(_e,[Q],l)}catch(e){const t=`Unable to decode inline image: "${e}".`;if(!this.options.ignoreErrors)throw new Error(t);warn(t)}return}let u=`img_${this.idFactory.createObjId()}`,d=!1;if(this.parsingType3Font)u=`${this.idFactory.getDocId()}_type3_${u}`;else if(s&&o){d=this.globalImageCache.shouldCache(o,this.pageIndex);if(d){assert(!i,"Cannot cache an inline image globally.");u=`${this.idFactory.getDocId()}_${u}`}}a.addDependency(u);E=[u,c,C];a.addImageOps(ze,E,l);if(d){if(this.globalImageCache.hasDecodeFailed(o)){this.globalImageCache.setData(o,{objId:u,fn:ze,args:E,optionalContent:l,byteSize:0});this._sendImgData(u,null,d);return}if(c*C>25e4||g.has("SMask")||g.has("Mask")){const e=await this.handler.sendWithPromise("commonobj",[u,"CopyLocalImage",{imageRef:o}]);if(e){this.globalImageCache.setData(o,{objId:u,fn:ze,args:E,optionalContent:l,byteSize:0});this.globalImageCache.addByteSize(o,e);return}}}PDFImage.buildImage({xref:this.xref,res:e,image:t,isInline:i,pdfFunctionFactory:this._pdfFunctionFactory,localColorSpaceCache:n}).then((async e=>{Q=await e.createImageData(!1,this.options.isOffscreenCanvasSupported);Q.dataLen=Q.bitmap?Q.width*Q.height*4:Q.data.length;Q.ref=o;d&&this.globalImageCache.addByteSize(o,Q.dataLen);return this._sendImgData(u,Q,d)})).catch((e=>{warn(`Unable to decode image "${u}": "${e}".`);o&&this.globalImageCache.addDecodeFailed(o);return this._sendImgData(u,null,d)}));if(s){const e={objId:u,fn:ze,args:E,optionalContent:l};r.set(s,o,e);if(o){this._regionalImageCache.set(null,o,e);d&&this.globalImageCache.setData(o,{objId:u,fn:ze,args:E,optionalContent:l,byteSize:0})}}}handleSMask(e,t,i,a,s,r){const n=e.get("G"),g={subtype:e.get("S").name,backdrop:e.get("BC")},o=e.get("TR");if(isPDFFunction(o)){const e=this._pdfFunctionFactory.create(o),t=new Uint8Array(256),i=new Float32Array(1);for(let a=0;a<256;a++){i[0]=a/255;e(i,0,i,0);t[a]=255*i[0]|0}g.transferMap=t}return this.buildFormXObject(t,n,g,i,a,s.state.clone(),r)}handleTransferFunction(e){let t;if(Array.isArray(e))t=e;else{if(!isPDFFunction(e))return null;t=[e]}const i=[];let a=0,s=0;for(const e of t){const t=this.xref.fetchIfRef(e);a++;if(isName(t,"Identity")){i.push(null);continue}if(!isPDFFunction(t))return null;const r=this._pdfFunctionFactory.create(t),n=new Uint8Array(256),g=new Float32Array(1);for(let e=0;e<256;e++){g[0]=e/255;r(g,0,g,0);n[e]=255*g[0]|0}i.push(n);s++}return 1!==a&&4!==a||0===s?null:i}handleTilingType(e,t,i,a,s,r,n,g){const o=new OperatorList,c=Dict.merge({xref:this.xref,dictArray:[s.get("Resources"),i]});return this.getOperatorList({stream:a,task:n,resources:c,operatorList:o}).then((function(){const i=o.getIR(),a=getTilingPatternIR(i,s,t);r.addDependencies(o.dependencies);r.addOp(e,a);s.objId&&g.set(null,s.objId,{operatorListIR:i,dict:s})})).catch((e=>{if(!(e instanceof AbortException)){if(!this.options.ignoreErrors)throw e;warn(`handleTilingType - ignoring pattern: "${e}".`)}}))}async handleSetFont(e,t,i,a,s,r,n=null,g=null){const o=t?.[0]instanceof Name?t[0].name:null;let c=await this.loadFont(o,i,e,n,g);if(c.font.isType3Font)try{await c.loadType3Data(this,e,s);a.addDependencies(c.type3Dependencies)}catch(e){c=new TranslatedFont({loadedName:"g_font_error",font:new ErrorFont(`Type3 font load error: ${e}`),dict:c.font,evaluatorOptions:this.options})}r.font=c.font;c.send(this.handler);return c.loadedName}handleText(e,t){const i=t.font,a=i.charsToGlyphs(e);if(i.data){(!!(t.textRenderingMode&D)||"Pattern"===t.fillColorSpace.name||i.disableFontFace||this.options.disableFontFace)&&PartialEvaluator.buildFontPaths(i,a,this.handler,this.options)}return a}ensureStateFont(e){if(e.font)return;const t=new FormatError("Missing setFont (Tf) operator before text rendering operator.");if(!this.options.ignoreErrors)throw t;warn(`ensureStateFont: "${t}".`)}async setGState({resources:e,gState:t,operatorList:i,cacheKey:a,task:s,stateManager:r,localGStateCache:n,localColorSpaceCache:g}){const o=t.objId;let c=!0;const C=[];let h=Promise.resolve();for(const a of t.getKeys()){const n=t.get(a);switch(a){case"Type":break;case"LW":case"LC":case"LJ":case"ML":case"D":case"RI":case"FL":case"CA":case"ca":C.push([a,n]);break;case"Font":c=!1;h=h.then((()=>this.handleSetFont(e,null,n[0],i,s,r.state).then((function(e){i.addDependency(e);C.push([a,[e,n[1]]])}))));break;case"BM":C.push([a,normalizeBlendMode(n)]);break;case"SMask":if(isName(n,"None")){C.push([a,!1]);break}if(n instanceof Dict){c=!1;h=h.then((()=>this.handleSMask(n,e,i,s,r,g)));C.push([a,!0])}else warn("Unsupported SMask type");break;case"TR":const t=this.handleTransferFunction(n);C.push([a,t]);break;case"OP":case"op":case"OPM":case"BG":case"BG2":case"UCR":case"UCR2":case"TR2":case"HT":case"SM":case"SA":case"AIS":case"TK":info("graphic state operator "+a);break;default:info("Unknown graphic state operator "+a)}}await h;C.length>0&&i.addOp(GA,[C]);c&&n.set(a,o,C)}loadFont(e,t,i,a=null,s=null){const errorFont=async()=>new TranslatedFont({loadedName:"g_font_error",font:new ErrorFont(`Font "${e}" is not available.`),dict:t,evaluatorOptions:this.options});let r;if(t)t instanceof Ref&&(r=t);else{const t=i.get("Font");t&&(r=t.getRaw(e))}if(r){if(this.type3FontRefs?.has(r))return errorFont();if(this.fontCache.has(r))return this.fontCache.get(r);try{t=this.xref.fetchIfRef(r)}catch(e){warn(`loadFont - lookup failed: "${e}".`)}}if(!(t instanceof Dict)){if(!this.options.ignoreErrors&&!this.parsingType3Font){warn(`Font "${e}" is not available.`);return errorFont()}warn(`Font "${e}" is not available -- attempting to fallback to a default font.`);t=a||PartialEvaluator.fallbackFontDict}if(t.cacheKey&&this.fontCache.has(t.cacheKey))return this.fontCache.get(t.cacheKey);const{promise:n,resolve:g}=Promise.withResolvers();let o;try{o=this.preEvaluateFont(t);o.cssFontInfo=s}catch(e){warn(`loadFont - preEvaluateFont failed: "${e}".`);return errorFont()}const{descriptor:c,hash:C}=o,h=r instanceof Ref;let l;if(C&&c instanceof Dict){const e=c.fontAliases||=Object.create(null);if(e[C]){const t=e[C].aliasRef;if(h&&t&&this.fontCache.has(t)){this.fontCache.putAlias(r,t);return this.fontCache.get(r)}}else e[C]={fontID:this.idFactory.createFontId()};h&&(e[C].aliasRef=r);l=e[C].fontID}else l=this.idFactory.createFontId();assert(l?.startsWith("f"),'The "fontID" must be (correctly) defined.');if(h)this.fontCache.put(r,n);else{t.cacheKey=`cacheKey_${l}`;this.fontCache.put(t.cacheKey,n)}t.loadedName=`${this.idFactory.getDocId()}_${l}`;this.translateFont(o).then((e=>{g(new TranslatedFont({loadedName:t.loadedName,font:e,dict:t,evaluatorOptions:this.options}))})).catch((e=>{warn(`loadFont - translateFont failed: "${e}".`);g(new TranslatedFont({loadedName:t.loadedName,font:new ErrorFont(e instanceof Error?e.message:e),dict:t,evaluatorOptions:this.options}))}));return n}buildPath(e,t,i,a=!1){const s=e.length-1;i||(i=[]);if(s<0||e.fnArray[s]!==it){if(a){warn(`Encountered path operator "${t}" inside of a text object.`);e.addOp(xA,null)}let s;switch(t){case TA:const e=i[0]+i[2],t=i[1]+i[3];s=[Math.min(i[0],e),Math.min(i[1],t),Math.max(i[0],e),Math.max(i[1],t)];break;case LA:case HA:s=[i[0],i[1],i[0],i[1]];break;default:s=[1/0,1/0,-1/0,-1/0]}e.addOp(it,[[t],i,s]);a&&e.addOp(UA,null)}else{const a=e.argsArray[s];a[0].push(t);a[1].push(...i);const r=a[2];switch(t){case TA:const e=i[0]+i[2],t=i[1]+i[3];r[0]=Math.min(r[0],i[0],e);r[1]=Math.min(r[1],i[1],t);r[2]=Math.max(r[2],i[0],e);r[3]=Math.max(r[3],i[1],t);break;case LA:case HA:r[0]=Math.min(r[0],i[0]);r[1]=Math.min(r[1],i[1]);r[2]=Math.max(r[2],i[0]);r[3]=Math.max(r[3],i[1])}}}parseColorSpace({cs:e,resources:t,localColorSpaceCache:i}){return ColorSpace.parseAsync({cs:e,xref:this.xref,resources:t,pdfFunctionFactory:this._pdfFunctionFactory,localColorSpaceCache:i}).catch((e=>{if(e instanceof AbortException)return null;if(this.options.ignoreErrors){warn(`parseColorSpace - ignoring ColorSpace: "${e}".`);return null}throw e}))}parseShading({shading:e,resources:t,localColorSpaceCache:i,localShadingPatternCache:a}){let s,r=a.get(e);if(r)return r;try{s=Pattern.parseShading(e,this.xref,t,this._pdfFunctionFactory,i).getIR()}catch(t){if(t instanceof AbortException)return null;if(this.options.ignoreErrors){warn(`parseShading - ignoring shading: "${t}".`);a.set(e,null);return null}throw t}r=`pattern_${this.idFactory.createObjId()}`;this.parsingType3Font&&(r=`${this.idFactory.getDocId()}_type3_${r}`);a.set(e,r);this.parsingType3Font?this.handler.send("commonobj",[r,"Pattern",s]):this.handler.send("obj",[r,this.pageIndex,"Pattern",s]);return r}handleColorN(e,t,i,a,s,r,n,g,o,c){const C=i.pop();if(C instanceof Name){const h=s.getRaw(C.name),l=h instanceof Ref&&o.getByRef(h);if(l)try{const s=a.base?a.base.getRgb(i,0):null,r=getTilingPatternIR(l.operatorListIR,l.dict,s);e.addOp(t,r);return}catch{}const Q=this.xref.fetchIfRef(h);if(Q){const s=Q instanceof BaseStream?Q.dict:Q,C=s.get("PatternType");if(C===Ns){const g=a.base?a.base.getRgb(i,0):null;return this.handleTilingType(t,g,r,Q,s,e,n,o)}if(C===Gs){const i=s.get("Shading"),a=this.parseShading({shading:i,resources:r,localColorSpaceCache:g,localShadingPatternCache:c});if(a){const i=lookupMatrix(s.getArray("Matrix"),null);e.addOp(t,["Shading",a,i])}return}throw new FormatError(`Unknown PatternType: ${C}`)}}throw new FormatError(`Unknown PatternName: ${C}`)}_parseVisibilityExpression(e,t,i){if(++t>10){warn("Visibility expression is too deeply nested");return}const a=e.length,s=this.xref.fetchIfRef(e[0]);if(!(a<2)&&s instanceof Name){switch(s.name){case"And":case"Or":case"Not":i.push(s.name);break;default:warn(`Invalid operator ${s.name} in visibility expression`);return}for(let s=1;s0)return{type:"OCMD",expression:t}}const t=i.get("OCGs");if(Array.isArray(t)||t instanceof Dict){const e=[];if(Array.isArray(t))for(const i of t)e.push(i.toString());else e.push(t.objId);return{type:a,ids:e,policy:i.get("P")instanceof Name?i.get("P").name:null,expression:null}}if(t instanceof Ref)return{type:a,id:t.toString()}}return null}getOperatorList({stream:e,task:t,resources:i,operatorList:a,initialState:s=null,fallbackFontDict:r=null}){i||=Dict.empty;s||=new EvalState;if(!a)throw new Error('getOperatorList: missing "operatorList" parameter');const n=this,g=this.xref;let o=!1;const c=new LocalImageCache,C=new LocalColorSpaceCache,h=new LocalGStateCache,l=new LocalTilingPatternCache,Q=new Map,E=i.get("XObject")||Dict.empty,u=i.get("Pattern")||Dict.empty,d=new StateManager(s),f=new EvaluatorPreprocessor(e,g,d),p=new TimeSlotManager;function closePendingRestoreOPS(e){for(let e=0,t=f.savedStatesDepth;e0&&a.addOp(GA,[t]);e=null;continue}}next(new Promise((function(e,s){if(!S)throw new FormatError("GState must be referred to by name.");const r=i.get("ExtGState");if(!(r instanceof Dict))throw new FormatError("ExtGState should be a dictionary.");const g=r.get(F);if(!(g instanceof Dict))throw new FormatError("GState should be a dictionary.");n.setGState({resources:i,gState:g,operatorList:a,cacheKey:F,task:t,stateManager:d,localGStateCache:h,localColorSpaceCache:C}).then(e,s)})).catch((function(e){if(!(e instanceof AbortException)){if(!n.options.ignoreErrors)throw e;warn(`getOperatorList - ignoring ExtGState: "${e}".`)}})));return;case LA:case HA:case JA:case YA:case vA:case KA:case TA:n.buildPath(a,s,e,o);continue;case Le:case He:case Ke:case Te:continue;case Ye:if(!(e[0]instanceof Name)){warn(`Expected name for beginMarkedContentProps arg0=${e[0]}`);a.addOp(Ye,["OC",null]);continue}if("OC"===e[0].name){next(n.parseMarkedContentProps(e[1],i).then((e=>{a.addOp(Ye,["OC",e])})).catch((e=>{if(!(e instanceof AbortException)){if(!n.options.ignoreErrors)throw e;warn(`getOperatorList - ignoring beginMarkedContentProps: "${e}".`);a.addOp(Ye,["OC",null])}})));return}e=[e[0].name,e[1]instanceof Dict?e[1].get("MCID"):null];break;default:if(null!==e){for(w=0,D=e.length;w{if(!(e instanceof AbortException)){if(!this.options.ignoreErrors)throw e;warn(`getOperatorList - ignoring errors during "${t.name}" task: "${e}".`);closePendingRestoreOPS()}}))}getTextContent({stream:e,task:t,resources:s,stateManager:r=null,includeMarkedContent:n=!1,sink:g,seenStyles:o=new Set,viewBox:c,lang:C=null,markedContentData:h=null,disableNormalization:l=!1,keepWhiteSpace:Q=!1}){s||=Dict.empty;r||=new StateManager(new TextState);n&&(h||={level:0});const E={items:[],styles:Object.create(null),lang:C},u={initialized:!1,str:[],totalWidth:0,totalHeight:0,width:0,height:0,vertical:!1,prevTransform:null,textAdvanceScale:0,spaceInFlowMin:0,spaceInFlowMax:0,trackingSpaceMin:1/0,negativeSpaceMax:-1/0,notASpace:-1/0,transform:null,fontName:null,hasEOL:!1},d=[" "," "];let f=0;function saveLastChar(e){const t=(f+1)%2,i=" "!==d[f]&&" "===d[t];d[f]=e;f=t;return!Q&&i}function shouldAddWhitepsace(){return!Q&&" "!==d[f]&&" "===d[(f+1)%2]}function resetLastChars(){d[0]=d[1]=" ";f=0}const p=this,m=this.xref,y=[];let w=null;const D=new LocalImageCache,b=new LocalGStateCache,F=new EvaluatorPreprocessor(e,m,r);let S;function pushWhitespace({width:e=0,height:t=0,transform:i=u.prevTransform,fontName:a=u.fontName}){E.items.push({str:" ",dir:"ltr",width:e,height:t,transform:i,fontName:a,hasEOL:!1})}function getCurrentTextTransform(){const e=S.font,t=[S.fontSize*S.textHScale,0,0,S.fontSize,0,S.textRise];if(e.isType3Font&&(S.fontSize<=1||e.isCharBBox)&&!isArrayEqual(S.fontMatrix,a)){const i=e.bbox[3]-e.bbox[1];i>0&&(t[3]*=i*S.fontMatrix[3])}return Util.transform(S.ctm,Util.transform(S.textMatrix,t))}function ensureTextContentItem(){if(u.initialized)return u;const{font:e,loadedName:t}=S;if(!o.has(t)){o.add(t);E.styles[t]={fontFamily:e.fallbackName,ascent:e.ascent,descent:e.descent,vertical:e.vertical};if(p.options.fontExtraProperties&&e.systemFontInfo){const i=E.styles[t];i.fontSubstitution=e.systemFontInfo.css;i.fontSubstitutionLoadedName=e.systemFontInfo.loadedName}}u.fontName=t;const i=u.transform=getCurrentTextTransform();if(e.vertical){u.width=u.totalWidth=Math.hypot(i[0],i[1]);u.height=u.totalHeight=0;u.vertical=!0}else{u.width=u.totalWidth=0;u.height=u.totalHeight=Math.hypot(i[2],i[3]);u.vertical=!1}const a=Math.hypot(S.textLineMatrix[0],S.textLineMatrix[1]),s=Math.hypot(S.ctm[0],S.ctm[1]);u.textAdvanceScale=s*a;const{fontSize:r}=S;u.trackingSpaceMin=.102*r;u.notASpace=.03*r;u.negativeSpaceMax=-.2*r;u.spaceInFlowMin=.102*r;u.spaceInFlowMax=.6*r;u.hasEOL=!1;u.initialized=!0;return u}function updateAdvanceScale(){if(!u.initialized)return;const e=Math.hypot(S.textLineMatrix[0],S.textLineMatrix[1]),t=Math.hypot(S.ctm[0],S.ctm[1])*e;if(t!==u.textAdvanceScale){if(u.vertical){u.totalHeight+=u.height*u.textAdvanceScale;u.height=0}else{u.totalWidth+=u.width*u.textAdvanceScale;u.width=0}u.textAdvanceScale=t}}function runBidiTransform(e){let t=e.str.join("");l||(t=function normalizeUnicode(e){if(!Ct){Ct=/([\u00a0\u00b5\u037e\u0eb3\u2000-\u200a\u202f\u2126\ufb00-\ufb04\ufb06\ufb20-\ufb36\ufb38-\ufb3c\ufb3e\ufb40-\ufb41\ufb43-\ufb44\ufb46-\ufba1\ufba4-\ufba9\ufbae-\ufbb1\ufbd3-\ufbdc\ufbde-\ufbe7\ufbea-\ufbf8\ufbfc-\ufbfd\ufc00-\ufc5d\ufc64-\ufcf1\ufcf5-\ufd3d\ufd88\ufdf4\ufdfa-\ufdfb\ufe71\ufe77\ufe79\ufe7b\ufe7d]+)|(\ufb05+)/gu;ht=new Map([["ſt","ſt"]])}return e.replaceAll(Ct,((e,t,i)=>t?t.normalize("NFKC"):ht.get(i)))}(t));const i=bidi(t,-1,e.vertical);return{str:i.str,dir:i.dir,width:Math.abs(e.totalWidth),height:Math.abs(e.totalHeight),transform:e.transform,fontName:e.fontName,hasEOL:e.hasEOL}}async function handleSetFont(e,i){const r=await p.loadFont(e,i,s);if(r.font.isType3Font)try{await r.loadType3Data(p,s,t)}catch{}S.loadedName=r.loadedName;S.font=r.font;S.fontMatrix=r.font.fontMatrix||a}function applyInverseRotation(e,t,i){const a=Math.hypot(i[0],i[1]);return[(i[0]*e+i[1]*t)/a,(i[2]*e+i[3]*t)/a]}function compareWithLastPosition(e){const t=getCurrentTextTransform();let i=t[4],a=t[5];if(S.font?.vertical){if(ic[2]||a+ec[3])return!1}else if(i+ec[2]||ac[3])return!1;if(!S.font||!u.prevTransform)return!0;let s=u.prevTransform[4],r=u.prevTransform[5];if(s===i&&r===a)return!0;let n=-1;t[0]&&0===t[1]&&0===t[2]?n=t[0]>0?0:180:t[1]&&0===t[0]&&0===t[3]&&(n=t[1]>0?90:270);switch(n){case 0:break;case 90:[i,a]=[a,i];[s,r]=[r,s];break;case 180:[i,a,s,r]=[-i,-a,-s,-r];break;case 270:[i,a]=[-a,-i];[s,r]=[-r,-s];break;default:[i,a]=applyInverseRotation(i,a,t);[s,r]=applyInverseRotation(s,r,u.prevTransform)}if(S.font.vertical){const e=(r-a)/u.textAdvanceScale,t=i-s,n=Math.sign(u.height);if(e.5*u.width){appendEOL();return!0}resetLastChars();flushTextContentItem();return!0}if(Math.abs(t)>u.width){appendEOL();return!0}e<=n*u.notASpace&&resetLastChars();if(e<=n*u.trackingSpaceMin)if(shouldAddWhitepsace()){resetLastChars();flushTextContentItem();pushWhitespace({height:Math.abs(e)})}else u.height+=e;else if(!addFakeSpaces(e,u.prevTransform,n))if(0===u.str.length){resetLastChars();pushWhitespace({height:Math.abs(e)})}else u.height+=e;Math.abs(t)>.25*u.width&&flushTextContentItem();return!0}const g=(i-s)/u.textAdvanceScale,o=a-r,C=Math.sign(u.width);if(g.5*u.height){appendEOL();return!0}resetLastChars();flushTextContentItem();return!0}if(Math.abs(o)>u.height){appendEOL();return!0}g<=C*u.notASpace&&resetLastChars();if(g<=C*u.trackingSpaceMin)if(shouldAddWhitepsace()){resetLastChars();flushTextContentItem();pushWhitespace({width:Math.abs(g)})}else u.width+=g;else if(!addFakeSpaces(g,u.prevTransform,C))if(0===u.str.length){resetLastChars();pushWhitespace({width:Math.abs(g)})}else u.width+=g;Math.abs(o)>.25*u.height&&flushTextContentItem();return!0}function buildTextContentItem({chars:e,extraSpacing:t}){const i=S.font;if(!e){const e=S.charSpacing+t;e&&(i.vertical?S.translateTextMatrix(0,-e):S.translateTextMatrix(e*S.textHScale,0));Q&&compareWithLastPosition(0);return}const a=i.charsToGlyphs(e),s=S.fontMatrix[0]*S.fontSize;for(let e=0,r=a.length;e0){const e=y.join("");y.length=0;buildTextContentItem({chars:e,extraSpacing:0})}break;case he:if(!r.state.font){p.ensureStateFont(r.state);continue}buildTextContentItem({chars:f[0],extraSpacing:0});break;case le:if(!r.state.font){p.ensureStateFont(r.state);continue}S.carriageReturn();buildTextContentItem({chars:f[0],extraSpacing:0});break;case Qe:if(!r.state.font){p.ensureStateFont(r.state);continue}S.wordSpacing=f[0];S.charSpacing=f[1];S.carriageReturn();buildTextContentItem({chars:f[2],extraSpacing:0});break;case Me:flushTextContentItem();w||(w=s.get("XObject")||Dict.empty);var G=f[0]instanceof Name,x=f[0].name;if(G&&D.getByName(x))break;next(new Promise((function(e,i){if(!G)throw new FormatError("XObject must be referred to by name.");let a=w.getRaw(x);if(a instanceof Ref){if(D.getByRef(a)){e();return}if(p.globalImageCache.getData(a,p.pageIndex)){e();return}a=m.fetch(a)}if(!(a instanceof BaseStream))throw new FormatError("XObject should be a stream");const E=a.dict.get("Subtype");if(!(E instanceof Name))throw new FormatError("XObject should have a Name subtype");if("Form"!==E.name){D.set(x,a.dict.objId,!0);e();return}const u=r.state.clone(),d=new StateManager(u),f=lookupMatrix(a.dict.getArray("Matrix"),null);f&&d.transform(f);enqueueChunk();const y={enqueueInvoked:!1,enqueue(e,t){this.enqueueInvoked=!0;g.enqueue(e,t)},get desiredSize(){return g.desiredSize},get ready(){return g.ready}};p.getTextContent({stream:a,task:t,resources:a.dict.get("Resources")||s,stateManager:d,includeMarkedContent:n,sink:y,seenStyles:o,viewBox:c,lang:C,markedContentData:h,disableNormalization:l,keepWhiteSpace:Q}).then((function(){y.enqueueInvoked||D.set(x,a.dict.objId,!0);e()}),i)})).catch((function(e){if(!(e instanceof AbortException)){if(!p.options.ignoreErrors)throw e;warn(`getTextContent - ignoring XObject: "${e}".`)}})));return;case GA:G=f[0]instanceof Name;x=f[0].name;if(G&&b.getByName(x))break;next(new Promise((function(e,t){if(!G)throw new FormatError("GState must be referred to by name.");const i=s.get("ExtGState");if(!(i instanceof Dict))throw new FormatError("ExtGState should be a dictionary.");const a=i.get(x);if(!(a instanceof Dict))throw new FormatError("GState should be a dictionary.");const r=a.get("Font");if(r){flushTextContentItem();S.fontName=null;S.fontSize=r[1];handleSetFont(null,r[0]).then(e,t)}else{b.set(x,a.objId,!0);e()}})).catch((function(e){if(!(e instanceof AbortException)){if(!p.options.ignoreErrors)throw e;warn(`getTextContent - ignoring ExtGState: "${e}".`)}})));return;case Je:flushTextContentItem();if(n){h.level++;E.items.push({type:"beginMarkedContent",tag:f[0]instanceof Name?f[0].name:null})}break;case Ye:flushTextContentItem();if(n){h.level++;let e=null;f[1]instanceof Dict&&(e=f[1].get("MCID"));E.items.push({type:"beginMarkedContentProps",id:Number.isInteger(e)?`${p.idFactory.getPageObjId()}_mc${e}`:null,tag:f[0]instanceof Name?f[0].name:null})}break;case ve:flushTextContentItem();if(n){if(0===h.level)break;h.level--;E.items.push({type:"endMarkedContent"})}break;case UA:!e||e.font===S.font&&e.fontSize===S.fontSize&&e.fontName===S.fontName||flushTextContentItem()}if(E.items.length>=g.desiredSize){d=!0;break}}if(d)next(xs);else{flushTextContentItem();enqueueChunk();e()}})).catch((e=>{if(!(e instanceof AbortException)){if(!this.options.ignoreErrors)throw e;warn(`getTextContent - ignoring errors during "${t.name}" task: "${e}".`);flushTextContentItem();enqueueChunk()}}))}async extractDataStructures(e,t){const i=this.xref;let a;const s=this.readToUnicode(t.toUnicode);if(t.composite){const i=e.get("CIDSystemInfo");i instanceof Dict&&(t.cidSystemInfo={registry:stringToPDFString(i.get("Registry")),ordering:stringToPDFString(i.get("Ordering")),supplement:i.get("Supplement")});try{const t=e.get("CIDToGIDMap");t instanceof BaseStream&&(a=t.getBytes())}catch(e){if(!this.options.ignoreErrors)throw e;warn(`extractDataStructures - ignoring CIDToGIDMap data: "${e}".`)}}const r=[];let n,g=null;if(e.has("Encoding")){n=e.get("Encoding");if(n instanceof Dict){g=n.get("BaseEncoding");g=g instanceof Name?g.name:null;if(n.has("Differences")){const e=n.get("Differences");let t=0;for(const a of e){const e=i.fetchIfRef(a);if("number"==typeof e)t=e;else{if(!(e instanceof Name))throw new FormatError(`Invalid entry in 'Differences' array: ${e}`);r[t++]=e.name}}}}else if(n instanceof Name)g=n.name;else{const e="Encoding is not a Name nor a Dict";if(!this.options.ignoreErrors)throw new FormatError(e);warn(e)}"MacRomanEncoding"!==g&&"MacExpertEncoding"!==g&&"WinAnsiEncoding"!==g&&(g=null)}const o=!t.file||t.isInternalFont,c=$i()[t.name];g&&o&&c&&(g=null);if(g)t.defaultEncoding=getEncoding(g);else{const e=!!(t.flags&Pi),i=!!(t.flags&Wi);n=yi;"TrueType"!==t.type||i||(n=wi);if(e||c){n=mi;o&&(/Symbol/i.test(t.name)?n=Di:/Dingbats/i.test(t.name)?n=bi:/Wingdings/i.test(t.name)&&(n=wi))}t.defaultEncoding=n}t.differences=r;t.baseEncodingName=g;t.hasEncoding=!!g||r.length>0;t.dict=e;t.toUnicode=await s;const C=await this.buildToUnicode(t);t.toUnicode=C;a&&(t.cidToGidMap=this.readCidToGidMap(a,C));return t}_simpleFontToUnicode(e,t=!1){assert(!e.composite,"Must be a simple font.");const i=[],a=e.defaultEncoding.slice(),s=e.baseEncodingName,r=e.differences;for(const e in r){const t=r[e];".notdef"!==t&&(a[e]=t)}const n=Mi();for(const r in a){let g=a[r];if(""===g)continue;let o=n[g];if(void 0!==o){i[r]=String.fromCharCode(o);continue}let c=0;switch(g[0]){case"G":3===g.length&&(c=parseInt(g.substring(1),16));break;case"g":5===g.length&&(c=parseInt(g.substring(1),16));break;case"C":case"c":if(g.length>=3&&g.length<=4){const i=g.substring(1);if(t){c=parseInt(i,16);break}c=+i;if(Number.isNaN(c)&&Number.isInteger(parseInt(i,16)))return this._simpleFontToUnicode(e,!0)}break;case"u":o=getUnicodeForGlyph(g,n);-1!==o&&(c=o);break;default:switch(g){case"f_h":case"f_t":case"T_h":i[r]=g.replaceAll("_","");continue}}if(c>0&&c<=1114111&&Number.isInteger(c)){if(s&&c===+r){const e=getEncoding(s);if(e&&(g=e[r])){i[r]=String.fromCharCode(n[g]);continue}}i[r]=String.fromCodePoint(c)}}return i}async buildToUnicode(e){e.hasIncludedToUnicodeMap=e.toUnicode?.length>0;if(e.hasIncludedToUnicodeMap){!e.composite&&e.hasEncoding&&(e.fallbackToUnicode=this._simpleFontToUnicode(e));return e.toUnicode}if(!e.composite)return new ToUnicodeMap(this._simpleFontToUnicode(e));if(e.composite&&(e.cMap.builtInCMap&&!(e.cMap instanceof IdentityCMap)||"Adobe"===e.cidSystemInfo?.registry&&("GB1"===e.cidSystemInfo.ordering||"CNS1"===e.cidSystemInfo.ordering||"Japan1"===e.cidSystemInfo.ordering||"Korea1"===e.cidSystemInfo.ordering))){const{registry:t,ordering:i}=e.cidSystemInfo,a=Name.get(`${t}-${i}-UCS2`),s=await CMapFactory.create({encoding:a,fetchBuiltInCMap:this._fetchBuiltInCMapBound,useCMap:null}),r=[],n=[];e.cMap.forEach((function(e,t){if(t>65535)throw new FormatError("Max size of CID is 65,535");const i=s.lookup(t);if(i){n.length=0;for(let e=0,t=i.length;e>1;(0!==s||t.has(r))&&(i[r]=s)}return i}extractWidths(e,t,i){const a=this.xref;let s=[],r=0;const n=[];let g;if(i.composite){const t=e.get("DW");r="number"==typeof t?Math.ceil(t):1e3;const o=e.get("W");if(Array.isArray(o))for(let e=0,t=o.length;e{const t=o.get(e),s=new OperatorList;return a.getOperatorList({stream:t,task:i,resources:c,operatorList:s}).then((()=>{s.fnArray[0]===ue&&this._removeType3ColorOperators(s,E);C[e]=s.getIR();for(const e of s.dependencies)n.add(e)})).catch((function(t){warn(`Type3 font resource "${e}" is not available.`);const i=new OperatorList;C[e]=i.getIR()}))}));this.type3Loaded=g.then((()=>{r.charProcOperatorList=C;if(this._bbox){r.isCharBBox=!0;r.bbox=this._bbox}}));return this.type3Loaded}_removeType3ColorOperators(e,t=NaN){const i=Util.normalizeRect(e.argsArray[0].slice(2)),a=i[2]-i[0],s=i[3]-i[1],r=Math.hypot(a,s);if(0===a||0===s){e.fnArray.splice(0,1);e.argsArray.splice(0,1)}else if(0===t||Math.round(r/t)>=10){this._bbox||(this._bbox=[1/0,1/0,-1/0,-1/0]);this._bbox[0]=Math.min(this._bbox[0],i[0]);this._bbox[1]=Math.min(this._bbox[1],i[1]);this._bbox[2]=Math.max(this._bbox[2],i[2]);this._bbox[3]=Math.max(this._bbox[3],i[3])}let n=0,g=e.length;for(;n=LA&&r<=zA;if(s.variableArgs)g>n&&info(`Command ${a}: expected [0, ${n}] args, but received ${g} args.`);else{if(g!==n){const e=this.nonProcessedArgs;for(;g>n;){e.push(t.shift());g--}for(;gEvaluatorPreprocessor.MAX_INVALID_PATH_OPS)throw new FormatError(`Invalid ${e}`);warn(`Skipping ${e}`);null!==t&&(t.length=0);continue}}this.preprocessCommand(r,t);e.fn=r;e.args=t;return!0}if(i===wt)return!1;if(null!==i){null===t&&(t=[]);t.push(i);if(t.length>33)throw new FormatError("Too many arguments")}}}preprocessCommand(e,t){switch(0|e){case xA:this.stateManager.save();break;case UA:this.stateManager.restore();break;case MA:this.stateManager.transform(t)}}}class DefaultAppearanceEvaluator extends EvaluatorPreprocessor{constructor(e){super(new StringStream(e))}parse(){const e={fn:0,args:[]},t={fontSize:0,fontName:"",fontColor:new Uint8ClampedArray(3)};try{for(;;){e.args.length=0;if(!this.read(e))break;if(0!==this.savedStatesDepth)continue;const{fn:i,args:a}=e;switch(0|i){case re:const[e,i]=a;e instanceof Name&&(t.fontName=e.name);"number"==typeof i&&i>0&&(t.fontSize=i);break;case Se:ColorSpace.singletons.rgb.getRgbItem(a,0,t.fontColor,0);break;case be:ColorSpace.singletons.gray.getRgbItem(a,0,t.fontColor,0);break;case Re:ColorSpace.singletons.cmyk.getRgbItem(a,0,t.fontColor,0)}}}catch(e){warn(`parseDefaultAppearance - ignoring errors: "${e}".`)}return t}}function parseDefaultAppearance(e){return new DefaultAppearanceEvaluator(e).parse()}class AppearanceStreamEvaluator extends EvaluatorPreprocessor{constructor(e,t,i){super(e);this.stream=e;this.evaluatorOptions=t;this.xref=i;this.resources=e.dict?.get("Resources")}parse(){const e={fn:0,args:[]};let t={scaleFactor:1,fontSize:0,fontName:"",fontColor:new Uint8ClampedArray(3),fillColorSpace:ColorSpace.singletons.gray},i=!1;const a=[];try{for(;;){e.args.length=0;if(i||!this.read(e))break;const{fn:s,args:r}=e;switch(0|s){case xA:a.push({scaleFactor:t.scaleFactor,fontSize:t.fontSize,fontName:t.fontName,fontColor:t.fontColor.slice(),fillColorSpace:t.fillColorSpace});break;case UA:t=a.pop()||t;break;case ce:t.scaleFactor*=Math.hypot(r[0],r[1]);break;case re:const[e,s]=r;e instanceof Name&&(t.fontName=e.name);"number"==typeof s&&s>0&&(t.fontSize=s*t.scaleFactor);break;case fe:t.fillColorSpace=ColorSpace.parse({cs:r[0],xref:this.xref,resources:this.resources,pdfFunctionFactory:this._pdfFunctionFactory,localColorSpaceCache:this._localColorSpaceCache});break;case ye:t.fillColorSpace.getRgbItem(r,0,t.fontColor,0);break;case Se:ColorSpace.singletons.rgb.getRgbItem(r,0,t.fontColor,0);break;case be:ColorSpace.singletons.gray.getRgbItem(r,0,t.fontColor,0);break;case Re:ColorSpace.singletons.cmyk.getRgbItem(r,0,t.fontColor,0);break;case he:case Be:case le:case Qe:i=!0}}}catch(e){warn(`parseAppearanceStream - ignoring errors: "${e}".`)}this.stream.reset();delete t.scaleFactor;delete t.fillColorSpace;return t}get _localColorSpaceCache(){return shadow(this,"_localColorSpaceCache",new LocalColorSpaceCache)}get _pdfFunctionFactory(){return shadow(this,"_pdfFunctionFactory",new PDFFunctionFactory({xref:this.xref,isEvalSupported:this.evaluatorOptions.isEvalSupported}))}}function getPdfColor(e,t){if(e[0]===e[1]&&e[1]===e[2]){return`${numberToString(e[0]/255)} ${t?"g":"G"}`}return Array.from(e,(e=>numberToString(e/255))).join(" ")+" "+(t?"rg":"RG")}class FakeUnicodeFont{constructor(e,t){this.xref=e;this.widths=null;this.firstChar=1/0;this.lastChar=-1/0;this.fontFamily=t;const i=new OffscreenCanvas(1,1);this.ctxMeasure=i.getContext("2d",{willReadFrequently:!0});FakeUnicodeFont._fontNameId||(FakeUnicodeFont._fontNameId=1);this.fontName=Name.get(`InvalidPDFjsFont_${t}_${FakeUnicodeFont._fontNameId++}`)}get fontDescriptorRef(){if(!FakeUnicodeFont._fontDescriptorRef){const e=new Dict(this.xref);e.set("Type",Name.get("FontDescriptor"));e.set("FontName",this.fontName);e.set("FontFamily","MyriadPro Regular");e.set("FontBBox",[0,0,0,0]);e.set("FontStretch",Name.get("Normal"));e.set("FontWeight",400);e.set("ItalicAngle",0);FakeUnicodeFont._fontDescriptorRef=this.xref.getNewPersistentRef(e)}return FakeUnicodeFont._fontDescriptorRef}get descendantFontRef(){const e=new Dict(this.xref);e.set("BaseFont",this.fontName);e.set("Type",Name.get("Font"));e.set("Subtype",Name.get("CIDFontType0"));e.set("CIDToGIDMap",Name.get("Identity"));e.set("FirstChar",this.firstChar);e.set("LastChar",this.lastChar);e.set("FontDescriptor",this.fontDescriptorRef);e.set("DW",1e3);const t=[],i=[...this.widths.entries()].sort();let a=null,s=null;for(const[e,r]of i)if(a)if(e===a+s.length)s.push(r);else{t.push(a,s);a=e;s=[r]}else{a=e;s=[r]}a&&t.push(a,s);e.set("W",t);const r=new Dict(this.xref);r.set("Ordering","Identity");r.set("Registry","Adobe");r.set("Supplement",0);e.set("CIDSystemInfo",r);return this.xref.getNewPersistentRef(e)}get baseFontRef(){const e=new Dict(this.xref);e.set("BaseFont",this.fontName);e.set("Type",Name.get("Font"));e.set("Subtype",Name.get("Type0"));e.set("Encoding",Name.get("Identity-H"));e.set("DescendantFonts",[this.descendantFontRef]);e.set("ToUnicode",Name.get("Identity-H"));return this.xref.getNewPersistentRef(e)}get resources(){const e=new Dict(this.xref),t=new Dict(this.xref);t.set(this.fontName.name,this.baseFontRef);e.set("Font",t);return e}_createContext(){this.widths=new Map;this.ctxMeasure.font=`1000px ${this.fontFamily}`;return this.ctxMeasure}createFontResources(e){const t=this._createContext();for(const i of e.split(/\r\n?|\n/))for(const e of i.split("")){const i=e.charCodeAt(0);if(this.widths.has(i))continue;const a=t.measureText(e),s=Math.ceil(a.width);this.widths.set(i,s);this.firstChar=Math.min(i,this.firstChar);this.lastChar=Math.max(i,this.lastChar)}return this.resources}static getFirstPositionInfo(e,t,i){const[a,n,g,o]=e;let c=g-a,C=o-n;t%180!=0&&([c,C]=[C,c]);const h=s*i;return{coords:[0,C+r*i-h],bbox:[0,0,c,C],matrix:0!==t?getRotationMatrix(t,C,h):void 0}}createAppearance(e,t,i,a,n,g){const o=this._createContext(),c=[];let C=-1/0;for(const t of e.split(/\r\n?|\n/)){c.push(t);const e=o.measureText(t).width;C=Math.max(C,e);for(const e of codePointIter(t)){const t=String.fromCodePoint(e);let i=this.widths.get(e);if(void 0===i){const a=o.measureText(t);i=Math.ceil(a.width);this.widths.set(e,i);this.firstChar=Math.min(e,this.firstChar);this.lastChar=Math.max(e,this.lastChar)}}}C*=a/1e3;const[h,l,Q,E]=t;let u=Q-h,d=E-l;i%180!=0&&([u,d]=[d,u]);let f=1;C>u&&(f=u/C);let p=1;const m=s*a,y=r*a,w=m*c.length;w>d&&(p=d/w);const D=a*Math.min(f,p),b=["q",`0 0 ${numberToString(u)} ${numberToString(d)} re W n`,"BT",`1 0 0 1 0 ${numberToString(d+y)} Tm 0 Tc ${getPdfColor(n,!0)}`,`/${this.fontName.name} ${numberToString(D)} Tf`],{resources:F}=this;if(1!==(g="number"==typeof g&&g>=0&&g<=1?g:1)){b.push("/R0 gs");const e=new Dict(this.xref),t=new Dict(this.xref);t.set("ca",g);t.set("CA",g);t.set("Type",Name.get("ExtGState"));e.set("R0",t);F.set("ExtGState",e)}const S=numberToString(m);for(const e of c)b.push(`0 -${S} Td <${stringToUTF16HexString(e)}> Tj`);b.push("ET","Q");const k=b.join("\n"),R=new Dict(this.xref);R.set("Subtype",Name.get("Form"));R.set("Type",Name.get("XObject"));R.set("BBox",[0,0,u,d]);R.set("Length",k.length);R.set("Resources",F);if(i){const e=getRotationMatrix(i,u,d);R.set("Matrix",e)}const N=new StringStream(k);N.dict=R;return N}}class NameOrNumberTree{constructor(e,t,i){this.root=e;this.xref=t;this._type=i}getAll(){const e=new Map;if(!this.root)return e;const t=this.xref,i=new RefSet;i.put(this.root);const a=[this.root];for(;a.length>0;){const s=t.fetchIfRef(a.shift());if(!(s instanceof Dict))continue;if(s.has("Kids")){const e=s.get("Kids");if(!Array.isArray(e))continue;for(const t of e){if(i.has(t))throw new FormatError(`Duplicate entry in "${this._type}" tree.`);a.push(t);i.put(t)}continue}const r=s.get(this._type);if(Array.isArray(r))for(let i=0,a=r.length;i10){warn(`Search depth limit reached for "${this._type}" tree.`);return null}const s=i.get("Kids");if(!Array.isArray(s))return null;let r=0,n=s.length-1;for(;r<=n;){const a=r+n>>1,g=t.fetchIfRef(s[a]),o=g.get("Limits");if(et.fetchIfRef(o[1]))){i=g;break}r=a+1}}if(r>n)return null}const s=i.get(this._type);if(Array.isArray(s)){let i=0,a=s.length-2;for(;i<=a;){const r=i+a>>1,n=r+(1&r),g=t.fetchIfRef(s[n]);if(eg))return s[n+1];i=n+2}}}return null}get(e){return this.xref.fetchIfRef(this.getRaw(e))}}class NameTree extends NameOrNumberTree{constructor(e,t){super(e,t,"Names")}}class NumberTree extends NameOrNumberTree{constructor(e,t){super(e,t,"Nums")}}function clearGlobalCaches(){!function clearPatternCaches(){Fa=Object.create(null)}();!function clearPrimitiveCaches(){Dt=Object.create(null);bt=Object.create(null);Ft=Object.create(null)}();!function clearUnicodeCaches(){Ki.clear()}();JpxImage.cleanup()}function pickPlatformItem(e){return e instanceof Dict?e.has("UF")?e.get("UF"):e.has("F")?e.get("F"):e.has("Unix")?e.get("Unix"):e.has("Mac")?e.get("Mac"):e.has("DOS")?e.get("DOS"):null:null}class FileSpec{#S=!1;constructor(e,t,i=!1){if(e instanceof Dict){this.xref=t;this.root=e;e.has("FS")&&(this.fs=e.get("FS"));e.has("RF")&&warn("Related file specifications are not supported");i||(e.has("EF")?this.#S=!0:warn("Non-embedded file specifications are not supported"))}}get filename(){let e="";const t=pickPlatformItem(this.root);t&&"string"==typeof t&&(e=stringToPDFString(t).replaceAll("\\\\","\\").replaceAll("\\/","/").replaceAll("\\","/"));return shadow(this,"filename",e||"unnamed")}get content(){if(!this.#S)return null;this._contentRef||=pickPlatformItem(this.root?.get("EF"));let e=null;if(this._contentRef){const t=this.xref.fetchIfRef(this._contentRef);t instanceof BaseStream?e=t.getBytes():warn("Embedded file specification points to non-existing/invalid content")}else warn("Embedded file specification does not have any content");return e}get description(){let e="";const t=this.root?.get("Desc");t&&"string"==typeof t&&(e=stringToPDFString(t));return shadow(this,"description",e)}get serializable(){return{rawFilename:this.filename,filename:(e=this.filename,e.substring(e.lastIndexOf("/")+1)),content:this.content,description:this.description};var e}}const Us=0,Ms=-2,Ls=-3,Hs=-4,Js=-5,Ys=-6,vs=-9;function isWhitespace(e,t){const i=e[t];return" "===i||"\n"===i||"\r"===i||"\t"===i}class XMLParserBase{_resolveEntities(e){return e.replaceAll(/&([^;]+);/g,((e,t)=>{if("#x"===t.substring(0,2))return String.fromCodePoint(parseInt(t.substring(2),16));if("#"===t.substring(0,1))return String.fromCodePoint(parseInt(t.substring(1),10));switch(t){case"lt":return"<";case"gt":return">";case"amp":return"&";case"quot":return'"';case"apos":return"'"}return this.onResolveEntity(t)}))}_parseContent(e,t){const i=[];let a=t;function skipWs(){for(;a"!==e[a]&&"/"!==e[a];)++a;const s=e.substring(t,a);skipWs();for(;a"!==e[a]&&"/"!==e[a]&&"?"!==e[a];){skipWs();let t="",s="";for(;a"!==e[i]&&"?"!==e[i]&&"/"!==e[i];)++i;const a=e.substring(t,i);!function skipWs(){for(;i"!==e[i+1]);)++i;return{name:a,value:e.substring(s,i),parsed:i-t}}parseXml(e){let t=0;for(;t",i);if(t<0){this.onError(vs);return}this.onEndElement(e.substring(i,t));i=t+1;break;case"?":++i;const a=this._parseProcessingInstruction(e,i);if("?>"!==e.substring(i+a.parsed,i+a.parsed+2)){this.onError(Ls);return}this.onPi(a.name,a.value);i+=a.parsed+2;break;case"!":if("--"===e.substring(i+1,i+3)){t=e.indexOf("--\x3e",i+3);if(t<0){this.onError(Js);return}this.onComment(e.substring(i+3,t));i=t+3}else if("[CDATA["===e.substring(i+1,i+8)){t=e.indexOf("]]>",i+8);if(t<0){this.onError(Ms);return}this.onCdata(e.substring(i+8,t));i=t+3}else{if("DOCTYPE"!==e.substring(i+1,i+8)){this.onError(Ys);return}{const a=e.indexOf("[",i+8);let s=!1;t=e.indexOf(">",i+8);if(t<0){this.onError(Hs);return}if(a>0&&t>a){t=e.indexOf("]>",i+8);if(t<0){this.onError(Hs);return}s=!0}const r=e.substring(i+8,t+(s?1:0));this.onDoctype(r);i=t+(s?2:1)}}break;default:const s=this._parseContent(e,i);if(null===s){this.onError(Ys);return}let r=!1;if("/>"===e.substring(i+s.parsed,i+s.parsed+2))r=!0;else if(">"!==e.substring(i+s.parsed,i+s.parsed+1)){this.onError(vs);return}this.onBeginElement(s.name,s.attributes,r);i+=s.parsed+(r?2:1)}}else{for(;i0}searchNode(e,t){if(t>=e.length)return this;const i=e[t];if(i.name.startsWith("#")&&t0){a.push([s,0]);s=s.childNodes[0]}else{if(0===a.length)return null;for(;0!==a.length;){const[e,t]=a.pop(),i=t+1;if(i");for(const t of this.childNodes)t.dump(e);e.push(``)}else this.nodeValue?e.push(`>${encodeToXmlString(this.nodeValue)}`):e.push("/>")}else e.push(encodeToXmlString(this.nodeValue))}}class SimpleXMLParser extends XMLParserBase{constructor({hasAttributes:e=!1,lowerCaseName:t=!1}){super();this._currentFragment=null;this._stack=null;this._errorCode=Us;this._hasAttributes=e;this._lowerCaseName=t}parseFromString(e){this._currentFragment=[];this._stack=[];this._errorCode=Us;this.parseXml(e);if(this._errorCode!==Us)return;const[t]=this._currentFragment;return t?{documentElement:t}:void 0}onText(e){if(function isWhitespaceString(e){for(let t=0,i=e.length;t\\376\\377([^<]+)/g,(function(e,t){const i=t.replaceAll(/\\([0-3])([0-7])([0-7])/g,(function(e,t,i,a){return String.fromCharCode(64*t+8*i+1*a)})).replaceAll(/&(amp|apos|gt|lt|quot);/g,(function(e,t){switch(t){case"amp":return"&";case"apos":return"'";case"gt":return">";case"lt":return"<";case"quot":return'"'}throw new Error(`_repair: ${t} isn't defined.`)})),a=[">"];for(let e=0,t=i.length;e=32&&t<127&&60!==t&&62!==t&&38!==t?a.push(String.fromCharCode(t)):a.push("&#x"+(65536+t).toString(16).substring(1)+";")}return a.join("")}))}_getSequence(e){const t=e.nodeName;return"rdf:bag"!==t&&"rdf:seq"!==t&&"rdf:alt"!==t?null:e.childNodes.filter((e=>"rdf:li"===e.nodeName))}_parseArray(e){if(!e.hasChildNodes())return;const[t]=e.childNodes,i=this._getSequence(t)||[];this._metadataMap.set(e.nodeName,i.map((e=>e.textContent.trim())))}_parse(e){let t=e.documentElement;if("rdf:rdf"!==t.nodeName){t=t.firstChild;for(;t&&"rdf:rdf"!==t.nodeName;)t=t.nextSibling}if(t&&"rdf:rdf"===t.nodeName&&t.hasChildNodes())for(const e of t.childNodes)if("rdf:description"===e.nodeName)for(const t of e.childNodes){const e=t.nodeName;switch(e){case"#text":continue;case"dc:creator":case"dc:subject":this._parseArray(t);continue}this._metadataMap.set(e,t.textContent.trim())}}get serializable(){return{parsedData:this._metadataMap,rawData:this._data}}}class DecryptStream extends DecodeStream{constructor(e,t,i){super(t);this.str=e;this.dict=e.dict;this.decrypt=i;this.nextChunk=null;this.initialized=!1}readBlock(){let e;if(this.initialized)e=this.nextChunk;else{e=this.str.getBytes(512);this.initialized=!0}if(!e||0===e.length){this.eof=!0;return}this.nextChunk=this.str.getBytes(512);const t=this.nextChunk?.length>0;e=(0,this.decrypt)(e,!t);const i=this.bufferLength,a=i+e.length;this.ensureBuffer(a).set(e,i);this.bufferLength=a}}class ARCFourCipher{constructor(e){this.a=0;this.b=0;const t=new Uint8Array(256),i=e.length;for(let e=0;e<256;++e)t[e]=e;for(let a=0,s=0;a<256;++a){const r=t[a];s=s+r+e[a%i]&255;t[a]=t[s];t[s]=r}this.s=t}encryptBlock(e){let t=this.a,i=this.b;const a=this.s,s=e.length,r=new Uint8Array(s);for(let n=0;n>5&255;C[h++]=s>>13&255;C[h++]=s>>21&255;C[h++]=s>>>29&255;C[h++]=0;C[h++]=0;C[h++]=0;const E=new Int32Array(16);for(h=0;h>>32-g)|0;s=r}r=r+s|0;n=n+c|0;g=g+Q|0;o=o+u|0}return new Uint8Array([255&r,r>>8&255,r>>16&255,r>>>24&255,255&n,n>>8&255,n>>16&255,n>>>24&255,255&g,g>>8&255,g>>16&255,g>>>24&255,255&o,o>>8&255,o>>16&255,o>>>24&255])}}();class Word64{constructor(e,t){this.high=0|e;this.low=0|t}and(e){this.high&=e.high;this.low&=e.low}xor(e){this.high^=e.high;this.low^=e.low}or(e){this.high|=e.high;this.low|=e.low}shiftRight(e){if(e>=32){this.low=this.high>>>e-32|0;this.high=0}else{this.low=this.low>>>e|this.high<<32-e;this.high=this.high>>>e|0}}shiftLeft(e){if(e>=32){this.high=this.low<>>32-e;this.low<<=e}}rotateRight(e){let t,i;if(32&e){i=this.low;t=this.high}else{t=this.low;i=this.high}e&=31;this.low=t>>>e|i<<32-e;this.high=i>>>e|t<<32-e}not(){this.high=~this.high;this.low=~this.low}add(e){const t=(this.low>>>0)+(e.low>>>0);let i=(this.high>>>0)+(e.high>>>0);t>4294967295&&(i+=1);this.low=0|t;this.high=0|i}copyTo(e,t){e[t]=this.high>>>24&255;e[t+1]=this.high>>16&255;e[t+2]=this.high>>8&255;e[t+3]=255&this.high;e[t+4]=this.low>>>24&255;e[t+5]=this.low>>16&255;e[t+6]=this.low>>8&255;e[t+7]=255&this.low}assign(e){this.high=e.high;this.low=e.low}}const Ts=function calculateSHA256Closure(){function rotr(e,t){return e>>>t|e<<32-t}function ch(e,t,i){return e&t^~e&i}function maj(e,t,i){return e&t^e&i^t&i}function sigma(e){return rotr(e,2)^rotr(e,13)^rotr(e,22)}function sigmaPrime(e){return rotr(e,6)^rotr(e,11)^rotr(e,25)}function littleSigma(e){return rotr(e,7)^rotr(e,18)^e>>>3}const e=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298];return function hash(t,i,a){let s=1779033703,r=3144134277,n=1013904242,g=2773480762,o=1359893119,c=2600822924,C=528734635,h=1541459225;const l=64*Math.ceil((a+9)/64),Q=new Uint8Array(l);let E,u;for(E=0;E>>29&255;Q[E++]=a>>21&255;Q[E++]=a>>13&255;Q[E++]=a>>5&255;Q[E++]=a<<3&255;const f=new Uint32Array(64);for(E=0;E>>10)+f[u-7]+littleSigma(f[u-15])+f[u-16]|0;let t,i,a=s,l=r,d=n,m=g,y=o,w=c,D=C,b=h;for(u=0;u<64;++u){t=b+sigmaPrime(y)+ch(y,w,D)+e[u]+f[u];i=sigma(a)+maj(a,l,d);b=D;D=w;w=y;y=m+t|0;m=d;d=l;l=a;a=t+i|0}s=s+a|0;r=r+l|0;n=n+d|0;g=g+m|0;o=o+y|0;c=c+w|0;C=C+D|0;h=h+b|0}var p;return new Uint8Array([s>>24&255,s>>16&255,s>>8&255,255&s,r>>24&255,r>>16&255,r>>8&255,255&r,n>>24&255,n>>16&255,n>>8&255,255&n,g>>24&255,g>>16&255,g>>8&255,255&g,o>>24&255,o>>16&255,o>>8&255,255&o,c>>24&255,c>>16&255,c>>8&255,255&c,C>>24&255,C>>16&255,C>>8&255,255&C,h>>24&255,h>>16&255,h>>8&255,255&h])}}(),qs=function calculateSHA512Closure(){function ch(e,t,i,a,s){e.assign(t);e.and(i);s.assign(t);s.not();s.and(a);e.xor(s)}function maj(e,t,i,a,s){e.assign(t);e.and(i);s.assign(t);s.and(a);e.xor(s);s.assign(i);s.and(a);e.xor(s)}function sigma(e,t,i){e.assign(t);e.rotateRight(28);i.assign(t);i.rotateRight(34);e.xor(i);i.assign(t);i.rotateRight(39);e.xor(i)}function sigmaPrime(e,t,i){e.assign(t);e.rotateRight(14);i.assign(t);i.rotateRight(18);e.xor(i);i.assign(t);i.rotateRight(41);e.xor(i)}function littleSigma(e,t,i){e.assign(t);e.rotateRight(1);i.assign(t);i.rotateRight(8);e.xor(i);i.assign(t);i.shiftRight(7);e.xor(i)}function littleSigmaPrime(e,t,i){e.assign(t);e.rotateRight(19);i.assign(t);i.rotateRight(61);e.xor(i);i.assign(t);i.shiftRight(6);e.xor(i)}const e=[new Word64(1116352408,3609767458),new Word64(1899447441,602891725),new Word64(3049323471,3964484399),new Word64(3921009573,2173295548),new Word64(961987163,4081628472),new Word64(1508970993,3053834265),new Word64(2453635748,2937671579),new Word64(2870763221,3664609560),new Word64(3624381080,2734883394),new Word64(310598401,1164996542),new Word64(607225278,1323610764),new Word64(1426881987,3590304994),new Word64(1925078388,4068182383),new Word64(2162078206,991336113),new Word64(2614888103,633803317),new Word64(3248222580,3479774868),new Word64(3835390401,2666613458),new Word64(4022224774,944711139),new Word64(264347078,2341262773),new Word64(604807628,2007800933),new Word64(770255983,1495990901),new Word64(1249150122,1856431235),new Word64(1555081692,3175218132),new Word64(1996064986,2198950837),new Word64(2554220882,3999719339),new Word64(2821834349,766784016),new Word64(2952996808,2566594879),new Word64(3210313671,3203337956),new Word64(3336571891,1034457026),new Word64(3584528711,2466948901),new Word64(113926993,3758326383),new Word64(338241895,168717936),new Word64(666307205,1188179964),new Word64(773529912,1546045734),new Word64(1294757372,1522805485),new Word64(1396182291,2643833823),new Word64(1695183700,2343527390),new Word64(1986661051,1014477480),new Word64(2177026350,1206759142),new Word64(2456956037,344077627),new Word64(2730485921,1290863460),new Word64(2820302411,3158454273),new Word64(3259730800,3505952657),new Word64(3345764771,106217008),new Word64(3516065817,3606008344),new Word64(3600352804,1432725776),new Word64(4094571909,1467031594),new Word64(275423344,851169720),new Word64(430227734,3100823752),new Word64(506948616,1363258195),new Word64(659060556,3750685593),new Word64(883997877,3785050280),new Word64(958139571,3318307427),new Word64(1322822218,3812723403),new Word64(1537002063,2003034995),new Word64(1747873779,3602036899),new Word64(1955562222,1575990012),new Word64(2024104815,1125592928),new Word64(2227730452,2716904306),new Word64(2361852424,442776044),new Word64(2428436474,593698344),new Word64(2756734187,3733110249),new Word64(3204031479,2999351573),new Word64(3329325298,3815920427),new Word64(3391569614,3928383900),new Word64(3515267271,566280711),new Word64(3940187606,3454069534),new Word64(4118630271,4000239992),new Word64(116418474,1914138554),new Word64(174292421,2731055270),new Word64(289380356,3203993006),new Word64(460393269,320620315),new Word64(685471733,587496836),new Word64(852142971,1086792851),new Word64(1017036298,365543100),new Word64(1126000580,2618297676),new Word64(1288033470,3409855158),new Word64(1501505948,4234509866),new Word64(1607167915,987167468),new Word64(1816402316,1246189591)];return function hash(t,i,a,s=!1){let r,n,g,o,c,C,h,l;if(s){r=new Word64(3418070365,3238371032);n=new Word64(1654270250,914150663);g=new Word64(2438529370,812702999);o=new Word64(355462360,4144912697);c=new Word64(1731405415,4290775857);C=new Word64(2394180231,1750603025);h=new Word64(3675008525,1694076839);l=new Word64(1203062813,3204075428)}else{r=new Word64(1779033703,4089235720);n=new Word64(3144134277,2227873595);g=new Word64(1013904242,4271175723);o=new Word64(2773480762,1595750129);c=new Word64(1359893119,2917565137);C=new Word64(2600822924,725511199);h=new Word64(528734635,4215389547);l=new Word64(1541459225,327033209)}const Q=128*Math.ceil((a+17)/128),E=new Uint8Array(Q);let u,d;for(u=0;u>>29&255;E[u++]=a>>21&255;E[u++]=a>>13&255;E[u++]=a>>5&255;E[u++]=a<<3&255;const p=new Array(80);for(u=0;u<80;u++)p[u]=new Word64(0,0);let m=new Word64(0,0),y=new Word64(0,0),w=new Word64(0,0),D=new Word64(0,0),b=new Word64(0,0),F=new Word64(0,0),S=new Word64(0,0),k=new Word64(0,0);const R=new Word64(0,0),N=new Word64(0,0),G=new Word64(0,0),x=new Word64(0,0);let U,M;for(u=0;u=1;--e){i=r[13];r[13]=r[9];r[9]=r[5];r[5]=r[1];r[1]=i;i=r[14];a=r[10];r[14]=r[6];r[10]=r[2];r[6]=i;r[2]=a;i=r[15];a=r[11];s=r[7];r[15]=r[3];r[11]=i;r[7]=a;r[3]=s;for(let e=0;e<16;++e)r[e]=this._inv_s[r[e]];for(let i=0,a=16*e;i<16;++i,++a)r[i]^=t[a];for(let e=0;e<16;e+=4){const t=this._mix[r[e]],a=this._mix[r[e+1]],s=this._mix[r[e+2]],n=this._mix[r[e+3]];i=t^a>>>8^a<<24^s>>>16^s<<16^n>>>24^n<<8;r[e]=i>>>24&255;r[e+1]=i>>16&255;r[e+2]=i>>8&255;r[e+3]=255&i}}i=r[13];r[13]=r[9];r[9]=r[5];r[5]=r[1];r[1]=i;i=r[14];a=r[10];r[14]=r[6];r[10]=r[2];r[6]=i;r[2]=a;i=r[15];a=r[11];s=r[7];r[15]=r[3];r[11]=i;r[7]=a;r[3]=s;for(let e=0;e<16;++e){r[e]=this._inv_s[r[e]];r[e]^=t[e]}return r}_encrypt(e,t){const i=this._s;let a,s,r;const n=new Uint8Array(16);n.set(e);for(let e=0;e<16;++e)n[e]^=t[e];for(let e=1;e=a;--i)if(e[i]!==t){t=0;break}g-=t;r[r.length-1]=e.subarray(0,16-t)}}const o=new Uint8Array(g);for(let e=0,t=0,i=r.length;e=256&&(g=255&(27^g))}for(let t=0;t<4;++t){i[e]=a^=i[e-32];e++;i[e]=s^=i[e-32];e++;i[e]=r^=i[e-32];e++;i[e]=n^=i[e-32];e++}}return i}}class PDF17{checkOwnerPassword(e,t,i,a){const s=new Uint8Array(e.length+56);s.set(e,0);s.set(t,e.length);s.set(i,e.length+t.length);return isArrayEqual(Ts(s,0,s.length),a)}checkUserPassword(e,t,i){const a=new Uint8Array(e.length+8);a.set(e,0);a.set(t,e.length);return isArrayEqual(Ts(a,0,a.length),i)}getOwnerKey(e,t,i,a){const s=new Uint8Array(e.length+56);s.set(e,0);s.set(t,e.length);s.set(i,e.length+t.length);const r=Ts(s,0,s.length);return new AES256Cipher(r).decryptBlock(a,!1,new Uint8Array(16))}getUserKey(e,t,i){const a=new Uint8Array(e.length+8);a.set(e,0);a.set(t,e.length);const s=Ts(a,0,a.length);return new AES256Cipher(s).decryptBlock(i,!1,new Uint8Array(16))}}class PDF20{_hash(e,t,i){let a=Ts(t,0,t.length).subarray(0,32),s=[0],r=0;for(;r<64||s.at(-1)>r-32;){const t=e.length+a.length+i.length,c=new Uint8Array(t);let C=0;c.set(e,C);C+=e.length;c.set(a,C);C+=a.length;c.set(i,C);const h=new Uint8Array(64*t);for(let e=0,i=0;e<64;e++,i+=t)h.set(c,i);s=new AES128Cipher(a.subarray(0,16)).encrypt(h,a.subarray(16,32));const l=s.slice(0,16).reduce(((e,t)=>e+t),0)%3;0===l?a=Ts(s,0,s.length):1===l?a=(n=s,g=0,o=s.length,qs(n,g,o,!0)):2===l&&(a=qs(s,0,s.length));r++}var n,g,o;return a.subarray(0,32)}checkOwnerPassword(e,t,i,a){const s=new Uint8Array(e.length+56);s.set(e,0);s.set(t,e.length);s.set(i,e.length+t.length);return isArrayEqual(this._hash(e,s,i),a)}checkUserPassword(e,t,i){const a=new Uint8Array(e.length+8);a.set(e,0);a.set(t,e.length);return isArrayEqual(this._hash(e,a,[]),i)}getOwnerKey(e,t,i,a){const s=new Uint8Array(e.length+56);s.set(e,0);s.set(t,e.length);s.set(i,e.length+t.length);const r=this._hash(e,s,i);return new AES256Cipher(r).decryptBlock(a,!1,new Uint8Array(16))}getUserKey(e,t,i){const a=new Uint8Array(e.length+8);a.set(e,0);a.set(t,e.length);const s=this._hash(e,a,[]);return new AES256Cipher(s).decryptBlock(i,!1,new Uint8Array(16))}}class CipherTransform{constructor(e,t){this.StringCipherConstructor=e;this.StreamCipherConstructor=t}createStream(e,t){const i=new this.StreamCipherConstructor;return new DecryptStream(e,t,(function cipherTransformDecryptStream(e,t){return i.decryptBlock(e,t)}))}decryptString(e){const t=new this.StringCipherConstructor;let i=stringToBytes(e);i=t.decryptBlock(i,!0);return bytesToString(i)}encryptString(e){const t=new this.StringCipherConstructor;if(t instanceof AESBaseCipher){const i=16-e.length%16;e+=String.fromCharCode(i).repeat(i);const a=new Uint8Array(16);if("undefined"!=typeof crypto)crypto.getRandomValues(a);else for(let e=0;e<16;e++)a[e]=Math.floor(256*Math.random());let s=stringToBytes(e);s=t.encrypt(s,a);const r=new Uint8Array(16+s.length);r.set(a);r.set(s,16);return bytesToString(r)}let i=stringToBytes(e);i=t.encrypt(i);return bytesToString(i)}}class CipherTransformFactory{static#k=new Uint8Array([40,191,78,94,78,117,138,65,100,0,78,86,255,250,1,8,46,46,0,182,208,104,62,128,47,12,169,254,100,83,105,122]);#R(e,t,i,a,s,r,n,g,o,c,C,h){if(t){const e=Math.min(127,t.length);t=t.subarray(0,e)}else t=[];const l=6===e?new PDF20:new PDF17;return l.checkUserPassword(t,g,n)?l.getUserKey(t,o,C):t.length&&l.checkOwnerPassword(t,a,r,i)?l.getOwnerKey(t,s,r,c):null}#N(e,t,i,a,s,r,n,g){const o=40+i.length+e.length,c=new Uint8Array(o);let C,h,l=0;if(t){h=Math.min(32,t.length);for(;l>8&255;c[l++]=s>>16&255;c[l++]=s>>>24&255;for(C=0,h=e.length;C=4&&!g){c[l++]=255;c[l++]=255;c[l++]=255;c[l++]=255}let Q=Ks(c,0,l);const E=n>>3;if(r>=3)for(C=0;C<50;++C)Q=Ks(Q,0,E);const u=Q.subarray(0,E);let d,f;if(r>=3){for(l=0;l<32;++l)c[l]=CipherTransformFactory.#k[l];for(C=0,h=e.length;C>3;if(i>=3)for(g=0;g<50;++g)o=Ks(o,0,o.length);let C,h;if(i>=3){h=t;const e=new Uint8Array(c);for(g=19;g>=0;g--){for(let t=0;t>8&255;s[n++]=e>>16&255;s[n++]=255&t;s[n++]=t>>8&255;if(a){s[n++]=115;s[n++]=65;s[n++]=108;s[n++]=84}return Ks(s,0,n).subarray(0,Math.min(i.length+5,16))}#U(e,t,i,a,s){if(!(t instanceof Name))throw new FormatError("Invalid crypt filter name.");const r=this,n=e.get(t.name),g=n?.get("CFM");if(!g||"None"===g.name)return function(){return new NullCipher};if("V2"===g.name)return function(){return new ARCFourCipher(r.#x(i,a,s,!1))};if("AESV2"===g.name)return function(){return new AES128Cipher(r.#x(i,a,s,!0))};if("AESV3"===g.name)return function(){return new AES256Cipher(s)};throw new FormatError("Unknown crypto method")}constructor(e,t,i){const a=e.get("Filter");if(!isName(a,"Standard"))throw new FormatError("unknown encryption method");this.filterName=a.name;this.dict=e;const s=e.get("V");if(!Number.isInteger(s)||1!==s&&2!==s&&4!==s&&5!==s)throw new FormatError("unsupported encryption algorithm");this.algorithm=s;let r=e.get("Length");if(!r)if(s<=3)r=40;else{const t=e.get("CF"),i=e.get("StmF");if(t instanceof Dict&&i instanceof Name){t.suppressEncryption=!0;const e=t.get(i.name);r=e?.get("Length")||128;r<40&&(r<<=3)}}if(!Number.isInteger(r)||r<40||r%8!=0)throw new FormatError("invalid key length");const n=stringToBytes(e.get("O")),g=stringToBytes(e.get("U")),o=n.subarray(0,32),c=g.subarray(0,32),C=e.get("P"),h=e.get("R"),l=(4===s||5===s)&&!1!==e.get("EncryptMetadata");this.encryptMetadata=l;const Q=stringToBytes(t);let E,u;if(i){if(6===h)try{i=utf8StringToString(i)}catch{warn("CipherTransformFactory: Unable to convert UTF8 encoded password.")}E=stringToBytes(i)}if(5!==s)u=this.#N(Q,E,o,c,C,h,r,l);else{const t=n.subarray(32,40),i=n.subarray(40,48),a=g.subarray(0,48),s=g.subarray(32,40),r=g.subarray(40,48),C=stringToBytes(e.get("OE")),l=stringToBytes(e.get("UE")),Q=stringToBytes(e.get("Perms"));u=this.#R(h,E,o,t,i,a,c,s,r,C,l,Q)}if(!u&&!i)throw new PasswordException("No password given",rt);if(!u&&i){const e=this.#G(E,o,h,r);u=this.#N(Q,e,o,c,C,h,r,l)}if(!u)throw new PasswordException("Incorrect Password",nt);this.encryptionKey=u;if(s>=4){const t=e.get("CF");t instanceof Dict&&(t.suppressEncryption=!0);this.cf=t;this.stmf=e.get("StmF")||Name.get("Identity");this.strf=e.get("StrF")||Name.get("Identity");this.eff=e.get("EFF")||this.stmf}}createCipherTransform(e,t){if(4===this.algorithm||5===this.algorithm)return new CipherTransform(this.#U(this.cf,this.strf,e,t,this.encryptionKey),this.#U(this.cf,this.stmf,e,t,this.encryptionKey));const i=this.#x(e,t,this.encryptionKey,!1),cipherConstructor=function(){return new ARCFourCipher(i)};return new CipherTransform(cipherConstructor,cipherConstructor)}}async function writeObject(e,t,i,{encrypt:a=null}){const s=a?.createCipherTransform(e.num,e.gen);i.push(`${e.num} ${e.gen} obj\n`);t instanceof Dict?await writeDict(t,i,s):t instanceof BaseStream?await writeStream(t,i,s):(Array.isArray(t)||ArrayBuffer.isView(t))&&await writeArray(t,i,s);i.push("\nendobj\n")}async function writeDict(e,t,i){t.push("<<");for(const a of e.getKeys()){t.push(` /${escapePDFName(a)} `);await writeValue(e.getRaw(a),t,i)}t.push(">>")}async function writeStream(e,t,i){let a=e.getBytes();const{dict:s}=e,[r,n]=await Promise.all([s.getAsync("Filter"),s.getAsync("DecodeParms")]),g=isName(Array.isArray(r)?await s.xref.fetchIfRefAsync(r[0]):r,"FlateDecode");if(a.length>=256||g)try{const e=new CompressionStream("deflate"),t=e.writable.getWriter();t.write(a);t.close();const i=await new Response(e.readable).arrayBuffer();a=new Uint8Array(i);let o,c;if(r){if(!g){o=Array.isArray(r)?[Name.get("FlateDecode"),...r]:[Name.get("FlateDecode"),r];n&&(c=Array.isArray(n)?[null,...n]:[null,n])}}else o=Name.get("FlateDecode");o&&s.set("Filter",o);c&&s.set("DecodeParms",c)}catch(e){info(`writeStream - cannot compress data: "${e}".`)}let o=bytesToString(a);i&&(o=i.encryptString(o));s.set("Length",o.length);await writeDict(s,t,i);t.push(" stream\n",o,"\nendstream")}async function writeArray(e,t,i){t.push("[");let a=!0;for(const s of e){a?a=!1:t.push(" ");await writeValue(s,t,i)}t.push("]")}async function writeValue(e,t,i){if(e instanceof Name)t.push(`/${escapePDFName(e.name)}`);else if(e instanceof Ref)t.push(`${e.num} ${e.gen} R`);else if(Array.isArray(e)||ArrayBuffer.isView(e))await writeArray(e,t,i);else if("string"==typeof e){i&&(e=i.encryptString(e));t.push(`(${escapeString(e)})`)}else"number"==typeof e?t.push(numberToString(e)):"boolean"==typeof e?t.push(e.toString()):e instanceof Dict?await writeDict(e,t,i):e instanceof BaseStream?await writeStream(e,t,i):null===e?t.push("null"):warn(`Unhandled value in writer: ${typeof e}, please file a bug.`)}function writeInt(e,t,i,a){for(let s=t+i-1;s>i-1;s--){a[s]=255&e;e>>=8}return i+t}function writeString(e,t,i){for(let a=0,s=e.length;a1&&(r=i.documentElement.searchNode([s.at(-1)],0));r?r.childNodes=Array.isArray(a)?a.map((e=>new SimpleDOMNode("value",e))):[new SimpleDOMNode("#text",a)]:warn(`Node not found for path: ${t}`)}const a=[];i.documentElement.dump(a);return a.join("")}(a.fetchIfRef(t).getString(),i)}const s=a.encrypt;if(s){e=s.createCipherTransform(t.num,t.gen).encryptString(e)}const r=`${t.num} ${t.gen} obj\n<< /Type /EmbeddedFile /Length ${e.length}>>\nstream\n`+e+"\nendstream\nendobj\n";i.push({ref:t,data:r})}function getIndexes(e){const t=[];for(const{ref:i}of e)i.num===t.at(-2)+t.at(-1)?t[t.length-1]+=1:t.push(i.num,1);return t}function computeIDs(e,t,i){if(Array.isArray(t.fileIds)&&t.fileIds.length>0){const a=function computeMD5(e,t){const i=Math.floor(Date.now()/1e3),a=t.filename||"",s=[i.toString(),a,e.toString()];let r=s.reduce(((e,t)=>e+t.length),0);for(const e of Object.values(t.info)){s.push(e);r+=e.length}const n=new Uint8Array(r);let g=0;for(const e of s){writeString(e,g,n);g+=e.length}return bytesToString(Ks(n))}(e,t);i.set("ID",[t.fileIds[0],a])}}async function incrementalUpdate({originalData:e,xrefInfo:t,newRefs:i,xref:a=null,hasXfa:s=!1,xfaDatasetsRef:r=null,hasXfaDatasetsEntry:n=!1,needAppearances:g,acroFormRef:o=null,acroForm:c=null,xfaData:C=null,useXrefStream:h=!1}){await async function updateAcroform({xref:e,acroForm:t,acroFormRef:i,hasXfa:a,hasXfaDatasetsEntry:s,xfaDatasetsRef:r,needAppearances:n,newRefs:g}){!a||s||r||warn("XFA - Cannot save it");if(!n&&(!a||!r||s))return;const o=t.clone();if(a&&!s){const e=t.get("XFA").slice();e.splice(2,0,"datasets");e.splice(3,0,r);o.set("XFA",e)}n&&o.set("NeedAppearances",!0);const c=[];await writeObject(i,o,c,e);g.push({ref:i,data:c.join("")})}({xref:a,acroForm:c,acroFormRef:o,hasXfa:s,hasXfaDatasetsEntry:n,xfaDatasetsRef:r,needAppearances:g,newRefs:i});s&&updateXFA({xfaData:C,xfaDatasetsRef:r,newRefs:i,xref:a});const l=[];let Q=e.length;const E=e.at(-1);if(10!==E&&13!==E){l.push("\n");Q+=1}const u=function getTrailerDict(e,t,i){const a=new Dict(null);a.set("Prev",e.startXRef);const s=e.newRef;if(i){t.push({ref:s,data:""});a.set("Size",s.num+1);a.set("Type",Name.get("XRef"))}else a.set("Size",s.num);null!==e.rootRef&&a.set("Root",e.rootRef);null!==e.infoRef&&a.set("Info",e.infoRef);null!==e.encryptRef&&a.set("Encrypt",e.encryptRef);return a}(t,i,h);i=i.sort(((e,t)=>e.ref.num-t.ref.num));for(const{data:e}of i)null!==e&&l.push(e);await(h?async function getXRefStreamTable(e,t,i,a,s){const r=[];let n=0,g=0;for(const{ref:e,data:a}of i){let i;n=Math.max(n,t);if(null!==a){i=Math.min(e.gen,65535);r.push([1,t,i]);t+=a.length}else{i=Math.min(e.gen+1,65535);r.push([0,0,i])}g=Math.max(g,i)}a.set("Index",getIndexes(i));const o=[1,getSizeInBytes(n),getSizeInBytes(g)];a.set("W",o);computeIDs(t,e,a);const c=o.reduce(((e,t)=>e+t),0),C=new Uint8Array(c*r.length),h=new Stream(C);h.dict=a;let l=0;for(const[e,t,i]of r){l=writeInt(e,o[0],l,C);l=writeInt(t,o[1],l,C);l=writeInt(i,o[2],l,C)}await writeObject(e.newRef,h,s,{});s.push("startxref\n",t.toString(),"\n%%EOF\n")}(t,Q,i,u,l):async function getXRefTable(e,t,i,a,s){s.push("xref\n");const r=getIndexes(i);let n=0;for(const{ref:e,data:a}of i){if(e.num===r[n]){s.push(`${r[n]} ${r[n+1]}\n`);n+=2}if(null!==a){s.push(`${t.toString().padStart(10,"0")} ${Math.min(e.gen,65535).toString().padStart(5,"0")} n\r\n`);t+=a.length}else s.push(`0000000000 ${Math.min(e.gen+1,65535).toString().padStart(5,"0")} f\r\n`)}computeIDs(t,e,a);s.push("trailer\n");await writeDict(a,s);s.push("\nstartxref\n",t.toString(),"\n%%EOF\n")}(t,Q,i,u,l));const d=l.reduce(((e,t)=>e+t.length),e.length),f=new Uint8Array(d);f.set(e);let p=e.length;for(const e of l){writeString(e,p,f);p+=e.length}return f}const Os=1,Ws=2,js=3,Xs=4,Zs=5;class StructTreeRoot{constructor(e,t){this.dict=e;this.ref=t instanceof Ref?t:null;this.roleMap=new Map;this.structParentIds=null}init(){this.readRoleMap()}#M(e,t,i){if(!(e instanceof Ref)||t<0)return;this.structParentIds||=new RefSetCache;let a=this.structParentIds.get(e);if(!a){a=[];this.structParentIds.put(e,a)}a.push([t,i])}addAnnotationIdToPage(e,t){this.#M(e,t,Xs)}readRoleMap(){const e=this.dict.get("RoleMap");e instanceof Dict&&e.forEach(((e,t)=>{t instanceof Name&&this.roleMap.set(e,t.name)}))}static async canCreateStructureTree({catalogRef:e,pdfManager:t,newAnnotationsByPage:i}){if(!(e instanceof Ref)){warn("Cannot save the struct tree: no catalog reference.");return!1}let a=0,s=!0;for(const[e,r]of i){const{ref:i}=await t.getPage(e);if(!(i instanceof Ref)){warn(`Cannot save the struct tree: page ${e} has no ref.`);s=!0;break}for(const e of r)if(e.accessibilityData?.type){e.parentTreeId=a++;s=!1}}if(s){for(const e of i.values())for(const t of e)delete t.parentTreeId;return!1}return!0}static async createStructureTree({newAnnotationsByPage:e,xref:t,catalogRef:i,pdfManager:a,newRefs:s}){const r=a.catalog.cloneDict(),n=new RefSetCache;n.put(i,r);const g=t.getNewTemporaryRef();r.set("StructTreeRoot",g);const o=new Dict(t);o.set("Type",Name.get("StructTreeRoot"));const c=t.getNewTemporaryRef();o.set("ParentTree",c);const C=[];o.set("K",C);n.put(g,o);const h=new Dict(t),l=[];h.set("Nums",l);const Q=await this.#L({newAnnotationsByPage:e,structTreeRootRef:g,structTreeRoot:null,kids:C,nums:l,xref:t,pdfManager:a,newRefs:s,cache:n});o.set("ParentTreeNextKey",Q);n.put(c,h);const E=[];for(const[e,i]of n.items()){E.length=0;await writeObject(e,i,E,t);s.push({ref:e,data:E.join("")})}}async canUpdateStructTree({pdfManager:e,xref:t,newAnnotationsByPage:i}){if(!this.ref){warn("Cannot update the struct tree: no root reference.");return!1}let a=this.dict.get("ParentTreeNextKey");if(!Number.isInteger(a)||a<0){warn("Cannot update the struct tree: invalid next key.");return!1}const s=this.dict.get("ParentTree");if(!(s instanceof Dict)){warn("Cannot update the struct tree: ParentTree isn't a dict.");return!1}const r=s.get("Nums");if(!Array.isArray(r)){warn("Cannot update the struct tree: nums isn't an array.");return!1}const n=new NumberTree(s,t);for(const t of i.keys()){const{pageDict:i}=await e.getPage(t);if(!i.has("StructParents"))continue;const a=i.get("StructParents");if(!Number.isInteger(a)||!Array.isArray(n.get(a))){warn(`Cannot save the struct tree: page ${t} has a wrong id.`);return!1}}let g=!0;for(const[t,s]of i){const{pageDict:i}=await e.getPage(t);StructTreeRoot.#H({elements:s,xref:this.dict.xref,pageDict:i,numberTree:n});for(const e of s)if(e.accessibilityData?.type){e.accessibilityData.structParent>=0||(e.parentTreeId=a++);g=!1}}if(g){for(const e of i.values())for(const t of e){delete t.parentTreeId;delete t.structTreeParent}return!1}return!0}async updateStructureTree({newAnnotationsByPage:e,pdfManager:t,newRefs:i}){const a=this.dict.xref,s=this.dict.clone(),r=this.ref,n=new RefSetCache;n.put(r,s);let g,o=s.getRaw("ParentTree");if(o instanceof Ref)g=a.fetch(o);else{g=o;o=a.getNewTemporaryRef();s.set("ParentTree",o)}g=g.clone();n.put(o,g);let c=g.getRaw("Nums"),C=null;if(c instanceof Ref){C=c;c=a.fetch(C)}c=c.slice();C||g.set("Nums",c);const h=await StructTreeRoot.#L({newAnnotationsByPage:e,structTreeRootRef:r,structTreeRoot:this,kids:null,nums:c,xref:a,pdfManager:t,newRefs:i,cache:n});if(-1===h)return;s.set("ParentTreeNextKey",h);C&&n.put(C,c);const l=[];for(const[e,t]of n.items()){l.length=0;await writeObject(e,t,l,a);i.push({ref:e,data:l.join("")})}}static async#L({newAnnotationsByPage:e,structTreeRootRef:t,structTreeRoot:i,kids:a,nums:s,xref:r,pdfManager:n,newRefs:g,cache:o}){const c=Name.get("OBJR");let C,h=-1;const l=[];for(const[Q,E]of e){const e=await n.getPage(Q),{ref:u}=e,d=u instanceof Ref;for(const{accessibilityData:n,ref:f,parentTreeId:p,structTreeParent:m}of E){if(!n?.type)continue;const{structParent:E}=n;if(i&&Number.isInteger(E)&&E>=0){let t=(C||=new Map).get(Q);if(void 0===t){t=new StructTreePage(i,e.pageDict).collectObjects(u);C.set(Q,t)}const a=t?.get(E);if(a){const e=r.fetch(a).clone();StructTreeRoot.#J(e,n);l.length=0;await writeObject(a,e,l,r);g.push({ref:a,data:l.join("")});continue}}h=Math.max(h,p);const y=r.getNewTemporaryRef(),w=new Dict(r);StructTreeRoot.#J(w,n);await this.#Y({structTreeParent:m,tagDict:w,newTagRef:y,structTreeRootRef:t,fallbackKids:a,xref:r,cache:o});const D=new Dict(r);w.set("K",D);D.set("Type",c);d&&D.set("Pg",u);D.set("Obj",f);o.put(y,w);s.push(p,y)}}return h+1}static#J(e,{type:t,title:i,lang:a,alt:s,expanded:r,actualText:n}){e.set("S",Name.get(t));i&&e.set("T",stringToAsciiOrUTF16BE(i));a&&e.set("Lang",stringToAsciiOrUTF16BE(a));s&&e.set("Alt",stringToAsciiOrUTF16BE(s));r&&e.set("E",stringToAsciiOrUTF16BE(r));n&&e.set("ActualText",stringToAsciiOrUTF16BE(n))}static#H({elements:e,xref:t,pageDict:i,numberTree:a}){const s=new Map;for(const t of e)if(t.structTreeParentId){const e=parseInt(t.structTreeParentId.split("_mc")[1],10);let i=s.get(e);if(!i){i=[];s.set(e,i)}i.push(t)}const r=i.get("StructParents");if(!Number.isInteger(r))return;const n=a.get(r),updateElement=(e,i,a)=>{const r=s.get(e);if(r){const e=i.getRaw("P"),s=t.fetchIfRef(e);if(e instanceof Ref&&s instanceof Dict){const e={ref:a,dict:i};for(const t of r)t.structTreeParent=e}return!0}return!1};for(const e of n){if(!(e instanceof Ref))continue;const i=t.fetch(e),a=i.get("K");if(Number.isInteger(a))updateElement(a,i,e);else if(Array.isArray(a))for(let s of a){s=t.fetchIfRef(s);if(Number.isInteger(s)&&updateElement(s,i,e))break;if(!(s instanceof Dict))continue;if(!isName(s.get("Type"),"MCR"))break;const a=s.get("MCID");if(Number.isInteger(a)&&updateElement(a,i,e))break}}}static async#Y({structTreeParent:e,tagDict:t,newTagRef:i,structTreeRootRef:a,fallbackKids:s,xref:r,cache:n}){let g,o=null;if(e){({ref:o}=e);g=e.dict.getRaw("P")||a}else g=a;t.set("P",g);const c=r.fetchIfRef(g);if(!c){s.push(i);return}let C=n.get(g);if(!C){C=c.clone();n.put(g,C)}const h=C.getRaw("K");let l=h instanceof Ref?n.get(h):null;if(!l){l=r.fetchIfRef(h);l=Array.isArray(l)?l.slice():[h];const e=r.getNewTemporaryRef();C.set("K",e);n.put(e,l)}const Q=l.indexOf(o);l.splice(Q>=0?Q+1:l.length,0,i)}}class StructElementNode{constructor(e,t){this.tree=e;this.dict=t;this.kids=[];this.parseKids()}get role(){const e=this.dict.get("S"),t=e instanceof Name?e.name:"",{root:i}=this.tree;return i.roleMap.has(t)?i.roleMap.get(t):t}parseKids(){let e=null;const t=this.dict.getRaw("Pg");t instanceof Ref&&(e=t.toString());const i=this.dict.get("K");if(Array.isArray(i))for(const t of i){const i=this.parseKid(e,t);i&&this.kids.push(i)}else{const t=this.parseKid(e,i);t&&this.kids.push(t)}}parseKid(e,t){if(Number.isInteger(t))return this.tree.pageDict.objId!==e?null:new StructElement({type:Os,mcid:t,pageObjId:e});let i=null;t instanceof Ref?i=this.dict.xref.fetch(t):t instanceof Dict&&(i=t);if(!i)return null;const a=i.getRaw("Pg");a instanceof Ref&&(e=a.toString());const s=i.get("Type")instanceof Name?i.get("Type").name:null;if("MCR"===s){if(this.tree.pageDict.objId!==e)return null;const t=i.getRaw("Stm");return new StructElement({type:Ws,refObjId:t instanceof Ref?t.toString():null,pageObjId:e,mcid:i.get("MCID")})}if("OBJR"===s){if(this.tree.pageDict.objId!==e)return null;const t=i.getRaw("Obj");return new StructElement({type:js,refObjId:t instanceof Ref?t.toString():null,pageObjId:e})}return new StructElement({type:Zs,dict:i})}}class StructElement{constructor({type:e,dict:t=null,mcid:i=null,pageObjId:a=null,refObjId:s=null}){this.type=e;this.dict=t;this.mcid=i;this.pageObjId=a;this.refObjId=s;this.parentNode=null}}class StructTreePage{constructor(e,t){this.root=e;this.rootDict=e?e.dict:null;this.pageDict=t;this.nodes=[]}collectObjects(e){if(!(this.root&&this.rootDict&&e instanceof Ref))return null;const t=this.rootDict.get("ParentTree");if(!t)return null;const i=this.root.structParentIds?.get(e);if(!i)return null;const a=new Map,s=new NumberTree(t,this.rootDict.xref);for(const[e]of i){const t=s.getRaw(e);t instanceof Ref&&a.set(e,t)}return a}parse(e){if(!(this.root&&this.rootDict&&e instanceof Ref))return;const t=this.rootDict.get("ParentTree");if(!t)return;const i=this.pageDict.get("StructParents"),a=this.root.structParentIds?.get(e);if(!Number.isInteger(i)&&!a)return;const s=new Map,r=new NumberTree(t,this.rootDict.xref);if(Number.isInteger(i)){const e=r.get(i);if(Array.isArray(e))for(const t of e)t instanceof Ref&&this.addNode(this.rootDict.xref.fetch(t),s)}if(a)for(const[e,t]of a){const i=r.get(e);if(i){const e=this.addNode(this.rootDict.xref.fetchIfRef(i),s);1===e?.kids?.length&&e.kids[0].type===js&&(e.kids[0].type=t)}}}addNode(e,t,i=0){if(i>40){warn("StructTree MAX_DEPTH reached.");return null}if(!(e instanceof Dict))return null;if(t.has(e))return t.get(e);const a=new StructElementNode(this,e);t.set(e,a);const s=e.get("P");if(!s||isName(s.get("Type"),"StructTreeRoot")){this.addTopLevelNode(e,a)||t.delete(e);return a}const r=this.addNode(s,t,i+1);if(!r)return a;let n=!1;for(const t of r.kids)if(t.type===Zs&&t.dict===e){t.parentNode=a;n=!0}n||t.delete(e);return a}addTopLevelNode(e,t){const i=this.rootDict.get("K");if(!i)return!1;if(i instanceof Dict){if(i.objId!==e.objId)return!1;this.nodes[0]=t;return!0}if(!Array.isArray(i))return!0;let a=!1;for(let s=0;s40){warn("StructTree too deep to be fully serialized.");return}const a=Object.create(null);a.role=e.role;a.children=[];t.children.push(a);let s=e.dict.get("Alt");"string"!=typeof s&&(s=e.dict.get("ActualText"));"string"==typeof s&&(a.alt=stringToPDFString(s));const r=e.dict.get("A");if(r instanceof Dict){const e=lookupNormalRect(r.getArray("BBox"),null);if(e)a.bbox=e;else{const e=r.get("Width"),t=r.get("Height");"number"==typeof e&&e>0&&"number"==typeof t&&t>0&&(a.bbox=[0,0,e,t])}}const n=e.dict.get("Lang");"string"==typeof n&&(a.lang=stringToPDFString(n));for(const t of e.kids){const e=t.type===Zs?t.parentNode:null;e?nodeToSerializable(e,a,i+1):t.type===Os||t.type===Ws?a.children.push({type:"content",id:`p${t.pageObjId}_mc${t.mcid}`}):t.type===js?a.children.push({type:"object",id:t.refObjId}):t.type===Xs&&a.children.push({type:"annotation",id:`pdfjs_internal_id_${t.refObjId}`})}}const e=Object.create(null);e.children=[];e.role="Root";for(const t of this.nodes)t&&nodeToSerializable(t,e);return e}}function isValidExplicitDest(e){if(!Array.isArray(e)||e.length<2)return!1;const[t,i,...a]=e;if(!(t instanceof Ref||Number.isInteger(t)))return!1;if(!(i instanceof Name))return!1;const s=a.length;let r=!0;switch(i.name){case"XYZ":if(s<2||s>3)return!1;break;case"Fit":case"FitB":return 0===s;case"FitH":case"FitBH":case"FitV":case"FitBV":if(s>1)return!1;break;case"FitR":if(4!==s)return!1;r=!1;break;default:return!1}for(const e of a)if(!("number"==typeof e||r&&null===e))return!1;return!0}function fetchDest(e){e instanceof Dict&&(e=e.get("D"));return isValidExplicitDest(e)?e:null}function fetchRemoteDest(e){let t=e.get("D");if(t){t instanceof Name&&(t=t.name);if("string"==typeof t)return stringToPDFString(t);if(isValidExplicitDest(t))return JSON.stringify(t)}return null}class Catalog{constructor(e,t){this.pdfManager=e;this.xref=t;this._catDict=t.getCatalogObj();if(!(this._catDict instanceof Dict))throw new FormatError("Catalog object is not a dictionary.");this.toplevelPagesDict;this._actualNumPages=null;this.fontCache=new RefSetCache;this.builtInCMapCache=new Map;this.standardFontDataCache=new Map;this.globalImageCache=new GlobalImageCache;this.pageKidsCountCache=new RefSetCache;this.pageIndexCache=new RefSetCache;this.pageDictCache=new RefSetCache;this.nonBlendModesSet=new RefSet;this.systemFontCache=new Map}cloneDict(){return this._catDict.clone()}get version(){const e=this._catDict.get("Version");if(e instanceof Name){if(kt.test(e.name))return shadow(this,"version",e.name);warn(`Invalid PDF catalog version: ${e.name}`)}return shadow(this,"version",null)}get lang(){const e=this._catDict.get("Lang");return shadow(this,"lang",e&&"string"==typeof e?stringToPDFString(e):null)}get needsRendering(){const e=this._catDict.get("NeedsRendering");return shadow(this,"needsRendering","boolean"==typeof e&&e)}get collection(){let e=null;try{const t=this._catDict.get("Collection");t instanceof Dict&&t.size>0&&(e=t)}catch(e){if(e instanceof MissingDataException)throw e;info("Cannot fetch Collection entry; assuming no collection is present.")}return shadow(this,"collection",e)}get acroForm(){let e=null;try{const t=this._catDict.get("AcroForm");t instanceof Dict&&t.size>0&&(e=t)}catch(e){if(e instanceof MissingDataException)throw e;info("Cannot fetch AcroForm entry; assuming no forms are present.")}return shadow(this,"acroForm",e)}get acroFormRef(){const e=this._catDict.getRaw("AcroForm");return shadow(this,"acroFormRef",e instanceof Ref?e:null)}get metadata(){const e=this._catDict.getRaw("Metadata");if(!(e instanceof Ref))return shadow(this,"metadata",null);let t=null;try{const i=this.xref.fetch(e,!this.xref.encrypt?.encryptMetadata);if(i instanceof BaseStream&&i.dict instanceof Dict){const e=i.dict.get("Type"),a=i.dict.get("Subtype");if(isName(e,"Metadata")&&isName(a,"XML")){const e=stringToUTF8String(i.getString());e&&(t=new MetadataParser(e).serializable)}}}catch(e){if(e instanceof MissingDataException)throw e;info(`Skipping invalid Metadata: "${e}".`)}return shadow(this,"metadata",t)}get markInfo(){let e=null;try{e=this._readMarkInfo()}catch(e){if(e instanceof MissingDataException)throw e;warn("Unable to read mark info.")}return shadow(this,"markInfo",e)}_readMarkInfo(){const e=this._catDict.get("MarkInfo");if(!(e instanceof Dict))return null;const t={Marked:!1,UserProperties:!1,Suspects:!1};for(const i in t){const a=e.get(i);"boolean"==typeof a&&(t[i]=a)}return t}get structTreeRoot(){let e=null;try{e=this._readStructTreeRoot()}catch(e){if(e instanceof MissingDataException)throw e;warn("Unable read to structTreeRoot info.")}return shadow(this,"structTreeRoot",e)}_readStructTreeRoot(){const e=this._catDict.getRaw("StructTreeRoot"),t=this.xref.fetchIfRef(e);if(!(t instanceof Dict))return null;const i=new StructTreeRoot(t,e);i.init();return i}get toplevelPagesDict(){const e=this._catDict.get("Pages");if(!(e instanceof Dict))throw new FormatError("Invalid top-level pages dictionary.");return shadow(this,"toplevelPagesDict",e)}get documentOutline(){let e=null;try{e=this._readDocumentOutline()}catch(e){if(e instanceof MissingDataException)throw e;warn("Unable to read document outline.")}return shadow(this,"documentOutline",e)}_readDocumentOutline(){let e=this._catDict.get("Outlines");if(!(e instanceof Dict))return null;e=e.getRaw("First");if(!(e instanceof Ref))return null;const t={items:[]},i=[{obj:e,parent:t}],a=new RefSet;a.put(e);const s=this.xref,r=new Uint8ClampedArray(3);for(;i.length>0;){const t=i.shift(),n=s.fetchIfRef(t.obj);if(null===n)continue;n.has("Title")||warn("Invalid outline item encountered.");const g={url:null,dest:null,action:null};Catalog.parseDestDictionary({destDict:n,resultObj:g,docBaseUrl:this.baseUrl,docAttachments:this.attachments});const o=n.get("Title"),c=n.get("F")||0,C=n.getArray("C"),h=n.get("Count");let l=r;!isNumberArray(C,3)||0===C[0]&&0===C[1]&&0===C[2]||(l=ColorSpace.singletons.rgb.getRgb(C,0));const Q={action:g.action,attachment:g.attachment,dest:g.dest,url:g.url,unsafeUrl:g.unsafeUrl,newWindow:g.newWindow,setOCGState:g.setOCGState,title:"string"==typeof o?stringToPDFString(o):"",color:l,count:Number.isInteger(h)?h:void 0,bold:!!(2&c),italic:!!(1&c),items:[]};t.parent.items.push(Q);e=n.getRaw("First");if(e instanceof Ref&&!a.has(e)){i.push({obj:e,parent:Q});a.put(e)}e=n.getRaw("Next");if(e instanceof Ref&&!a.has(e)){i.push({obj:e,parent:t.parent});a.put(e)}}return t.items.length>0?t.items:null}get permissions(){let e=null;try{e=this._readPermissions()}catch(e){if(e instanceof MissingDataException)throw e;warn("Unable to read permissions.")}return shadow(this,"permissions",e)}_readPermissions(){const e=this.xref.trailer.get("Encrypt");if(!(e instanceof Dict))return null;let t=e.get("P");if("number"!=typeof t)return null;t+=2**32;const i=[];for(const e in y){const a=y[e];t&a&&i.push(a)}return i}get optionalContentConfig(){let e=null;try{const t=this._catDict.get("OCProperties");if(!t)return shadow(this,"optionalContentConfig",null);const i=t.get("D");if(!i)return shadow(this,"optionalContentConfig",null);const a=t.get("OCGs");if(!Array.isArray(a))return shadow(this,"optionalContentConfig",null);const s=[],r=new RefSet;for(const e of a)if(e instanceof Ref&&!r.has(e)){r.put(e);s.push(this.#v(e))}e=this.#K(i,r);e.groups=s}catch(e){if(e instanceof MissingDataException)throw e;warn(`Unable to read optional content config: ${e}`)}return shadow(this,"optionalContentConfig",e)}#v(e){const t=this.xref.fetch(e),i={id:e.toString(),name:null,intent:null,usage:{print:null,view:null}},a=t.get("Name");"string"==typeof a&&(i.name=stringToPDFString(a));let s=t.getArray("Intent");Array.isArray(s)||(s=[s]);s.every((e=>e instanceof Name))&&(i.intent=s.map((e=>e.name)));const r=t.get("Usage");if(!(r instanceof Dict))return i;const n=i.usage,g=r.get("Print");if(g instanceof Dict){const e=g.get("PrintState");if(e instanceof Name)switch(e.name){case"ON":case"OFF":n.print={printState:e.name}}}const o=r.get("View");if(o instanceof Dict){const e=o.get("ViewState");if(e instanceof Name)switch(e.name){case"ON":case"OFF":n.view={viewState:e.name}}}return i}#K(e,t){function parseOnOff(e){const i=[];if(Array.isArray(e))for(const a of e)a instanceof Ref&&t.has(a)&&i.push(a.toString());return i}function parseOrder(e,i=0){if(!Array.isArray(e))return null;const s=[];for(const r of e){if(r instanceof Ref&&t.has(r)){a.put(r);s.push(r.toString());continue}const e=parseNestedOrder(r,i);e&&s.push(e)}if(i>0)return s;const r=[];for(const e of t)a.has(e)||r.push(e.toString());r.length&&s.push({name:null,order:r});return s}function parseNestedOrder(e,t){if(++t>s){warn("parseNestedOrder - reached MAX_NESTED_LEVELS.");return null}const a=i.fetchIfRef(e);if(!Array.isArray(a))return null;const r=i.fetchIfRef(a[0]);if("string"!=typeof r)return null;const n=parseOrder(a.slice(1),t);return n&&n.length?{name:stringToPDFString(r),order:n}:null}const i=this.xref,a=new RefSet,s=10;return{name:"string"==typeof e.get("Name")?stringToPDFString(e.get("Name")):null,creator:"string"==typeof e.get("Creator")?stringToPDFString(e.get("Creator")):null,baseState:e.get("BaseState")instanceof Name?e.get("BaseState").name:null,on:parseOnOff(e.get("ON")),off:parseOnOff(e.get("OFF")),order:parseOrder(e.get("Order")),groups:null}}setActualNumPages(e=null){this._actualNumPages=e}get hasActualNumPages(){return null!==this._actualNumPages}get _pagesCount(){const e=this.toplevelPagesDict.get("Count");if(!Number.isInteger(e))throw new FormatError("Page count in top-level pages dictionary is not an integer.");return shadow(this,"_pagesCount",e)}get numPages(){return this.hasActualNumPages?this._actualNumPages:this._pagesCount}get destinations(){const e=this._readDests(),t=Object.create(null);if(e instanceof NameTree)for(const[i,a]of e.getAll()){const e=fetchDest(a);e&&(t[stringToPDFString(i)]=e)}else e instanceof Dict&&e.forEach((function(e,i){const a=fetchDest(i);a&&(t[e]=a)}));return shadow(this,"destinations",t)}getDestination(e){const t=this._readDests();if(t instanceof NameTree){const i=fetchDest(t.get(e));if(i)return i;const a=this.destinations[e];if(a){warn(`Found "${e}" at an incorrect position in the NameTree.`);return a}}else if(t instanceof Dict){const i=fetchDest(t.get(e));if(i)return i}return null}_readDests(){const e=this._catDict.get("Names");return e?.has("Dests")?new NameTree(e.getRaw("Dests"),this.xref):this._catDict.has("Dests")?this._catDict.get("Dests"):void 0}get pageLabels(){let e=null;try{e=this._readPageLabels()}catch(e){if(e instanceof MissingDataException)throw e;warn("Unable to read page labels.")}return shadow(this,"pageLabels",e)}_readPageLabels(){const e=this._catDict.getRaw("PageLabels");if(!e)return null;const t=new Array(this.numPages);let i=null,a="";const s=new NumberTree(e,this.xref).getAll();let r="",n=1;for(let e=0,g=this.numPages;e=1))throw new FormatError("Invalid start in PageLabel dictionary.");n=e}else n=1}switch(i){case"D":r=n;break;case"R":case"r":r=toRomanNumerals(n,"r"===i);break;case"A":case"a":const e=26,t="a"===i?97:65,a=n-1;r=String.fromCharCode(t+a%e).repeat(Math.floor(a/e)+1);break;default:if(i)throw new FormatError(`Invalid style "${i}" in PageLabel dictionary.`);r=""}t[e]=a+r;n++}return t}get pageLayout(){const e=this._catDict.get("PageLayout");let t="";if(e instanceof Name)switch(e.name){case"SinglePage":case"OneColumn":case"TwoColumnLeft":case"TwoColumnRight":case"TwoPageLeft":case"TwoPageRight":t=e.name}return shadow(this,"pageLayout",t)}get pageMode(){const e=this._catDict.get("PageMode");let t="UseNone";if(e instanceof Name)switch(e.name){case"UseNone":case"UseOutlines":case"UseThumbs":case"FullScreen":case"UseOC":case"UseAttachments":t=e.name}return shadow(this,"pageMode",t)}get viewerPreferences(){const e=this._catDict.get("ViewerPreferences");if(!(e instanceof Dict))return shadow(this,"viewerPreferences",null);let t=null;for(const i of e.getKeys()){const a=e.get(i);let s;switch(i){case"HideToolbar":case"HideMenubar":case"HideWindowUI":case"FitWindow":case"CenterWindow":case"DisplayDocTitle":case"PickTrayByPDFSize":"boolean"==typeof a&&(s=a);break;case"NonFullScreenPageMode":if(a instanceof Name)switch(a.name){case"UseNone":case"UseOutlines":case"UseThumbs":case"UseOC":s=a.name;break;default:s="UseNone"}break;case"Direction":if(a instanceof Name)switch(a.name){case"L2R":case"R2L":s=a.name;break;default:s="L2R"}break;case"ViewArea":case"ViewClip":case"PrintArea":case"PrintClip":if(a instanceof Name)switch(a.name){case"MediaBox":case"CropBox":case"BleedBox":case"TrimBox":case"ArtBox":s=a.name;break;default:s="CropBox"}break;case"PrintScaling":if(a instanceof Name)switch(a.name){case"None":case"AppDefault":s=a.name;break;default:s="AppDefault"}break;case"Duplex":if(a instanceof Name)switch(a.name){case"Simplex":case"DuplexFlipShortEdge":case"DuplexFlipLongEdge":s=a.name;break;default:s="None"}break;case"PrintPageRange":if(Array.isArray(a)&&a.length%2==0){a.every(((e,t,i)=>Number.isInteger(e)&&e>0&&(0===t||e>=i[t-1])&&e<=this.numPages))&&(s=a)}break;case"NumCopies":Number.isInteger(a)&&a>0&&(s=a);break;default:warn(`Ignoring non-standard key in ViewerPreferences: ${i}.`);continue}if(void 0!==s){t||(t=Object.create(null));t[i]=s}else warn(`Bad value, for key "${i}", in ViewerPreferences: ${a}.`)}return shadow(this,"viewerPreferences",t)}get openAction(){const e=this._catDict.get("OpenAction"),t=Object.create(null);if(e instanceof Dict){const i=new Dict(this.xref);i.set("A",e);const a={url:null,dest:null,action:null};Catalog.parseDestDictionary({destDict:i,resultObj:a});Array.isArray(a.dest)?t.dest=a.dest:a.action&&(t.action=a.action)}else Array.isArray(e)&&(t.dest=e);return shadow(this,"openAction",objectSize(t)>0?t:null)}get attachments(){const e=this._catDict.get("Names");let t=null;if(e instanceof Dict&&e.has("EmbeddedFiles")){const i=new NameTree(e.getRaw("EmbeddedFiles"),this.xref);for(const[e,a]of i.getAll()){const i=new FileSpec(a,this.xref);t||(t=Object.create(null));t[stringToPDFString(e)]=i.serializable}}return shadow(this,"attachments",t)}get xfaImages(){const e=this._catDict.get("Names");let t=null;if(e instanceof Dict&&e.has("XFAImages")){const i=new NameTree(e.getRaw("XFAImages"),this.xref);for(const[e,a]of i.getAll()){t||(t=new Dict(this.xref));t.set(stringToPDFString(e),a)}}return shadow(this,"xfaImages",t)}_collectJavaScript(){const e=this._catDict.get("Names");let t=null;function appendIfJavaScriptDict(e,i){if(!(i instanceof Dict))return;if(!isName(i.get("S"),"JavaScript"))return;let a=i.get("JS");if(a instanceof BaseStream)a=a.getString();else if("string"!=typeof a)return;a=stringToPDFString(a).replaceAll("\0","");a&&(t||=new Map).set(e,a)}if(e instanceof Dict&&e.has("JavaScript")){const t=new NameTree(e.getRaw("JavaScript"),this.xref);for(const[e,i]of t.getAll())appendIfJavaScriptDict(stringToPDFString(e),i)}const i=this._catDict.get("OpenAction");i&&appendIfJavaScriptDict("OpenAction",i);return t}get jsActions(){const e=this._collectJavaScript();let t=collectActions(this.xref,this._catDict,fA);if(e){t||=Object.create(null);for(const[i,a]of e)i in t?t[i].push(a):t[i]=[a]}return shadow(this,"jsActions",t)}async fontFallback(e,t){const i=await Promise.all(this.fontCache);for(const a of i)if(a.loadedName===e){a.fallback(t);return}}async cleanup(e=!1){clearGlobalCaches();this.globalImageCache.clear(e);this.pageKidsCountCache.clear();this.pageIndexCache.clear();this.pageDictCache.clear();this.nonBlendModesSet.clear();const t=await Promise.all(this.fontCache);for(const{dict:e}of t)delete e.cacheKey;this.fontCache.clear();this.builtInCMapCache.clear();this.standardFontDataCache.clear();this.systemFontCache.clear()}async getPageDict(e){const t=[this.toplevelPagesDict],i=new RefSet,a=this._catDict.getRaw("Pages");a instanceof Ref&&i.put(a);const s=this.xref,r=this.pageKidsCountCache,n=this.pageIndexCache,g=this.pageDictCache;let o=0;for(;t.length;){const a=t.pop();if(a instanceof Ref){const c=r.get(a);if(c>=0&&o+c<=e){o+=c;continue}if(i.has(a))throw new FormatError("Pages tree contains circular reference.");i.put(a);const C=await(g.get(a)||s.fetchAsync(a));if(C instanceof Dict){let t=C.getRaw("Type");t instanceof Ref&&(t=await s.fetchAsync(t));if(isName(t,"Page")||!C.has("Kids")){r.has(a)||r.put(a,1);n.has(a)||n.put(a,o);if(o===e)return[C,a];o++;continue}}t.push(C);continue}if(!(a instanceof Dict))throw new FormatError("Page dictionary kid reference points to wrong type of object.");const{objId:c}=a;let C=a.getRaw("Count");C instanceof Ref&&(C=await s.fetchAsync(C));if(Number.isInteger(C)&&C>=0){c&&!r.has(c)&&r.put(c,C);if(o+C<=e){o+=C;continue}}let h=a.getRaw("Kids");h instanceof Ref&&(h=await s.fetchAsync(h));if(!Array.isArray(h)){let t=a.getRaw("Type");t instanceof Ref&&(t=await s.fetchAsync(t));if(isName(t,"Page")||!a.has("Kids")){if(o===e)return[a,null];o++;continue}throw new FormatError("Page dictionary kids object is not an array.")}for(let e=h.length-1;e>=0;e--){const i=h[e];t.push(i);a===this.toplevelPagesDict&&i instanceof Ref&&!g.has(i)&&g.put(i,s.fetchAsync(i))}}throw new Error(`Page index ${e} not found.`)}async getAllPageDicts(e=!1){const{ignoreErrors:t}=this.pdfManager.evaluatorOptions,i=[{currentNode:this.toplevelPagesDict,posInKids:0}],a=new RefSet,s=this._catDict.getRaw("Pages");s instanceof Ref&&a.put(s);const r=new Map,n=this.xref,g=this.pageIndexCache;let o=0;function addPageDict(e,t){t&&!g.has(t)&&g.put(t,o);r.set(o++,[e,t])}function addPageError(i){if(i instanceof XRefEntryException&&!e)throw i;if(e&&t&&0===o){warn(`getAllPageDicts - Skipping invalid first page: "${i}".`);i=Dict.empty}r.set(o++,[i,null])}for(;i.length>0;){const e=i.at(-1),{currentNode:t,posInKids:s}=e;let r=t.getRaw("Kids");if(r instanceof Ref)try{r=await n.fetchAsync(r)}catch(e){addPageError(e);break}if(!Array.isArray(r)){addPageError(new FormatError("Page dictionary kids object is not an array."));break}if(s>=r.length){i.pop();continue}const g=r[s];let o;if(g instanceof Ref){if(a.has(g)){addPageError(new FormatError("Pages tree contains circular reference."));break}a.put(g);try{o=await n.fetchAsync(g)}catch(e){addPageError(e);break}}else o=g;if(!(o instanceof Dict)){addPageError(new FormatError("Page dictionary kid reference points to wrong type of object."));break}let c=o.getRaw("Type");if(c instanceof Ref)try{c=await n.fetchAsync(c)}catch(e){addPageError(e);break}isName(c,"Page")||!o.has("Kids")?addPageDict(o,g instanceof Ref?g:null):i.push({currentNode:o,posInKids:0});e.posInKids++}return r}getPageIndex(e){const t=this.pageIndexCache.get(e);if(void 0!==t)return Promise.resolve(t);const i=this.xref;let a=0;const next=t=>function pagesBeforeRef(t){let a,s=0;return i.fetchAsync(t).then((function(i){if(isRefsEqual(t,e)&&!isDict(i,"Page")&&!(i instanceof Dict&&!i.has("Type")&&i.has("Contents")))throw new FormatError("The reference does not point to a /Page dictionary.");if(!i)return null;if(!(i instanceof Dict))throw new FormatError("Node must be a dictionary.");a=i.getRaw("Parent");return i.getAsync("Parent")})).then((function(e){if(!e)return null;if(!(e instanceof Dict))throw new FormatError("Parent must be a dictionary.");return e.getAsync("Kids")})).then((function(e){if(!e)return null;const r=[];let n=!1;for(const a of e){if(!(a instanceof Ref))throw new FormatError("Kid must be a reference.");if(isRefsEqual(a,t)){n=!0;break}r.push(i.fetchAsync(a).then((function(e){if(!(e instanceof Dict))throw new FormatError("Kid node must be a dictionary.");e.has("Count")?s+=e.get("Count"):s++})))}if(!n)throw new FormatError("Kid reference not found in parent's kids.");return Promise.all(r).then((function(){return[s,a]}))}))}(t).then((t=>{if(!t){this.pageIndexCache.put(e,a);return a}const[i,s]=t;a+=i;return next(s)}));return next(e)}get baseUrl(){const e=this._catDict.get("URI");if(e instanceof Dict){const t=e.get("Base");if("string"==typeof t){const e=createValidAbsoluteUrl(t,null,{tryConvertEncoding:!0});if(e)return shadow(this,"baseUrl",e.href)}}return shadow(this,"baseUrl",this.pdfManager.docBaseUrl)}static parseDestDictionary({destDict:e,resultObj:t,docBaseUrl:i=null,docAttachments:a=null}){if(!(e instanceof Dict)){warn("parseDestDictionary: `destDict` must be a dictionary.");return}let s,r,n=e.get("A");if(!(n instanceof Dict))if(e.has("Dest"))n=e.get("Dest");else{n=e.get("AA");n instanceof Dict&&(n.has("D")?n=n.get("D"):n.has("U")&&(n=n.get("U")))}if(n instanceof Dict){const e=n.get("S");if(!(e instanceof Name)){warn("parseDestDictionary: Invalid type in Action dictionary.");return}const i=e.name;switch(i){case"ResetForm":const e=n.get("Flags"),g=0==(1&("number"==typeof e?e:0)),o=[],c=[];for(const e of n.get("Fields")||[])e instanceof Ref?c.push(e.toString()):"string"==typeof e&&o.push(stringToPDFString(e));t.resetForm={fields:o,refs:c,include:g};break;case"URI":s=n.get("URI");s instanceof Name&&(s="/"+s.name);break;case"GoTo":r=n.get("D");break;case"Launch":case"GoToR":const C=n.get("F");if(C instanceof Dict){const e=new FileSpec(C,null,!0),{rawFilename:t}=e.serializable;s=t}else"string"==typeof C&&(s=C);const h=fetchRemoteDest(n);h&&"string"==typeof s&&(s=s.split("#",1)[0]+"#"+h);const l=n.get("NewWindow");"boolean"==typeof l&&(t.newWindow=l);break;case"GoToE":const Q=n.get("T");let E;if(a&&Q instanceof Dict){const e=Q.get("R"),t=Q.get("N");isName(e,"C")&&"string"==typeof t&&(E=a[stringToPDFString(t)])}if(E){t.attachment=E;const e=fetchRemoteDest(n);e&&(t.attachmentDest=e)}else warn('parseDestDictionary - unimplemented "GoToE" action.');break;case"Named":const u=n.get("N");u instanceof Name&&(t.action=u.name);break;case"SetOCGState":const d=n.get("State"),f=n.get("PreserveRB");if(!Array.isArray(d)||0===d.length)break;const p=[];for(const e of d)if(e instanceof Name)switch(e.name){case"ON":case"OFF":case"Toggle":p.push(e.name)}else e instanceof Ref&&p.push(e.toString());if(p.length!==d.length)break;t.setOCGState={state:p,preserveRB:"boolean"!=typeof f||f};break;case"JavaScript":const m=n.get("JS");let y;m instanceof BaseStream?y=m.getString():"string"==typeof m&&(y=m);const w=y&&recoverJsURL(stringToPDFString(y));if(w){s=w.url;t.newWindow=w.newWindow;break}default:if("JavaScript"===i||"SubmitForm"===i)break;warn(`parseDestDictionary - unsupported action: "${i}".`)}}else e.has("Dest")&&(r=e.get("Dest"));if("string"==typeof s){const e=createValidAbsoluteUrl(s,i,{addDefaultProtocol:!0,tryConvertEncoding:!0});e&&(t.url=e.href);t.unsafeUrl=s}if(r){r instanceof Name&&(r=r.name);"string"==typeof r?t.dest=stringToPDFString(r):isValidExplicitDest(r)&&(t.dest=r)}}}function addChildren(e,t){if(e instanceof Dict)e=e.getRawValues();else if(e instanceof BaseStream)e=e.dict.getRawValues();else if(!Array.isArray(e))return;for(const a of e)((i=a)instanceof Ref||i instanceof Dict||i instanceof BaseStream||Array.isArray(i))&&t.push(a);var i}class ObjectLoader{constructor(e,t,i){this.dict=e;this.keys=t;this.xref=i;this.refSet=null}async load(){if(this.xref.stream.isDataLoaded)return;const{keys:e,dict:t}=this;this.refSet=new RefSet;const i=[];for(const a of e){const e=t.getRaw(a);void 0!==e&&i.push(e)}return this._walk(i)}async _walk(e){const t=[],i=[];for(;e.length;){let a=e.pop();if(a instanceof Ref){if(this.refSet.has(a))continue;try{this.refSet.put(a);a=this.xref.fetch(a)}catch(e){if(!(e instanceof MissingDataException)){warn(`ObjectLoader._walk - requesting all data: "${e}".`);this.refSet=null;const{manager:t}=this.xref.stream;return t.requestAllChunks()}t.push(a);i.push({begin:e.begin,end:e.end})}}if(a instanceof BaseStream){const e=a.getBaseStreams();if(e){let s=!1;for(const t of e)if(!t.isDataLoaded){s=!0;i.push({begin:t.start,end:t.end})}s&&t.push(a)}}addChildren(a,e)}if(i.length){await this.xref.stream.manager.requestRanges(i);for(const e of t)e instanceof Ref&&this.refSet.remove(e);return this._walk(t)}this.refSet=null}}const Vs=Symbol(),zs=Symbol(),_s=Symbol(),$s=Symbol(),Ar=Symbol(),er=Symbol(),tr=Symbol(),ir=Symbol(),ar=Symbol(),sr=Symbol("content"),rr=Symbol("data"),nr=Symbol(),gr=Symbol("extra"),or=Symbol(),Ir=Symbol(),cr=Symbol(),Cr=Symbol(),hr=Symbol(),lr=Symbol(),Qr=Symbol(),Er=Symbol(),ur=Symbol(),dr=Symbol(),fr=Symbol(),pr=Symbol(),mr=Symbol(),yr=Symbol(),wr=Symbol(),Dr=Symbol(),br=Symbol(),Fr=Symbol(),Sr=Symbol(),kr=Symbol(),Rr=Symbol(),Nr=Symbol(),Gr=Symbol(),xr=Symbol(),Ur=Symbol(),Mr=Symbol(),Lr=Symbol(),Hr=Symbol(),Jr=Symbol(),Yr=Symbol(),vr=Symbol(),Kr=Symbol(),Tr=Symbol("namespaceId"),qr=Symbol("nodeName"),Or=Symbol(),Pr=Symbol(),Wr=Symbol(),jr=Symbol(),Xr=Symbol(),Zr=Symbol(),Vr=Symbol(),zr=Symbol(),_r=Symbol("root"),$r=Symbol(),An=Symbol(),en=Symbol(),tn=Symbol(),an=Symbol(),sn=Symbol(),rn=Symbol(),nn=Symbol(),gn=Symbol(),on=Symbol(),In=Symbol(),cn=Symbol("uid"),Cn=Symbol(),hn={config:{id:0,check:e=>e.startsWith("http://www.xfa.org/schema/xci/")},connectionSet:{id:1,check:e=>e.startsWith("http://www.xfa.org/schema/xfa-connection-set/")},datasets:{id:2,check:e=>e.startsWith("http://www.xfa.org/schema/xfa-data/")},form:{id:3,check:e=>e.startsWith("http://www.xfa.org/schema/xfa-form/")},localeSet:{id:4,check:e=>e.startsWith("http://www.xfa.org/schema/xfa-locale-set/")},pdf:{id:5,check:e=>"http://ns.adobe.com/xdp/pdf/"===e},signature:{id:6,check:e=>"http://www.w3.org/2000/09/xmldsig#"===e},sourceSet:{id:7,check:e=>e.startsWith("http://www.xfa.org/schema/xfa-source-set/")},stylesheet:{id:8,check:e=>"http://www.w3.org/1999/XSL/Transform"===e},template:{id:9,check:e=>e.startsWith("http://www.xfa.org/schema/xfa-template/")},xdc:{id:10,check:e=>e.startsWith("http://www.xfa.org/schema/xdc/")},xdp:{id:11,check:e=>"http://ns.adobe.com/xdp/"===e},xfdf:{id:12,check:e=>"http://ns.adobe.com/xfdf/"===e},xhtml:{id:13,check:e=>"http://www.w3.org/1999/xhtml"===e},xmpmeta:{id:14,check:e=>"http://ns.adobe.com/xmpmeta/"===e}},Bn={pt:e=>e,cm:e=>e/2.54*72,mm:e=>e/25.4*72,in:e=>72*e,px:e=>e},ln=/([+-]?\d+\.?\d*)(.*)/;function stripQuotes(e){return e.startsWith("'")||e.startsWith('"')?e.slice(1,-1):e}function getInteger({data:e,defaultValue:t,validate:i}){if(!e)return t;e=e.trim();const a=parseInt(e,10);return!isNaN(a)&&i(a)?a:t}function getFloat({data:e,defaultValue:t,validate:i}){if(!e)return t;e=e.trim();const a=parseFloat(e);return!isNaN(a)&&i(a)?a:t}function getKeyword({data:e,defaultValue:t,validate:i}){return e&&i(e=e.trim())?e:t}function getStringOption(e,t){return getKeyword({data:e,defaultValue:t[0],validate:e=>t.includes(e)})}function getMeasurement(e,t="0"){t||="0";if(!e)return getMeasurement(t);const i=e.trim().match(ln);if(!i)return getMeasurement(t);const[,a,s]=i,r=parseFloat(a);if(isNaN(r))return getMeasurement(t);if(0===r)return 0;const n=Bn[s];return n?n(r):r}function getRatio(e){if(!e)return{num:1,den:1};const t=e.trim().split(/\s*:\s*/).map((e=>parseFloat(e))).filter((e=>!isNaN(e)));1===t.length&&t.push(1);if(0===t.length)return{num:1,den:1};const[i,a]=t;return{num:i,den:a}}function getRelevant(e){return e?e.trim().split(/\s+/).map((e=>({excluded:"-"===e[0],viewname:e.substring(1)}))):[]}class HTMLResult{static get FAILURE(){return shadow(this,"FAILURE",new HTMLResult(!1,null,null,null))}static get EMPTY(){return shadow(this,"EMPTY",new HTMLResult(!0,null,null,null))}constructor(e,t,i,a){this.success=e;this.html=t;this.bbox=i;this.breakNode=a}isBreak(){return!!this.breakNode}static breakNode(e){return new HTMLResult(!1,null,null,e)}static success(e,t=null){return new HTMLResult(!0,e,t,null)}}class FontFinder{constructor(e){this.fonts=new Map;this.cache=new Map;this.warned=new Set;this.defaultFont=null;this.add(e)}add(e,t=null){for(const t of e)this.addPdfFont(t);for(const e of this.fonts.values())e.regular||(e.regular=e.italic||e.bold||e.bolditalic);if(!t||0===t.size)return;const i=this.fonts.get("PdfJS-Fallback-PdfJS-XFA");for(const e of t)this.fonts.set(e,i)}addPdfFont(e){const t=e.cssFontInfo,i=t.fontFamily;let a=this.fonts.get(i);if(!a){a=Object.create(null);this.fonts.set(i,a);this.defaultFont||(this.defaultFont=a)}let s="";const r=parseFloat(t.fontWeight);0!==parseFloat(t.italicAngle)?s=r>=700?"bolditalic":"italic":r>=700&&(s="bold");if(!s){(e.name.includes("Bold")||e.psName?.includes("Bold"))&&(s="bold");(e.name.includes("Italic")||e.name.endsWith("It")||e.psName?.includes("Italic")||e.psName?.endsWith("It"))&&(s+="italic")}s||(s="regular");a[s]=e}getDefault(){return this.defaultFont}find(e,t=!0){let i=this.fonts.get(e)||this.cache.get(e);if(i)return i;const a=/,|-|_| |bolditalic|bold|italic|regular|it/gi;let s=e.replaceAll(a,"");i=this.fonts.get(s);if(i){this.cache.set(e,i);return i}s=s.toLowerCase();const r=[];for(const[e,t]of this.fonts.entries())e.replaceAll(a,"").toLowerCase().startsWith(s)&&r.push(t);if(0===r.length)for(const[,e]of this.fonts.entries())e.regular.name?.replaceAll(a,"").toLowerCase().startsWith(s)&&r.push(e);if(0===r.length){s=s.replaceAll(/psmt|mt/gi,"");for(const[e,t]of this.fonts.entries())e.replaceAll(a,"").toLowerCase().startsWith(s)&&r.push(t)}if(0===r.length)for(const e of this.fonts.values())e.regular.name?.replaceAll(a,"").toLowerCase().startsWith(s)&&r.push(e);if(r.length>=1){1!==r.length&&t&&warn(`XFA - Too many choices to guess the correct font: ${e}`);this.cache.set(e,r[0]);return r[0]}if(t&&!this.warned.has(e)){this.warned.add(e);warn(`XFA - Cannot find the font: ${e}`)}return null}}function selectFont(e,t){return"italic"===e.posture?"bold"===e.weight?t.bolditalic:t.italic:"bold"===e.weight?t.bold:t.regular}class FontInfo{constructor(e,t,i,a){this.lineHeight=i;this.paraMargin=t||{top:0,bottom:0,left:0,right:0};if(!e){[this.pdfFont,this.xfaFont]=this.defaultFont(a);return}this.xfaFont={typeface:e.typeface,posture:e.posture,weight:e.weight,size:e.size,letterSpacing:e.letterSpacing};const s=a.find(e.typeface);if(s){this.pdfFont=selectFont(e,s);this.pdfFont||([this.pdfFont,this.xfaFont]=this.defaultFont(a))}else[this.pdfFont,this.xfaFont]=this.defaultFont(a)}defaultFont(e){const t=e.find("Helvetica",!1)||e.find("Myriad Pro",!1)||e.find("Arial",!1)||e.getDefault();if(t?.regular){const e=t.regular;return[e,{typeface:e.cssFontInfo.fontFamily,posture:"normal",weight:"normal",size:10,letterSpacing:0}]}return[null,{typeface:"Courier",posture:"normal",weight:"normal",size:10,letterSpacing:0}]}}class FontSelector{constructor(e,t,i,a){this.fontFinder=a;this.stack=[new FontInfo(e,t,i,a)]}pushData(e,t,i){const a=this.stack.at(-1);for(const t of["typeface","posture","weight","size","letterSpacing"])e[t]||(e[t]=a.xfaFont[t]);for(const e of["top","bottom","left","right"])isNaN(t[e])&&(t[e]=a.paraMargin[e]);const s=new FontInfo(e,t,i||a.lineHeight,this.fontFinder);s.pdfFont||(s.pdfFont=a.pdfFont);this.stack.push(s)}popFont(){this.stack.pop()}topFont(){return this.stack.at(-1)}}class TextMeasure{constructor(e,t,i,a){this.glyphs=[];this.fontSelector=new FontSelector(e,t,i,a);this.extraHeight=0}pushData(e,t,i){this.fontSelector.pushData(e,t,i)}popFont(e){return this.fontSelector.popFont()}addPara(){const e=this.fontSelector.topFont();this.extraHeight+=e.paraMargin.top+e.paraMargin.bottom}addString(e){if(!e)return;const t=this.fontSelector.topFont(),i=t.xfaFont.size;if(t.pdfFont){const a=t.xfaFont.letterSpacing,s=t.pdfFont,r=s.lineHeight||1.2,n=t.lineHeight||Math.max(1.2,r)*i,g=r-(void 0===s.lineGap?.2:s.lineGap),o=Math.max(1,g)*i,c=i/1e3,C=s.defaultWidth||s.charsToGlyphs(" ")[0].width;for(const t of e.split(/[\u2029\n]/)){const e=s.encodeString(t).join(""),i=s.charsToGlyphs(e);for(const e of i){const t=e.width||C;this.glyphs.push([t*c+a,n,o,e.unicode,!1])}this.glyphs.push([0,0,0,"\n",!0])}this.glyphs.pop()}else{for(const t of e.split(/[\u2029\n]/)){for(const e of t.split(""))this.glyphs.push([i,1.2*i,i,e,!1]);this.glyphs.push([0,0,0,"\n",!0])}this.glyphs.pop()}}compute(e){let t=-1,i=0,a=0,s=0,r=0,n=0,g=!1,o=!0;for(let c=0,C=this.glyphs.length;ce){a=Math.max(a,r);r=0;s+=n;n=d;t=-1;i=0;g=!0;o=!1}else{n=Math.max(d,n);i=r;r+=C;t=c}else if(r+C>e){s+=n;n=d;if(-1!==t){c=t;a=Math.max(a,i);r=0;t=-1;i=0}else{a=Math.max(a,r);r=C}g=!0;o=!1}else{r+=C;n=Math.max(d,n)}}a=Math.max(a,r);s+=n+this.extraHeight;return{width:1.02*a,height:s,isBroken:g}}}const Qn=/^[^.[]+/,En=/^[^\]]+/,un={dot:0,dotDot:1,dotHash:2,dotBracket:3,dotParen:4},dn=new Map([["$data",(e,t)=>e.datasets?e.datasets.data:e],["$record",(e,t)=>(e.datasets?e.datasets.data:e)[pr]()[0]],["$template",(e,t)=>e.template],["$connectionSet",(e,t)=>e.connectionSet],["$form",(e,t)=>e.form],["$layout",(e,t)=>e.layout],["$host",(e,t)=>e.host],["$dataWindow",(e,t)=>e.dataWindow],["$event",(e,t)=>e.event],["!",(e,t)=>e.datasets],["$xfa",(e,t)=>e],["xfa",(e,t)=>e],["$",(e,t)=>t]]),fn=new WeakMap;function parseExpression(e,t,i=!0){let a=e.match(Qn);if(!a)return null;let[s]=a;const r=[{name:s,cacheName:"."+s,index:0,js:null,formCalc:null,operator:un.dot}];let n=s.length;for(;n0&&C.push(e)}if(0!==C.length||g||0!==o)e=isFinite(c)?C.filter((e=>ce[c])):C.flat();else{const i=t[Dr]();if(!(t=i))return null;o=-1;e=[t]}}return 0===e.length?null:e}function createDataNode(e,t,i){const a=parseExpression(i);if(!a)return null;if(a.some((e=>e.operator===un.dotDot)))return null;const s=dn.get(a[0].name);let r=0;if(s){e=s(e,t);r=1}else e=t||e;for(let t=a.length;re[rn]())).join("")}get[yn](){const e=Object.getPrototypeOf(this);if(!e._attributes){const t=e._attributes=new Set;for(const e of Object.getOwnPropertyNames(this)){if(null===this[e]||this[e]instanceof XFAObject||this[e]instanceof XFAObjectArray)break;t.add(e)}}return shadow(this,yn,e._attributes)}[Mr](e){let t=this;for(;t;){if(t===e)return!0;t=t[Dr]()}return!1}[Dr](){return this[Un]}[wr](){return this[Dr]()}[pr](e=null){return e?this[e]:this[wn]}[nr](){const e=Object.create(null);this[sr]&&(e.$content=this[sr]);for(const t of Object.getOwnPropertyNames(this)){const i=this[t];null!==i&&(i instanceof XFAObject?e[t]=i[nr]():i instanceof XFAObjectArray?i.isEmpty()||(e[t]=i.dump()):e[t]=i)}return e}[In](){return null}[gn](){return HTMLResult.EMPTY}*[mr](){for(const e of this[pr]())yield e}*[Sn](e,t){for(const i of this[mr]())if(!e||t===e.has(i[qr])){const e=this[hr](),t=i[gn](e);t.success||(this[gr].failingNode=i);yield t}}[Ir](){return null}[zs](e,t){this[gr].children.push(e)}[hr](){}[$s]({filter:e=null,include:t=!0}){if(this[gr].generator){const e=this[hr](),t=this[gr].failingNode[gn](e);if(!t.success)return t;t.html&&this[zs](t.html,t.bbox);delete this[gr].failingNode}else this[gr].generator=this[Sn](e,t);for(;;){const e=this[gr].generator.next();if(e.done)break;const t=e.value;if(!t.success)return t;t.html&&this[zs](t.html,t.bbox)}this[gr].generator=null;return HTMLResult.EMPTY}[tn](e){this[Ln]=new Set(Object.keys(e))}[Rn](e){const t=this[yn],i=this[Ln];return[...e].filter((e=>t.has(e)&&!i.has(e)))}[$r](e,t=new Set){for(const i of this[wn])i[Mn](e,t)}[Mn](e,t){const i=this[kn](e,t);i?this[pn](i,e,t):this[$r](e,t)}[kn](e,t){const{use:i,usehref:a}=this;if(!i&&!a)return null;let s=null,r=null,n=null,g=i;if(a){g=a;a.startsWith("#som(")&&a.endsWith(")")?r=a.slice(5,-1):a.startsWith(".#som(")&&a.endsWith(")")?r=a.slice(6,-1):a.startsWith("#")?n=a.slice(1):a.startsWith(".#")&&(n=a.slice(2))}else i.startsWith("#")?n=i.slice(1):r=i;this.use=this.usehref="";if(n)s=e.get(n);else{s=searchNode(e.get(_r),this,r,!0,!1);s&&(s=s[0])}if(!s){warn(`XFA - Invalid prototype reference: ${g}.`);return null}if(s[qr]!==this[qr]){warn(`XFA - Incompatible prototype: ${s[qr]} !== ${this[qr]}.`);return null}if(t.has(s)){warn("XFA - Cycle detected in prototypes use.");return null}t.add(s);const o=s[kn](e,t);o&&s[pn](o,e,t);s[$r](e,t);t.delete(s);return s}[pn](e,t,i){if(i.has(e)){warn("XFA - Cycle detected in prototypes use.");return}!this[sr]&&e[sr]&&(this[sr]=e[sr]);new Set(i).add(e);for(const t of this[Rn](e[Ln])){this[t]=e[t];this[Ln]&&this[Ln].add(t)}for(const a of Object.getOwnPropertyNames(this)){if(this[yn].has(a))continue;const s=this[a],r=e[a];if(s instanceof XFAObjectArray){for(const e of s[wn])e[Mn](t,i);for(let a=s[wn].length,n=r[wn].length;aXFAObject[Dn](e))):"object"==typeof e&&null!==e?Object.assign({},e):e}[ir](){const e=Object.create(Object.getPrototypeOf(this));for(const t of Object.getOwnPropertySymbols(this))try{e[t]=this[t]}catch{shadow(e,t,this[t])}e[cn]=`${e[qr]}${Jn++}`;e[wn]=[];for(const t of Object.getOwnPropertyNames(this)){if(this[yn].has(t)){e[t]=XFAObject[Dn](this[t]);continue}const i=this[t];e[t]=i instanceof XFAObjectArray?new XFAObjectArray(i[Gn]):null}for(const t of this[wn]){const i=t[qr],a=t[ir]();e[wn].push(a);a[Un]=e;null===e[i]?e[i]=a:e[i][wn].push(a)}return e}[pr](e=null){return e?this[wn].filter((t=>t[qr]===e)):this[wn]}[lr](e){return this[e]}[Qr](e,t,i=!0){return Array.from(this[Er](e,t,i))}*[Er](e,t,i=!0){if("parent"!==e){for(const i of this[wn]){i[qr]===e&&(yield i);i.name===e&&(yield i);(t||i[Yr]())&&(yield*i[Er](e,t,!1))}i&&this[yn].has(e)&&(yield new XFAAttribute(this,e,this[e]))}else yield this[Un]}}class XFAObjectArray{constructor(e=1/0){this[Gn]=e;this[wn]=[]}get isXFAObject(){return!1}get isXFAObjectArray(){return!0}push(e){if(this[wn].length<=this[Gn]){this[wn].push(e);return!0}warn(`XFA - node "${e[qr]}" accepts no more than ${this[Gn]} children`);return!1}isEmpty(){return 0===this[wn].length}dump(){return 1===this[wn].length?this[wn][0][nr]():this[wn].map((e=>e[nr]()))}[ir](){const e=new XFAObjectArray(this[Gn]);e[wn]=this[wn].map((e=>e[ir]()));return e}get children(){return this[wn]}clear(){this[wn].length=0}}class XFAAttribute{constructor(e,t,i){this[Un]=e;this[qr]=t;this[sr]=i;this[ar]=!1;this[cn]="attribute"+Jn++}[Dr](){return this[Un]}[Ur](){return!0}[ur](){return this[sr].trim()}[an](e){e=e.value||"";this[sr]=e.toString()}[rn](){return this[sr]}[Mr](e){return this[Un]===e||this[Un][Mr](e)}}class XmlObject extends XFAObject{constructor(e,t,i={}){super(e,t);this[sr]="";this[bn]=null;if("#text"!==t){const e=new Map;this[mn]=e;for(const[t,a]of Object.entries(i))e.set(t,new XFAAttribute(this,t,a));if(i.hasOwnProperty(Or)){const e=i[Or].xfa.dataNode;void 0!==e&&("dataGroup"===e?this[bn]=!1:"dataValue"===e&&(this[bn]=!0))}}this[ar]=!1}[on](e){const t=this[qr];if("#text"===t){e.push(encodeToXmlString(this[sr]));return}const i=utf8StringToString(t),a=this[Tr]===Yn?"xfa:":"";e.push(`<${a}${i}`);for(const[t,i]of this[mn].entries()){const a=utf8StringToString(t);e.push(` ${a}="${encodeToXmlString(i[sr])}"`)}null!==this[bn]&&(this[bn]?e.push(' xfa:dataNode="dataValue"'):e.push(' xfa:dataNode="dataGroup"'));if(this[sr]||0!==this[wn].length){e.push(">");if(this[sr])"string"==typeof this[sr]?e.push(encodeToXmlString(this[sr])):this[sr][on](e);else for(const t of this[wn])t[on](e);e.push(``)}else e.push("/>")}[Pr](e){if(this[sr]){const e=new XmlObject(this[Tr],"#text");this[_s](e);e[sr]=this[sr];this[sr]=""}this[_s](e);return!0}[jr](e){this[sr]+=e}[or](){if(this[sr]&&this[wn].length>0){const e=new XmlObject(this[Tr],"#text");this[_s](e);e[sr]=this[sr];delete this[sr]}}[gn](){return"#text"===this[qr]?HTMLResult.success({name:"#text",value:this[sr]}):HTMLResult.EMPTY}[pr](e=null){return e?this[wn].filter((t=>t[qr]===e)):this[wn]}[Cr](){return this[mn]}[lr](e){const t=this[mn].get(e);return void 0!==t?t:this[pr](e)}*[Er](e,t){const i=this[mn].get(e);i&&(yield i);for(const i of this[wn]){i[qr]===e&&(yield i);t&&(yield*i[Er](e,t))}}*[cr](e,t){const i=this[mn].get(e);!i||t&&i[ar]||(yield i);for(const i of this[wn])yield*i[cr](e,t)}*[fr](e,t,i){for(const a of this[wn]){a[qr]!==e||i&&a[ar]||(yield a);t&&(yield*a[fr](e,t,i))}}[Ur](){return null===this[bn]?0===this[wn].length||this[wn][0][Tr]===hn.xhtml.id:this[bn]}[ur](){return null===this[bn]?0===this[wn].length?this[sr].trim():this[wn][0][Tr]===hn.xhtml.id?this[wn][0][rn]().trim():null:this[sr].trim()}[an](e){e=e.value||"";this[sr]=e.toString()}[nr](e=!1){const t=Object.create(null);e&&(t.$ns=this[Tr]);this[sr]&&(t.$content=this[sr]);t.$name=this[qr];t.children=[];for(const i of this[wn])t.children.push(i[nr](e));t.attributes=Object.create(null);for(const[e,i]of this[mn])t.attributes[e]=i[sr];return t}}class ContentObject extends XFAObject{constructor(e,t){super(e,t);this[sr]=""}[jr](e){this[sr]+=e}[or](){}}class OptionObject extends ContentObject{constructor(e,t,i){super(e,t);this[xn]=i}[or](){this[sr]=getKeyword({data:this[sr],defaultValue:this[xn][0],validate:e=>this[xn].includes(e)})}[Ar](e){super[Ar](e);delete this[xn]}}class StringObject extends ContentObject{[or](){this[sr]=this[sr].trim()}}class IntegerObject extends ContentObject{constructor(e,t,i,a){super(e,t);this[Fn]=i;this[Hn]=a}[or](){this[sr]=getInteger({data:this[sr],defaultValue:this[Fn],validate:this[Hn]})}[Ar](e){super[Ar](e);delete this[Fn];delete this[Hn]}}class Option01 extends IntegerObject{constructor(e,t){super(e,t,0,(e=>1===e))}}class Option10 extends IntegerObject{constructor(e,t){super(e,t,1,(e=>0===e))}}function measureToString(e){return"string"==typeof e?"0px":Number.isInteger(e)?`${e}px`:`${e.toFixed(2)}px`}const vn={anchorType(e,t){const i=e[wr]();if(i&&(!i.layout||"position"===i.layout)){"transform"in t||(t.transform="");switch(e.anchorType){case"bottomCenter":t.transform+="translate(-50%, -100%)";break;case"bottomLeft":t.transform+="translate(0,-100%)";break;case"bottomRight":t.transform+="translate(-100%,-100%)";break;case"middleCenter":t.transform+="translate(-50%,-50%)";break;case"middleLeft":t.transform+="translate(0,-50%)";break;case"middleRight":t.transform+="translate(-100%,-50%)";break;case"topCenter":t.transform+="translate(-50%,0)";break;case"topRight":t.transform+="translate(-100%,0)"}}},dimensions(e,t){const i=e[wr]();let a=e.w;const s=e.h;if(i.layout?.includes("row")){const t=i[gr],s=e.colSpan;let r;if(-1===s){r=t.columnWidths.slice(t.currentColumn).reduce(((e,t)=>e+t),0);t.currentColumn=0}else{r=t.columnWidths.slice(t.currentColumn,t.currentColumn+s).reduce(((e,t)=>e+t),0);t.currentColumn=(t.currentColumn+e.colSpan)%t.columnWidths.length}isNaN(r)||(a=e.w=r)}t.width=""!==a?measureToString(a):"auto";t.height=""!==s?measureToString(s):"auto"},position(e,t){const i=e[wr]();if(!i?.layout||"position"===i.layout){t.position="absolute";t.left=measureToString(e.x);t.top=measureToString(e.y)}},rotate(e,t){if(e.rotate){"transform"in t||(t.transform="");t.transform+=`rotate(-${e.rotate}deg)`;t.transformOrigin="top left"}},presence(e,t){switch(e.presence){case"invisible":t.visibility="hidden";break;case"hidden":case"inactive":t.display="none"}},hAlign(e,t){if("para"===e[qr])switch(e.hAlign){case"justifyAll":t.textAlign="justify-all";break;case"radix":t.textAlign="left";break;default:t.textAlign=e.hAlign}else switch(e.hAlign){case"left":t.alignSelf="start";break;case"center":t.alignSelf="center";break;case"right":t.alignSelf="end"}},margin(e,t){e.margin&&(t.margin=e.margin[In]().margin)}};function setMinMaxDimensions(e,t){if("position"===e[wr]().layout){e.minW>0&&(t.minWidth=measureToString(e.minW));e.maxW>0&&(t.maxWidth=measureToString(e.maxW));e.minH>0&&(t.minHeight=measureToString(e.minH));e.maxH>0&&(t.maxHeight=measureToString(e.maxH))}}function layoutText(e,t,i,a,s,r){const n=new TextMeasure(t,i,a,s);"string"==typeof e?n.addString(e):e[Xr](n);return n.compute(r)}function layoutNode(e,t){let i=null,a=null,s=!1;if((!e.w||!e.h)&&e.value){let r=0,n=0;if(e.margin){r=e.margin.leftInset+e.margin.rightInset;n=e.margin.topInset+e.margin.bottomInset}let g=null,o=null;if(e.para){o=Object.create(null);g=""===e.para.lineHeight?null:e.para.lineHeight;o.top=""===e.para.spaceAbove?0:e.para.spaceAbove;o.bottom=""===e.para.spaceBelow?0:e.para.spaceBelow;o.left=""===e.para.marginLeft?0:e.para.marginLeft;o.right=""===e.para.marginRight?0:e.para.marginRight}let c=e.font;if(!c){const t=e[br]();let i=e[Dr]();for(;i&&i!==t;){if(i.font){c=i.font;break}i=i[Dr]()}}const C=(e.w||t.width)-r,h=e[Fr].fontFinder;if(e.value.exData&&e.value.exData[sr]&&"text/html"===e.value.exData.contentType){const t=layoutText(e.value.exData[sr],c,o,g,h,C);a=t.width;i=t.height;s=t.isBroken}else{const t=e.value[rn]();if(t){const e=layoutText(t,c,o,g,h,C);a=e.width;i=e.height;s=e.isBroken}}null===a||e.w||(a+=r);null===i||e.h||(i+=n)}return{w:a,h:i,isBroken:s}}function computeBbox(e,t,i){let a;if(""!==e.w&&""!==e.h)a=[e.x,e.y,e.w,e.h];else{if(!i)return null;let s=e.w;if(""===s){if(0===e.maxW){const t=e[wr]();s="position"===t.layout&&""!==t.w?0:e.minW}else s=Math.min(e.maxW,i.width);t.attributes.style.width=measureToString(s)}let r=e.h;if(""===r){if(0===e.maxH){const t=e[wr]();r="position"===t.layout&&""!==t.h?0:e.minH}else r=Math.min(e.maxH,i.height);t.attributes.style.height=measureToString(r)}a=[e.x,e.y,s,r]}return a}function fixDimensions(e){const t=e[wr]();if(t.layout?.includes("row")){const i=t[gr],a=e.colSpan;let s;s=-1===a?i.columnWidths.slice(i.currentColumn).reduce(((e,t)=>e+t),0):i.columnWidths.slice(i.currentColumn,i.currentColumn+a).reduce(((e,t)=>e+t),0);isNaN(s)||(e.w=s)}t.layout&&"position"!==t.layout&&(e.x=e.y=0);"table"===e.layout&&""===e.w&&Array.isArray(e.columnWidths)&&(e.w=e.columnWidths.reduce(((e,t)=>e+t),0))}function layoutClass(e){switch(e.layout){case"position":default:return"xfaPosition";case"lr-tb":return"xfaLrTb";case"rl-row":return"xfaRlRow";case"rl-tb":return"xfaRlTb";case"row":return"xfaRow";case"table":return"xfaTable";case"tb":return"xfaTb"}}function toStyle(e,...t){const i=Object.create(null);for(const a of t){const t=e[a];if(null!==t)if(vn.hasOwnProperty(a))vn[a](e,i);else if(t instanceof XFAObject){const e=t[In]();e?Object.assign(i,e):warn(`(DEBUG) - XFA - style for ${a} not implemented yet`)}}return i}function createWrapper(e,t){const{attributes:i}=t,{style:a}=i,s={name:"div",attributes:{class:["xfaWrapper"],style:Object.create(null)},children:[]};i.class.push("xfaWrapped");if(e.border){const{widths:i,insets:r}=e.border[gr];let n,g,o=r[0],c=r[3];const C=r[0]+r[2],h=r[1]+r[3];switch(e.border.hand){case"even":o-=i[0]/2;c-=i[3]/2;n=`calc(100% + ${(i[1]+i[3])/2-h}px)`;g=`calc(100% + ${(i[0]+i[2])/2-C}px)`;break;case"left":o-=i[0];c-=i[3];n=`calc(100% + ${i[1]+i[3]-h}px)`;g=`calc(100% + ${i[0]+i[2]-C}px)`;break;case"right":n=h?`calc(100% - ${h}px)`:"100%";g=C?`calc(100% - ${C}px)`:"100%"}const l=["xfaBorder"];isPrintOnly(e.border)&&l.push("xfaPrintOnly");const Q={name:"div",attributes:{class:l,style:{top:`${o}px`,left:`${c}px`,width:n,height:g}},children:[]};for(const e of["border","borderWidth","borderColor","borderRadius","borderStyle"])if(void 0!==a[e]){Q.attributes.style[e]=a[e];delete a[e]}s.children.push(Q,t)}else s.children.push(t);for(const e of["background","backgroundClip","top","left","width","height","minWidth","minHeight","maxWidth","maxHeight","transform","transformOrigin","visibility"])if(void 0!==a[e]){s.attributes.style[e]=a[e];delete a[e]}s.attributes.style.position="absolute"===a.position?"absolute":"relative";delete a.position;if(a.alignSelf){s.attributes.style.alignSelf=a.alignSelf;delete a.alignSelf}return s}function fixTextIndent(e){const t=getMeasurement(e.textIndent,"0px");if(t>=0)return;const i="padding"+("left"===("right"===e.textAlign?"right":"left")?"Left":"Right"),a=getMeasurement(e[i],"0px");e[i]=a-t+"px"}function setAccess(e,t){switch(e.access){case"nonInteractive":t.push("xfaNonInteractive");break;case"readOnly":t.push("xfaReadOnly");break;case"protected":t.push("xfaDisabled")}}function isPrintOnly(e){return e.relevant.length>0&&!e.relevant[0].excluded&&"print"===e.relevant[0].viewname}function getCurrentPara(e){const t=e[br]()[gr].paraStack;return t.length?t.at(-1):null}function setPara(e,t,i){if(i.attributes.class?.includes("xfaRich")){if(t){""===e.h&&(t.height="auto");""===e.w&&(t.width="auto")}const a=getCurrentPara(e);if(a){const e=i.attributes.style;e.display="flex";e.flexDirection="column";switch(a.vAlign){case"top":e.justifyContent="start";break;case"bottom":e.justifyContent="end";break;case"middle":e.justifyContent="center"}const t=a[In]();for(const[i,a]of Object.entries(t))i in e||(e[i]=a)}}}function setFontFamily(e,t,i,a){if(!i){delete a.fontFamily;return}const s=stripQuotes(e.typeface);a.fontFamily=`"${s}"`;const r=i.find(s);if(r){const{fontFamily:i}=r.regular.cssFontInfo;i!==s&&(a.fontFamily=`"${i}"`);const n=getCurrentPara(t);if(n&&""!==n.lineHeight)return;if(a.lineHeight)return;const g=selectFont(e,r);g&&(a.lineHeight=Math.max(1.2,g.lineHeight))}}function fixURL(e){const t=createValidAbsoluteUrl(e,null,{addDefaultProtocol:!0,tryConvertEncoding:!0});return t?t.href:null}function createLine(e,t){return{name:"div",attributes:{class:["lr-tb"===e.layout?"xfaLr":"xfaRl"]},children:t}}function flushHTML(e){if(!e[gr])return null;const t={name:"div",attributes:e[gr].attributes,children:e[gr].children};if(e[gr].failingNode){const i=e[gr].failingNode[Ir]();i&&(e.layout.endsWith("-tb")?t.children.push(createLine(e,[i])):t.children.push(i))}return 0===t.children.length?null:t}function addHTML(e,t,i){const a=e[gr],s=a.availableSpace,[r,n,g,o]=i;switch(e.layout){case"position":a.width=Math.max(a.width,r+g);a.height=Math.max(a.height,n+o);a.children.push(t);break;case"lr-tb":case"rl-tb":if(!a.line||1===a.attempt){a.line=createLine(e,[]);a.children.push(a.line);a.numberInLine=0}a.numberInLine+=1;a.line.children.push(t);if(0===a.attempt){a.currentWidth+=g;a.height=Math.max(a.height,a.prevHeight+o)}else{a.currentWidth=g;a.prevHeight=a.height;a.height+=o;a.attempt=0}a.width=Math.max(a.width,a.currentWidth);break;case"rl-row":case"row":{a.children.push(t);a.width+=g;a.height=Math.max(a.height,o);const e=measureToString(a.height);for(const t of a.children)t.attributes.style.height=e;break}case"table":case"tb":a.width=Math.min(s.width,Math.max(a.width,g));a.height+=o;a.children.push(t)}}function getAvailableSpace(e){const t=e[gr].availableSpace,i=e.margin?e.margin.topInset+e.margin.bottomInset:0,a=e.margin?e.margin.leftInset+e.margin.rightInset:0;switch(e.layout){case"lr-tb":case"rl-tb":return 0===e[gr].attempt?{width:t.width-a-e[gr].currentWidth,height:t.height-i-e[gr].prevHeight}:{width:t.width-a,height:t.height-i-e[gr].height};case"rl-row":case"row":return{width:e[gr].columnWidths.slice(e[gr].currentColumn).reduce(((e,t)=>e+t)),height:t.height-a};case"table":case"tb":return{width:t.width-a,height:t.height-i-e[gr].height};default:return t}}function checkDimensions(e,t){if(null===e[br]()[gr].firstUnsplittable)return!0;if(0===e.w||0===e.h)return!0;const i=e[wr](),a=i[gr]?.attempt||0,[,s,r,n]=function getTransformedBBox(e){let t,i,a=""===e.w?NaN:e.w,s=""===e.h?NaN:e.h,[r,n]=[0,0];switch(e.anchorType||""){case"bottomCenter":[r,n]=[a/2,s];break;case"bottomLeft":[r,n]=[0,s];break;case"bottomRight":[r,n]=[a,s];break;case"middleCenter":[r,n]=[a/2,s/2];break;case"middleLeft":[r,n]=[0,s/2];break;case"middleRight":[r,n]=[a,s/2];break;case"topCenter":[r,n]=[a/2,0];break;case"topRight":[r,n]=[a,0]}switch(e.rotate||0){case 0:[t,i]=[-r,-n];break;case 90:[t,i]=[-n,r];[a,s]=[s,-a];break;case 180:[t,i]=[r,n];[a,s]=[-a,-s];break;case 270:[t,i]=[n,-r];[a,s]=[-s,a]}return[e.x+t+Math.min(0,a),e.y+i+Math.min(0,s),Math.abs(a),Math.abs(s)]}(e);switch(i.layout){case"lr-tb":case"rl-tb":return 0===a?e[br]()[gr].noLayoutFailure?""!==e.w?Math.round(r-t.width)<=2:t.width>2:!(""!==e.h&&Math.round(n-t.height)>2)&&(""!==e.w?Math.round(r-t.width)<=2||0===i[gr].numberInLine&&t.height>2:t.width>2):!!e[br]()[gr].noLayoutFailure||!(""!==e.h&&Math.round(n-t.height)>2)&&((""===e.w||Math.round(r-t.width)<=2||!i[Jr]())&&t.height>2);case"table":case"tb":return!!e[br]()[gr].noLayoutFailure||(""===e.h||e[Hr]()?(""===e.w||Math.round(r-t.width)<=2||!i[Jr]())&&t.height>2:Math.round(n-t.height)<=2);case"position":if(e[br]()[gr].noLayoutFailure)return!0;if(""===e.h||Math.round(n+s-t.height)<=2)return!0;return n+s>e[br]()[gr].currentContentArea.h;case"rl-row":case"row":return!!e[br]()[gr].noLayoutFailure||(""===e.h||Math.round(n-t.height)<=2);default:return!0}}const Kn=hn.template.id,Tn="http://www.w3.org/2000/svg",qn=/^H(\d+)$/,On=new Set(["image/gif","image/jpeg","image/jpg","image/pjpeg","image/png","image/apng","image/x-png","image/bmp","image/x-ms-bmp","image/tiff","image/tif","application/octet-stream"]),Pn=[[[66,77],"image/bmp"],[[255,216,255],"image/jpeg"],[[73,73,42,0],"image/tiff"],[[77,77,0,42],"image/tiff"],[[71,73,70,56,57,97],"image/gif"],[[137,80,78,71,13,10,26,10],"image/png"]];function getBorderDims(e){if(!e||!e.border)return{w:0,h:0};const t=e.border[dr]();return t?{w:t.widths[0]+t.widths[2]+t.insets[0]+t.insets[2],h:t.widths[1]+t.widths[3]+t.insets[1]+t.insets[3]}:{w:0,h:0}}function hasMargin(e){return e.margin&&(e.margin.topInset||e.margin.rightInset||e.margin.bottomInset||e.margin.leftInset)}function _setValue(e,t){if(!e.value){const t=new Value({});e[_s](t);e.value=t}e.value[an](t)}function*getContainedChildren(e){for(const t of e[pr]())t instanceof SubformSet?yield*t[mr]():yield t}function isRequired(e){return"error"===e.validate?.nullTest}function setTabIndex(e){for(;e;){if(!e.traversal){e[sn]=e[Dr]()[sn];return}if(e[sn])return;let t=null;for(const i of e.traversal[pr]())if("next"===i.operation){t=i;break}if(!t||!t.ref){e[sn]=e[Dr]()[sn];return}const i=e[br]();e[sn]=++i[sn];const a=i[An](t.ref,e);if(!a)return;e=a[0]}}function applyAssist(e,t){const i=e.assist;if(i){const e=i[gn]();e&&(t.title=e);const a=i.role.match(qn);if(a){const e="heading",i=a[1];t.role=e;t["aria-level"]=i}}if("table"===e.layout)t.role="table";else if("row"===e.layout)t.role="row";else{const i=e[Dr]();"row"===i.layout&&(t.role="TH"===i.assist?.role?"columnheader":"cell")}}function ariaLabel(e){if(!e.assist)return null;const t=e.assist;return t.speak&&""!==t.speak[sr]?t.speak[sr]:t.toolTip?t.toolTip[sr]:null}function valueToHtml(e){return HTMLResult.success({name:"div",attributes:{class:["xfaRich"],style:Object.create(null)},children:[{name:"span",attributes:{style:Object.create(null)},value:e}]})}function setFirstUnsplittable(e){const t=e[br]();if(null===t[gr].firstUnsplittable){t[gr].firstUnsplittable=e;t[gr].noLayoutFailure=!0}}function unsetFirstUnsplittable(e){const t=e[br]();t[gr].firstUnsplittable===e&&(t[gr].noLayoutFailure=!1)}function handleBreak(e){if(e[gr])return!1;e[gr]=Object.create(null);if("auto"===e.targetType)return!1;const t=e[br]();let i=null;if(e.target){i=t[An](e.target,e[Dr]());if(!i)return!1;i=i[0]}const{currentPageArea:a,currentContentArea:s}=t[gr];if("pageArea"===e.targetType){i instanceof PageArea||(i=null);if(e.startNew){e[gr].target=i||a;return!0}if(i&&i!==a){e[gr].target=i;return!0}return!1}i instanceof ContentArea||(i=null);const r=i&&i[Dr]();let n,g=r;if(e.startNew)if(i){const e=r.contentArea.children,t=e.indexOf(s),a=e.indexOf(i);-1!==t&&te;a[gr].noLayoutFailure=!0;const n=t[gn](i);e[zs](n.html,n.bbox);a[gr].noLayoutFailure=s;t[wr]=r}class AppearanceFilter extends StringObject{constructor(e){super(Kn,"appearanceFilter");this.id=e.id||"";this.type=getStringOption(e.type,["optional","required"]);this.use=e.use||"";this.usehref=e.usehref||""}}class Arc extends XFAObject{constructor(e){super(Kn,"arc",!0);this.circular=getInteger({data:e.circular,defaultValue:0,validate:e=>1===e});this.hand=getStringOption(e.hand,["even","left","right"]);this.id=e.id||"";this.startAngle=getFloat({data:e.startAngle,defaultValue:0,validate:e=>!0});this.sweepAngle=getFloat({data:e.sweepAngle,defaultValue:360,validate:e=>!0});this.use=e.use||"";this.usehref=e.usehref||"";this.edge=null;this.fill=null}[gn](){const e=this.edge||new Edge({}),t=e[In](),i=Object.create(null);"visible"===this.fill?.presence?Object.assign(i,this.fill[In]()):i.fill="transparent";i.strokeWidth=measureToString("visible"===e.presence?e.thickness:0);i.stroke=t.color;let a;const s={xmlns:Tn,style:{width:"100%",height:"100%",overflow:"visible"}};if(360===this.sweepAngle)a={name:"ellipse",attributes:{xmlns:Tn,cx:"50%",cy:"50%",rx:"50%",ry:"50%",style:i}};else{const e=this.startAngle*Math.PI/180,t=this.sweepAngle*Math.PI/180,r=this.sweepAngle>180?1:0,[n,g,o,c]=[50*(1+Math.cos(e)),50*(1-Math.sin(e)),50*(1+Math.cos(e+t)),50*(1-Math.sin(e+t))];a={name:"path",attributes:{xmlns:Tn,d:`M ${n} ${g} A 50 50 0 ${r} 0 ${o} ${c}`,vectorEffect:"non-scaling-stroke",style:i}};Object.assign(s,{viewBox:"0 0 100 100",preserveAspectRatio:"none"})}const r={name:"svg",children:[a],attributes:s};if(hasMargin(this[Dr]()[Dr]()))return HTMLResult.success({name:"div",attributes:{style:{display:"inline",width:"100%",height:"100%"}},children:[r]});r.attributes.style.position="absolute";return HTMLResult.success(r)}}class Area extends XFAObject{constructor(e){super(Kn,"area",!0);this.colSpan=getInteger({data:e.colSpan,defaultValue:1,validate:e=>e>=1||-1===e});this.id=e.id||"";this.name=e.name||"";this.relevant=getRelevant(e.relevant);this.use=e.use||"";this.usehref=e.usehref||"";this.x=getMeasurement(e.x,"0pt");this.y=getMeasurement(e.y,"0pt");this.desc=null;this.extras=null;this.area=new XFAObjectArray;this.draw=new XFAObjectArray;this.exObject=new XFAObjectArray;this.exclGroup=new XFAObjectArray;this.field=new XFAObjectArray;this.subform=new XFAObjectArray;this.subformSet=new XFAObjectArray}*[mr](){yield*getContainedChildren(this)}[Yr](){return!0}[xr](){return!0}[zs](e,t){const[i,a,s,r]=t;this[gr].width=Math.max(this[gr].width,i+s);this[gr].height=Math.max(this[gr].height,a+r);this[gr].children.push(e)}[hr](){return this[gr].availableSpace}[gn](e){const t=toStyle(this,"position"),i={style:t,id:this[cn],class:["xfaArea"]};isPrintOnly(this)&&i.class.push("xfaPrintOnly");this.name&&(i.xfaName=this.name);const a=[];this[gr]={children:a,width:0,height:0,availableSpace:e};const s=this[$s]({filter:new Set(["area","draw","field","exclGroup","subform","subformSet"]),include:!0});if(!s.success){if(s.isBreak())return s;delete this[gr];return HTMLResult.FAILURE}t.width=measureToString(this[gr].width);t.height=measureToString(this[gr].height);const r={name:"div",attributes:i,children:a},n=[this.x,this.y,this[gr].width,this[gr].height];delete this[gr];return HTMLResult.success(r,n)}}class Assist extends XFAObject{constructor(e){super(Kn,"assist",!0);this.id=e.id||"";this.role=e.role||"";this.use=e.use||"";this.usehref=e.usehref||"";this.speak=null;this.toolTip=null}[gn](){return this.toolTip?.[sr]||null}}class Barcode extends XFAObject{constructor(e){super(Kn,"barcode",!0);this.charEncoding=getKeyword({data:e.charEncoding?e.charEncoding.toLowerCase():"",defaultValue:"",validate:e=>["utf-8","big-five","fontspecific","gbk","gb-18030","gb-2312","ksc-5601","none","shift-jis","ucs-2","utf-16"].includes(e)||e.match(/iso-8859-\d{2}/)});this.checksum=getStringOption(e.checksum,["none","1mod10","1mod10_1mod11","2mod10","auto"]);this.dataColumnCount=getInteger({data:e.dataColumnCount,defaultValue:-1,validate:e=>e>=0});this.dataLength=getInteger({data:e.dataLength,defaultValue:-1,validate:e=>e>=0});this.dataPrep=getStringOption(e.dataPrep,["none","flateCompress"]);this.dataRowCount=getInteger({data:e.dataRowCount,defaultValue:-1,validate:e=>e>=0});this.endChar=e.endChar||"";this.errorCorrectionLevel=getInteger({data:e.errorCorrectionLevel,defaultValue:-1,validate:e=>e>=0&&e<=8});this.id=e.id||"";this.moduleHeight=getMeasurement(e.moduleHeight,"5mm");this.moduleWidth=getMeasurement(e.moduleWidth,"0.25mm");this.printCheckDigit=getInteger({data:e.printCheckDigit,defaultValue:0,validate:e=>1===e});this.rowColumnRatio=getRatio(e.rowColumnRatio);this.startChar=e.startChar||"";this.textLocation=getStringOption(e.textLocation,["below","above","aboveEmbedded","belowEmbedded","none"]);this.truncate=getInteger({data:e.truncate,defaultValue:0,validate:e=>1===e});this.type=getStringOption(e.type?e.type.toLowerCase():"",["aztec","codabar","code2of5industrial","code2of5interleaved","code2of5matrix","code2of5standard","code3of9","code3of9extended","code11","code49","code93","code128","code128a","code128b","code128c","code128sscc","datamatrix","ean8","ean8add2","ean8add5","ean13","ean13add2","ean13add5","ean13pwcd","fim","logmars","maxicode","msi","pdf417","pdf417macro","plessey","postauscust2","postauscust3","postausreplypaid","postausstandard","postukrm4scc","postusdpbc","postusimb","postusstandard","postus5zip","qrcode","rfid","rss14","rss14expanded","rss14limited","rss14stacked","rss14stackedomni","rss14truncated","telepen","ucc128","ucc128random","ucc128sscc","upca","upcaadd2","upcaadd5","upcapwcd","upce","upceadd2","upceadd5","upcean2","upcean5","upsmaxicode"]);this.upsMode=getStringOption(e.upsMode,["usCarrier","internationalCarrier","secureSymbol","standardSymbol"]);this.use=e.use||"";this.usehref=e.usehref||"";this.wideNarrowRatio=getRatio(e.wideNarrowRatio);this.encrypt=null;this.extras=null}}class Bind extends XFAObject{constructor(e){super(Kn,"bind",!0);this.match=getStringOption(e.match,["once","dataRef","global","none"]);this.ref=e.ref||"";this.picture=null}}class BindItems extends XFAObject{constructor(e){super(Kn,"bindItems");this.connection=e.connection||"";this.labelRef=e.labelRef||"";this.ref=e.ref||"";this.valueRef=e.valueRef||""}}class Bookend extends XFAObject{constructor(e){super(Kn,"bookend");this.id=e.id||"";this.leader=e.leader||"";this.trailer=e.trailer||"";this.use=e.use||"";this.usehref=e.usehref||""}}class BooleanElement extends Option01{constructor(e){super(Kn,"boolean");this.id=e.id||"";this.name=e.name||"";this.use=e.use||"";this.usehref=e.usehref||""}[gn](e){return valueToHtml(1===this[sr]?"1":"0")}}class Border extends XFAObject{constructor(e){super(Kn,"border",!0);this.break=getStringOption(e.break,["close","open"]);this.hand=getStringOption(e.hand,["even","left","right"]);this.id=e.id||"";this.presence=getStringOption(e.presence,["visible","hidden","inactive","invisible"]);this.relevant=getRelevant(e.relevant);this.use=e.use||"";this.usehref=e.usehref||"";this.corner=new XFAObjectArray(4);this.edge=new XFAObjectArray(4);this.extras=null;this.fill=null;this.margin=null}[dr](){if(!this[gr]){const e=this.edge.children.slice();if(e.length<4){const t=e.at(-1)||new Edge({});for(let i=e.length;i<4;i++)e.push(t)}const t=e.map((e=>e.thickness)),i=[0,0,0,0];if(this.margin){i[0]=this.margin.topInset;i[1]=this.margin.rightInset;i[2]=this.margin.bottomInset;i[3]=this.margin.leftInset}this[gr]={widths:t,insets:i,edges:e}}return this[gr]}[In](){const{edges:e}=this[dr](),t=e.map((e=>{const t=e[In]();t.color||="#000000";return t})),i=Object.create(null);this.margin&&Object.assign(i,this.margin[In]());"visible"===this.fill?.presence&&Object.assign(i,this.fill[In]());if(this.corner.children.some((e=>0!==e.radius))){const e=this.corner.children.map((e=>e[In]()));if(2===e.length||3===e.length){const t=e.at(-1);for(let i=e.length;i<4;i++)e.push(t)}i.borderRadius=e.map((e=>e.radius)).join(" ")}switch(this.presence){case"invisible":case"hidden":i.borderStyle="";break;case"inactive":i.borderStyle="none";break;default:i.borderStyle=t.map((e=>e.style)).join(" ")}i.borderWidth=t.map((e=>e.width)).join(" ");i.borderColor=t.map((e=>e.color)).join(" ");return i}}class Break extends XFAObject{constructor(e){super(Kn,"break",!0);this.after=getStringOption(e.after,["auto","contentArea","pageArea","pageEven","pageOdd"]);this.afterTarget=e.afterTarget||"";this.before=getStringOption(e.before,["auto","contentArea","pageArea","pageEven","pageOdd"]);this.beforeTarget=e.beforeTarget||"";this.bookendLeader=e.bookendLeader||"";this.bookendTrailer=e.bookendTrailer||"";this.id=e.id||"";this.overflowLeader=e.overflowLeader||"";this.overflowTarget=e.overflowTarget||"";this.overflowTrailer=e.overflowTrailer||"";this.startNew=getInteger({data:e.startNew,defaultValue:0,validate:e=>1===e});this.use=e.use||"";this.usehref=e.usehref||"";this.extras=null}}class BreakAfter extends XFAObject{constructor(e){super(Kn,"breakAfter",!0);this.id=e.id||"";this.leader=e.leader||"";this.startNew=getInteger({data:e.startNew,defaultValue:0,validate:e=>1===e});this.target=e.target||"";this.targetType=getStringOption(e.targetType,["auto","contentArea","pageArea"]);this.trailer=e.trailer||"";this.use=e.use||"";this.usehref=e.usehref||"";this.script=null}}class BreakBefore extends XFAObject{constructor(e){super(Kn,"breakBefore",!0);this.id=e.id||"";this.leader=e.leader||"";this.startNew=getInteger({data:e.startNew,defaultValue:0,validate:e=>1===e});this.target=e.target||"";this.targetType=getStringOption(e.targetType,["auto","contentArea","pageArea"]);this.trailer=e.trailer||"";this.use=e.use||"";this.usehref=e.usehref||"";this.script=null}[gn](e){this[gr]={};return HTMLResult.FAILURE}}class Button extends XFAObject{constructor(e){super(Kn,"button",!0);this.highlight=getStringOption(e.highlight,["inverted","none","outline","push"]);this.id=e.id||"";this.use=e.use||"";this.usehref=e.usehref||"";this.extras=null}[gn](e){const t=this[Dr]()[Dr](),i={name:"button",attributes:{id:this[cn],class:["xfaButton"],style:{}},children:[]};for(const e of t.event.children){if("click"!==e.activity||!e.script)continue;const t=recoverJsURL(e.script[sr]);if(!t)continue;const a=fixURL(t.url);a&&i.children.push({name:"a",attributes:{id:"link"+this[cn],href:a,newWindow:t.newWindow,class:["xfaLink"],style:{}},children:[]})}return HTMLResult.success(i)}}class Calculate extends XFAObject{constructor(e){super(Kn,"calculate",!0);this.id=e.id||"";this.override=getStringOption(e.override,["disabled","error","ignore","warning"]);this.use=e.use||"";this.usehref=e.usehref||"";this.extras=null;this.message=null;this.script=null}}class Caption extends XFAObject{constructor(e){super(Kn,"caption",!0);this.id=e.id||"";this.placement=getStringOption(e.placement,["left","bottom","inline","right","top"]);this.presence=getStringOption(e.presence,["visible","hidden","inactive","invisible"]);this.reserve=Math.ceil(getMeasurement(e.reserve));this.use=e.use||"";this.usehref=e.usehref||"";this.extras=null;this.font=null;this.margin=null;this.para=null;this.value=null}[an](e){_setValue(this,e)}[dr](e){if(!this[gr]){let{width:t,height:i}=e;switch(this.placement){case"left":case"right":case"inline":t=this.reserve<=0?t:this.reserve;break;case"top":case"bottom":i=this.reserve<=0?i:this.reserve}this[gr]=layoutNode(this,{width:t,height:i})}return this[gr]}[gn](e){if(!this.value)return HTMLResult.EMPTY;this[Vr]();const t=this.value[gn](e).html;if(!t){this[Zr]();return HTMLResult.EMPTY}const i=this.reserve;if(this.reserve<=0){const{w:t,h:i}=this[dr](e);switch(this.placement){case"left":case"right":case"inline":this.reserve=t;break;case"top":case"bottom":this.reserve=i}}const a=[];"string"==typeof t?a.push({name:"#text",value:t}):a.push(t);const s=toStyle(this,"font","margin","visibility");switch(this.placement){case"left":case"right":this.reserve>0&&(s.width=measureToString(this.reserve));break;case"top":case"bottom":this.reserve>0&&(s.height=measureToString(this.reserve))}setPara(this,null,t);this[Zr]();this.reserve=i;return HTMLResult.success({name:"div",attributes:{style:s,class:["xfaCaption"]},children:a})}}class Certificate extends StringObject{constructor(e){super(Kn,"certificate");this.id=e.id||"";this.name=e.name||"";this.use=e.use||"";this.usehref=e.usehref||""}}class Certificates extends XFAObject{constructor(e){super(Kn,"certificates",!0);this.credentialServerPolicy=getStringOption(e.credentialServerPolicy,["optional","required"]);this.id=e.id||"";this.url=e.url||"";this.urlPolicy=e.urlPolicy||"";this.use=e.use||"";this.usehref=e.usehref||"";this.encryption=null;this.issuers=null;this.keyUsage=null;this.oids=null;this.signing=null;this.subjectDNs=null}}class CheckButton extends XFAObject{constructor(e){super(Kn,"checkButton",!0);this.id=e.id||"";this.mark=getStringOption(e.mark,["default","check","circle","cross","diamond","square","star"]);this.shape=getStringOption(e.shape,["square","round"]);this.size=getMeasurement(e.size,"10pt");this.use=e.use||"";this.usehref=e.usehref||"";this.border=null;this.extras=null;this.margin=null}[gn](e){const t=toStyle("margin"),i=measureToString(this.size);t.width=t.height=i;let a,s,r;const n=this[Dr]()[Dr](),g=n.items.children.length&&n.items.children[0][gn]().html||[],o={on:(void 0!==g[0]?g[0]:"on").toString(),off:(void 0!==g[1]?g[1]:"off").toString()},c=(n.value?.[rn]()||"off")===o.on||void 0,C=n[wr](),h=n[cn];let l;if(C instanceof ExclGroup){r=C[cn];a="radio";s="xfaRadio";l=C[rr]?.[cn]||C[cn]}else{a="checkbox";s="xfaCheckbox";l=n[rr]?.[cn]||n[cn]}const Q={name:"input",attributes:{class:[s],style:t,fieldId:h,dataId:l,type:a,checked:c,xfaOn:o.on,xfaOff:o.off,"aria-label":ariaLabel(n),"aria-required":!1}};r&&(Q.attributes.name=r);if(isRequired(n)){Q.attributes["aria-required"]=!0;Q.attributes.required=!0}return HTMLResult.success({name:"label",attributes:{class:["xfaLabel"]},children:[Q]})}}class ChoiceList extends XFAObject{constructor(e){super(Kn,"choiceList",!0);this.commitOn=getStringOption(e.commitOn,["select","exit"]);this.id=e.id||"";this.open=getStringOption(e.open,["userControl","always","multiSelect","onEntry"]);this.textEntry=getInteger({data:e.textEntry,defaultValue:0,validate:e=>1===e});this.use=e.use||"";this.usehref=e.usehref||"";this.border=null;this.extras=null;this.margin=null}[gn](e){const t=toStyle(this,"border","margin"),i=this[Dr]()[Dr](),a={fontSize:`calc(${i.font?.size||10}px * var(--scale-factor))`},s=[];if(i.items.children.length>0){const e=i.items;let t=0,r=0;if(2===e.children.length){t=e.children[0].save;r=1-t}const n=e.children[t][gn]().html,g=e.children[r][gn]().html;let o=!1;const c=i.value?.[rn]()||"";for(let e=0,t=n.length;eMath.min(Math.max(0,parseInt(e.trim(),10)),255))).map((e=>isNaN(e)?0:e));if(r.length<3)return{r:i,g:a,b:s};[i,a,s]=r;return{r:i,g:a,b:s}}(e.value):"";this.extras=null}[Sr](){return!1}[In](){return this.value?Util.makeHexColor(this.value.r,this.value.g,this.value.b):null}}class Comb extends XFAObject{constructor(e){super(Kn,"comb");this.id=e.id||"";this.numberOfCells=getInteger({data:e.numberOfCells,defaultValue:0,validate:e=>e>=0});this.use=e.use||"";this.usehref=e.usehref||""}}class Connect extends XFAObject{constructor(e){super(Kn,"connect",!0);this.connection=e.connection||"";this.id=e.id||"";this.ref=e.ref||"";this.usage=getStringOption(e.usage,["exportAndImport","exportOnly","importOnly"]);this.use=e.use||"";this.usehref=e.usehref||"";this.picture=null}}class ContentArea extends XFAObject{constructor(e){super(Kn,"contentArea",!0);this.h=getMeasurement(e.h);this.id=e.id||"";this.name=e.name||"";this.relevant=getRelevant(e.relevant);this.use=e.use||"";this.usehref=e.usehref||"";this.w=getMeasurement(e.w);this.x=getMeasurement(e.x,"0pt");this.y=getMeasurement(e.y,"0pt");this.desc=null;this.extras=null}[gn](e){const t={left:measureToString(this.x),top:measureToString(this.y),width:measureToString(this.w),height:measureToString(this.h)},i=["xfaContentarea"];isPrintOnly(this)&&i.push("xfaPrintOnly");return HTMLResult.success({name:"div",children:[],attributes:{style:t,class:i,id:this[cn]}})}}class Corner extends XFAObject{constructor(e){super(Kn,"corner",!0);this.id=e.id||"";this.inverted=getInteger({data:e.inverted,defaultValue:0,validate:e=>1===e});this.join=getStringOption(e.join,["square","round"]);this.presence=getStringOption(e.presence,["visible","hidden","inactive","invisible"]);this.radius=getMeasurement(e.radius);this.stroke=getStringOption(e.stroke,["solid","dashDot","dashDotDot","dashed","dotted","embossed","etched","lowered","raised"]);this.thickness=getMeasurement(e.thickness,"0.5pt");this.use=e.use||"";this.usehref=e.usehref||"";this.color=null;this.extras=null}[In](){const e=toStyle(this,"visibility");e.radius=measureToString("square"===this.join?0:this.radius);return e}}class DateElement extends ContentObject{constructor(e){super(Kn,"date");this.id=e.id||"";this.name=e.name||"";this.use=e.use||"";this.usehref=e.usehref||""}[or](){const e=this[sr].trim();this[sr]=e?new Date(e):null}[gn](e){return valueToHtml(this[sr]?this[sr].toString():"")}}class DateTime extends ContentObject{constructor(e){super(Kn,"dateTime");this.id=e.id||"";this.name=e.name||"";this.use=e.use||"";this.usehref=e.usehref||""}[or](){const e=this[sr].trim();this[sr]=e?new Date(e):null}[gn](e){return valueToHtml(this[sr]?this[sr].toString():"")}}class DateTimeEdit extends XFAObject{constructor(e){super(Kn,"dateTimeEdit",!0);this.hScrollPolicy=getStringOption(e.hScrollPolicy,["auto","off","on"]);this.id=e.id||"";this.picker=getStringOption(e.picker,["host","none"]);this.use=e.use||"";this.usehref=e.usehref||"";this.border=null;this.comb=null;this.extras=null;this.margin=null}[gn](e){const t=toStyle(this,"border","font","margin"),i=this[Dr]()[Dr](),a={name:"input",attributes:{type:"text",fieldId:i[cn],dataId:i[rr]?.[cn]||i[cn],class:["xfaTextfield"],style:t,"aria-label":ariaLabel(i),"aria-required":!1}};if(isRequired(i)){a.attributes["aria-required"]=!0;a.attributes.required=!0}return HTMLResult.success({name:"label",attributes:{class:["xfaLabel"]},children:[a]})}}class Decimal extends ContentObject{constructor(e){super(Kn,"decimal");this.fracDigits=getInteger({data:e.fracDigits,defaultValue:2,validate:e=>!0});this.id=e.id||"";this.leadDigits=getInteger({data:e.leadDigits,defaultValue:-1,validate:e=>!0});this.name=e.name||"";this.use=e.use||"";this.usehref=e.usehref||""}[or](){const e=parseFloat(this[sr].trim());this[sr]=isNaN(e)?null:e}[gn](e){return valueToHtml(null!==this[sr]?this[sr].toString():"")}}class DefaultUi extends XFAObject{constructor(e){super(Kn,"defaultUi",!0);this.id=e.id||"";this.use=e.use||"";this.usehref=e.usehref||"";this.extras=null}}class Desc extends XFAObject{constructor(e){super(Kn,"desc",!0);this.id=e.id||"";this.use=e.use||"";this.usehref=e.usehref||"";this.boolean=new XFAObjectArray;this.date=new XFAObjectArray;this.dateTime=new XFAObjectArray;this.decimal=new XFAObjectArray;this.exData=new XFAObjectArray;this.float=new XFAObjectArray;this.image=new XFAObjectArray;this.integer=new XFAObjectArray;this.text=new XFAObjectArray;this.time=new XFAObjectArray}}class DigestMethod extends OptionObject{constructor(e){super(Kn,"digestMethod",["","SHA1","SHA256","SHA512","RIPEMD160"]);this.id=e.id||"";this.use=e.use||"";this.usehref=e.usehref||""}}class DigestMethods extends XFAObject{constructor(e){super(Kn,"digestMethods",!0);this.id=e.id||"";this.type=getStringOption(e.type,["optional","required"]);this.use=e.use||"";this.usehref=e.usehref||"";this.digestMethod=new XFAObjectArray}}class Draw extends XFAObject{constructor(e){super(Kn,"draw",!0);this.anchorType=getStringOption(e.anchorType,["topLeft","bottomCenter","bottomLeft","bottomRight","middleCenter","middleLeft","middleRight","topCenter","topRight"]);this.colSpan=getInteger({data:e.colSpan,defaultValue:1,validate:e=>e>=1||-1===e});this.h=e.h?getMeasurement(e.h):"";this.hAlign=getStringOption(e.hAlign,["left","center","justify","justifyAll","radix","right"]);this.id=e.id||"";this.locale=e.locale||"";this.maxH=getMeasurement(e.maxH,"0pt");this.maxW=getMeasurement(e.maxW,"0pt");this.minH=getMeasurement(e.minH,"0pt");this.minW=getMeasurement(e.minW,"0pt");this.name=e.name||"";this.presence=getStringOption(e.presence,["visible","hidden","inactive","invisible"]);this.relevant=getRelevant(e.relevant);this.rotate=getInteger({data:e.rotate,defaultValue:0,validate:e=>e%90==0});this.use=e.use||"";this.usehref=e.usehref||"";this.w=e.w?getMeasurement(e.w):"";this.x=getMeasurement(e.x,"0pt");this.y=getMeasurement(e.y,"0pt");this.assist=null;this.border=null;this.caption=null;this.desc=null;this.extras=null;this.font=null;this.keep=null;this.margin=null;this.para=null;this.traversal=null;this.ui=null;this.value=null;this.setProperty=new XFAObjectArray}[an](e){_setValue(this,e)}[gn](e){setTabIndex(this);if("hidden"===this.presence||"inactive"===this.presence)return HTMLResult.EMPTY;fixDimensions(this);this[Vr]();const t=this.w,i=this.h,{w:a,h:s,isBroken:r}=layoutNode(this,e);if(a&&""===this.w){if(r&&this[wr]()[Jr]()){this[Zr]();return HTMLResult.FAILURE}this.w=a}s&&""===this.h&&(this.h=s);setFirstUnsplittable(this);if(!checkDimensions(this,e)){this.w=t;this.h=i;this[Zr]();return HTMLResult.FAILURE}unsetFirstUnsplittable(this);const n=toStyle(this,"font","hAlign","dimensions","position","presence","rotate","anchorType","border","margin");setMinMaxDimensions(this,n);if(n.margin){n.padding=n.margin;delete n.margin}const g=["xfaDraw"];this.font&&g.push("xfaFont");isPrintOnly(this)&&g.push("xfaPrintOnly");const o={style:n,id:this[cn],class:g};this.name&&(o.xfaName=this.name);const c={name:"div",attributes:o,children:[]};applyAssist(this,o);const C=computeBbox(this,c,e),h=this.value?this.value[gn](e).html:null;if(null===h){this.w=t;this.h=i;this[Zr]();return HTMLResult.success(createWrapper(this,c),C)}c.children.push(h);setPara(this,n,h);this.w=t;this.h=i;this[Zr]();return HTMLResult.success(createWrapper(this,c),C)}}class Edge extends XFAObject{constructor(e){super(Kn,"edge",!0);this.cap=getStringOption(e.cap,["square","butt","round"]);this.id=e.id||"";this.presence=getStringOption(e.presence,["visible","hidden","inactive","invisible"]);this.stroke=getStringOption(e.stroke,["solid","dashDot","dashDotDot","dashed","dotted","embossed","etched","lowered","raised"]);this.thickness=getMeasurement(e.thickness,"0.5pt");this.use=e.use||"";this.usehref=e.usehref||"";this.color=null;this.extras=null}[In](){const e=toStyle(this,"visibility");Object.assign(e,{linecap:this.cap,width:measureToString(this.thickness),color:this.color?this.color[In]():"#000000",style:""});if("visible"!==this.presence)e.style="none";else switch(this.stroke){case"solid":e.style="solid";break;case"dashDot":case"dashDotDot":case"dashed":e.style="dashed";break;case"dotted":e.style="dotted";break;case"embossed":e.style="ridge";break;case"etched":e.style="groove";break;case"lowered":e.style="inset";break;case"raised":e.style="outset"}return e}}class Encoding extends OptionObject{constructor(e){super(Kn,"encoding",["adbe.x509.rsa_sha1","adbe.pkcs7.detached","adbe.pkcs7.sha1"]);this.id=e.id||"";this.use=e.use||"";this.usehref=e.usehref||""}}class Encodings extends XFAObject{constructor(e){super(Kn,"encodings",!0);this.id=e.id||"";this.type=getStringOption(e.type,["optional","required"]);this.use=e.use||"";this.usehref=e.usehref||"";this.encoding=new XFAObjectArray}}class Encrypt extends XFAObject{constructor(e){super(Kn,"encrypt",!0);this.id=e.id||"";this.use=e.use||"";this.usehref=e.usehref||"";this.certificate=null}}class EncryptData extends XFAObject{constructor(e){super(Kn,"encryptData",!0);this.id=e.id||"";this.operation=getStringOption(e.operation,["encrypt","decrypt"]);this.target=e.target||"";this.use=e.use||"";this.usehref=e.usehref||"";this.filter=null;this.manifest=null}}class Encryption extends XFAObject{constructor(e){super(Kn,"encryption",!0);this.id=e.id||"";this.type=getStringOption(e.type,["optional","required"]);this.use=e.use||"";this.usehref=e.usehref||"";this.certificate=new XFAObjectArray}}class EncryptionMethod extends OptionObject{constructor(e){super(Kn,"encryptionMethod",["","AES256-CBC","TRIPLEDES-CBC","AES128-CBC","AES192-CBC"]);this.id=e.id||"";this.use=e.use||"";this.usehref=e.usehref||""}}class EncryptionMethods extends XFAObject{constructor(e){super(Kn,"encryptionMethods",!0);this.id=e.id||"";this.type=getStringOption(e.type,["optional","required"]);this.use=e.use||"";this.usehref=e.usehref||"";this.encryptionMethod=new XFAObjectArray}}class Event extends XFAObject{constructor(e){super(Kn,"event",!0);this.activity=getStringOption(e.activity,["click","change","docClose","docReady","enter","exit","full","indexChange","initialize","mouseDown","mouseEnter","mouseExit","mouseUp","postExecute","postOpen","postPrint","postSave","postSign","postSubmit","preExecute","preOpen","prePrint","preSave","preSign","preSubmit","ready","validationState"]);this.id=e.id||"";this.listen=getStringOption(e.listen,["refOnly","refAndDescendents"]);this.name=e.name||"";this.ref=e.ref||"";this.use=e.use||"";this.usehref=e.usehref||"";this.extras=null;this.encryptData=null;this.execute=null;this.script=null;this.signData=null;this.submit=null}}class ExData extends ContentObject{constructor(e){super(Kn,"exData");this.contentType=e.contentType||"";this.href=e.href||"";this.id=e.id||"";this.maxLength=getInteger({data:e.maxLength,defaultValue:-1,validate:e=>e>=-1});this.name=e.name||"";this.rid=e.rid||"";this.transferEncoding=getStringOption(e.transferEncoding,["none","base64","package"]);this.use=e.use||"";this.usehref=e.usehref||""}[Gr](){return"text/html"===this.contentType}[Pr](e){if("text/html"===this.contentType&&e[Tr]===hn.xhtml.id){this[sr]=e;return!0}if("text/xml"===this.contentType){this[sr]=e;return!0}return!1}[gn](e){return"text/html"===this.contentType&&this[sr]?this[sr][gn](e):HTMLResult.EMPTY}}class ExObject extends XFAObject{constructor(e){super(Kn,"exObject",!0);this.archive=e.archive||"";this.classId=e.classId||"";this.codeBase=e.codeBase||"";this.codeType=e.codeType||"";this.id=e.id||"";this.name=e.name||"";this.use=e.use||"";this.usehref=e.usehref||"";this.extras=null;this.boolean=new XFAObjectArray;this.date=new XFAObjectArray;this.dateTime=new XFAObjectArray;this.decimal=new XFAObjectArray;this.exData=new XFAObjectArray;this.exObject=new XFAObjectArray;this.float=new XFAObjectArray;this.image=new XFAObjectArray;this.integer=new XFAObjectArray;this.text=new XFAObjectArray;this.time=new XFAObjectArray}}class ExclGroup extends XFAObject{constructor(e){super(Kn,"exclGroup",!0);this.access=getStringOption(e.access,["open","nonInteractive","protected","readOnly"]);this.accessKey=e.accessKey||"";this.anchorType=getStringOption(e.anchorType,["topLeft","bottomCenter","bottomLeft","bottomRight","middleCenter","middleLeft","middleRight","topCenter","topRight"]);this.colSpan=getInteger({data:e.colSpan,defaultValue:1,validate:e=>e>=1||-1===e});this.h=e.h?getMeasurement(e.h):"";this.hAlign=getStringOption(e.hAlign,["left","center","justify","justifyAll","radix","right"]);this.id=e.id||"";this.layout=getStringOption(e.layout,["position","lr-tb","rl-row","rl-tb","row","table","tb"]);this.maxH=getMeasurement(e.maxH,"0pt");this.maxW=getMeasurement(e.maxW,"0pt");this.minH=getMeasurement(e.minH,"0pt");this.minW=getMeasurement(e.minW,"0pt");this.name=e.name||"";this.presence=getStringOption(e.presence,["visible","hidden","inactive","invisible"]);this.relevant=getRelevant(e.relevant);this.use=e.use||"";this.usehref=e.usehref||"";this.w=e.w?getMeasurement(e.w):"";this.x=getMeasurement(e.x,"0pt");this.y=getMeasurement(e.y,"0pt");this.assist=null;this.bind=null;this.border=null;this.calculate=null;this.caption=null;this.desc=null;this.extras=null;this.margin=null;this.para=null;this.traversal=null;this.validate=null;this.connect=new XFAObjectArray;this.event=new XFAObjectArray;this.field=new XFAObjectArray;this.setProperty=new XFAObjectArray}[xr](){return!0}[Sr](){return!0}[an](e){for(const t of this.field.children){if(!t.value){const e=new Value({});t[_s](e);t.value=e}t.value[an](e)}}[Jr](){return this.layout.endsWith("-tb")&&0===this[gr].attempt&&this[gr].numberInLine>0||this[Dr]()[Jr]()}[Hr](){const e=this[wr]();if(!e[Hr]())return!1;if(void 0!==this[gr]._isSplittable)return this[gr]._isSplittable;if("position"===this.layout||this.layout.includes("row")){this[gr]._isSplittable=!1;return!1}if(e.layout?.endsWith("-tb")&&0!==e[gr].numberInLine)return!1;this[gr]._isSplittable=!0;return!0}[Ir](){return flushHTML(this)}[zs](e,t){addHTML(this,e,t)}[hr](){return getAvailableSpace(this)}[gn](e){setTabIndex(this);if("hidden"===this.presence||"inactive"===this.presence||0===this.h||0===this.w)return HTMLResult.EMPTY;fixDimensions(this);const t=[],i={id:this[cn],class:[]};setAccess(this,i.class);this[gr]||(this[gr]=Object.create(null));Object.assign(this[gr],{children:t,attributes:i,attempt:0,line:null,numberInLine:0,availableSpace:{width:Math.min(this.w||1/0,e.width),height:Math.min(this.h||1/0,e.height)},width:0,height:0,prevHeight:0,currentWidth:0});const a=this[Hr]();a||setFirstUnsplittable(this);if(!checkDimensions(this,e))return HTMLResult.FAILURE;const s=new Set(["field"]);if(this.layout.includes("row")){const e=this[wr]().columnWidths;if(Array.isArray(e)&&e.length>0){this[gr].columnWidths=e;this[gr].currentColumn=0}}const r=toStyle(this,"anchorType","dimensions","position","presence","border","margin","hAlign"),n=["xfaExclgroup"],g=layoutClass(this);g&&n.push(g);isPrintOnly(this)&&n.push("xfaPrintOnly");i.style=r;i.class=n;this.name&&(i.xfaName=this.name);this[Vr]();const o="lr-tb"===this.layout||"rl-tb"===this.layout,c=o?2:1;for(;this[gr].attempte>=1||-1===e});this.h=e.h?getMeasurement(e.h):"";this.hAlign=getStringOption(e.hAlign,["left","center","justify","justifyAll","radix","right"]);this.id=e.id||"";this.locale=e.locale||"";this.maxH=getMeasurement(e.maxH,"0pt");this.maxW=getMeasurement(e.maxW,"0pt");this.minH=getMeasurement(e.minH,"0pt");this.minW=getMeasurement(e.minW,"0pt");this.name=e.name||"";this.presence=getStringOption(e.presence,["visible","hidden","inactive","invisible"]);this.relevant=getRelevant(e.relevant);this.rotate=getInteger({data:e.rotate,defaultValue:0,validate:e=>e%90==0});this.use=e.use||"";this.usehref=e.usehref||"";this.w=e.w?getMeasurement(e.w):"";this.x=getMeasurement(e.x,"0pt");this.y=getMeasurement(e.y,"0pt");this.assist=null;this.bind=null;this.border=null;this.calculate=null;this.caption=null;this.desc=null;this.extras=null;this.font=null;this.format=null;this.items=new XFAObjectArray(2);this.keep=null;this.margin=null;this.para=null;this.traversal=null;this.ui=null;this.validate=null;this.value=null;this.bindItems=new XFAObjectArray;this.connect=new XFAObjectArray;this.event=new XFAObjectArray;this.setProperty=new XFAObjectArray}[xr](){return!0}[an](e){_setValue(this,e)}[gn](e){setTabIndex(this);if(!this.ui){this.ui=new Ui({});this.ui[Fr]=this[Fr];this[_s](this.ui);let e;switch(this.items.children.length){case 0:e=new TextEdit({});this.ui.textEdit=e;break;case 1:e=new CheckButton({});this.ui.checkButton=e;break;case 2:e=new ChoiceList({});this.ui.choiceList=e}this.ui[_s](e)}if(!this.ui||"hidden"===this.presence||"inactive"===this.presence||0===this.h||0===this.w)return HTMLResult.EMPTY;this.caption&&delete this.caption[gr];this[Vr]();const t=this.caption?this.caption[gn](e).html:null,i=this.w,a=this.h;let s=0,r=0;if(this.margin){s=this.margin.leftInset+this.margin.rightInset;r=this.margin.topInset+this.margin.bottomInset}let n=null;if(""===this.w||""===this.h){let t=null,i=null,a=0,g=0;if(this.ui.checkButton)a=g=this.ui.checkButton.size;else{const{w:t,h:i}=layoutNode(this,e);if(null!==t){a=t;g=i}else g=function fonts_getMetrics(e,t=!1){let i=null;if(e){const t=stripQuotes(e.typeface),a=e[Fr].fontFinder.find(t);i=selectFont(e,a)}if(!i)return{lineHeight:12,lineGap:2,lineNoGap:10};const a=e.size||10,s=i.lineHeight?Math.max(t?0:1.2,i.lineHeight):1.2,r=void 0===i.lineGap?.2:i.lineGap;return{lineHeight:s*a,lineGap:r*a,lineNoGap:Math.max(1,s-r)*a}}(this.font,!0).lineNoGap}n=getBorderDims(this.ui[dr]());a+=n.w;g+=n.h;if(this.caption){const{w:s,h:r,isBroken:n}=this.caption[dr](e);if(n&&this[wr]()[Jr]()){this[Zr]();return HTMLResult.FAILURE}t=s;i=r;switch(this.caption.placement){case"left":case"right":case"inline":t+=a;break;case"top":case"bottom":i+=g}}else{t=a;i=g}if(t&&""===this.w){t+=s;this.w=Math.min(this.maxW<=0?1/0:this.maxW,this.minW+1e>=1&&e<=5});this.appearanceFilter=null;this.certificates=null;this.digestMethods=null;this.encodings=null;this.encryptionMethods=null;this.handler=null;this.lockDocument=null;this.mdp=null;this.reasons=null;this.timeStamp=null}}class Float extends ContentObject{constructor(e){super(Kn,"float");this.id=e.id||"";this.name=e.name||"";this.use=e.use||"";this.usehref=e.usehref||""}[or](){const e=parseFloat(this[sr].trim());this[sr]=isNaN(e)?null:e}[gn](e){return valueToHtml(null!==this[sr]?this[sr].toString():"")}}class template_Font extends XFAObject{constructor(e){super(Kn,"font",!0);this.baselineShift=getMeasurement(e.baselineShift);this.fontHorizontalScale=getFloat({data:e.fontHorizontalScale,defaultValue:100,validate:e=>e>=0});this.fontVerticalScale=getFloat({data:e.fontVerticalScale,defaultValue:100,validate:e=>e>=0});this.id=e.id||"";this.kerningMode=getStringOption(e.kerningMode,["none","pair"]);this.letterSpacing=getMeasurement(e.letterSpacing,"0");this.lineThrough=getInteger({data:e.lineThrough,defaultValue:0,validate:e=>1===e||2===e});this.lineThroughPeriod=getStringOption(e.lineThroughPeriod,["all","word"]);this.overline=getInteger({data:e.overline,defaultValue:0,validate:e=>1===e||2===e});this.overlinePeriod=getStringOption(e.overlinePeriod,["all","word"]);this.posture=getStringOption(e.posture,["normal","italic"]);this.size=getMeasurement(e.size,"10pt");this.typeface=e.typeface||"Courier";this.underline=getInteger({data:e.underline,defaultValue:0,validate:e=>1===e||2===e});this.underlinePeriod=getStringOption(e.underlinePeriod,["all","word"]);this.use=e.use||"";this.usehref=e.usehref||"";this.weight=getStringOption(e.weight,["normal","bold"]);this.extras=null;this.fill=null}[Ar](e){super[Ar](e);this[Fr].usedTypefaces.add(this.typeface)}[In](){const e=toStyle(this,"fill"),t=e.color;if(t)if("#000000"===t)delete e.color;else if(!t.startsWith("#")){e.background=t;e.backgroundClip="text";e.color="transparent"}this.baselineShift&&(e.verticalAlign=measureToString(this.baselineShift));e.fontKerning="none"===this.kerningMode?"none":"normal";e.letterSpacing=measureToString(this.letterSpacing);if(0!==this.lineThrough){e.textDecoration="line-through";2===this.lineThrough&&(e.textDecorationStyle="double")}if(0!==this.overline){e.textDecoration="overline";2===this.overline&&(e.textDecorationStyle="double")}e.fontStyle=this.posture;e.fontSize=measureToString(.99*this.size);setFontFamily(this,this,this[Fr].fontFinder,e);if(0!==this.underline){e.textDecoration="underline";2===this.underline&&(e.textDecorationStyle="double")}e.fontWeight=this.weight;return e}}class Format extends XFAObject{constructor(e){super(Kn,"format",!0);this.id=e.id||"";this.use=e.use||"";this.usehref=e.usehref||"";this.extras=null;this.picture=null}}class Handler extends StringObject{constructor(e){super(Kn,"handler");this.id=e.id||"";this.type=getStringOption(e.type,["optional","required"]);this.use=e.use||"";this.usehref=e.usehref||""}}class Hyphenation extends XFAObject{constructor(e){super(Kn,"hyphenation");this.excludeAllCaps=getInteger({data:e.excludeAllCaps,defaultValue:0,validate:e=>1===e});this.excludeInitialCap=getInteger({data:e.excludeInitialCap,defaultValue:0,validate:e=>1===e});this.hyphenate=getInteger({data:e.hyphenate,defaultValue:0,validate:e=>1===e});this.id=e.id||"";this.pushCharacterCount=getInteger({data:e.pushCharacterCount,defaultValue:3,validate:e=>e>=0});this.remainCharacterCount=getInteger({data:e.remainCharacterCount,defaultValue:3,validate:e=>e>=0});this.use=e.use||"";this.usehref=e.usehref||"";this.wordCharacterCount=getInteger({data:e.wordCharacterCount,defaultValue:7,validate:e=>e>=0})}}class Image extends StringObject{constructor(e){super(Kn,"image");this.aspect=getStringOption(e.aspect,["fit","actual","height","none","width"]);this.contentType=e.contentType||"";this.href=e.href||"";this.id=e.id||"";this.name=e.name||"";this.transferEncoding=getStringOption(e.transferEncoding,["base64","none","package"]);this.use=e.use||"";this.usehref=e.usehref||""}[gn](){if(this.contentType&&!On.has(this.contentType.toLowerCase()))return HTMLResult.EMPTY;let e=this[Fr].images&&this[Fr].images.get(this.href);if(!e&&(this.href||!this[sr]))return HTMLResult.EMPTY;e||"base64"!==this.transferEncoding||(e=stringToBytes(atob(this[sr])));if(!e)return HTMLResult.EMPTY;if(!this.contentType){for(const[t,i]of Pn)if(e.length>t.length&&t.every(((t,i)=>t===e[i]))){this.contentType=i;break}if(!this.contentType)return HTMLResult.EMPTY}const t=new Blob([e],{type:this.contentType});let i;switch(this.aspect){case"fit":case"actual":break;case"height":i={height:"100%",objectFit:"fill"};break;case"none":i={width:"100%",height:"100%",objectFit:"fill"};break;case"width":i={width:"100%",objectFit:"fill"}}const a=this[Dr]();return HTMLResult.success({name:"img",attributes:{class:["xfaImage"],style:i,src:URL.createObjectURL(t),alt:a?ariaLabel(a[Dr]()):null}})}}class ImageEdit extends XFAObject{constructor(e){super(Kn,"imageEdit",!0);this.data=getStringOption(e.data,["link","embed"]);this.id=e.id||"";this.use=e.use||"";this.usehref=e.usehref||"";this.border=null;this.extras=null;this.margin=null}[gn](e){return"embed"===this.data?HTMLResult.success({name:"div",children:[],attributes:{}}):HTMLResult.EMPTY}}class Integer extends ContentObject{constructor(e){super(Kn,"integer");this.id=e.id||"";this.name=e.name||"";this.use=e.use||"";this.usehref=e.usehref||""}[or](){const e=parseInt(this[sr].trim(),10);this[sr]=isNaN(e)?null:e}[gn](e){return valueToHtml(null!==this[sr]?this[sr].toString():"")}}class Issuers extends XFAObject{constructor(e){super(Kn,"issuers",!0);this.id=e.id||"";this.type=getStringOption(e.type,["optional","required"]);this.use=e.use||"";this.usehref=e.usehref||"";this.certificate=new XFAObjectArray}}class Items extends XFAObject{constructor(e){super(Kn,"items",!0);this.id=e.id||"";this.name=e.name||"";this.presence=getStringOption(e.presence,["visible","hidden","inactive","invisible"]);this.ref=e.ref||"";this.save=getInteger({data:e.save,defaultValue:0,validate:e=>1===e});this.use=e.use||"";this.usehref=e.usehref||"";this.boolean=new XFAObjectArray;this.date=new XFAObjectArray;this.dateTime=new XFAObjectArray;this.decimal=new XFAObjectArray;this.exData=new XFAObjectArray;this.float=new XFAObjectArray;this.image=new XFAObjectArray;this.integer=new XFAObjectArray;this.text=new XFAObjectArray;this.time=new XFAObjectArray}[gn](){const e=[];for(const t of this[pr]())e.push(t[rn]());return HTMLResult.success(e)}}class Keep extends XFAObject{constructor(e){super(Kn,"keep",!0);this.id=e.id||"";const t=["none","contentArea","pageArea"];this.intact=getStringOption(e.intact,t);this.next=getStringOption(e.next,t);this.previous=getStringOption(e.previous,t);this.use=e.use||"";this.usehref=e.usehref||"";this.extras=null}}class KeyUsage extends XFAObject{constructor(e){super(Kn,"keyUsage");const t=["","yes","no"];this.crlSign=getStringOption(e.crlSign,t);this.dataEncipherment=getStringOption(e.dataEncipherment,t);this.decipherOnly=getStringOption(e.decipherOnly,t);this.digitalSignature=getStringOption(e.digitalSignature,t);this.encipherOnly=getStringOption(e.encipherOnly,t);this.id=e.id||"";this.keyAgreement=getStringOption(e.keyAgreement,t);this.keyCertSign=getStringOption(e.keyCertSign,t);this.keyEncipherment=getStringOption(e.keyEncipherment,t);this.nonRepudiation=getStringOption(e.nonRepudiation,t);this.type=getStringOption(e.type,["optional","required"]);this.use=e.use||"";this.usehref=e.usehref||""}}class Line extends XFAObject{constructor(e){super(Kn,"line",!0);this.hand=getStringOption(e.hand,["even","left","right"]);this.id=e.id||"";this.slope=getStringOption(e.slope,["\\","/"]);this.use=e.use||"";this.usehref=e.usehref||"";this.edge=null}[gn](){const e=this[Dr]()[Dr](),t=this.edge||new Edge({}),i=t[In](),a=Object.create(null),s="visible"===t.presence?t.thickness:0;a.strokeWidth=measureToString(s);a.stroke=i.color;let r,n,g,o,c="100%",C="100%";if(e.w<=s){[r,n,g,o]=["50%",0,"50%","100%"];c=a.strokeWidth}else if(e.h<=s){[r,n,g,o]=[0,"50%","100%","50%"];C=a.strokeWidth}else"\\"===this.slope?[r,n,g,o]=[0,0,"100%","100%"]:[r,n,g,o]=[0,"100%","100%",0];const h={name:"svg",children:[{name:"line",attributes:{xmlns:Tn,x1:r,y1:n,x2:g,y2:o,style:a}}],attributes:{xmlns:Tn,width:c,height:C,style:{overflow:"visible"}}};if(hasMargin(e))return HTMLResult.success({name:"div",attributes:{style:{display:"inline",width:"100%",height:"100%"}},children:[h]});h.attributes.style.position="absolute";return HTMLResult.success(h)}}class Linear extends XFAObject{constructor(e){super(Kn,"linear",!0);this.id=e.id||"";this.type=getStringOption(e.type,["toRight","toBottom","toLeft","toTop"]);this.use=e.use||"";this.usehref=e.usehref||"";this.color=null;this.extras=null}[In](e){e=e?e[In]():"#FFFFFF";return`linear-gradient(${this.type.replace(/([RBLT])/," $1").toLowerCase()}, ${e}, ${this.color?this.color[In]():"#000000"})`}}class LockDocument extends ContentObject{constructor(e){super(Kn,"lockDocument");this.id=e.id||"";this.type=getStringOption(e.type,["optional","required"]);this.use=e.use||"";this.usehref=e.usehref||""}[or](){this[sr]=getStringOption(this[sr],["auto","0","1"])}}class Manifest extends XFAObject{constructor(e){super(Kn,"manifest",!0);this.action=getStringOption(e.action,["include","all","exclude"]);this.id=e.id||"";this.name=e.name||"";this.use=e.use||"";this.usehref=e.usehref||"";this.extras=null;this.ref=new XFAObjectArray}}class Margin extends XFAObject{constructor(e){super(Kn,"margin",!0);this.bottomInset=getMeasurement(e.bottomInset,"0");this.id=e.id||"";this.leftInset=getMeasurement(e.leftInset,"0");this.rightInset=getMeasurement(e.rightInset,"0");this.topInset=getMeasurement(e.topInset,"0");this.use=e.use||"";this.usehref=e.usehref||"";this.extras=null}[In](){return{margin:measureToString(this.topInset)+" "+measureToString(this.rightInset)+" "+measureToString(this.bottomInset)+" "+measureToString(this.leftInset)}}}class Mdp extends XFAObject{constructor(e){super(Kn,"mdp");this.id=e.id||"";this.permissions=getInteger({data:e.permissions,defaultValue:2,validate:e=>1===e||3===e});this.signatureType=getStringOption(e.signatureType,["filler","author"]);this.use=e.use||"";this.usehref=e.usehref||""}}class Medium extends XFAObject{constructor(e){super(Kn,"medium");this.id=e.id||"";this.imagingBBox=function getBBox(e){const t=-1;if(!e)return{x:t,y:t,width:t,height:t};const i=e.trim().split(/\s*,\s*/).map((e=>getMeasurement(e,"-1")));if(i.length<4||i[2]<0||i[3]<0)return{x:t,y:t,width:t,height:t};const[a,s,r,n]=i;return{x:a,y:s,width:r,height:n}}(e.imagingBBox);this.long=getMeasurement(e.long);this.orientation=getStringOption(e.orientation,["portrait","landscape"]);this.short=getMeasurement(e.short);this.stock=e.stock||"";this.trayIn=getStringOption(e.trayIn,["auto","delegate","pageFront"]);this.trayOut=getStringOption(e.trayOut,["auto","delegate"]);this.use=e.use||"";this.usehref=e.usehref||""}}class Message extends XFAObject{constructor(e){super(Kn,"message",!0);this.id=e.id||"";this.use=e.use||"";this.usehref=e.usehref||"";this.text=new XFAObjectArray}}class NumericEdit extends XFAObject{constructor(e){super(Kn,"numericEdit",!0);this.hScrollPolicy=getStringOption(e.hScrollPolicy,["auto","off","on"]);this.id=e.id||"";this.use=e.use||"";this.usehref=e.usehref||"";this.border=null;this.comb=null;this.extras=null;this.margin=null}[gn](e){const t=toStyle(this,"border","font","margin"),i=this[Dr]()[Dr](),a={name:"input",attributes:{type:"text",fieldId:i[cn],dataId:i[rr]?.[cn]||i[cn],class:["xfaTextfield"],style:t,"aria-label":ariaLabel(i),"aria-required":!1}};if(isRequired(i)){a.attributes["aria-required"]=!0;a.attributes.required=!0}return HTMLResult.success({name:"label",attributes:{class:["xfaLabel"]},children:[a]})}}class Occur extends XFAObject{constructor(e){super(Kn,"occur",!0);this.id=e.id||"";this.initial=""!==e.initial?getInteger({data:e.initial,defaultValue:"",validate:e=>!0}):"";this.max=""!==e.max?getInteger({data:e.max,defaultValue:1,validate:e=>!0}):"";this.min=""!==e.min?getInteger({data:e.min,defaultValue:1,validate:e=>!0}):"";this.use=e.use||"";this.usehref=e.usehref||"";this.extras=null}[Ar](){const e=this[Dr](),t=this.min;""===this.min&&(this.min=e instanceof PageArea||e instanceof PageSet?0:1);""===this.max&&(this.max=""===t?e instanceof PageArea||e instanceof PageSet?-1:1:this.min);-1!==this.max&&this.max!0});this.name=e.name||"";this.numbered=getInteger({data:e.numbered,defaultValue:1,validate:e=>!0});this.oddOrEven=getStringOption(e.oddOrEven,["any","even","odd"]);this.pagePosition=getStringOption(e.pagePosition,["any","first","last","only","rest"]);this.relevant=getRelevant(e.relevant);this.use=e.use||"";this.usehref=e.usehref||"";this.desc=null;this.extras=null;this.medium=null;this.occur=null;this.area=new XFAObjectArray;this.contentArea=new XFAObjectArray;this.draw=new XFAObjectArray;this.exclGroup=new XFAObjectArray;this.field=new XFAObjectArray;this.subform=new XFAObjectArray}[vr](){if(!this[gr]){this[gr]={numberOfUse:0};return!0}return!this.occur||-1===this.occur.max||this[gr].numberOfUsee.oddOrEven===t&&e.pagePosition===i));if(a)return a;a=this.pageArea.children.find((e=>"any"===e.oddOrEven&&e.pagePosition===i));if(a)return a;a=this.pageArea.children.find((e=>"any"===e.oddOrEven&&"any"===e.pagePosition));return a||this.pageArea.children[0]}}class Para extends XFAObject{constructor(e){super(Kn,"para",!0);this.hAlign=getStringOption(e.hAlign,["left","center","justify","justifyAll","radix","right"]);this.id=e.id||"";this.lineHeight=e.lineHeight?getMeasurement(e.lineHeight,"0pt"):"";this.marginLeft=e.marginLeft?getMeasurement(e.marginLeft,"0pt"):"";this.marginRight=e.marginRight?getMeasurement(e.marginRight,"0pt"):"";this.orphans=getInteger({data:e.orphans,defaultValue:0,validate:e=>e>=0});this.preserve=e.preserve||"";this.radixOffset=e.radixOffset?getMeasurement(e.radixOffset,"0pt"):"";this.spaceAbove=e.spaceAbove?getMeasurement(e.spaceAbove,"0pt"):"";this.spaceBelow=e.spaceBelow?getMeasurement(e.spaceBelow,"0pt"):"";this.tabDefault=e.tabDefault?getMeasurement(this.tabDefault):"";this.tabStops=(e.tabStops||"").trim().split(/\s+/).map(((e,t)=>t%2==1?getMeasurement(e):e));this.textIndent=e.textIndent?getMeasurement(e.textIndent,"0pt"):"";this.use=e.use||"";this.usehref=e.usehref||"";this.vAlign=getStringOption(e.vAlign,["top","bottom","middle"]);this.widows=getInteger({data:e.widows,defaultValue:0,validate:e=>e>=0});this.hyphenation=null}[In](){const e=toStyle(this,"hAlign");""!==this.marginLeft&&(e.paddingLeft=measureToString(this.marginLeft));""!==this.marginRight&&(e.paddingight=measureToString(this.marginRight));""!==this.spaceAbove&&(e.paddingTop=measureToString(this.spaceAbove));""!==this.spaceBelow&&(e.paddingBottom=measureToString(this.spaceBelow));if(""!==this.textIndent){e.textIndent=measureToString(this.textIndent);fixTextIndent(e)}this.lineHeight>0&&(e.lineHeight=measureToString(this.lineHeight));""!==this.tabDefault&&(e.tabSize=measureToString(this.tabDefault));this.tabStops.length;this.hyphenatation&&Object.assign(e,this.hyphenatation[In]());return e}}class PasswordEdit extends XFAObject{constructor(e){super(Kn,"passwordEdit",!0);this.hScrollPolicy=getStringOption(e.hScrollPolicy,["auto","off","on"]);this.id=e.id||"";this.passwordChar=e.passwordChar||"*";this.use=e.use||"";this.usehref=e.usehref||"";this.border=null;this.extras=null;this.margin=null}}class template_Pattern extends XFAObject{constructor(e){super(Kn,"pattern",!0);this.id=e.id||"";this.type=getStringOption(e.type,["crossHatch","crossDiagonal","diagonalLeft","diagonalRight","horizontal","vertical"]);this.use=e.use||"";this.usehref=e.usehref||"";this.color=null;this.extras=null}[In](e){e=e?e[In]():"#FFFFFF";const t=this.color?this.color[In]():"#000000",i="repeating-linear-gradient",a=`${e},${e} 5px,${t} 5px,${t} 10px`;switch(this.type){case"crossHatch":return`${i}(to top,${a}) ${i}(to right,${a})`;case"crossDiagonal":return`${i}(45deg,${a}) ${i}(-45deg,${a})`;case"diagonalLeft":return`${i}(45deg,${a})`;case"diagonalRight":return`${i}(-45deg,${a})`;case"horizontal":return`${i}(to top,${a})`;case"vertical":return`${i}(to right,${a})`}return""}}class Picture extends StringObject{constructor(e){super(Kn,"picture");this.id=e.id||"";this.use=e.use||"";this.usehref=e.usehref||""}}class Proto extends XFAObject{constructor(e){super(Kn,"proto",!0);this.appearanceFilter=new XFAObjectArray;this.arc=new XFAObjectArray;this.area=new XFAObjectArray;this.assist=new XFAObjectArray;this.barcode=new XFAObjectArray;this.bindItems=new XFAObjectArray;this.bookend=new XFAObjectArray;this.boolean=new XFAObjectArray;this.border=new XFAObjectArray;this.break=new XFAObjectArray;this.breakAfter=new XFAObjectArray;this.breakBefore=new XFAObjectArray;this.button=new XFAObjectArray;this.calculate=new XFAObjectArray;this.caption=new XFAObjectArray;this.certificate=new XFAObjectArray;this.certificates=new XFAObjectArray;this.checkButton=new XFAObjectArray;this.choiceList=new XFAObjectArray;this.color=new XFAObjectArray;this.comb=new XFAObjectArray;this.connect=new XFAObjectArray;this.contentArea=new XFAObjectArray;this.corner=new XFAObjectArray;this.date=new XFAObjectArray;this.dateTime=new XFAObjectArray;this.dateTimeEdit=new XFAObjectArray;this.decimal=new XFAObjectArray;this.defaultUi=new XFAObjectArray;this.desc=new XFAObjectArray;this.digestMethod=new XFAObjectArray;this.digestMethods=new XFAObjectArray;this.draw=new XFAObjectArray;this.edge=new XFAObjectArray;this.encoding=new XFAObjectArray;this.encodings=new XFAObjectArray;this.encrypt=new XFAObjectArray;this.encryptData=new XFAObjectArray;this.encryption=new XFAObjectArray;this.encryptionMethod=new XFAObjectArray;this.encryptionMethods=new XFAObjectArray;this.event=new XFAObjectArray;this.exData=new XFAObjectArray;this.exObject=new XFAObjectArray;this.exclGroup=new XFAObjectArray;this.execute=new XFAObjectArray;this.extras=new XFAObjectArray;this.field=new XFAObjectArray;this.fill=new XFAObjectArray;this.filter=new XFAObjectArray;this.float=new XFAObjectArray;this.font=new XFAObjectArray;this.format=new XFAObjectArray;this.handler=new XFAObjectArray;this.hyphenation=new XFAObjectArray;this.image=new XFAObjectArray;this.imageEdit=new XFAObjectArray;this.integer=new XFAObjectArray;this.issuers=new XFAObjectArray;this.items=new XFAObjectArray;this.keep=new XFAObjectArray;this.keyUsage=new XFAObjectArray;this.line=new XFAObjectArray;this.linear=new XFAObjectArray;this.lockDocument=new XFAObjectArray;this.manifest=new XFAObjectArray;this.margin=new XFAObjectArray;this.mdp=new XFAObjectArray;this.medium=new XFAObjectArray;this.message=new XFAObjectArray;this.numericEdit=new XFAObjectArray;this.occur=new XFAObjectArray;this.oid=new XFAObjectArray;this.oids=new XFAObjectArray;this.overflow=new XFAObjectArray;this.pageArea=new XFAObjectArray;this.pageSet=new XFAObjectArray;this.para=new XFAObjectArray;this.passwordEdit=new XFAObjectArray;this.pattern=new XFAObjectArray;this.picture=new XFAObjectArray;this.radial=new XFAObjectArray;this.reason=new XFAObjectArray;this.reasons=new XFAObjectArray;this.rectangle=new XFAObjectArray;this.ref=new XFAObjectArray;this.script=new XFAObjectArray;this.setProperty=new XFAObjectArray;this.signData=new XFAObjectArray;this.signature=new XFAObjectArray;this.signing=new XFAObjectArray;this.solid=new XFAObjectArray;this.speak=new XFAObjectArray;this.stipple=new XFAObjectArray;this.subform=new XFAObjectArray;this.subformSet=new XFAObjectArray;this.subjectDN=new XFAObjectArray;this.subjectDNs=new XFAObjectArray;this.submit=new XFAObjectArray;this.text=new XFAObjectArray;this.textEdit=new XFAObjectArray;this.time=new XFAObjectArray;this.timeStamp=new XFAObjectArray;this.toolTip=new XFAObjectArray;this.traversal=new XFAObjectArray;this.traverse=new XFAObjectArray;this.ui=new XFAObjectArray;this.validate=new XFAObjectArray;this.value=new XFAObjectArray;this.variables=new XFAObjectArray}}class Radial extends XFAObject{constructor(e){super(Kn,"radial",!0);this.id=e.id||"";this.type=getStringOption(e.type,["toEdge","toCenter"]);this.use=e.use||"";this.usehref=e.usehref||"";this.color=null;this.extras=null}[In](e){e=e?e[In]():"#FFFFFF";const t=this.color?this.color[In]():"#000000";return`radial-gradient(circle at center, ${"toEdge"===this.type?`${e},${t}`:`${t},${e}`})`}}class Reason extends StringObject{constructor(e){super(Kn,"reason");this.id=e.id||"";this.name=e.name||"";this.use=e.use||"";this.usehref=e.usehref||""}}class Reasons extends XFAObject{constructor(e){super(Kn,"reasons",!0);this.id=e.id||"";this.type=getStringOption(e.type,["optional","required"]);this.use=e.use||"";this.usehref=e.usehref||"";this.reason=new XFAObjectArray}}class Rectangle extends XFAObject{constructor(e){super(Kn,"rectangle",!0);this.hand=getStringOption(e.hand,["even","left","right"]);this.id=e.id||"";this.use=e.use||"";this.usehref=e.usehref||"";this.corner=new XFAObjectArray(4);this.edge=new XFAObjectArray(4);this.fill=null}[gn](){const e=this.edge.children.length?this.edge.children[0]:new Edge({}),t=e[In](),i=Object.create(null);"visible"===this.fill?.presence?Object.assign(i,this.fill[In]()):i.fill="transparent";i.strokeWidth=measureToString("visible"===e.presence?e.thickness:0);i.stroke=t.color;const a=(this.corner.children.length?this.corner.children[0]:new Corner({}))[In](),s={name:"svg",children:[{name:"rect",attributes:{xmlns:Tn,width:"100%",height:"100%",x:0,y:0,rx:a.radius,ry:a.radius,style:i}}],attributes:{xmlns:Tn,style:{overflow:"visible"},width:"100%",height:"100%"}};if(hasMargin(this[Dr]()[Dr]()))return HTMLResult.success({name:"div",attributes:{style:{display:"inline",width:"100%",height:"100%"}},children:[s]});s.attributes.style.position="absolute";return HTMLResult.success(s)}}class RefElement extends StringObject{constructor(e){super(Kn,"ref");this.id=e.id||"";this.use=e.use||"";this.usehref=e.usehref||""}}class Script extends StringObject{constructor(e){super(Kn,"script");this.binding=e.binding||"";this.contentType=e.contentType||"";this.id=e.id||"";this.name=e.name||"";this.runAt=getStringOption(e.runAt,["client","both","server"]);this.use=e.use||"";this.usehref=e.usehref||""}}class SetProperty extends XFAObject{constructor(e){super(Kn,"setProperty");this.connection=e.connection||"";this.ref=e.ref||"";this.target=e.target||""}}class SignData extends XFAObject{constructor(e){super(Kn,"signData",!0);this.id=e.id||"";this.operation=getStringOption(e.operation,["sign","clear","verify"]);this.ref=e.ref||"";this.target=e.target||"";this.use=e.use||"";this.usehref=e.usehref||"";this.filter=null;this.manifest=null}}class Signature extends XFAObject{constructor(e){super(Kn,"signature",!0);this.id=e.id||"";this.type=getStringOption(e.type,["PDF1.3","PDF1.6"]);this.use=e.use||"";this.usehref=e.usehref||"";this.border=null;this.extras=null;this.filter=null;this.manifest=null;this.margin=null}}class Signing extends XFAObject{constructor(e){super(Kn,"signing",!0);this.id=e.id||"";this.type=getStringOption(e.type,["optional","required"]);this.use=e.use||"";this.usehref=e.usehref||"";this.certificate=new XFAObjectArray}}class Solid extends XFAObject{constructor(e){super(Kn,"solid",!0);this.id=e.id||"";this.use=e.use||"";this.usehref=e.usehref||"";this.extras=null}[In](e){return e?e[In]():"#FFFFFF"}}class Speak extends StringObject{constructor(e){super(Kn,"speak");this.disable=getInteger({data:e.disable,defaultValue:0,validate:e=>1===e});this.id=e.id||"";this.priority=getStringOption(e.priority,["custom","caption","name","toolTip"]);this.rid=e.rid||"";this.use=e.use||"";this.usehref=e.usehref||""}}class Stipple extends XFAObject{constructor(e){super(Kn,"stipple",!0);this.id=e.id||"";this.rate=getInteger({data:e.rate,defaultValue:50,validate:e=>e>=0&&e<=100});this.use=e.use||"";this.usehref=e.usehref||"";this.color=null;this.extras=null}[In](e){const t=this.rate/100;return Util.makeHexColor(Math.round(e.value.r*(1-t)+this.value.r*t),Math.round(e.value.g*(1-t)+this.value.g*t),Math.round(e.value.b*(1-t)+this.value.b*t))}}class Subform extends XFAObject{constructor(e){super(Kn,"subform",!0);this.access=getStringOption(e.access,["open","nonInteractive","protected","readOnly"]);this.allowMacro=getInteger({data:e.allowMacro,defaultValue:0,validate:e=>1===e});this.anchorType=getStringOption(e.anchorType,["topLeft","bottomCenter","bottomLeft","bottomRight","middleCenter","middleLeft","middleRight","topCenter","topRight"]);this.colSpan=getInteger({data:e.colSpan,defaultValue:1,validate:e=>e>=1||-1===e});this.columnWidths=(e.columnWidths||"").trim().split(/\s+/).map((e=>"-1"===e?-1:getMeasurement(e)));this.h=e.h?getMeasurement(e.h):"";this.hAlign=getStringOption(e.hAlign,["left","center","justify","justifyAll","radix","right"]);this.id=e.id||"";this.layout=getStringOption(e.layout,["position","lr-tb","rl-row","rl-tb","row","table","tb"]);this.locale=e.locale||"";this.maxH=getMeasurement(e.maxH,"0pt");this.maxW=getMeasurement(e.maxW,"0pt");this.mergeMode=getStringOption(e.mergeMode,["consumeData","matchTemplate"]);this.minH=getMeasurement(e.minH,"0pt");this.minW=getMeasurement(e.minW,"0pt");this.name=e.name||"";this.presence=getStringOption(e.presence,["visible","hidden","inactive","invisible"]);this.relevant=getRelevant(e.relevant);this.restoreState=getStringOption(e.restoreState,["manual","auto"]);this.scope=getStringOption(e.scope,["name","none"]);this.use=e.use||"";this.usehref=e.usehref||"";this.w=e.w?getMeasurement(e.w):"";this.x=getMeasurement(e.x,"0pt");this.y=getMeasurement(e.y,"0pt");this.assist=null;this.bind=null;this.bookend=null;this.border=null;this.break=null;this.calculate=null;this.desc=null;this.extras=null;this.keep=null;this.margin=null;this.occur=null;this.overflow=null;this.pageSet=null;this.para=null;this.traversal=null;this.validate=null;this.variables=null;this.area=new XFAObjectArray;this.breakAfter=new XFAObjectArray;this.breakBefore=new XFAObjectArray;this.connect=new XFAObjectArray;this.draw=new XFAObjectArray;this.event=new XFAObjectArray;this.exObject=new XFAObjectArray;this.exclGroup=new XFAObjectArray;this.field=new XFAObjectArray;this.proto=new XFAObjectArray;this.setProperty=new XFAObjectArray;this.subform=new XFAObjectArray;this.subformSet=new XFAObjectArray}[wr](){const e=this[Dr]();return e instanceof SubformSet?e[wr]():e}[xr](){return!0}[Jr](){return this.layout.endsWith("-tb")&&0===this[gr].attempt&&this[gr].numberInLine>0||this[Dr]()[Jr]()}*[mr](){yield*getContainedChildren(this)}[Ir](){return flushHTML(this)}[zs](e,t){addHTML(this,e,t)}[hr](){return getAvailableSpace(this)}[Hr](){const e=this[wr]();if(!e[Hr]())return!1;if(void 0!==this[gr]._isSplittable)return this[gr]._isSplittable;if("position"===this.layout||this.layout.includes("row")){this[gr]._isSplittable=!1;return!1}if(this.keep&&"none"!==this.keep.intact){this[gr]._isSplittable=!1;return!1}if(e.layout?.endsWith("-tb")&&0!==e[gr].numberInLine)return!1;this[gr]._isSplittable=!0;return!0}[gn](e){setTabIndex(this);if(this.break){if("auto"!==this.break.after||""!==this.break.afterTarget){const e=new BreakAfter({targetType:this.break.after,target:this.break.afterTarget,startNew:this.break.startNew.toString()});e[Fr]=this[Fr];this[_s](e);this.breakAfter.push(e)}if("auto"!==this.break.before||""!==this.break.beforeTarget){const e=new BreakBefore({targetType:this.break.before,target:this.break.beforeTarget,startNew:this.break.startNew.toString()});e[Fr]=this[Fr];this[_s](e);this.breakBefore.push(e)}if(""!==this.break.overflowTarget){const e=new Overflow({target:this.break.overflowTarget,leader:this.break.overflowLeader,trailer:this.break.overflowTrailer});e[Fr]=this[Fr];this[_s](e);this.overflow.push(e)}this[zr](this.break);this.break=null}if("hidden"===this.presence||"inactive"===this.presence)return HTMLResult.EMPTY;(this.breakBefore.children.length>1||this.breakAfter.children.length>1)&&warn("XFA - Several breakBefore or breakAfter in subforms: please file a bug.");if(this.breakBefore.children.length>=1){const e=this.breakBefore.children[0];if(handleBreak(e))return HTMLResult.breakNode(e)}if(this[gr]?.afterBreakAfter)return HTMLResult.EMPTY;fixDimensions(this);const t=[],i={id:this[cn],class:[]};setAccess(this,i.class);this[gr]||(this[gr]=Object.create(null));Object.assign(this[gr],{children:t,line:null,attributes:i,attempt:0,numberInLine:0,availableSpace:{width:Math.min(this.w||1/0,e.width),height:Math.min(this.h||1/0,e.height)},width:0,height:0,prevHeight:0,currentWidth:0});const a=this[br](),s=a[gr].noLayoutFailure,r=this[Hr]();r||setFirstUnsplittable(this);if(!checkDimensions(this,e))return HTMLResult.FAILURE;const n=new Set(["area","draw","exclGroup","field","subform","subformSet"]);if(this.layout.includes("row")){const e=this[wr]().columnWidths;if(Array.isArray(e)&&e.length>0){this[gr].columnWidths=e;this[gr].currentColumn=0}}const g=toStyle(this,"anchorType","dimensions","position","presence","border","margin","hAlign"),o=["xfaSubform"],c=layoutClass(this);c&&o.push(c);i.style=g;i.class=o;this.name&&(i.xfaName=this.name);if(this.overflow){const t=this.overflow[dr]();if(t.addLeader){t.addLeader=!1;handleOverflow(this,t.leader,e)}}this[Vr]();const C="lr-tb"===this.layout||"rl-tb"===this.layout,h=C?2:1;for(;this[gr].attempt=1){const e=this.breakAfter.children[0];if(handleBreak(e)){this[gr].afterBreakAfter=p;return HTMLResult.breakNode(e)}}delete this[gr];return p}}class SubformSet extends XFAObject{constructor(e){super(Kn,"subformSet",!0);this.id=e.id||"";this.name=e.name||"";this.relation=getStringOption(e.relation,["ordered","choice","unordered"]);this.relevant=getRelevant(e.relevant);this.use=e.use||"";this.usehref=e.usehref||"";this.bookend=null;this.break=null;this.desc=null;this.extras=null;this.occur=null;this.overflow=null;this.breakAfter=new XFAObjectArray;this.breakBefore=new XFAObjectArray;this.subform=new XFAObjectArray;this.subformSet=new XFAObjectArray}*[mr](){yield*getContainedChildren(this)}[wr](){let e=this[Dr]();for(;!(e instanceof Subform);)e=e[Dr]();return e}[xr](){return!0}}class SubjectDN extends ContentObject{constructor(e){super(Kn,"subjectDN");this.delimiter=e.delimiter||",";this.id=e.id||"";this.name=e.name||"";this.use=e.use||"";this.usehref=e.usehref||""}[or](){this[sr]=new Map(this[sr].split(this.delimiter).map((e=>{(e=e.split("=",2))[0]=e[0].trim();return e})))}}class SubjectDNs extends XFAObject{constructor(e){super(Kn,"subjectDNs",!0);this.id=e.id||"";this.type=getStringOption(e.type,["optional","required"]);this.use=e.use||"";this.usehref=e.usehref||"";this.subjectDN=new XFAObjectArray}}class Submit extends XFAObject{constructor(e){super(Kn,"submit",!0);this.embedPDF=getInteger({data:e.embedPDF,defaultValue:0,validate:e=>1===e});this.format=getStringOption(e.format,["xdp","formdata","pdf","urlencoded","xfd","xml"]);this.id=e.id||"";this.target=e.target||"";this.textEncoding=getKeyword({data:e.textEncoding?e.textEncoding.toLowerCase():"",defaultValue:"",validate:e=>["utf-8","big-five","fontspecific","gbk","gb-18030","gb-2312","ksc-5601","none","shift-jis","ucs-2","utf-16"].includes(e)||e.match(/iso-8859-\d{2}/)});this.use=e.use||"";this.usehref=e.usehref||"";this.xdpContent=e.xdpContent||"";this.encrypt=null;this.encryptData=new XFAObjectArray;this.signData=new XFAObjectArray}}class Template extends XFAObject{constructor(e){super(Kn,"template",!0);this.baseProfile=getStringOption(e.baseProfile,["full","interactiveForms"]);this.extras=null;this.subform=new XFAObjectArray}[or](){0===this.subform.children.length&&warn("XFA - No subforms in template node.");this.subform.children.length>=2&&warn("XFA - Several subforms in template node: please file a bug.");this[sn]=5e3}[Hr](){return!0}[An](e,t){return e.startsWith("#")?[this[kr].get(e.slice(1))]:searchNode(this,t,e,!0,!0)}*[nn](){if(!this.subform.children.length)return HTMLResult.success({name:"div",children:[]});this[gr]={overflowNode:null,firstUnsplittable:null,currentContentArea:null,currentPageArea:null,noLayoutFailure:!1,pageNumber:1,pagePosition:"first",oddOrEven:"odd",blankOrNotBlank:"nonBlank",paraStack:[]};const e=this.subform.children[0];e.pageSet[er]();const t=e.pageSet.pageArea.children,i={name:"div",children:[]};let a=null,s=null,r=null;if(e.breakBefore.children.length>=1){s=e.breakBefore.children[0];r=s.target}else if(e.subform.children.length>=1&&e.subform.children[0].breakBefore.children.length>=1){s=e.subform.children[0].breakBefore.children[0];r=s.target}else if(e.break?.beforeTarget){s=e.break;r=s.beforeTarget}else if(e.subform.children.length>=1&&e.subform.children[0].break?.beforeTarget){s=e.subform.children[0].break;r=s.beforeTarget}if(s){const e=this[An](r,s[Dr]());if(e instanceof PageArea){a=e;s[gr]={}}}a||(a=t[0]);a[gr]={numberOfUse:1};const n=a[Dr]();n[gr]={numberOfUse:1,pageIndex:n.pageArea.children.indexOf(a),pageSetIndex:0};let g,o=null,c=null,C=!0,h=0,l=0;for(;;){if(C)h=0;else{i.children.pop();if(3==++h){warn("XFA - Something goes wrong: please file a bug.");return i}}g=null;this[gr].currentPageArea=a;const t=a[gn]().html;i.children.push(t);if(o){this[gr].noLayoutFailure=!0;t.children.push(o[gn](a[gr].space).html);o=null}if(c){this[gr].noLayoutFailure=!0;t.children.push(c[gn](a[gr].space).html);c=null}const s=a.contentArea.children,r=t.children.filter((e=>e.attributes.class.includes("xfaContentarea")));C=!1;this[gr].firstUnsplittable=null;this[gr].noLayoutFailure=!1;const flush=t=>{const i=e[Ir]();if(i){C||=i.children?.length>0;r[t].children.push(i)}};for(let t=l,a=s.length;t0;r[t].children.push(h.html)}else!C&&i.children.length>1&&i.children.pop();return i}if(h.isBreak()){const e=h.breakNode;flush(t);if("auto"===e.targetType)continue;if(e.leader){o=this[An](e.leader,e[Dr]());o=o?o[0]:null}if(e.trailer){c=this[An](e.trailer,e[Dr]());c=c?c[0]:null}if("pageArea"===e.targetType){g=e[gr].target;t=1/0}else if(e[gr].target){g=e[gr].target;l=e[gr].index+1;t=1/0}else t=e[gr].index}else if(this[gr].overflowNode){const e=this[gr].overflowNode;this[gr].overflowNode=null;const i=e[dr](),a=i.target;i.addLeader=null!==i.leader;i.addTrailer=null!==i.trailer;flush(t);const r=t;t=1/0;if(a instanceof PageArea)g=a;else if(a instanceof ContentArea){const e=s.indexOf(a);if(-1!==e)e>r?t=e-1:l=e;else{g=a[Dr]();l=g.contentArea.children.indexOf(a)}}}else flush(t)}this[gr].pageNumber+=1;g&&(g[vr]()?g[gr].numberOfUse+=1:g=null);a=g||a[yr]();yield null}}}class Text extends ContentObject{constructor(e){super(Kn,"text");this.id=e.id||"";this.maxChars=getInteger({data:e.maxChars,defaultValue:0,validate:e=>e>=0});this.name=e.name||"";this.rid=e.rid||"";this.use=e.use||"";this.usehref=e.usehref||""}[Vs](){return!0}[Pr](e){if(e[Tr]===hn.xhtml.id){this[sr]=e;return!0}warn(`XFA - Invalid content in Text: ${e[qr]}.`);return!1}[jr](e){this[sr]instanceof XFAObject||super[jr](e)}[or](){"string"==typeof this[sr]&&(this[sr]=this[sr].replaceAll("\r\n","\n"))}[dr](){return"string"==typeof this[sr]?this[sr].split(/[\u2029\u2028\n]/).reduce(((e,t)=>{t&&e.push(t);return e}),[]).join("\n"):this[sr][rn]()}[gn](e){if("string"==typeof this[sr]){const e=valueToHtml(this[sr]).html;if(this[sr].includes("\u2029")){e.name="div";e.children=[];this[sr].split("\u2029").map((e=>e.split(/[\u2028\n]/).reduce(((e,t)=>{e.push({name:"span",value:t},{name:"br"});return e}),[]))).forEach((t=>{e.children.push({name:"p",children:t})}))}else if(/[\u2028\n]/.test(this[sr])){e.name="div";e.children=[];this[sr].split(/[\u2028\n]/).forEach((t=>{e.children.push({name:"span",value:t},{name:"br"})}))}return HTMLResult.success(e)}return this[sr][gn](e)}}class TextEdit extends XFAObject{constructor(e){super(Kn,"textEdit",!0);this.allowRichText=getInteger({data:e.allowRichText,defaultValue:0,validate:e=>1===e});this.hScrollPolicy=getStringOption(e.hScrollPolicy,["auto","off","on"]);this.id=e.id||"";this.multiLine=getInteger({data:e.multiLine,defaultValue:"",validate:e=>0===e||1===e});this.use=e.use||"";this.usehref=e.usehref||"";this.vScrollPolicy=getStringOption(e.vScrollPolicy,["auto","off","on"]);this.border=null;this.comb=null;this.extras=null;this.margin=null}[gn](e){const t=toStyle(this,"border","font","margin");let i;const a=this[Dr]()[Dr]();""===this.multiLine&&(this.multiLine=a instanceof Draw?1:0);i=1===this.multiLine?{name:"textarea",attributes:{dataId:a[rr]?.[cn]||a[cn],fieldId:a[cn],class:["xfaTextfield"],style:t,"aria-label":ariaLabel(a),"aria-required":!1}}:{name:"input",attributes:{type:"text",dataId:a[rr]?.[cn]||a[cn],fieldId:a[cn],class:["xfaTextfield"],style:t,"aria-label":ariaLabel(a),"aria-required":!1}};if(isRequired(a)){i.attributes["aria-required"]=!0;i.attributes.required=!0}return HTMLResult.success({name:"label",attributes:{class:["xfaLabel"]},children:[i]})}}class Time extends StringObject{constructor(e){super(Kn,"time");this.id=e.id||"";this.name=e.name||"";this.use=e.use||"";this.usehref=e.usehref||""}[or](){const e=this[sr].trim();this[sr]=e?new Date(e):null}[gn](e){return valueToHtml(this[sr]?this[sr].toString():"")}}class TimeStamp extends XFAObject{constructor(e){super(Kn,"timeStamp");this.id=e.id||"";this.server=e.server||"";this.type=getStringOption(e.type,["optional","required"]);this.use=e.use||"";this.usehref=e.usehref||""}}class ToolTip extends StringObject{constructor(e){super(Kn,"toolTip");this.id=e.id||"";this.rid=e.rid||"";this.use=e.use||"";this.usehref=e.usehref||""}}class Traversal extends XFAObject{constructor(e){super(Kn,"traversal",!0);this.id=e.id||"";this.use=e.use||"";this.usehref=e.usehref||"";this.extras=null;this.traverse=new XFAObjectArray}}class Traverse extends XFAObject{constructor(e){super(Kn,"traverse",!0);this.id=e.id||"";this.operation=getStringOption(e.operation,["next","back","down","first","left","right","up"]);this.ref=e.ref||"";this.use=e.use||"";this.usehref=e.usehref||"";this.extras=null;this.script=null}get name(){return this.operation}[Yr](){return!1}}class Ui extends XFAObject{constructor(e){super(Kn,"ui",!0);this.id=e.id||"";this.use=e.use||"";this.usehref=e.usehref||"";this.extras=null;this.picture=null;this.barcode=null;this.button=null;this.checkButton=null;this.choiceList=null;this.dateTimeEdit=null;this.defaultUi=null;this.imageEdit=null;this.numericEdit=null;this.passwordEdit=null;this.signature=null;this.textEdit=null}[dr](){if(void 0===this[gr]){for(const e of Object.getOwnPropertyNames(this)){if("extras"===e||"picture"===e)continue;const t=this[e];if(t instanceof XFAObject){this[gr]=t;return t}}this[gr]=null}return this[gr]}[gn](e){const t=this[dr]();return t?t[gn](e):HTMLResult.EMPTY}}class Validate extends XFAObject{constructor(e){super(Kn,"validate",!0);this.formatTest=getStringOption(e.formatTest,["warning","disabled","error"]);this.id=e.id||"";this.nullTest=getStringOption(e.nullTest,["disabled","error","warning"]);this.scriptTest=getStringOption(e.scriptTest,["error","disabled","warning"]);this.use=e.use||"";this.usehref=e.usehref||"";this.extras=null;this.message=null;this.picture=null;this.script=null}}class Value extends XFAObject{constructor(e){super(Kn,"value",!0);this.id=e.id||"";this.override=getInteger({data:e.override,defaultValue:0,validate:e=>1===e});this.relevant=getRelevant(e.relevant);this.use=e.use||"";this.usehref=e.usehref||"";this.arc=null;this.boolean=null;this.date=null;this.dateTime=null;this.decimal=null;this.exData=null;this.float=null;this.image=null;this.integer=null;this.line=null;this.rectangle=null;this.text=null;this.time=null}[an](e){const t=this[Dr]();if(t instanceof Field&&t.ui?.imageEdit){if(!this.image){this.image=new Image({});this[_s](this.image)}this.image[sr]=e[sr];return}const i=e[qr];if(null===this[i]){for(const e of Object.getOwnPropertyNames(this)){const t=this[e];if(t instanceof XFAObject){this[e]=null;this[zr](t)}}this[e[qr]]=e;this[_s](e)}else this[i][sr]=e[sr]}[rn](){if(this.exData)return"string"==typeof this.exData[sr]?this.exData[sr].trim():this.exData[sr][rn]().trim();for(const e of Object.getOwnPropertyNames(this)){if("image"===e)continue;const t=this[e];if(t instanceof XFAObject)return(t[sr]||"").toString().trim()}return null}[gn](e){for(const t of Object.getOwnPropertyNames(this)){const i=this[t];if(i instanceof XFAObject)return i[gn](e)}return HTMLResult.EMPTY}}class Variables extends XFAObject{constructor(e){super(Kn,"variables",!0);this.id=e.id||"";this.use=e.use||"";this.usehref=e.usehref||"";this.boolean=new XFAObjectArray;this.date=new XFAObjectArray;this.dateTime=new XFAObjectArray;this.decimal=new XFAObjectArray;this.exData=new XFAObjectArray;this.float=new XFAObjectArray;this.image=new XFAObjectArray;this.integer=new XFAObjectArray;this.manifest=new XFAObjectArray;this.script=new XFAObjectArray;this.text=new XFAObjectArray;this.time=new XFAObjectArray}[Yr](){return!0}}class TemplateNamespace{static[Cn](e,t){if(TemplateNamespace.hasOwnProperty(e)){const i=TemplateNamespace[e](t);i[tn](t);return i}}static appearanceFilter(e){return new AppearanceFilter(e)}static arc(e){return new Arc(e)}static area(e){return new Area(e)}static assist(e){return new Assist(e)}static barcode(e){return new Barcode(e)}static bind(e){return new Bind(e)}static bindItems(e){return new BindItems(e)}static bookend(e){return new Bookend(e)}static boolean(e){return new BooleanElement(e)}static border(e){return new Border(e)}static break(e){return new Break(e)}static breakAfter(e){return new BreakAfter(e)}static breakBefore(e){return new BreakBefore(e)}static button(e){return new Button(e)}static calculate(e){return new Calculate(e)}static caption(e){return new Caption(e)}static certificate(e){return new Certificate(e)}static certificates(e){return new Certificates(e)}static checkButton(e){return new CheckButton(e)}static choiceList(e){return new ChoiceList(e)}static color(e){return new Color(e)}static comb(e){return new Comb(e)}static connect(e){return new Connect(e)}static contentArea(e){return new ContentArea(e)}static corner(e){return new Corner(e)}static date(e){return new DateElement(e)}static dateTime(e){return new DateTime(e)}static dateTimeEdit(e){return new DateTimeEdit(e)}static decimal(e){return new Decimal(e)}static defaultUi(e){return new DefaultUi(e)}static desc(e){return new Desc(e)}static digestMethod(e){return new DigestMethod(e)}static digestMethods(e){return new DigestMethods(e)}static draw(e){return new Draw(e)}static edge(e){return new Edge(e)}static encoding(e){return new Encoding(e)}static encodings(e){return new Encodings(e)}static encrypt(e){return new Encrypt(e)}static encryptData(e){return new EncryptData(e)}static encryption(e){return new Encryption(e)}static encryptionMethod(e){return new EncryptionMethod(e)}static encryptionMethods(e){return new EncryptionMethods(e)}static event(e){return new Event(e)}static exData(e){return new ExData(e)}static exObject(e){return new ExObject(e)}static exclGroup(e){return new ExclGroup(e)}static execute(e){return new Execute(e)}static extras(e){return new Extras(e)}static field(e){return new Field(e)}static fill(e){return new Fill(e)}static filter(e){return new Filter(e)}static float(e){return new Float(e)}static font(e){return new template_Font(e)}static format(e){return new Format(e)}static handler(e){return new Handler(e)}static hyphenation(e){return new Hyphenation(e)}static image(e){return new Image(e)}static imageEdit(e){return new ImageEdit(e)}static integer(e){return new Integer(e)}static issuers(e){return new Issuers(e)}static items(e){return new Items(e)}static keep(e){return new Keep(e)}static keyUsage(e){return new KeyUsage(e)}static line(e){return new Line(e)}static linear(e){return new Linear(e)}static lockDocument(e){return new LockDocument(e)}static manifest(e){return new Manifest(e)}static margin(e){return new Margin(e)}static mdp(e){return new Mdp(e)}static medium(e){return new Medium(e)}static message(e){return new Message(e)}static numericEdit(e){return new NumericEdit(e)}static occur(e){return new Occur(e)}static oid(e){return new Oid(e)}static oids(e){return new Oids(e)}static overflow(e){return new Overflow(e)}static pageArea(e){return new PageArea(e)}static pageSet(e){return new PageSet(e)}static para(e){return new Para(e)}static passwordEdit(e){return new PasswordEdit(e)}static pattern(e){return new template_Pattern(e)}static picture(e){return new Picture(e)}static proto(e){return new Proto(e)}static radial(e){return new Radial(e)}static reason(e){return new Reason(e)}static reasons(e){return new Reasons(e)}static rectangle(e){return new Rectangle(e)}static ref(e){return new RefElement(e)}static script(e){return new Script(e)}static setProperty(e){return new SetProperty(e)}static signData(e){return new SignData(e)}static signature(e){return new Signature(e)}static signing(e){return new Signing(e)}static solid(e){return new Solid(e)}static speak(e){return new Speak(e)}static stipple(e){return new Stipple(e)}static subform(e){return new Subform(e)}static subformSet(e){return new SubformSet(e)}static subjectDN(e){return new SubjectDN(e)}static subjectDNs(e){return new SubjectDNs(e)}static submit(e){return new Submit(e)}static template(e){return new Template(e)}static text(e){return new Text(e)}static textEdit(e){return new TextEdit(e)}static time(e){return new Time(e)}static timeStamp(e){return new TimeStamp(e)}static toolTip(e){return new ToolTip(e)}static traversal(e){return new Traversal(e)}static traverse(e){return new Traverse(e)}static ui(e){return new Ui(e)}static validate(e){return new Validate(e)}static value(e){return new Value(e)}static variables(e){return new Variables(e)}}const Wn=hn.datasets.id;function createText(e){const t=new Text({});t[sr]=e;return t}class Binder{constructor(e){this.root=e;this.datasets=e.datasets;this.data=e.datasets?.data||new XmlObject(hn.datasets.id,"data");this.emptyMerge=0===this.data[pr]().length;this.root.form=this.form=e.template[ir]()}_isConsumeData(){return!this.emptyMerge&&this._mergeMode}_isMatchTemplate(){return!this._isConsumeData()}bind(){this._bindElement(this.form,this.data);return this.form}getData(){return this.data}_bindValue(e,t,i){e[rr]=t;if(e[Sr]())if(t[Ur]()){const i=t[ur]();e[an](createText(i))}else if(e instanceof Field&&"multiSelect"===e.ui?.choiceList?.open){const i=t[pr]().map((e=>e[sr].trim())).join("\n");e[an](createText(i))}else this._isConsumeData()&&warn("XFA - Nodes haven't the same type.");else!t[Ur]()||this._isMatchTemplate()?this._bindElement(e,t):warn("XFA - Nodes haven't the same type.")}_findDataByNameToConsume(e,t,i,a){if(!e)return null;let s,r;for(let a=0;a<3;a++){s=i[fr](e,!1,!0);for(;;){r=s.next().value;if(!r)break;if(t===r[Ur]())return r}if(i[Tr]===hn.datasets.id&&"data"===i[qr])break;i=i[Dr]()}if(!a)return null;s=this.data[fr](e,!0,!1);r=s.next().value;if(r)return r;s=this.data[cr](e,!0);r=s.next().value;return r?.[Ur]()?r:null}_setProperties(e,t){if(e.hasOwnProperty("setProperty"))for(const{ref:i,target:a,connection:s}of e.setProperty.children){if(s)continue;if(!i)continue;const r=searchNode(this.root,t,i,!1,!1);if(!r){warn(`XFA - Invalid reference: ${i}.`);continue}const[n]=r;if(!n[Mr](this.data)){warn("XFA - Invalid node: must be a data node.");continue}const g=searchNode(this.root,e,a,!1,!1);if(!g){warn(`XFA - Invalid target: ${a}.`);continue}const[o]=g;if(!o[Mr](e)){warn("XFA - Invalid target: must be a property or subproperty.");continue}const c=o[Dr]();if(o instanceof SetProperty||c instanceof SetProperty){warn("XFA - Invalid target: cannot be a setProperty or one of its properties.");continue}if(o instanceof BindItems||c instanceof BindItems){warn("XFA - Invalid target: cannot be a bindItems or one of its properties.");continue}const C=n[rn](),h=o[qr];if(o instanceof XFAAttribute){const e=Object.create(null);e[h]=C;const t=Reflect.construct(Object.getPrototypeOf(c).constructor,[e]);c[h]=t[h]}else if(o.hasOwnProperty(sr)){o[rr]=n;o[sr]=C;o[or]()}else warn("XFA - Invalid node to use in setProperty")}}_bindItems(e,t){if(!e.hasOwnProperty("items")||!e.hasOwnProperty("bindItems")||e.bindItems.isEmpty())return;for(const t of e.items.children)e[zr](t);e.items.clear();const i=new Items({}),a=new Items({});e[_s](i);e.items.push(i);e[_s](a);e.items.push(a);for(const{ref:s,labelRef:r,valueRef:n,connection:g}of e.bindItems.children){if(g)continue;if(!s)continue;const e=searchNode(this.root,t,s,!1,!1);if(e)for(const t of e){if(!t[Mr](this.datasets)){warn(`XFA - Invalid ref (${s}): must be a datasets child.`);continue}const e=searchNode(this.root,t,r,!0,!1);if(!e){warn(`XFA - Invalid label: ${r}.`);continue}const[g]=e;if(!g[Mr](this.datasets)){warn("XFA - Invalid label: must be a datasets child.");continue}const o=searchNode(this.root,t,n,!0,!1);if(!o){warn(`XFA - Invalid value: ${n}.`);continue}const[c]=o;if(!c[Mr](this.datasets)){warn("XFA - Invalid value: must be a datasets child.");continue}const C=createText(g[rn]()),h=createText(c[rn]());i[_s](C);i.text.push(C);a[_s](h);a.text.push(h)}else warn(`XFA - Invalid reference: ${s}.`)}}_bindOccurrences(e,t,i){let a;if(t.length>1){a=e[ir]();a[zr](a.occur);a.occur=null}this._bindValue(e,t[0],i);this._setProperties(e,t[0]);this._bindItems(e,t[0]);if(1===t.length)return;const s=e[Dr](),r=e[qr],n=s[Rr](e);for(let e=1,g=t.length;et.name===e.name)).length:i[a].children.length;const r=i[Rr](e)+1,n=t.initial-s;if(n){const t=e[ir]();t[zr](t.occur);t.occur=null;i[a].push(t);i[Nr](r,t);for(let e=1;e0)this._bindOccurrences(a,[e[0]],null);else if(this.emptyMerge){const e=t[Tr]===Wn?-1:t[Tr],i=a[rr]=new XmlObject(e,a.name||"root");t[_s](i);this._bindElement(a,i)}continue}if(!a[xr]())continue;let e=!1,s=null,r=null,n=null;if(a.bind){switch(a.bind.match){case"none":this._setAndBind(a,t);continue;case"global":e=!0;break;case"dataRef":if(!a.bind.ref){warn(`XFA - ref is empty in node ${a[qr]}.`);this._setAndBind(a,t);continue}r=a.bind.ref}a.bind.picture&&(s=a.bind.picture[sr])}const[g,o]=this._getOccurInfo(a);if(r){n=searchNode(this.root,t,r,!0,!1);if(null===n){n=createDataNode(this.data,t,r);if(!n)continue;this._isConsumeData()&&(n[ar]=!0);this._setAndBind(a,n);continue}this._isConsumeData()&&(n=n.filter((e=>!e[ar])));n.length>o?n=n.slice(0,o):0===n.length&&(n=null);n&&this._isConsumeData()&&n.forEach((e=>{e[ar]=!0}))}else{if(!a.name){this._setAndBind(a,t);continue}if(this._isConsumeData()){const i=[];for(;i.length0?i:null}else{n=t[fr](a.name,!1,this.emptyMerge).next().value;if(!n){if(0===g){i.push(a);continue}const e=t[Tr]===Wn?-1:t[Tr];n=a[rr]=new XmlObject(e,a.name);this.emptyMerge&&(n[ar]=!0);t[_s](n);this._setAndBind(a,n);continue}this.emptyMerge&&(n[ar]=!0);n=[n]}}n?this._bindOccurrences(a,n,s):g>0?this._setAndBind(a,t):i.push(a)}i.forEach((e=>e[Dr]()[zr](e)))}}class DataHandler{constructor(e,t){this.data=t;this.dataset=e.datasets||null}serialize(e){const t=[[-1,this.data[pr]()]];for(;t.length>0;){const i=t.at(-1),[a,s]=i;if(a+1===s.length){t.pop();continue}const r=s[++i[0]],n=e.get(r[cn]);if(n)r[an](n);else{const t=r[Cr]();for(const i of t.values()){const t=e.get(i[cn]);if(t){i[an](t);break}}}const g=r[pr]();g.length>0&&t.push([-1,g])}const i=[''];if(this.dataset)for(const e of this.dataset[pr]())"data"!==e[qr]&&e[on](i);this.data[on](i);i.push("");return i.join("")}}const jn=hn.config.id;class Acrobat extends XFAObject{constructor(e){super(jn,"acrobat",!0);this.acrobat7=null;this.autoSave=null;this.common=null;this.validate=null;this.validateApprovalSignatures=null;this.submitUrl=new XFAObjectArray}}class Acrobat7 extends XFAObject{constructor(e){super(jn,"acrobat7",!0);this.dynamicRender=null}}class ADBE_JSConsole extends OptionObject{constructor(e){super(jn,"ADBE_JSConsole",["delegate","Enable","Disable"])}}class ADBE_JSDebugger extends OptionObject{constructor(e){super(jn,"ADBE_JSDebugger",["delegate","Enable","Disable"])}}class AddSilentPrint extends Option01{constructor(e){super(jn,"addSilentPrint")}}class AddViewerPreferences extends Option01{constructor(e){super(jn,"addViewerPreferences")}}class AdjustData extends Option10{constructor(e){super(jn,"adjustData")}}class AdobeExtensionLevel extends IntegerObject{constructor(e){super(jn,"adobeExtensionLevel",0,(e=>e>=1&&e<=8))}}class Agent extends XFAObject{constructor(e){super(jn,"agent",!0);this.name=e.name?e.name.trim():"";this.common=new XFAObjectArray}}class AlwaysEmbed extends ContentObject{constructor(e){super(jn,"alwaysEmbed")}}class Amd extends StringObject{constructor(e){super(jn,"amd")}}class config_Area extends XFAObject{constructor(e){super(jn,"area");this.level=getInteger({data:e.level,defaultValue:0,validate:e=>e>=1&&e<=3});this.name=getStringOption(e.name,["","barcode","coreinit","deviceDriver","font","general","layout","merge","script","signature","sourceSet","templateCache"])}}class Attributes extends OptionObject{constructor(e){super(jn,"attributes",["preserve","delegate","ignore"])}}class AutoSave extends OptionObject{constructor(e){super(jn,"autoSave",["disabled","enabled"])}}class Base extends StringObject{constructor(e){super(jn,"base")}}class BatchOutput extends XFAObject{constructor(e){super(jn,"batchOutput");this.format=getStringOption(e.format,["none","concat","zip","zipCompress"])}}class BehaviorOverride extends ContentObject{constructor(e){super(jn,"behaviorOverride")}[or](){this[sr]=new Map(this[sr].trim().split(/\s+/).filter((e=>e.includes(":"))).map((e=>e.split(":",2))))}}class Cache extends XFAObject{constructor(e){super(jn,"cache",!0);this.templateCache=null}}class Change extends Option01{constructor(e){super(jn,"change")}}class Common extends XFAObject{constructor(e){super(jn,"common",!0);this.data=null;this.locale=null;this.localeSet=null;this.messaging=null;this.suppressBanner=null;this.template=null;this.validationMessaging=null;this.versionControl=null;this.log=new XFAObjectArray}}class Compress extends XFAObject{constructor(e){super(jn,"compress");this.scope=getStringOption(e.scope,["imageOnly","document"])}}class CompressLogicalStructure extends Option01{constructor(e){super(jn,"compressLogicalStructure")}}class CompressObjectStream extends Option10{constructor(e){super(jn,"compressObjectStream")}}class Compression extends XFAObject{constructor(e){super(jn,"compression",!0);this.compressLogicalStructure=null;this.compressObjectStream=null;this.level=null;this.type=null}}class Config extends XFAObject{constructor(e){super(jn,"config",!0);this.acrobat=null;this.present=null;this.trace=null;this.agent=new XFAObjectArray}}class Conformance extends OptionObject{constructor(e){super(jn,"conformance",["A","B"])}}class ContentCopy extends Option01{constructor(e){super(jn,"contentCopy")}}class Copies extends IntegerObject{constructor(e){super(jn,"copies",1,(e=>e>=1))}}class Creator extends StringObject{constructor(e){super(jn,"creator")}}class CurrentPage extends IntegerObject{constructor(e){super(jn,"currentPage",0,(e=>e>=0))}}class Data extends XFAObject{constructor(e){super(jn,"data",!0);this.adjustData=null;this.attributes=null;this.incrementalLoad=null;this.outputXSL=null;this.range=null;this.record=null;this.startNode=null;this.uri=null;this.window=null;this.xsl=null;this.excludeNS=new XFAObjectArray;this.transform=new XFAObjectArray}}class Debug extends XFAObject{constructor(e){super(jn,"debug",!0);this.uri=null}}class DefaultTypeface extends ContentObject{constructor(e){super(jn,"defaultTypeface");this.writingScript=getStringOption(e.writingScript,["*","Arabic","Cyrillic","EastEuropeanRoman","Greek","Hebrew","Japanese","Korean","Roman","SimplifiedChinese","Thai","TraditionalChinese","Vietnamese"])}}class Destination extends OptionObject{constructor(e){super(jn,"destination",["pdf","pcl","ps","webClient","zpl"])}}class DocumentAssembly extends Option01{constructor(e){super(jn,"documentAssembly")}}class Driver extends XFAObject{constructor(e){super(jn,"driver",!0);this.name=e.name?e.name.trim():"";this.fontInfo=null;this.xdc=null}}class DuplexOption extends OptionObject{constructor(e){super(jn,"duplexOption",["simplex","duplexFlipLongEdge","duplexFlipShortEdge"])}}class DynamicRender extends OptionObject{constructor(e){super(jn,"dynamicRender",["forbidden","required"])}}class Embed extends Option01{constructor(e){super(jn,"embed")}}class config_Encrypt extends Option01{constructor(e){super(jn,"encrypt")}}class config_Encryption extends XFAObject{constructor(e){super(jn,"encryption",!0);this.encrypt=null;this.encryptionLevel=null;this.permissions=null}}class EncryptionLevel extends OptionObject{constructor(e){super(jn,"encryptionLevel",["40bit","128bit"])}}class Enforce extends StringObject{constructor(e){super(jn,"enforce")}}class Equate extends XFAObject{constructor(e){super(jn,"equate");this.force=getInteger({data:e.force,defaultValue:1,validate:e=>0===e});this.from=e.from||"";this.to=e.to||""}}class EquateRange extends XFAObject{constructor(e){super(jn,"equateRange");this.from=e.from||"";this.to=e.to||"";this._unicodeRange=e.unicodeRange||""}get unicodeRange(){const e=[],t=/U\+([0-9a-fA-F]+)/,i=this._unicodeRange;for(let a of i.split(",").map((e=>e.trim())).filter((e=>!!e))){a=a.split("-",2).map((e=>{const i=e.match(t);return i?parseInt(i[1],16):0}));1===a.length&&a.push(a[0]);e.push(a)}return shadow(this,"unicodeRange",e)}}class Exclude extends ContentObject{constructor(e){super(jn,"exclude")}[or](){this[sr]=this[sr].trim().split(/\s+/).filter((e=>e&&["calculate","close","enter","exit","initialize","ready","validate"].includes(e)))}}class ExcludeNS extends StringObject{constructor(e){super(jn,"excludeNS")}}class FlipLabel extends OptionObject{constructor(e){super(jn,"flipLabel",["usePrinterSetting","on","off"])}}class config_FontInfo extends XFAObject{constructor(e){super(jn,"fontInfo",!0);this.embed=null;this.map=null;this.subsetBelow=null;this.alwaysEmbed=new XFAObjectArray;this.defaultTypeface=new XFAObjectArray;this.neverEmbed=new XFAObjectArray}}class FormFieldFilling extends Option01{constructor(e){super(jn,"formFieldFilling")}}class GroupParent extends StringObject{constructor(e){super(jn,"groupParent")}}class IfEmpty extends OptionObject{constructor(e){super(jn,"ifEmpty",["dataValue","dataGroup","ignore","remove"])}}class IncludeXDPContent extends StringObject{constructor(e){super(jn,"includeXDPContent")}}class IncrementalLoad extends OptionObject{constructor(e){super(jn,"incrementalLoad",["none","forwardOnly"])}}class IncrementalMerge extends Option01{constructor(e){super(jn,"incrementalMerge")}}class Interactive extends Option01{constructor(e){super(jn,"interactive")}}class Jog extends OptionObject{constructor(e){super(jn,"jog",["usePrinterSetting","none","pageSet"])}}class LabelPrinter extends XFAObject{constructor(e){super(jn,"labelPrinter",!0);this.name=getStringOption(e.name,["zpl","dpl","ipl","tcpl"]);this.batchOutput=null;this.flipLabel=null;this.fontInfo=null;this.xdc=null}}class Layout extends OptionObject{constructor(e){super(jn,"layout",["paginate","panel"])}}class Level extends IntegerObject{constructor(e){super(jn,"level",0,(e=>e>0))}}class Linearized extends Option01{constructor(e){super(jn,"linearized")}}class Locale extends StringObject{constructor(e){super(jn,"locale")}}class LocaleSet extends StringObject{constructor(e){super(jn,"localeSet")}}class Log extends XFAObject{constructor(e){super(jn,"log",!0);this.mode=null;this.threshold=null;this.to=null;this.uri=null}}class MapElement extends XFAObject{constructor(e){super(jn,"map",!0);this.equate=new XFAObjectArray;this.equateRange=new XFAObjectArray}}class MediumInfo extends XFAObject{constructor(e){super(jn,"mediumInfo",!0);this.map=null}}class config_Message extends XFAObject{constructor(e){super(jn,"message",!0);this.msgId=null;this.severity=null}}class Messaging extends XFAObject{constructor(e){super(jn,"messaging",!0);this.message=new XFAObjectArray}}class Mode extends OptionObject{constructor(e){super(jn,"mode",["append","overwrite"])}}class ModifyAnnots extends Option01{constructor(e){super(jn,"modifyAnnots")}}class MsgId extends IntegerObject{constructor(e){super(jn,"msgId",1,(e=>e>=1))}}class NameAttr extends StringObject{constructor(e){super(jn,"nameAttr")}}class NeverEmbed extends ContentObject{constructor(e){super(jn,"neverEmbed")}}class NumberOfCopies extends IntegerObject{constructor(e){super(jn,"numberOfCopies",null,(e=>e>=2&&e<=5))}}class OpenAction extends XFAObject{constructor(e){super(jn,"openAction",!0);this.destination=null}}class Output extends XFAObject{constructor(e){super(jn,"output",!0);this.to=null;this.type=null;this.uri=null}}class OutputBin extends StringObject{constructor(e){super(jn,"outputBin")}}class OutputXSL extends XFAObject{constructor(e){super(jn,"outputXSL",!0);this.uri=null}}class Overprint extends OptionObject{constructor(e){super(jn,"overprint",["none","both","draw","field"])}}class Packets extends StringObject{constructor(e){super(jn,"packets")}[or](){"*"!==this[sr]&&(this[sr]=this[sr].trim().split(/\s+/).filter((e=>["config","datasets","template","xfdf","xslt"].includes(e))))}}class PageOffset extends XFAObject{constructor(e){super(jn,"pageOffset");this.x=getInteger({data:e.x,defaultValue:"useXDCSetting",validate:e=>!0});this.y=getInteger({data:e.y,defaultValue:"useXDCSetting",validate:e=>!0})}}class PageRange extends StringObject{constructor(e){super(jn,"pageRange")}[or](){const e=this[sr].trim().split(/\s+/).map((e=>parseInt(e,10))),t=[];for(let i=0,a=e.length;i!1))}}class Pcl extends XFAObject{constructor(e){super(jn,"pcl",!0);this.name=e.name||"";this.batchOutput=null;this.fontInfo=null;this.jog=null;this.mediumInfo=null;this.outputBin=null;this.pageOffset=null;this.staple=null;this.xdc=null}}class Pdf extends XFAObject{constructor(e){super(jn,"pdf",!0);this.name=e.name||"";this.adobeExtensionLevel=null;this.batchOutput=null;this.compression=null;this.creator=null;this.encryption=null;this.fontInfo=null;this.interactive=null;this.linearized=null;this.openAction=null;this.pdfa=null;this.producer=null;this.renderPolicy=null;this.scriptModel=null;this.silentPrint=null;this.submitFormat=null;this.tagged=null;this.version=null;this.viewerPreferences=null;this.xdc=null}}class Pdfa extends XFAObject{constructor(e){super(jn,"pdfa",!0);this.amd=null;this.conformance=null;this.includeXDPContent=null;this.part=null}}class Permissions extends XFAObject{constructor(e){super(jn,"permissions",!0);this.accessibleContent=null;this.change=null;this.contentCopy=null;this.documentAssembly=null;this.formFieldFilling=null;this.modifyAnnots=null;this.plaintextMetadata=null;this.print=null;this.printHighQuality=null}}class PickTrayByPDFSize extends Option01{constructor(e){super(jn,"pickTrayByPDFSize")}}class config_Picture extends StringObject{constructor(e){super(jn,"picture")}}class PlaintextMetadata extends Option01{constructor(e){super(jn,"plaintextMetadata")}}class Presence extends OptionObject{constructor(e){super(jn,"presence",["preserve","dissolve","dissolveStructure","ignore","remove"])}}class Present extends XFAObject{constructor(e){super(jn,"present",!0);this.behaviorOverride=null;this.cache=null;this.common=null;this.copies=null;this.destination=null;this.incrementalMerge=null;this.layout=null;this.output=null;this.overprint=null;this.pagination=null;this.paginationOverride=null;this.script=null;this.validate=null;this.xdp=null;this.driver=new XFAObjectArray;this.labelPrinter=new XFAObjectArray;this.pcl=new XFAObjectArray;this.pdf=new XFAObjectArray;this.ps=new XFAObjectArray;this.submitUrl=new XFAObjectArray;this.webClient=new XFAObjectArray;this.zpl=new XFAObjectArray}}class Print extends Option01{constructor(e){super(jn,"print")}}class PrintHighQuality extends Option01{constructor(e){super(jn,"printHighQuality")}}class PrintScaling extends OptionObject{constructor(e){super(jn,"printScaling",["appdefault","noScaling"])}}class PrinterName extends StringObject{constructor(e){super(jn,"printerName")}}class Producer extends StringObject{constructor(e){super(jn,"producer")}}class Ps extends XFAObject{constructor(e){super(jn,"ps",!0);this.name=e.name||"";this.batchOutput=null;this.fontInfo=null;this.jog=null;this.mediumInfo=null;this.outputBin=null;this.staple=null;this.xdc=null}}class Range extends ContentObject{constructor(e){super(jn,"range")}[or](){this[sr]=this[sr].trim().split(/\s*,\s*/,2).map((e=>e.split("-").map((e=>parseInt(e.trim(),10))))).filter((e=>e.every((e=>!isNaN(e))))).map((e=>{1===e.length&&e.push(e[0]);return e}))}}class Record extends ContentObject{constructor(e){super(jn,"record")}[or](){this[sr]=this[sr].trim();const e=parseInt(this[sr],10);!isNaN(e)&&e>=0&&(this[sr]=e)}}class Relevant extends ContentObject{constructor(e){super(jn,"relevant")}[or](){this[sr]=this[sr].trim().split(/\s+/)}}class Rename extends ContentObject{constructor(e){super(jn,"rename")}[or](){this[sr]=this[sr].trim();(this[sr].toLowerCase().startsWith("xml")||new RegExp("[\\p{L}_][\\p{L}\\d._\\p{M}-]*","u").test(this[sr]))&&warn("XFA - Rename: invalid XFA name")}}class RenderPolicy extends OptionObject{constructor(e){super(jn,"renderPolicy",["server","client"])}}class RunScripts extends OptionObject{constructor(e){super(jn,"runScripts",["both","client","none","server"])}}class config_Script extends XFAObject{constructor(e){super(jn,"script",!0);this.currentPage=null;this.exclude=null;this.runScripts=null}}class ScriptModel extends OptionObject{constructor(e){super(jn,"scriptModel",["XFA","none"])}}class Severity extends OptionObject{constructor(e){super(jn,"severity",["ignore","error","information","trace","warning"])}}class SilentPrint extends XFAObject{constructor(e){super(jn,"silentPrint",!0);this.addSilentPrint=null;this.printerName=null}}class Staple extends XFAObject{constructor(e){super(jn,"staple");this.mode=getStringOption(e.mode,["usePrinterSetting","on","off"])}}class StartNode extends StringObject{constructor(e){super(jn,"startNode")}}class StartPage extends IntegerObject{constructor(e){super(jn,"startPage",0,(e=>!0))}}class SubmitFormat extends OptionObject{constructor(e){super(jn,"submitFormat",["html","delegate","fdf","xml","pdf"])}}class SubmitUrl extends StringObject{constructor(e){super(jn,"submitUrl")}}class SubsetBelow extends IntegerObject{constructor(e){super(jn,"subsetBelow",100,(e=>e>=0&&e<=100))}}class SuppressBanner extends Option01{constructor(e){super(jn,"suppressBanner")}}class Tagged extends Option01{constructor(e){super(jn,"tagged")}}class config_Template extends XFAObject{constructor(e){super(jn,"template",!0);this.base=null;this.relevant=null;this.startPage=null;this.uri=null;this.xsl=null}}class Threshold extends OptionObject{constructor(e){super(jn,"threshold",["trace","error","information","warning"])}}class To extends OptionObject{constructor(e){super(jn,"to",["null","memory","stderr","stdout","system","uri"])}}class TemplateCache extends XFAObject{constructor(e){super(jn,"templateCache");this.maxEntries=getInteger({data:e.maxEntries,defaultValue:5,validate:e=>e>=0})}}class Trace extends XFAObject{constructor(e){super(jn,"trace",!0);this.area=new XFAObjectArray}}class Transform extends XFAObject{constructor(e){super(jn,"transform",!0);this.groupParent=null;this.ifEmpty=null;this.nameAttr=null;this.picture=null;this.presence=null;this.rename=null;this.whitespace=null}}class Type extends OptionObject{constructor(e){super(jn,"type",["none","ascii85","asciiHex","ccittfax","flate","lzw","runLength","native","xdp","mergedXDP"])}}class Uri extends StringObject{constructor(e){super(jn,"uri")}}class config_Validate extends OptionObject{constructor(e){super(jn,"validate",["preSubmit","prePrint","preExecute","preSave"])}}class ValidateApprovalSignatures extends ContentObject{constructor(e){super(jn,"validateApprovalSignatures")}[or](){this[sr]=this[sr].trim().split(/\s+/).filter((e=>["docReady","postSign"].includes(e)))}}class ValidationMessaging extends OptionObject{constructor(e){super(jn,"validationMessaging",["allMessagesIndividually","allMessagesTogether","firstMessageOnly","noMessages"])}}class Version extends OptionObject{constructor(e){super(jn,"version",["1.7","1.6","1.5","1.4","1.3","1.2"])}}class VersionControl extends XFAObject{constructor(e){super(jn,"VersionControl");this.outputBelow=getStringOption(e.outputBelow,["warn","error","update"]);this.sourceAbove=getStringOption(e.sourceAbove,["warn","error"]);this.sourceBelow=getStringOption(e.sourceBelow,["update","maintain"])}}class ViewerPreferences extends XFAObject{constructor(e){super(jn,"viewerPreferences",!0);this.ADBE_JSConsole=null;this.ADBE_JSDebugger=null;this.addViewerPreferences=null;this.duplexOption=null;this.enforce=null;this.numberOfCopies=null;this.pageRange=null;this.pickTrayByPDFSize=null;this.printScaling=null}}class WebClient extends XFAObject{constructor(e){super(jn,"webClient",!0);this.name=e.name?e.name.trim():"";this.fontInfo=null;this.xdc=null}}class Whitespace extends OptionObject{constructor(e){super(jn,"whitespace",["preserve","ltrim","normalize","rtrim","trim"])}}class Window extends ContentObject{constructor(e){super(jn,"window")}[or](){const e=this[sr].trim().split(/\s*,\s*/,2).map((e=>parseInt(e,10)));if(e.some((e=>isNaN(e))))this[sr]=[0,0];else{1===e.length&&e.push(e[0]);this[sr]=e}}}class Xdc extends XFAObject{constructor(e){super(jn,"xdc",!0);this.uri=new XFAObjectArray;this.xsl=new XFAObjectArray}}class Xdp extends XFAObject{constructor(e){super(jn,"xdp",!0);this.packets=null}}class Xsl extends XFAObject{constructor(e){super(jn,"xsl",!0);this.debug=null;this.uri=null}}class Zpl extends XFAObject{constructor(e){super(jn,"zpl",!0);this.name=e.name?e.name.trim():"";this.batchOutput=null;this.flipLabel=null;this.fontInfo=null;this.xdc=null}}class ConfigNamespace{static[Cn](e,t){if(ConfigNamespace.hasOwnProperty(e))return ConfigNamespace[e](t)}static acrobat(e){return new Acrobat(e)}static acrobat7(e){return new Acrobat7(e)}static ADBE_JSConsole(e){return new ADBE_JSConsole(e)}static ADBE_JSDebugger(e){return new ADBE_JSDebugger(e)}static addSilentPrint(e){return new AddSilentPrint(e)}static addViewerPreferences(e){return new AddViewerPreferences(e)}static adjustData(e){return new AdjustData(e)}static adobeExtensionLevel(e){return new AdobeExtensionLevel(e)}static agent(e){return new Agent(e)}static alwaysEmbed(e){return new AlwaysEmbed(e)}static amd(e){return new Amd(e)}static area(e){return new config_Area(e)}static attributes(e){return new Attributes(e)}static autoSave(e){return new AutoSave(e)}static base(e){return new Base(e)}static batchOutput(e){return new BatchOutput(e)}static behaviorOverride(e){return new BehaviorOverride(e)}static cache(e){return new Cache(e)}static change(e){return new Change(e)}static common(e){return new Common(e)}static compress(e){return new Compress(e)}static compressLogicalStructure(e){return new CompressLogicalStructure(e)}static compressObjectStream(e){return new CompressObjectStream(e)}static compression(e){return new Compression(e)}static config(e){return new Config(e)}static conformance(e){return new Conformance(e)}static contentCopy(e){return new ContentCopy(e)}static copies(e){return new Copies(e)}static creator(e){return new Creator(e)}static currentPage(e){return new CurrentPage(e)}static data(e){return new Data(e)}static debug(e){return new Debug(e)}static defaultTypeface(e){return new DefaultTypeface(e)}static destination(e){return new Destination(e)}static documentAssembly(e){return new DocumentAssembly(e)}static driver(e){return new Driver(e)}static duplexOption(e){return new DuplexOption(e)}static dynamicRender(e){return new DynamicRender(e)}static embed(e){return new Embed(e)}static encrypt(e){return new config_Encrypt(e)}static encryption(e){return new config_Encryption(e)}static encryptionLevel(e){return new EncryptionLevel(e)}static enforce(e){return new Enforce(e)}static equate(e){return new Equate(e)}static equateRange(e){return new EquateRange(e)}static exclude(e){return new Exclude(e)}static excludeNS(e){return new ExcludeNS(e)}static flipLabel(e){return new FlipLabel(e)}static fontInfo(e){return new config_FontInfo(e)}static formFieldFilling(e){return new FormFieldFilling(e)}static groupParent(e){return new GroupParent(e)}static ifEmpty(e){return new IfEmpty(e)}static includeXDPContent(e){return new IncludeXDPContent(e)}static incrementalLoad(e){return new IncrementalLoad(e)}static incrementalMerge(e){return new IncrementalMerge(e)}static interactive(e){return new Interactive(e)}static jog(e){return new Jog(e)}static labelPrinter(e){return new LabelPrinter(e)}static layout(e){return new Layout(e)}static level(e){return new Level(e)}static linearized(e){return new Linearized(e)}static locale(e){return new Locale(e)}static localeSet(e){return new LocaleSet(e)}static log(e){return new Log(e)}static map(e){return new MapElement(e)}static mediumInfo(e){return new MediumInfo(e)}static message(e){return new config_Message(e)}static messaging(e){return new Messaging(e)}static mode(e){return new Mode(e)}static modifyAnnots(e){return new ModifyAnnots(e)}static msgId(e){return new MsgId(e)}static nameAttr(e){return new NameAttr(e)}static neverEmbed(e){return new NeverEmbed(e)}static numberOfCopies(e){return new NumberOfCopies(e)}static openAction(e){return new OpenAction(e)}static output(e){return new Output(e)}static outputBin(e){return new OutputBin(e)}static outputXSL(e){return new OutputXSL(e)}static overprint(e){return new Overprint(e)}static packets(e){return new Packets(e)}static pageOffset(e){return new PageOffset(e)}static pageRange(e){return new PageRange(e)}static pagination(e){return new Pagination(e)}static paginationOverride(e){return new PaginationOverride(e)}static part(e){return new Part(e)}static pcl(e){return new Pcl(e)}static pdf(e){return new Pdf(e)}static pdfa(e){return new Pdfa(e)}static permissions(e){return new Permissions(e)}static pickTrayByPDFSize(e){return new PickTrayByPDFSize(e)}static picture(e){return new config_Picture(e)}static plaintextMetadata(e){return new PlaintextMetadata(e)}static presence(e){return new Presence(e)}static present(e){return new Present(e)}static print(e){return new Print(e)}static printHighQuality(e){return new PrintHighQuality(e)}static printScaling(e){return new PrintScaling(e)}static printerName(e){return new PrinterName(e)}static producer(e){return new Producer(e)}static ps(e){return new Ps(e)}static range(e){return new Range(e)}static record(e){return new Record(e)}static relevant(e){return new Relevant(e)}static rename(e){return new Rename(e)}static renderPolicy(e){return new RenderPolicy(e)}static runScripts(e){return new RunScripts(e)}static script(e){return new config_Script(e)}static scriptModel(e){return new ScriptModel(e)}static severity(e){return new Severity(e)}static silentPrint(e){return new SilentPrint(e)}static staple(e){return new Staple(e)}static startNode(e){return new StartNode(e)}static startPage(e){return new StartPage(e)}static submitFormat(e){return new SubmitFormat(e)}static submitUrl(e){return new SubmitUrl(e)}static subsetBelow(e){return new SubsetBelow(e)}static suppressBanner(e){return new SuppressBanner(e)}static tagged(e){return new Tagged(e)}static template(e){return new config_Template(e)}static templateCache(e){return new TemplateCache(e)}static threshold(e){return new Threshold(e)}static to(e){return new To(e)}static trace(e){return new Trace(e)}static transform(e){return new Transform(e)}static type(e){return new Type(e)}static uri(e){return new Uri(e)}static validate(e){return new config_Validate(e)}static validateApprovalSignatures(e){return new ValidateApprovalSignatures(e)}static validationMessaging(e){return new ValidationMessaging(e)}static version(e){return new Version(e)}static versionControl(e){return new VersionControl(e)}static viewerPreferences(e){return new ViewerPreferences(e)}static webClient(e){return new WebClient(e)}static whitespace(e){return new Whitespace(e)}static window(e){return new Window(e)}static xdc(e){return new Xdc(e)}static xdp(e){return new Xdp(e)}static xsl(e){return new Xsl(e)}static zpl(e){return new Zpl(e)}}const Xn=hn.connectionSet.id;class ConnectionSet extends XFAObject{constructor(e){super(Xn,"connectionSet",!0);this.wsdlConnection=new XFAObjectArray;this.xmlConnection=new XFAObjectArray;this.xsdConnection=new XFAObjectArray}}class EffectiveInputPolicy extends XFAObject{constructor(e){super(Xn,"effectiveInputPolicy");this.id=e.id||"";this.name=e.name||"";this.use=e.use||"";this.usehref=e.usehref||""}}class EffectiveOutputPolicy extends XFAObject{constructor(e){super(Xn,"effectiveOutputPolicy");this.id=e.id||"";this.name=e.name||"";this.use=e.use||"";this.usehref=e.usehref||""}}class Operation extends StringObject{constructor(e){super(Xn,"operation");this.id=e.id||"";this.input=e.input||"";this.name=e.name||"";this.output=e.output||"";this.use=e.use||"";this.usehref=e.usehref||""}}class RootElement extends StringObject{constructor(e){super(Xn,"rootElement");this.id=e.id||"";this.name=e.name||"";this.use=e.use||"";this.usehref=e.usehref||""}}class SoapAction extends StringObject{constructor(e){super(Xn,"soapAction");this.id=e.id||"";this.name=e.name||"";this.use=e.use||"";this.usehref=e.usehref||""}}class SoapAddress extends StringObject{constructor(e){super(Xn,"soapAddress");this.id=e.id||"";this.name=e.name||"";this.use=e.use||"";this.usehref=e.usehref||""}}class connection_set_Uri extends StringObject{constructor(e){super(Xn,"uri");this.id=e.id||"";this.name=e.name||"";this.use=e.use||"";this.usehref=e.usehref||""}}class WsdlAddress extends StringObject{constructor(e){super(Xn,"wsdlAddress");this.id=e.id||"";this.name=e.name||"";this.use=e.use||"";this.usehref=e.usehref||""}}class WsdlConnection extends XFAObject{constructor(e){super(Xn,"wsdlConnection",!0);this.dataDescription=e.dataDescription||"";this.name=e.name||"";this.effectiveInputPolicy=null;this.effectiveOutputPolicy=null;this.operation=null;this.soapAction=null;this.soapAddress=null;this.wsdlAddress=null}}class XmlConnection extends XFAObject{constructor(e){super(Xn,"xmlConnection",!0);this.dataDescription=e.dataDescription||"";this.name=e.name||"";this.uri=null}}class XsdConnection extends XFAObject{constructor(e){super(Xn,"xsdConnection",!0);this.dataDescription=e.dataDescription||"";this.name=e.name||"";this.rootElement=null;this.uri=null}}class ConnectionSetNamespace{static[Cn](e,t){if(ConnectionSetNamespace.hasOwnProperty(e))return ConnectionSetNamespace[e](t)}static connectionSet(e){return new ConnectionSet(e)}static effectiveInputPolicy(e){return new EffectiveInputPolicy(e)}static effectiveOutputPolicy(e){return new EffectiveOutputPolicy(e)}static operation(e){return new Operation(e)}static rootElement(e){return new RootElement(e)}static soapAction(e){return new SoapAction(e)}static soapAddress(e){return new SoapAddress(e)}static uri(e){return new connection_set_Uri(e)}static wsdlAddress(e){return new WsdlAddress(e)}static wsdlConnection(e){return new WsdlConnection(e)}static xmlConnection(e){return new XmlConnection(e)}static xsdConnection(e){return new XsdConnection(e)}}const Zn=hn.datasets.id;class datasets_Data extends XmlObject{constructor(e){super(Zn,"data",e)}[Lr](){return!0}}class Datasets extends XFAObject{constructor(e){super(Zn,"datasets",!0);this.data=null;this.Signature=null}[Pr](e){const t=e[qr];("data"===t&&e[Tr]===Zn||"Signature"===t&&e[Tr]===hn.signature.id)&&(this[t]=e);this[_s](e)}}class DatasetsNamespace{static[Cn](e,t){if(DatasetsNamespace.hasOwnProperty(e))return DatasetsNamespace[e](t)}static datasets(e){return new Datasets(e)}static data(e){return new datasets_Data(e)}}const Vn=hn.localeSet.id;class CalendarSymbols extends XFAObject{constructor(e){super(Vn,"calendarSymbols",!0);this.name="gregorian";this.dayNames=new XFAObjectArray(2);this.eraNames=null;this.meridiemNames=null;this.monthNames=new XFAObjectArray(2)}}class CurrencySymbol extends StringObject{constructor(e){super(Vn,"currencySymbol");this.name=getStringOption(e.name,["symbol","isoname","decimal"])}}class CurrencySymbols extends XFAObject{constructor(e){super(Vn,"currencySymbols",!0);this.currencySymbol=new XFAObjectArray(3)}}class DatePattern extends StringObject{constructor(e){super(Vn,"datePattern");this.name=getStringOption(e.name,["full","long","med","short"])}}class DatePatterns extends XFAObject{constructor(e){super(Vn,"datePatterns",!0);this.datePattern=new XFAObjectArray(4)}}class DateTimeSymbols extends ContentObject{constructor(e){super(Vn,"dateTimeSymbols")}}class Day extends StringObject{constructor(e){super(Vn,"day")}}class DayNames extends XFAObject{constructor(e){super(Vn,"dayNames",!0);this.abbr=getInteger({data:e.abbr,defaultValue:0,validate:e=>1===e});this.day=new XFAObjectArray(7)}}class Era extends StringObject{constructor(e){super(Vn,"era")}}class EraNames extends XFAObject{constructor(e){super(Vn,"eraNames",!0);this.era=new XFAObjectArray(2)}}class locale_set_Locale extends XFAObject{constructor(e){super(Vn,"locale",!0);this.desc=e.desc||"";this.name="isoname";this.calendarSymbols=null;this.currencySymbols=null;this.datePatterns=null;this.dateTimeSymbols=null;this.numberPatterns=null;this.numberSymbols=null;this.timePatterns=null;this.typeFaces=null}}class locale_set_LocaleSet extends XFAObject{constructor(e){super(Vn,"localeSet",!0);this.locale=new XFAObjectArray}}class Meridiem extends StringObject{constructor(e){super(Vn,"meridiem")}}class MeridiemNames extends XFAObject{constructor(e){super(Vn,"meridiemNames",!0);this.meridiem=new XFAObjectArray(2)}}class Month extends StringObject{constructor(e){super(Vn,"month")}}class MonthNames extends XFAObject{constructor(e){super(Vn,"monthNames",!0);this.abbr=getInteger({data:e.abbr,defaultValue:0,validate:e=>1===e});this.month=new XFAObjectArray(12)}}class NumberPattern extends StringObject{constructor(e){super(Vn,"numberPattern");this.name=getStringOption(e.name,["full","long","med","short"])}}class NumberPatterns extends XFAObject{constructor(e){super(Vn,"numberPatterns",!0);this.numberPattern=new XFAObjectArray(4)}}class NumberSymbol extends StringObject{constructor(e){super(Vn,"numberSymbol");this.name=getStringOption(e.name,["decimal","grouping","percent","minus","zero"])}}class NumberSymbols extends XFAObject{constructor(e){super(Vn,"numberSymbols",!0);this.numberSymbol=new XFAObjectArray(5)}}class TimePattern extends StringObject{constructor(e){super(Vn,"timePattern");this.name=getStringOption(e.name,["full","long","med","short"])}}class TimePatterns extends XFAObject{constructor(e){super(Vn,"timePatterns",!0);this.timePattern=new XFAObjectArray(4)}}class TypeFace extends XFAObject{constructor(e){super(Vn,"typeFace",!0);this.name=""|e.name}}class TypeFaces extends XFAObject{constructor(e){super(Vn,"typeFaces",!0);this.typeFace=new XFAObjectArray}}class LocaleSetNamespace{static[Cn](e,t){if(LocaleSetNamespace.hasOwnProperty(e))return LocaleSetNamespace[e](t)}static calendarSymbols(e){return new CalendarSymbols(e)}static currencySymbol(e){return new CurrencySymbol(e)}static currencySymbols(e){return new CurrencySymbols(e)}static datePattern(e){return new DatePattern(e)}static datePatterns(e){return new DatePatterns(e)}static dateTimeSymbols(e){return new DateTimeSymbols(e)}static day(e){return new Day(e)}static dayNames(e){return new DayNames(e)}static era(e){return new Era(e)}static eraNames(e){return new EraNames(e)}static locale(e){return new locale_set_Locale(e)}static localeSet(e){return new locale_set_LocaleSet(e)}static meridiem(e){return new Meridiem(e)}static meridiemNames(e){return new MeridiemNames(e)}static month(e){return new Month(e)}static monthNames(e){return new MonthNames(e)}static numberPattern(e){return new NumberPattern(e)}static numberPatterns(e){return new NumberPatterns(e)}static numberSymbol(e){return new NumberSymbol(e)}static numberSymbols(e){return new NumberSymbols(e)}static timePattern(e){return new TimePattern(e)}static timePatterns(e){return new TimePatterns(e)}static typeFace(e){return new TypeFace(e)}static typeFaces(e){return new TypeFaces(e)}}const zn=hn.signature.id;class signature_Signature extends XFAObject{constructor(e){super(zn,"signature",!0)}}class SignatureNamespace{static[Cn](e,t){if(SignatureNamespace.hasOwnProperty(e))return SignatureNamespace[e](t)}static signature(e){return new signature_Signature(e)}}const _n=hn.stylesheet.id;class Stylesheet extends XFAObject{constructor(e){super(_n,"stylesheet",!0)}}class StylesheetNamespace{static[Cn](e,t){if(StylesheetNamespace.hasOwnProperty(e))return StylesheetNamespace[e](t)}static stylesheet(e){return new Stylesheet(e)}}const $n=hn.xdp.id;class xdp_Xdp extends XFAObject{constructor(e){super($n,"xdp",!0);this.uuid=e.uuid||"";this.timeStamp=e.timeStamp||"";this.config=null;this.connectionSet=null;this.datasets=null;this.localeSet=null;this.stylesheet=new XFAObjectArray;this.template=null}[Wr](e){const t=hn[e[qr]];return t&&e[Tr]===t.id}}class XdpNamespace{static[Cn](e,t){if(XdpNamespace.hasOwnProperty(e))return XdpNamespace[e](t)}static xdp(e){return new xdp_Xdp(e)}}const Ag=hn.xhtml.id,eg=Symbol(),tg=new Set(["color","font","font-family","font-size","font-stretch","font-style","font-weight","margin","margin-bottom","margin-left","margin-right","margin-top","letter-spacing","line-height","orphans","page-break-after","page-break-before","page-break-inside","tab-interval","tab-stop","text-align","text-decoration","text-indent","vertical-align","widows","kerning-mode","xfa-font-horizontal-scale","xfa-font-vertical-scale","xfa-spacerun","xfa-tab-stops"]),ig=new Map([["page-break-after","breakAfter"],["page-break-before","breakBefore"],["page-break-inside","breakInside"],["kerning-mode",e=>"none"===e?"none":"normal"],["xfa-font-horizontal-scale",e=>`scaleX(${Math.max(0,Math.min(parseInt(e)/100)).toFixed(2)})`],["xfa-font-vertical-scale",e=>`scaleY(${Math.max(0,Math.min(parseInt(e)/100)).toFixed(2)})`],["xfa-spacerun",""],["xfa-tab-stops",""],["font-size",(e,t)=>measureToString(.99*(e=t.fontSize=getMeasurement(e)))],["letter-spacing",e=>measureToString(getMeasurement(e))],["line-height",e=>measureToString(getMeasurement(e))],["margin",e=>measureToString(getMeasurement(e))],["margin-bottom",e=>measureToString(getMeasurement(e))],["margin-left",e=>measureToString(getMeasurement(e))],["margin-right",e=>measureToString(getMeasurement(e))],["margin-top",e=>measureToString(getMeasurement(e))],["text-indent",e=>measureToString(getMeasurement(e))],["font-family",e=>e],["vertical-align",e=>measureToString(getMeasurement(e))]]),ag=/\s+/g,sg=/[\r\n]+/g,rg=/\r\n?/g;function mapStyle(e,t,i){const a=Object.create(null);if(!e)return a;const s=Object.create(null);for(const[t,i]of e.split(";").map((e=>e.split(":",2)))){const e=ig.get(t);if(""===e)continue;let r=i;e&&(r="string"==typeof e?e:e(i,s));t.endsWith("scale")?a.transform=a.transform?`${a[t]} ${r}`:r:a[t.replaceAll(/-([a-zA-Z])/g,((e,t)=>t.toUpperCase()))]=r}a.fontFamily&&setFontFamily({typeface:a.fontFamily,weight:a.fontWeight||"normal",posture:a.fontStyle||"normal",size:s.fontSize||0},t,t[Fr].fontFinder,a);if(i&&a.verticalAlign&&"0px"!==a.verticalAlign&&a.fontSize){const e=.583,t=.333,i=getMeasurement(a.fontSize);a.fontSize=measureToString(i*e);a.verticalAlign=measureToString(Math.sign(getMeasurement(a.verticalAlign))*i*t)}i&&a.fontSize&&(a.fontSize=`calc(${a.fontSize} * var(--scale-factor))`);fixTextIndent(a);return a}const ng=new Set(["body","html"]);class XhtmlObject extends XmlObject{constructor(e,t){super(Ag,t);this[eg]=!1;this.style=e.style||""}[Ar](e){super[Ar](e);this.style=function checkStyle(e){return e.style?e.style.trim().split(/\s*;\s*/).filter((e=>!!e)).map((e=>e.split(/\s*:\s*/,2))).filter((([t,i])=>{"font-family"===t&&e[Fr].usedTypefaces.add(i);return tg.has(t)})).map((e=>e.join(":"))).join(";"):""}(this)}[Vs](){return!ng.has(this[qr])}[jr](e,t=!1){if(t)this[eg]=!0;else{e=e.replaceAll(sg,"");this.style.includes("xfa-spacerun:yes")||(e=e.replaceAll(ag," "))}e&&(this[sr]+=e)}[Xr](e,t=!0){const i=Object.create(null),a={top:NaN,bottom:NaN,left:NaN,right:NaN};let s=null;for(const[e,t]of this.style.split(";").map((e=>e.split(":",2))))switch(e){case"font-family":i.typeface=stripQuotes(t);break;case"font-size":i.size=getMeasurement(t);break;case"font-weight":i.weight=t;break;case"font-style":i.posture=t;break;case"letter-spacing":i.letterSpacing=getMeasurement(t);break;case"margin":const e=t.split(/ \t/).map((e=>getMeasurement(e)));switch(e.length){case 1:a.top=a.bottom=a.left=a.right=e[0];break;case 2:a.top=a.bottom=e[0];a.left=a.right=e[1];break;case 3:a.top=e[0];a.bottom=e[2];a.left=a.right=e[1];break;case 4:a.top=e[0];a.left=e[1];a.bottom=e[2];a.right=e[3]}break;case"margin-top":a.top=getMeasurement(t);break;case"margin-bottom":a.bottom=getMeasurement(t);break;case"margin-left":a.left=getMeasurement(t);break;case"margin-right":a.right=getMeasurement(t);break;case"line-height":s=getMeasurement(t)}e.pushData(i,a,s);if(this[sr])e.addString(this[sr]);else for(const t of this[pr]())"#text"!==t[qr]?t[Xr](e):e.addString(t[sr]);t&&e.popFont()}[gn](e){const t=[];this[gr]={children:t};this[$s]({});if(0===t.length&&!this[sr])return HTMLResult.EMPTY;let i;i=this[eg]?this[sr]?this[sr].replaceAll(rg,"\n"):void 0:this[sr]||void 0;return HTMLResult.success({name:this[qr],attributes:{href:this.href,style:mapStyle(this.style,this,this[eg])},children:t,value:i})}}class A extends XhtmlObject{constructor(e){super(e,"a");this.href=fixURL(e.href)||""}}class B extends XhtmlObject{constructor(e){super(e,"b")}[Xr](e){e.pushFont({weight:"bold"});super[Xr](e);e.popFont()}}class Body extends XhtmlObject{constructor(e){super(e,"body")}[gn](e){const t=super[gn](e),{html:i}=t;if(!i)return HTMLResult.EMPTY;i.name="div";i.attributes.class=["xfaRich"];return t}}class Br extends XhtmlObject{constructor(e){super(e,"br")}[rn](){return"\n"}[Xr](e){e.addString("\n")}[gn](e){return HTMLResult.success({name:"br"})}}class Html extends XhtmlObject{constructor(e){super(e,"html")}[gn](e){const t=[];this[gr]={children:t};this[$s]({});if(0===t.length)return HTMLResult.success({name:"div",attributes:{class:["xfaRich"],style:{}},value:this[sr]||""});if(1===t.length){const e=t[0];if(e.attributes?.class.includes("xfaRich"))return HTMLResult.success(e)}return HTMLResult.success({name:"div",attributes:{class:["xfaRich"],style:{}},children:t})}}class I extends XhtmlObject{constructor(e){super(e,"i")}[Xr](e){e.pushFont({posture:"italic"});super[Xr](e);e.popFont()}}class Li extends XhtmlObject{constructor(e){super(e,"li")}}class Ol extends XhtmlObject{constructor(e){super(e,"ol")}}class P extends XhtmlObject{constructor(e){super(e,"p")}[Xr](e){super[Xr](e,!1);e.addString("\n");e.addPara();e.popFont()}[rn](){return this[Dr]()[pr]().at(-1)===this?super[rn]():super[rn]()+"\n"}}class Span extends XhtmlObject{constructor(e){super(e,"span")}}class Sub extends XhtmlObject{constructor(e){super(e,"sub")}}class Sup extends XhtmlObject{constructor(e){super(e,"sup")}}class Ul extends XhtmlObject{constructor(e){super(e,"ul")}}class XhtmlNamespace{static[Cn](e,t){if(XhtmlNamespace.hasOwnProperty(e))return XhtmlNamespace[e](t)}static a(e){return new A(e)}static b(e){return new B(e)}static body(e){return new Body(e)}static br(e){return new Br(e)}static html(e){return new Html(e)}static i(e){return new I(e)}static li(e){return new Li(e)}static ol(e){return new Ol(e)}static p(e){return new P(e)}static span(e){return new Span(e)}static sub(e){return new Sub(e)}static sup(e){return new Sup(e)}static ul(e){return new Ul(e)}}const gg={config:ConfigNamespace,connection:ConnectionSetNamespace,datasets:DatasetsNamespace,localeSet:LocaleSetNamespace,signature:SignatureNamespace,stylesheet:StylesheetNamespace,template:TemplateNamespace,xdp:XdpNamespace,xhtml:XhtmlNamespace};class UnknownNamespace{constructor(e){this.namespaceId=e}[Cn](e,t){return new XmlObject(this.namespaceId,e,t)}}class Root extends XFAObject{constructor(e){super(-1,"root",Object.create(null));this.element=null;this[kr]=e}[Pr](e){this.element=e;return!0}[or](){super[or]();if(this.element.template instanceof Template){this[kr].set(_r,this.element);this.element.template[$r](this[kr]);this.element.template[kr]=this[kr]}}}class Empty extends XFAObject{constructor(){super(-1,"",Object.create(null))}[Pr](e){return!1}}class Builder{constructor(e=null){this._namespaceStack=[];this._nsAgnosticLevel=0;this._namespacePrefixes=new Map;this._namespaces=new Map;this._nextNsId=Math.max(...Object.values(hn).map((({id:e})=>e)));this._currentNamespace=e||new UnknownNamespace(++this._nextNsId)}buildRoot(e){return new Root(e)}build({nsPrefix:e,name:t,attributes:i,namespace:a,prefixes:s}){const r=null!==a;if(r){this._namespaceStack.push(this._currentNamespace);this._currentNamespace=this._searchNamespace(a)}s&&this._addNamespacePrefix(s);if(i.hasOwnProperty(Or)){const e=gg.datasets,t=i[Or];let a=null;for(const[i,s]of Object.entries(t)){if(this._getNamespaceToUse(i)===e){a={xfa:s};break}}a?i[Or]=a:delete i[Or]}const n=this._getNamespaceToUse(e),g=n?.[Cn](t,i)||new Empty;g[Lr]()&&this._nsAgnosticLevel++;(r||s||g[Lr]())&&(g[tr]={hasNamespace:r,prefixes:s,nsAgnostic:g[Lr]()});return g}isNsAgnostic(){return this._nsAgnosticLevel>0}_searchNamespace(e){let t=this._namespaces.get(e);if(t)return t;for(const[i,{check:a}]of Object.entries(hn))if(a(e)){t=gg[i];if(t){this._namespaces.set(e,t);return t}break}t=new UnknownNamespace(++this._nextNsId);this._namespaces.set(e,t);return t}_addNamespacePrefix(e){for(const{prefix:t,value:i}of e){const e=this._searchNamespace(i);let a=this._namespacePrefixes.get(t);if(!a){a=[];this._namespacePrefixes.set(t,a)}a.push(e)}}_getNamespaceToUse(e){if(!e)return this._currentNamespace;const t=this._namespacePrefixes.get(e);if(t?.length>0)return t.at(-1);warn(`Unknown namespace prefix: ${e}.`);return null}clean(e){const{hasNamespace:t,prefixes:i,nsAgnostic:a}=e;t&&(this._currentNamespace=this._namespaceStack.pop());i&&i.forEach((({prefix:e})=>{this._namespacePrefixes.get(e).pop()}));a&&this._nsAgnosticLevel--}}class XFAParser extends XMLParserBase{constructor(e=null,t=!1){super();this._builder=new Builder(e);this._stack=[];this._globalData={usedTypefaces:new Set};this._ids=new Map;this._current=this._builder.buildRoot(this._ids);this._errorCode=Us;this._whiteRegex=/^\s+$/;this._nbsps=/\xa0+/g;this._richText=t}parse(e){this.parseXml(e);if(this._errorCode===Us){this._current[or]();return this._current.element}}onText(e){e=e.replace(this._nbsps,(e=>e.slice(1)+" "));this._richText||this._current[Vs]()?this._current[jr](e,this._richText):this._whiteRegex.test(e)||this._current[jr](e.trim())}onCdata(e){this._current[jr](e)}_mkAttributes(e,t){let i=null,a=null;const s=Object.create({});for(const{name:r,value:n}of e)if("xmlns"===r)i?warn(`XFA - multiple namespace definition in <${t}>`):i=n;else if(r.startsWith("xmlns:")){const e=r.substring(6);a||(a=[]);a.push({prefix:e,value:n})}else{const e=r.indexOf(":");if(-1===e)s[r]=n;else{let t=s[Or];t||(t=s[Or]=Object.create(null));const[i,a]=[r.slice(0,e),r.slice(e+1)];(t[i]||=Object.create(null))[a]=n}}return[i,a,s]}_getNameAndPrefix(e,t){const i=e.indexOf(":");return-1===i?[e,null]:[e.substring(i+1),t?"":e.substring(0,i)]}onBeginElement(e,t,i){const[a,s,r]=this._mkAttributes(t,e),[n,g]=this._getNameAndPrefix(e,this._builder.isNsAgnostic()),o=this._builder.build({nsPrefix:g,name:n,attributes:r,namespace:a,prefixes:s});o[Fr]=this._globalData;if(i){o[or]();this._current[Pr](o)&&o[en](this._ids);o[Ar](this._builder)}else{this._stack.push(this._current);this._current=o}}onEndElement(e){const t=this._current;if(t[Gr]()&&"string"==typeof t[sr]){const e=new XFAParser;e._globalData=this._globalData;const i=e.parse(t[sr]);t[sr]=null;t[Pr](i)}t[or]();this._current=this._stack.pop();this._current[Pr](t)&&t[en](this._ids);t[Ar](this._builder)}onError(e){this._errorCode=e}}class XFAFactory{constructor(e){try{this.root=(new XFAParser).parse(XFAFactory._createDocument(e));const t=new Binder(this.root);this.form=t.bind();this.dataHandler=new DataHandler(this.root,t.getData());this.form[Fr].template=this.form}catch(e){warn(`XFA - an error occurred during parsing and binding: ${e}`)}}isValid(){return this.root&&this.form}_createPagesHelper(){const e=this.form[nn]();return new Promise(((t,i)=>{const nextIteration=()=>{try{const i=e.next();i.done?t(i.value):setTimeout(nextIteration,0)}catch(e){i(e)}};setTimeout(nextIteration,0)}))}async _createPages(){try{this.pages=await this._createPagesHelper();this.dims=this.pages.children.map((e=>{const{width:t,height:i}=e.attributes.style;return[0,0,parseInt(t),parseInt(i)]}))}catch(e){warn(`XFA - an error occurred during layout: ${e}`)}}getBoundingBox(e){return this.dims[e]}async getNumPages(){this.pages||await this._createPages();return this.dims.length}setImages(e){this.form[Fr].images=e}setFonts(e){this.form[Fr].fontFinder=new FontFinder(e);const t=[];for(let e of this.form[Fr].usedTypefaces){e=stripQuotes(e);this.form[Fr].fontFinder.find(e)||t.push(e)}return t.length>0?t:null}appendFonts(e,t){this.form[Fr].fontFinder.add(e,t)}async getPages(){this.pages||await this._createPages();const e=this.pages;this.pages=null;return e}serializeData(e){return this.dataHandler.serialize(e)}static _createDocument(e){return e["/xdp:xdp"]?Object.values(e).join(""):e["xdp:xdp"]}static getRichTextAsHtml(e){if(!e||"string"!=typeof e)return null;try{let t=new XFAParser(XhtmlNamespace,!0).parse(e);if(!["body","xhtml"].includes(t[qr])){const e=XhtmlNamespace.body({});e[_s](t);t=e}const i=t[gn]();if(!i.success)return null;const{html:a}=i,{attributes:s}=a;if(s){s.class&&(s.class=s.class.filter((e=>!e.startsWith("xfa"))));s.dir="auto"}return{html:a,str:t[rn]()}}catch(e){warn(`XFA - an error occurred during parsing of rich text: ${e}`)}return null}}class AnnotationFactory{static createGlobals(e){return Promise.all([e.ensureCatalog("acroForm"),e.ensureDoc("xfaDatasets"),e.ensureCatalog("structTreeRoot"),e.ensureCatalog("baseUrl"),e.ensureCatalog("attachments")]).then((([t,i,a,s,r])=>({pdfManager:e,acroForm:t instanceof Dict?t:Dict.empty,xfaDatasets:i,structTreeRoot:a,baseUrl:s,attachments:r})),(e=>{warn(`createGlobals: "${e}".`);return null}))}static async create(e,t,i,a,s,r,n){const g=s?await this._getPageIndex(e,t,i.pdfManager):null;return i.pdfManager.ensure(this,"_create",[e,t,i,a,s,r,g,n])}static _create(e,t,i,a,s=!1,r=null,n=null,g=null){const o=e.fetchIfRef(t);if(!(o instanceof Dict))return;const{acroForm:c,pdfManager:C}=i,h=t instanceof Ref?t.toString():`annot_${a.createObjId()}`;let l=o.get("Subtype");l=l instanceof Name?l.name:null;const Q={xref:e,ref:t,dict:o,subtype:l,id:h,annotationGlobals:i,collectFields:s,orphanFields:r,needAppearances:!s&&!0===c.get("NeedAppearances"),pageIndex:n,evaluatorOptions:C.evaluatorOptions,pageRef:g};switch(l){case"Link":return new LinkAnnotation(Q);case"Text":return new TextAnnotation(Q);case"Widget":let e=getInheritableProperty({dict:o,key:"FT"});e=e instanceof Name?e.name:null;switch(e){case"Tx":return new TextWidgetAnnotation(Q);case"Btn":return new ButtonWidgetAnnotation(Q);case"Ch":return new ChoiceWidgetAnnotation(Q);case"Sig":return new SignatureWidgetAnnotation(Q)}warn(`Unimplemented widget field type "${e}", falling back to base field type.`);return new WidgetAnnotation(Q);case"Popup":return new PopupAnnotation(Q);case"FreeText":return new FreeTextAnnotation(Q);case"Line":return new LineAnnotation(Q);case"Square":return new SquareAnnotation(Q);case"Circle":return new CircleAnnotation(Q);case"PolyLine":return new PolylineAnnotation(Q);case"Polygon":return new PolygonAnnotation(Q);case"Caret":return new CaretAnnotation(Q);case"Ink":return new InkAnnotation(Q);case"Highlight":return new HighlightAnnotation(Q);case"Underline":return new UnderlineAnnotation(Q);case"Squiggly":return new SquigglyAnnotation(Q);case"StrikeOut":return new StrikeOutAnnotation(Q);case"Stamp":return new StampAnnotation(Q);case"FileAttachment":return new FileAttachmentAnnotation(Q);default:s||warn(l?`Unimplemented annotation type "${l}", falling back to base annotation.`:"Annotation is missing the required /Subtype.");return new Annotation(Q)}}static async _getPageIndex(e,t,i){try{const a=await e.fetchIfRefAsync(t);if(!(a instanceof Dict))return-1;const s=a.getRaw("P");if(s instanceof Ref)try{return await i.ensureCatalog("getPageIndex",[s])}catch(e){info(`_getPageIndex -- not a valid page reference: "${e}".`)}if(a.has("Kids"))return-1;const r=await i.ensureDoc("numPages");for(let e=0;ee/255))}function getQuadPoints(e,t){const i=e.getArray("QuadPoints");if(!isNumberArray(i,null)||0===i.length||i.length%8>0)return null;const a=new Float32Array(i.length);for(let e=0,s=i.length;et[2]||Et[3]))return null;a.set([l,u,Q,u,l,E,Q,E],e)}return a}function getTransformMatrix(e,t,i){const[a,s,r,n]=Util.getAxialAlignedBoundingBox(t,i);if(a===r||s===n)return[1,0,0,1,e[0],e[1]];const g=(e[2]-e[0])/(r-a),o=(e[3]-e[1])/(n-s);return[g,0,0,o,e[0]-a*g,e[1]-s*o]}class Annotation{constructor(e){const{dict:t,xref:i,annotationGlobals:a,ref:s,orphanFields:r}=e,n=r?.get(s);n&&t.set("Parent",n);this.setTitle(t.get("T"));this.setContents(t.get("Contents"));this.setModificationDate(t.get("M"));this.setFlags(t.get("F"));this.setRectangle(t.getArray("Rect"));this.setColor(t.getArray("C"));this.setBorderStyle(t);this.setAppearance(t);this.setOptionalContent(t);const g=t.get("MK");this.setBorderAndBackgroundColors(g);this.setRotation(g,t);this.ref=e.ref instanceof Ref?e.ref:null;this._streams=[];this.appearance&&this._streams.push(this.appearance);const o=!!(this.flags&eA),c=!!(this.flags&tA);this.data={annotationFlags:this.flags,borderStyle:this.borderStyle,color:this.color,backgroundColor:this.backgroundColor,borderColor:this.borderColor,rotation:this.rotation,contentsObj:this._contents,hasAppearance:!!this.appearance,id:e.id,modificationDate:this.modificationDate,rect:this.rectangle,subtype:e.subtype,hasOwnCanvas:!1,noRotate:!!(this.flags&$),noHTML:o&&c,isEditable:!1,structParent:-1};if(a.structTreeRoot){let i=t.get("StructParent");this.data.structParent=i=Number.isInteger(i)&&i>=0?i:-1;a.structTreeRoot.addAnnotationIdToPage(e.pageRef,i)}if(e.collectFields){const a=t.get("Kids");if(Array.isArray(a)){const e=[];for(const t of a)t instanceof Ref&&e.push(t.toString());0!==e.length&&(this.data.kidIds=e)}this.data.actions=collectActions(i,t,dA);this.data.fieldName=this._constructFieldName(t);this.data.pageIndex=e.pageIndex}const C=t.get("IT");C instanceof Name&&(this.data.it=C.name);this._isOffscreenCanvasSupported=e.evaluatorOptions.isOffscreenCanvasSupported;this._fallbackFontDict=null;this._needAppearances=!1}_hasFlag(e,t){return!!(e&t)}_buildFlags(e,t){let{flags:i}=this;if(void 0===e){if(void 0===t)return;return t?i&~_:i&~z|_}if(e){i|=_;return t?i&~AA|z:i&~z|AA}i&=~(z|AA);return t?i&~_:i|_}_isViewable(e){return!this._hasFlag(e,V)&&!this._hasFlag(e,AA)}_isPrintable(e){return this._hasFlag(e,_)&&!this._hasFlag(e,z)&&!this._hasFlag(e,V)}mustBeViewed(e,t){const i=e?.get(this.data.id)?.noView;return void 0!==i?!i:this.viewable&&!this._hasFlag(this.flags,z)}mustBePrinted(e){const t=e?.get(this.data.id)?.noPrint;return void 0!==t?!t:this.printable}mustBeViewedWhenEditing(e,t=null){return e?!this.data.isEditable:!t?.has(this.data.id)}get viewable(){return null!==this.data.quadPoints&&(0===this.flags||this._isViewable(this.flags))}get printable(){return null!==this.data.quadPoints&&(0!==this.flags&&this._isPrintable(this.flags))}_parseStringHelper(e){const t="string"==typeof e?stringToPDFString(e):"";return{str:t,dir:t&&"rtl"===bidi(t).dir?"rtl":"ltr"}}setDefaultAppearance(e){const{dict:t,annotationGlobals:i}=e,a=getInheritableProperty({dict:t,key:"DA"})||i.acroForm.get("DA");this._defaultAppearance="string"==typeof a?a:"";this.data.defaultAppearanceData=parseDefaultAppearance(this._defaultAppearance)}setTitle(e){this._title=this._parseStringHelper(e)}setContents(e){this._contents=this._parseStringHelper(e)}setModificationDate(e){this.modificationDate="string"==typeof e?e:null}setFlags(e){this.flags=Number.isInteger(e)&&e>0?e:0;this.flags&V&&"Annotation"!==this.constructor.name&&(this.flags^=V)}hasFlag(e){return this._hasFlag(this.flags,e)}setRectangle(e){this.rectangle=lookupNormalRect(e,[0,0,0,0])}setColor(e){this.color=getRgbColor(e)}setLineEndings(e){this.lineEndings=["None","None"];if(Array.isArray(e)&&2===e.length)for(let t=0;t<2;t++){const i=e[t];if(i instanceof Name)switch(i.name){case"None":continue;case"Square":case"Circle":case"Diamond":case"OpenArrow":case"ClosedArrow":case"Butt":case"ROpenArrow":case"RClosedArrow":case"Slash":this.lineEndings[t]=i.name;continue}warn(`Ignoring invalid lineEnding: ${i}`)}}setRotation(e,t){this.rotation=0;let i=e instanceof Dict?e.get("R")||0:t.get("Rotate")||0;if(Number.isInteger(i)&&0!==i){i%=360;i<0&&(i+=360);i%90==0&&(this.rotation=i)}}setBorderAndBackgroundColors(e){if(e instanceof Dict){this.borderColor=getRgbColor(e.getArray("BC"),null);this.backgroundColor=getRgbColor(e.getArray("BG"),null)}else this.borderColor=this.backgroundColor=null}setBorderStyle(e){this.borderStyle=new AnnotationBorderStyle;if(e instanceof Dict)if(e.has("BS")){const t=e.get("BS");if(t instanceof Dict){const e=t.get("Type");if(!e||isName(e,"Border")){this.borderStyle.setWidth(t.get("W"),this.rectangle);this.borderStyle.setStyle(t.get("S"));this.borderStyle.setDashArray(t.getArray("D"))}}}else if(e.has("Border")){const t=e.getArray("Border");if(Array.isArray(t)&&t.length>=3){this.borderStyle.setHorizontalCornerRadius(t[0]);this.borderStyle.setVerticalCornerRadius(t[1]);this.borderStyle.setWidth(t[2],this.rectangle);4===t.length&&this.borderStyle.setDashArray(t[3],!0)}}else this.borderStyle.setWidth(0)}setAppearance(e){this.appearance=null;const t=e.get("AP");if(!(t instanceof Dict))return;const i=t.get("N");if(i instanceof BaseStream){this.appearance=i;return}if(!(i instanceof Dict))return;const a=e.get("AS");if(!(a instanceof Name&&i.has(a.name)))return;const s=i.get(a.name);s instanceof BaseStream&&(this.appearance=s)}setOptionalContent(e){this.oc=null;const t=e.get("OC");t instanceof Name?warn("setOptionalContent: Support for /Name-entry is not implemented."):t instanceof Dict&&(this.oc=t)}loadResources(e,t){return t.dict.getAsync("Resources").then((t=>{if(!t)return;return new ObjectLoader(t,e,t.xref).load().then((function(){return t}))}))}async getOperatorList(e,t,a,s){const{hasOwnCanvas:r,id:n,rect:g}=this.data;let c=this.appearance;const C=!!(r&&a&o);if(C&&(g[0]===g[2]||g[1]===g[3])){this.data.hasOwnCanvas=!1;return{opList:new OperatorList,separateForm:!1,separateCanvas:!1}}if(!c){if(!C)return{opList:new OperatorList,separateForm:!1,separateCanvas:!1};c=new StringStream("");c.dict=new Dict}const h=c.dict,l=await this.loadResources(["ExtGState","ColorSpace","Pattern","Shading","XObject","Font"],c),Q=lookupRect(h.getArray("BBox"),[0,0,1,1]),E=lookupMatrix(h.getArray("Matrix"),i),u=getTransformMatrix(g,Q,E),d=new OperatorList;let f;this.oc&&(f=await e.parseMarkedContentProps(this.oc,null));void 0!==f&&d.addOp(Ye,["OC",f]);d.addOp(je,[n,g,u,E,C]);await e.getOperatorList({stream:c,task:t,resources:l,operatorList:d,fallbackFontDict:this._fallbackFontDict});d.addOp(Xe,[]);void 0!==f&&d.addOp(ve,[]);this.reset();return{opList:d,separateForm:!1,separateCanvas:C}}async save(e,t,i){return null}get hasTextContent(){return!1}async extractTextContent(e,t,i){if(!this.appearance)return;const a=await this.loadResources(["ExtGState","Font","Properties","XObject"],this.appearance),s=[],r=[];let n=null;const g={desiredSize:Math.Infinity,ready:!0,enqueue(e,t){for(const t of e.items)if(void 0!==t.str){n||=t.transform.slice(-2);r.push(t.str);if(t.hasEOL){s.push(r.join("").trimEnd());r.length=0}}}};await e.getTextContent({stream:this.appearance,task:t,resources:a,includeMarkedContent:!0,keepWhiteSpace:!0,sink:g,viewBox:i});this.reset();r.length&&s.push(r.join("").trimEnd());if(s.length>1||s[0]){const e=this.appearance.dict,t=lookupRect(e.getArray("BBox"),null),i=lookupMatrix(e.getArray("Matrix"),null);this.data.textPosition=this._transformPoint(n,t,i);this.data.textContent=s}}_transformPoint(e,t,i){const{rect:a}=this.data;t||=[0,0,1,1];i||=[1,0,0,1,0,0];const s=getTransformMatrix(a,t,i);s[4]-=a[0];s[5]-=a[1];e=Util.applyTransform(e,s);return Util.applyTransform(e,i)}getFieldObject(){return this.data.kidIds?{id:this.data.id,actions:this.data.actions,name:this.data.fieldName,strokeColor:this.data.borderColor,fillColor:this.data.backgroundColor,type:"",kidIds:this.data.kidIds,page:this.data.pageIndex,rotation:this.rotation}:null}reset(){for(const e of this._streams)e.reset()}_constructFieldName(e){if(!e.has("T")&&!e.has("Parent")){warn("Unknown field name, falling back to empty field name.");return""}if(!e.has("Parent"))return stringToPDFString(e.get("T"));const t=[];e.has("T")&&t.unshift(stringToPDFString(e.get("T")));let i=e;const a=new RefSet;e.objId&&a.put(e.objId);for(;i.has("Parent");){i=i.get("Parent");if(!(i instanceof Dict)||i.objId&&a.has(i.objId))break;i.objId&&a.put(i.objId);i.has("T")&&t.unshift(stringToPDFString(i.get("T")))}return t.join(".")}}class AnnotationBorderStyle{constructor(){this.width=1;this.rawWidth=1;this.style=BA;this.dashArray=[3];this.horizontalCornerRadius=0;this.verticalCornerRadius=0}setWidth(e,t=[0,0,0,0]){if(e instanceof Name)this.width=0;else if("number"==typeof e){if(e>0){this.rawWidth=e;const i=(t[2]-t[0])/2,a=(t[3]-t[1])/2;if(i>0&&a>0&&(e>i||e>a)){warn(`AnnotationBorderStyle.setWidth - ignoring width: ${e}`);e=1}}this.width=e}}setStyle(e){if(e instanceof Name)switch(e.name){case"S":this.style=BA;break;case"D":this.style=lA;break;case"B":this.style=QA;break;case"I":this.style=EA;break;case"U":this.style=uA}}setDashArray(e,t=!1){if(Array.isArray(e)){let i=!0,a=!0;for(const t of e){if(!(+t>=0)){i=!1;break}t>0&&(a=!1)}if(0===e.length||i&&!a){this.dashArray=e;t&&this.setStyle(Name.get("D"))}else this.width=0}else e&&(this.width=0)}setHorizontalCornerRadius(e){Number.isInteger(e)&&(this.horizontalCornerRadius=e)}setVerticalCornerRadius(e){Number.isInteger(e)&&(this.verticalCornerRadius=e)}}class MarkupAnnotation extends Annotation{constructor(e){super(e);const{dict:t}=e;if(t.has("IRT")){const e=t.getRaw("IRT");this.data.inReplyTo=e instanceof Ref?e.toString():null;const i=t.get("RT");this.data.replyType=i instanceof Name?i.name:Z}let i=null;if(this.data.replyType===X){const e=t.get("IRT");this.setTitle(e.get("T"));this.data.titleObj=this._title;this.setContents(e.get("Contents"));this.data.contentsObj=this._contents;if(e.has("CreationDate")){this.setCreationDate(e.get("CreationDate"));this.data.creationDate=this.creationDate}else this.data.creationDate=null;if(e.has("M")){this.setModificationDate(e.get("M"));this.data.modificationDate=this.modificationDate}else this.data.modificationDate=null;i=e.getRaw("Popup");if(e.has("C")){this.setColor(e.getArray("C"));this.data.color=this.color}else this.data.color=null}else{this.data.titleObj=this._title;this.setCreationDate(t.get("CreationDate"));this.data.creationDate=this.creationDate;i=t.getRaw("Popup");t.has("C")||(this.data.color=null)}this.data.popupRef=i instanceof Ref?i.toString():null;t.has("RC")&&(this.data.richText=XFAFactory.getRichTextAsHtml(t.get("RC")))}setCreationDate(e){this.creationDate="string"==typeof e?e:null}_setDefaultAppearance({xref:e,extra:t,strokeColor:i,fillColor:a,blendMode:s,strokeAlpha:r,fillAlpha:n,pointsCallback:g}){let o=Number.MAX_VALUE,c=Number.MAX_VALUE,C=Number.MIN_VALUE,h=Number.MIN_VALUE;const l=["q"];t&&l.push(t);i&&l.push(`${i[0]} ${i[1]} ${i[2]} RG`);a&&l.push(`${a[0]} ${a[1]} ${a[2]} rg`);let Q=this.data.quadPoints;Q||(Q=Float32Array.from([this.rectangle[0],this.rectangle[3],this.rectangle[2],this.rectangle[3],this.rectangle[0],this.rectangle[1],this.rectangle[2],this.rectangle[1]]));for(let e=0,t=Q.length;e"string"==typeof e)).map((e=>stringToPDFString(e))):e instanceof Name?stringToPDFString(e.name):"string"==typeof e?stringToPDFString(e):null}hasFieldFlag(e){return!!(this.data.fieldFlags&e)}_isViewable(e){return!0}mustBeViewed(e,t){return t?this.viewable:super.mustBeViewed(e,t)&&!this._hasFlag(this.flags,AA)}getRotationMatrix(e){let t=e?.get(this.data.id)?.rotation;void 0===t&&(t=this.rotation);if(0===t)return i;return getRotationMatrix(t,this.data.rect[2]-this.data.rect[0],this.data.rect[3]-this.data.rect[1])}getBorderAndBackgroundAppearances(e){let t=e?.get(this.data.id)?.rotation;void 0===t&&(t=this.rotation);if(!this.backgroundColor&&!this.borderColor)return"";const i=this.data.rect[2]-this.data.rect[0],a=this.data.rect[3]-this.data.rect[1],s=0===t||180===t?`0 0 ${i} ${a} re`:`0 0 ${a} ${i} re`;let r="";this.backgroundColor&&(r=`${getPdfColor(this.backgroundColor,!0)} ${s} f `);if(this.borderColor){r+=`${this.borderStyle.width||1} w ${getPdfColor(this.borderColor,!1)} ${s} S `}return r}async getOperatorList(e,t,i,a){if(i&h&&!(this instanceof SignatureWidgetAnnotation)&&!this.data.noHTML&&!this.data.hasOwnCanvas)return{opList:new OperatorList,separateForm:!0,separateCanvas:!1};if(!this._hasText)return super.getOperatorList(e,t,i,a);const s=await this._getAppearance(e,t,i,a);if(this.appearance&&null===s)return super.getOperatorList(e,t,i,a);const r=new OperatorList;if(!this._defaultAppearance||null===s)return{opList:r,separateForm:!1,separateCanvas:!1};const n=!!(this.data.hasOwnCanvas&&i&o),g=[0,0,this.data.rect[2]-this.data.rect[0],this.data.rect[3]-this.data.rect[1]],c=getTransformMatrix(this.data.rect,g,[1,0,0,1,0,0]);let C;this.oc&&(C=await e.parseMarkedContentProps(this.oc,null));void 0!==C&&r.addOp(Ye,["OC",C]);r.addOp(je,[this.data.id,this.data.rect,c,this.getRotationMatrix(a),n]);const l=new StringStream(s);await e.getOperatorList({stream:l,task:t,resources:this._fieldResources.mergedResources,operatorList:r});r.addOp(Xe,[]);void 0!==C&&r.addOp(ve,[]);return{opList:r,separateForm:!1,separateCanvas:n}}_getMKDict(e){const t=new Dict(null);e&&t.set("R",e);this.borderColor&&t.set("BC",getPdfColorArray(this.borderColor));this.backgroundColor&&t.set("BG",getPdfColorArray(this.backgroundColor));return t.size>0?t:null}amendSavedDict(e,t){}async save(e,t,a){const s=a?.get(this.data.id),r=this._buildFlags(s?.noView,s?.noPrint);let n=s?.value,g=s?.rotation;if(n===this.data.fieldValue||void 0===n){if(!this._hasValueFromXFA&&void 0===g&&void 0===r)return null;n||=this.data.fieldValue}if(void 0===g&&!this._hasValueFromXFA&&Array.isArray(n)&&Array.isArray(this.data.fieldValue)&&isArrayEqual(n,this.data.fieldValue)&&void 0===r)return null;void 0===g&&(g=this.rotation);let o=null;if(!this._needAppearances){o=await this._getAppearance(e,t,C,a);if(null===o&&void 0===r)return null}let c=!1;if(o?.needAppearances){c=!0;o=null}const{xref:h}=e,l=h.fetchIfRef(this.ref);if(!(l instanceof Dict))return null;const Q=new Dict(h);for(const e of l.getKeys())"AP"!==e&&Q.set(e,l.getRaw(e));if(void 0!==r){Q.set("F",r);if(null===o&&!c){const e=l.getRaw("AP");e&&Q.set("AP",e)}}const E={path:this.data.fieldName,value:n};Q.set("V",Array.isArray(n)?n.map(stringToAsciiOrUTF16BE):stringToAsciiOrUTF16BE(n));this.amendSavedDict(a,Q);const u=this._getMKDict(g);u&&Q.set("MK",u);const d=[],f=[{ref:this.ref,data:"",xfa:E,needAppearances:c}];if(null!==o){const e=h.getNewTemporaryRef(),t=new Dict(h);Q.set("AP",t);t.set("N",e);const s=this._getSaveFieldResources(h),r=new StringStream(o),n=r.dict=new Dict(h);n.set("Subtype",Name.get("Form"));n.set("Resources",s);n.set("BBox",[0,0,this.data.rect[2]-this.data.rect[0],this.data.rect[3]-this.data.rect[1]]);const g=this.getRotationMatrix(a);g!==i&&n.set("Matrix",g);await writeObject(e,r,d,h);f.push({ref:e,data:d.join(""),xfa:null,needAppearances:!1});d.length=0}Q.set("M",`D:${getModificationDate()}`);await writeObject(this.ref,Q,d,h);f[0].data=d.join("");return f}async _getAppearance(e,t,i,a){if(this.hasFieldFlag(rA))return null;const s=a?.get(this.data.id);let r,g;if(s){r=s.formattedValue||s.value;g=s.rotation}if(void 0===g&&void 0===r&&!this._needAppearances&&(!this._hasValueFromXFA||this.appearance))return null;const o=this.getBorderAndBackgroundAppearances(a);if(void 0===r){r=this.data.fieldValue;if(!r)return`/Tx BMC q ${o}Q EMC`}Array.isArray(r)&&1===r.length&&(r=r[0]);assert("string"==typeof r,"Expected `value` to be a string.");r=r.trimEnd();if(this.data.combo){const e=this.data.options.find((({exportValue:e})=>r===e));r=e?.displayValue||r}if(""===r)return`/Tx BMC q ${o}Q EMC`;void 0===g&&(g=this.rotation);let c,h=-1;if(this.data.multiLine){c=r.split(/\r\n?|\n/).map((e=>e.normalize("NFC")));h=c.length}else c=[r.replace(/\r\n?|\n/,"").normalize("NFC")];let l=this.data.rect[3]-this.data.rect[1],Q=this.data.rect[2]-this.data.rect[0];90!==g&&270!==g||([Q,l]=[l,Q]);this._defaultAppearance||(this.data.defaultAppearanceData=parseDefaultAppearance(this._defaultAppearance="/Helvetica 0 Tf 0 g"));let E,u,d,f=await WidgetAnnotation._getFontData(e,t,this.data.defaultAppearanceData,this._fieldResources.mergedResources);const p=[];let m=!1;for(const e of c){const t=f.encodeString(e);t.length>1&&(m=!0);p.push(t.join(""))}if(m&&i&C)return{needAppearances:!0};if(m&&this._isOffscreenCanvasSupported){const i=this.data.comb?"monospace":"sans-serif",a=new FakeUnicodeFont(e.xref,i),s=a.createFontResources(c.join("")),n=s.getRaw("Font");if(this._fieldResources.mergedResources.has("Font")){const e=this._fieldResources.mergedResources.get("Font");for(const t of n.getKeys())e.set(t,n.getRaw(t))}else this._fieldResources.mergedResources.set("Font",n);const g=a.fontName.name;f=await WidgetAnnotation._getFontData(e,t,{fontName:g,fontSize:0},s);for(let e=0,t=p.length;e2)return`/Tx BMC q ${o}BT `+E+` 1 0 0 1 ${numberToString(2)} ${numberToString(b)} Tm (${escapeString(p[0])}) Tj ET Q EMC`;return`/Tx BMC q ${o}BT `+E+` 1 0 0 1 0 0 Tm ${this._renderText(p[0],f,u,Q,D,{shift:0},2,b)} ET Q EMC`}static async _getFontData(e,t,i,a){const s=new OperatorList,r={font:null,clone(){return this}},{fontName:n,fontSize:g}=i;await e.handleSetFont(a,[n&&Name.get(n),g],null,s,t,r,null);return r.font}_getTextWidth(e,t){return t.charsToGlyphs(e).reduce(((e,t)=>e+t.width),0)/1e3}_computeFontSize(e,t,i,a,r){let{fontSize:n}=this.data.defaultAppearanceData,g=(n||12)*s,o=Math.round(e/g);if(!n){const roundWithTwoDigits=e=>Math.floor(100*e)/100;if(-1===r){const r=this._getTextWidth(i,a);n=roundWithTwoDigits(Math.min(e/s,t/r));o=1}else{const c=i.split(/\r\n?|\n/),C=[];for(const e of c){const t=a.encodeString(e).join(""),i=a.charsToGlyphs(t),s=a.getCharPositions(t);C.push({line:t,glyphs:i,positions:s})}const isTooBig=i=>{let s=0;for(const r of C){s+=this._splitLine(null,a,i,t,r).length*i;if(s>e)return!0}return!1};o=Math.max(o,r);for(;;){g=e/o;n=roundWithTwoDigits(g/s);if(!isTooBig(n))break;o++}}const{fontName:c,fontColor:C}=this.data.defaultAppearanceData;this._defaultAppearance=function createDefaultAppearance({fontSize:e,fontName:t,fontColor:i}){return`/${escapePDFName(t)} ${e} Tf ${getPdfColor(i,!0)}`}({fontSize:n,fontName:c,fontColor:C})}return[this._defaultAppearance,n,e/o]}_renderText(e,t,i,a,s,r,n,g){let o;if(1===s){o=(a-this._getTextWidth(e,t)*i)/2}else if(2===s){o=a-this._getTextWidth(e,t)*i-n}else o=n;const c=numberToString(o-r.shift);r.shift=o;return`${c} ${g=numberToString(g)} Td (${escapeString(e)}) Tj`}_getSaveFieldResources(e){const{localResources:t,appearanceResources:i,acroFormResources:a}=this._fieldResources,s=this.data.defaultAppearanceData?.fontName;if(!s)return t||Dict.empty;for(const e of[t,i])if(e instanceof Dict){const t=e.get("Font");if(t instanceof Dict&&t.has(s))return e}if(a instanceof Dict){const i=a.get("Font");if(i instanceof Dict&&i.has(s)){const a=new Dict(e);a.set(s,i.getRaw(s));const r=new Dict(e);r.set("Font",a);return Dict.merge({xref:e,dictArray:[r,t],mergeSubDicts:!0})}}return t||Dict.empty}getFieldObject(){return null}}class TextWidgetAnnotation extends WidgetAnnotation{constructor(e){super(e);const{dict:t}=e;if(t.has("PMD")){this.flags|=z;this.data.hidden=!0;warn("Barcodes are not supported")}this.data.hasOwnCanvas=this.data.readOnly&&!this.data.noHTML;this._hasText=!0;"string"!=typeof this.data.fieldValue&&(this.data.fieldValue="");let i=getInheritableProperty({dict:t,key:"Q"});(!Number.isInteger(i)||i<0||i>2)&&(i=null);this.data.textAlignment=i;let a=getInheritableProperty({dict:t,key:"MaxLen"});(!Number.isInteger(a)||a<0)&&(a=0);this.data.maxLen=a;this.data.multiLine=this.hasFieldFlag(sA);this.data.comb=this.hasFieldFlag(hA)&&!this.hasFieldFlag(sA)&&!this.hasFieldFlag(rA)&&!this.hasFieldFlag(IA)&&0!==this.data.maxLen;this.data.doNotScroll=this.hasFieldFlag(CA)}get hasTextContent(){return!!this.appearance&&!this._needAppearances}_getCombAppearance(e,t,i,a,s,r,n,g,o,c,C){const h=s/this.data.maxLen,l=this.getBorderAndBackgroundAppearances(C),Q=[],E=t.getCharPositions(i);for(const[e,t]of E)Q.push(`(${escapeString(i.substring(e,t))}) Tj`);const u=Q.join(` ${numberToString(h)} 0 Td `);return`/Tx BMC q ${l}BT `+e+` 1 0 0 1 ${numberToString(n)} ${numberToString(g+o)} Tm ${u} ET Q EMC`}_getMultilineAppearance(e,t,i,a,s,r,n,g,o,c,C,h){const l=[],Q=s-2*g,E={shift:0};for(let e=0,r=t.length;ea){o.push(e.substring(l,i));l=i;Q=u;c=-1;h=-1}else{Q+=u;c=i;C=s;h=t}else if(Q+u>a)if(-1!==c){o.push(e.substring(l,C));l=C;t=h+1;c=-1;Q=0}else{o.push(e.substring(l,i));l=i;Q=u}else Q+=u}lt?`\\${t}`:"\\s+"));new RegExp(`^\\s*${r}\\s*$`).test(this.data.fieldValue)&&(this.data.textContent=this.data.fieldValue.split("\n"))}getFieldObject(){return{id:this.data.id,value:this.data.fieldValue,defaultValue:this.data.defaultFieldValue||"",multiline:this.data.multiLine,password:this.hasFieldFlag(rA),charLimit:this.data.maxLen,comb:this.data.comb,editable:!this.data.readOnly,hidden:this.data.hidden,name:this.data.fieldName,rect:this.data.rect,actions:this.data.actions,page:this.data.pageIndex,strokeColor:this.data.borderColor,fillColor:this.data.backgroundColor,rotation:this.rotation,type:"text"}}}class ButtonWidgetAnnotation extends WidgetAnnotation{constructor(e){super(e);this.checkedAppearance=null;this.uncheckedAppearance=null;this.data.checkBox=!this.hasFieldFlag(nA)&&!this.hasFieldFlag(gA);this.data.radioButton=this.hasFieldFlag(nA)&&!this.hasFieldFlag(gA);this.data.pushButton=this.hasFieldFlag(gA);this.data.isTooltipOnly=!1;if(this.data.checkBox)this._processCheckBox(e);else if(this.data.radioButton)this._processRadioButton(e);else if(this.data.pushButton){this.data.hasOwnCanvas=!0;this.data.noHTML=!1;this._processPushButton(e)}else warn("Invalid field flags for button widget annotation")}async getOperatorList(e,t,a,s){if(this.data.pushButton)return super.getOperatorList(e,t,a,!1,s);let r=null,n=null;if(s){const e=s.get(this.data.id);r=e?e.value:null;n=e?e.rotation:null}if(null===r&&this.appearance)return super.getOperatorList(e,t,a,s);null==r&&(r=this.data.checkBox?this.data.fieldValue===this.data.exportValue:this.data.fieldValue===this.data.buttonValue);const g=r?this.checkedAppearance:this.uncheckedAppearance;if(g){const r=this.appearance,o=lookupMatrix(g.dict.getArray("Matrix"),i);n&&g.dict.set("Matrix",this.getRotationMatrix(s));this.appearance=g;const c=super.getOperatorList(e,t,a,s);this.appearance=r;g.dict.set("Matrix",o);return c}return{opList:new OperatorList,separateForm:!1,separateCanvas:!1}}async save(e,t,i){return this.data.checkBox?this._saveCheckbox(e,t,i):this.data.radioButton?this._saveRadioButton(e,t,i):null}async _saveCheckbox(e,t,i){if(!i)return null;const a=i.get(this.data.id),s=this._buildFlags(a?.noView,a?.noPrint);let r=a?.rotation,n=a?.value;if(void 0===r&&void 0===s){if(void 0===n)return null;if(this.data.fieldValue===this.data.exportValue===n)return null}let g=e.xref.fetchIfRef(this.ref);if(!(g instanceof Dict))return null;g=g.clone();void 0===r&&(r=this.rotation);void 0===n&&(n=this.data.fieldValue===this.data.exportValue);const o={path:this.data.fieldName,value:n?this.data.exportValue:""},c=Name.get(n?this.data.exportValue:"Off");g.set("V",c);g.set("AS",c);g.set("M",`D:${getModificationDate()}`);void 0!==s&&g.set("F",s);const C=this._getMKDict(r);C&&g.set("MK",C);const h=[];await writeObject(this.ref,g,h,e.xref);return[{ref:this.ref,data:h.join(""),xfa:o}]}async _saveRadioButton(e,t,i){if(!i)return null;const a=i.get(this.data.id),s=this._buildFlags(a?.noView,a?.noPrint);let r=a?.rotation,n=a?.value;if(void 0===r&&void 0===s){if(void 0===n)return null;if(this.data.fieldValue===this.data.buttonValue===n)return null}let g=e.xref.fetchIfRef(this.ref);if(!(g instanceof Dict))return null;g=g.clone();void 0===n&&(n=this.data.fieldValue===this.data.buttonValue);void 0===r&&(r=this.rotation);const o={path:this.data.fieldName,value:n?this.data.buttonValue:""},c=Name.get(n?this.data.buttonValue:"Off"),C=[];let h=null;if(n)if(this.parent instanceof Ref){const t=e.xref.fetch(this.parent);t.set("V",c);await writeObject(this.parent,t,C,e.xref);h=C.join("");C.length=0}else this.parent instanceof Dict&&this.parent.set("V",c);this.parent||g.set("V",c);g.set("AS",c);g.set("M",`D:${getModificationDate()}`);void 0!==s&&g.set("F",s);const l=this._getMKDict(r);l&&g.set("MK",l);await writeObject(this.ref,g,C,e.xref);const Q=[{ref:this.ref,data:C.join(""),xfa:o}];h&&Q.push({ref:this.parent,data:h,xfa:null});return Q}_getDefaultCheckedAppearance(e,t){const i=this.data.rect[2]-this.data.rect[0],a=this.data.rect[3]-this.data.rect[1],s=[0,0,i,a],r=.8*Math.min(i,a);let n,g;if("check"===t){n={width:.755*r,height:.705*r};g="3"}else if("disc"===t){n={width:.791*r,height:.705*r};g="l"}else unreachable(`_getDefaultCheckedAppearance - unsupported type: ${t}`);const o=`q BT /PdfJsZaDb ${r} Tf 0 g ${numberToString((i-n.width)/2)} ${numberToString((a-n.height)/2)} Td (${g}) Tj ET Q`,c=new Dict(e.xref);c.set("FormType",1);c.set("Subtype",Name.get("Form"));c.set("Type",Name.get("XObject"));c.set("BBox",s);c.set("Matrix",[1,0,0,1,0,0]);c.set("Length",o.length);const C=new Dict(e.xref),h=new Dict(e.xref);h.set("PdfJsZaDb",this.fallbackFontDict);C.set("Font",h);c.set("Resources",C);this.checkedAppearance=new StringStream(o);this.checkedAppearance.dict=c;this._streams.push(this.checkedAppearance)}_processCheckBox(e){const t=e.dict.get("AP");if(!(t instanceof Dict))return;const i=t.get("N");if(!(i instanceof Dict))return;const a=this._decodeFormValue(e.dict.get("AS"));"string"==typeof a&&(this.data.fieldValue=a);const s=null!==this.data.fieldValue&&"Off"!==this.data.fieldValue?this.data.fieldValue:"Yes",r=i.getKeys();if(0===r.length)r.push("Off",s);else if(1===r.length)"Off"===r[0]?r.push(s):r.unshift("Off");else if(r.includes(s)){r.length=0;r.push("Off",s)}else{const e=r.find((e=>"Off"!==e));r.length=0;r.push("Off",e)}r.includes(this.data.fieldValue)||(this.data.fieldValue="Off");this.data.exportValue=r[1];const n=i.get(this.data.exportValue);this.checkedAppearance=n instanceof BaseStream?n:null;const g=i.get("Off");this.uncheckedAppearance=g instanceof BaseStream?g:null;this.checkedAppearance?this._streams.push(this.checkedAppearance):this._getDefaultCheckedAppearance(e,"check");this.uncheckedAppearance&&this._streams.push(this.uncheckedAppearance);this._fallbackFontDict=this.fallbackFontDict;null===this.data.defaultFieldValue&&(this.data.defaultFieldValue="Off")}_processRadioButton(e){this.data.buttonValue=null;const t=e.dict.get("Parent");if(t instanceof Dict){this.parent=e.dict.getRaw("Parent");const i=t.get("V");i instanceof Name&&(this.data.fieldValue=this._decodeFormValue(i))}const i=e.dict.get("AP");if(!(i instanceof Dict))return;const a=i.get("N");if(!(a instanceof Dict))return;for(const e of a.getKeys())if("Off"!==e){this.data.buttonValue=this._decodeFormValue(e);break}const s=a.get(this.data.buttonValue);this.checkedAppearance=s instanceof BaseStream?s:null;const r=a.get("Off");this.uncheckedAppearance=r instanceof BaseStream?r:null;this.checkedAppearance?this._streams.push(this.checkedAppearance):this._getDefaultCheckedAppearance(e,"disc");this.uncheckedAppearance&&this._streams.push(this.uncheckedAppearance);this._fallbackFontDict=this.fallbackFontDict;null===this.data.defaultFieldValue&&(this.data.defaultFieldValue="Off")}_processPushButton(e){const{dict:t,annotationGlobals:i}=e;if(t.has("A")||t.has("AA")||this.data.alternativeText){this.data.isTooltipOnly=!t.has("A")&&!t.has("AA");Catalog.parseDestDictionary({destDict:t,resultObj:this.data,docBaseUrl:i.baseUrl,docAttachments:i.attachments})}else warn("Push buttons without action dictionaries are not supported")}getFieldObject(){let e,t="button";if(this.data.checkBox){t="checkbox";e=this.data.exportValue}else if(this.data.radioButton){t="radiobutton";e=this.data.buttonValue}return{id:this.data.id,value:this.data.fieldValue||"Off",defaultValue:this.data.defaultFieldValue,exportValues:e,editable:!this.data.readOnly,name:this.data.fieldName,rect:this.data.rect,hidden:this.data.hidden,actions:this.data.actions,page:this.data.pageIndex,strokeColor:this.data.borderColor,fillColor:this.data.backgroundColor,rotation:this.rotation,type:t}}get fallbackFontDict(){const e=new Dict;e.set("BaseFont",Name.get("ZapfDingbats"));e.set("Type",Name.get("FallbackType"));e.set("Subtype",Name.get("FallbackType"));e.set("Encoding",Name.get("ZapfDingbatsEncoding"));return shadow(this,"fallbackFontDict",e)}}class ChoiceWidgetAnnotation extends WidgetAnnotation{constructor(e){super(e);const{dict:t,xref:i}=e;this.indices=t.getArray("I");this.hasIndices=Array.isArray(this.indices)&&this.indices.length>0;this.data.options=[];const a=getInheritableProperty({dict:t,key:"Opt"});if(Array.isArray(a))for(let e=0,t=a.length;e=0&&t0?this.data.fieldValue[0]:null;return{id:this.data.id,value:t,defaultValue:this.data.defaultFieldValue,editable:!this.data.readOnly,name:this.data.fieldName,rect:this.data.rect,numItems:this.data.fieldValue.length,multipleSelection:this.data.multiSelect,hidden:this.data.hidden,actions:this.data.actions,items:this.data.options,page:this.data.pageIndex,strokeColor:this.data.borderColor,fillColor:this.data.backgroundColor,rotation:this.rotation,type:e}}amendSavedDict(e,t){if(!this.hasIndices)return;let i=e?.get(this.data.id)?.value;Array.isArray(i)||(i=[i]);const a=[],{options:s}=this.data;for(let e=0,t=0,r=s.length;ei){i=a;t=e}}[Q,E]=this._computeFontSize(e,c-4,t,l,-1)}const u=E*s,d=(u-E)/2,f=Math.floor(o/u);let p=0;if(h.length>0){const e=Math.min(...h),t=Math.max(...h);p=Math.max(0,t-f+1);p>e&&(p=e)}const m=Math.min(p+f+1,C),y=["/Tx BMC q",`1 1 ${c} ${o} re W n`];if(h.length){y.push("0.600006 0.756866 0.854904 rg");for(const e of h)p<=e&&ee.trimEnd()));const{coords:e,bbox:t,matrix:i}=FakeUnicodeFont.getFirstPositionInfo(this.rectangle,this.rotation,a);this.data.textPosition=this._transformPoint(e,t,i)}if(this._isOffscreenCanvasSupported){const s=e.dict.get("CA"),r=new FakeUnicodeFont(i,"sans-serif");this.appearance=r.createAppearance(this._contents.str,this.rectangle,this.rotation,a,t,s);this._streams.push(this.appearance)}else warn("FreeTextAnnotation: OffscreenCanvas is not supported, annotation may not render correctly.")}}get hasTextContent(){return this._hasAppearance}static createNewDict(e,t,{apRef:i,ap:a}){const{color:s,fontSize:r,oldAnnotation:n,rect:g,rotation:o,user:c,value:C}=e,h=n||new Dict(t);h.set("Type",Name.get("Annot"));h.set("Subtype",Name.get("FreeText"));if(n){h.set("M",`D:${getModificationDate()}`);h.delete("RC")}else h.set("CreationDate",`D:${getModificationDate()}`);h.set("Rect",g);const l=`/Helv ${r} Tf ${getPdfColor(s,!0)}`;h.set("DA",l);h.set("Contents",stringToAsciiOrUTF16BE(C));h.set("F",4);h.set("Border",[0,0,0]);h.set("Rotate",o);c&&h.set("T",stringToAsciiOrUTF16BE(c));if(i||a){const e=new Dict(t);h.set("AP",e);i?e.set("N",i):e.set("N",a)}return h}static async createNewAppearanceStream(e,t,i){const{baseFontRef:a,evaluator:r,task:n}=i,{color:g,fontSize:o,rect:c,rotation:C,value:h}=e,l=new Dict(t),Q=new Dict(t);if(a)Q.set("Helv",a);else{const e=new Dict(t);e.set("BaseFont",Name.get("Helvetica"));e.set("Type",Name.get("Font"));e.set("Subtype",Name.get("Type1"));e.set("Encoding",Name.get("WinAnsiEncoding"));Q.set("Helv",e)}l.set("Font",Q);const E=await WidgetAnnotation._getFontData(r,n,{fontName:"Helv",fontSize:o},l),[u,d,f,p]=c;let m=f-u,y=p-d;C%180!=0&&([m,y]=[y,m]);const w=h.split("\n"),D=o/1e3;let b=-1/0;const F=[];for(let e of w){const t=E.encodeString(e);if(t.length>1)return null;e=t.join("");F.push(e);let i=0;const a=E.charsToGlyphs(e);for(const e of a)i+=e.width*D;b=Math.max(b,i)}let S=1;b>m&&(S=m/b);let k=1;const R=s*o,N=1*o,G=R*w.length;G>y&&(k=y/G);const x=o*Math.min(S,k);let U,M,L;switch(C){case 0:L=[1,0,0,1];M=[c[0],c[1],m,y];U=[c[0],c[3]-N];break;case 90:L=[0,1,-1,0];M=[c[1],-c[2],m,y];U=[c[1],-c[0]-N];break;case 180:L=[-1,0,0,-1];M=[-c[2],-c[3],m,y];U=[-c[2],-c[1]-N];break;case 270:L=[0,-1,1,0];M=[-c[3],c[0],m,y];U=[-c[3],c[2]-N]}const H=["q",`${L.join(" ")} 0 0 cm`,`${M.join(" ")} re W n`,"BT",`${getPdfColor(g,!0)}`,`0 Tc /Helv ${numberToString(x)} Tf`];H.push(`${U.join(" ")} Td (${escapeString(F[0])}) Tj`);const J=numberToString(R);for(let e=1,t=F.length;e{e.push(`${a[0]} ${a[1]} m`,`${a[2]} ${a[3]} l`,"S");return[t[0]-o,t[2]+o,t[7]-o,t[3]+o]}})}}}class SquareAnnotation extends MarkupAnnotation{constructor(e){super(e);const{dict:t,xref:i}=e;this.data.annotationType=x;this.data.hasOwnCanvas=this.data.noRotate;this.data.noHTML=!1;if(!this.appearance){const e=this.color?getPdfColorArray(this.color):[0,0,0],a=t.get("CA"),s=getRgbColor(t.getArray("IC"),null),r=s?getPdfColorArray(s):null,n=r?a:null;if(0===this.borderStyle.width&&!r)return;this._setDefaultAppearance({xref:i,extra:`${this.borderStyle.width} w`,strokeColor:e,fillColor:r,strokeAlpha:a,fillAlpha:n,pointsCallback:(e,t)=>{const i=t[4]+this.borderStyle.width/2,a=t[5]+this.borderStyle.width/2,s=t[6]-t[4]-this.borderStyle.width,n=t[3]-t[7]-this.borderStyle.width;e.push(`${i} ${a} ${s} ${n} re`);r?e.push("B"):e.push("S");return[t[0],t[2],t[7],t[3]]}})}}}class CircleAnnotation extends MarkupAnnotation{constructor(e){super(e);const{dict:t,xref:i}=e;this.data.annotationType=U;if(!this.appearance){const e=this.color?getPdfColorArray(this.color):[0,0,0],a=t.get("CA"),s=getRgbColor(t.getArray("IC"),null),r=s?getPdfColorArray(s):null,n=r?a:null;if(0===this.borderStyle.width&&!r)return;const g=4/3*Math.tan(Math.PI/8);this._setDefaultAppearance({xref:i,extra:`${this.borderStyle.width} w`,strokeColor:e,fillColor:r,strokeAlpha:a,fillAlpha:n,pointsCallback:(e,t)=>{const i=t[0]+this.borderStyle.width/2,a=t[1]-this.borderStyle.width/2,s=t[6]-this.borderStyle.width/2,n=t[7]+this.borderStyle.width/2,o=i+(s-i)/2,c=a+(n-a)/2,C=(s-i)/2*g,h=(n-a)/2*g;e.push(`${o} ${n} m`,`${o+C} ${n} ${s} ${c+h} ${s} ${c} c`,`${s} ${c-h} ${o+C} ${a} ${o} ${a} c`,`${o-C} ${a} ${i} ${c-h} ${i} ${c} c`,`${i} ${c+h} ${o-C} ${n} ${o} ${n} c`,"h");r?e.push("B"):e.push("S");return[t[0],t[2],t[7],t[3]]}})}}}class PolylineAnnotation extends MarkupAnnotation{constructor(e){super(e);const{dict:t,xref:i}=e;this.data.annotationType=L;this.data.hasOwnCanvas=this.data.noRotate;this.data.noHTML=!1;this.data.vertices=null;if(!(this instanceof PolygonAnnotation)){this.setLineEndings(t.getArray("LE"));this.data.lineEndings=this.lineEndings}const a=t.getArray("Vertices");if(!isNumberArray(a,null))return;const s=this.data.vertices=Float32Array.from(a);if(!this.appearance){const e=this.color?getPdfColorArray(this.color):[0,0,0],a=t.get("CA"),r=this.borderStyle.width||1,n=2*r,g=[1/0,1/0,-1/0,-1/0];for(let e=0,t=s.length;e{for(let t=0,i=s.length;t{for(const t of this.data.inkLists){for(let i=0,a=t.length;ie.points)));h.set("F",4);h.set("Rotate",c);g&&h.set("IT",Name.get("InkHighlight"));const l=new Dict(t);h.set("BS",l);l.set("W",C);h.set("C",Array.from(s,(e=>e/255)));h.set("CA",r);const Q=new Dict(t);h.set("AP",Q);i?Q.set("N",i):Q.set("N",a);return h}static async createNewAppearanceStream(e,t,i){if(e.outlines)return this.createNewAppearanceStreamForHighlight(e,t,i);const{color:a,rect:s,paths:r,thickness:n,opacity:g}=e,o=[`${n} w 1 J 1 j`,`${getPdfColor(a,!1)}`];1!==g&&o.push("/R0 gs");const c=[];for(const{bezier:e}of r){c.length=0;c.push(`${numberToString(e[0])} ${numberToString(e[1])} m`);if(2===e.length)c.push(`${numberToString(e[0])} ${numberToString(e[1])} l S`);else{for(let t=2,i=e.length;t{e.push(`${t[0]} ${t[1]} m`,`${t[2]} ${t[3]} l`,`${t[6]} ${t[7]} l`,`${t[4]} ${t[5]} l`,"f");return[t[0],t[2],t[7],t[3]]}})}}else this.data.popupRef=null}static createNewDict(e,t,{apRef:i,ap:a}){const{color:s,oldAnnotation:r,opacity:n,rect:g,rotation:o,user:c,quadPoints:C}=e,h=r||new Dict(t);h.set("Type",Name.get("Annot"));h.set("Subtype",Name.get("Highlight"));h.set(r?"M":"CreationDate",`D:${getModificationDate()}`);h.set("CreationDate",`D:${getModificationDate()}`);h.set("Rect",g);h.set("F",4);h.set("Border",[0,0,0]);h.set("Rotate",o);h.set("QuadPoints",C);h.set("C",Array.from(s,(e=>e/255)));h.set("CA",n);c&&h.set("T",stringToAsciiOrUTF16BE(c));if(i||a){const e=new Dict(t);h.set("AP",e);e.set("N",i||a)}return h}static async createNewAppearanceStream(e,t,i){const{color:a,rect:s,outlines:r,opacity:n}=e,g=[`${getPdfColor(a,!0)}`,"/R0 gs"],o=[];for(const e of r){o.length=0;o.push(`${numberToString(e[0])} ${numberToString(e[1])} m`);for(let t=2,i=e.length;t{e.push(`${t[4]} ${t[5]+1.3} m`,`${t[6]} ${t[7]+1.3} l`,"S");return[t[0],t[2],t[7],t[3]]}})}}else this.data.popupRef=null}}class SquigglyAnnotation extends MarkupAnnotation{constructor(e){super(e);const{dict:t,xref:i}=e;this.data.annotationType=Y;if(this.data.quadPoints=getQuadPoints(t,null)){if(!this.appearance){const e=this.color?getPdfColorArray(this.color):[0,0,0],a=t.get("CA");this._setDefaultAppearance({xref:i,extra:"[] 0 d 1 w",strokeColor:e,strokeAlpha:a,pointsCallback:(e,t)=>{const i=(t[1]-t[5])/6;let a=i,s=t[4];const r=t[5],n=t[6];e.push(`${s} ${r+a} m`);do{s+=2;a=0===a?i:0;e.push(`${s} ${r+a} l`)}while(s{e.push((t[0]+t[4])/2+" "+(t[1]+t[5])/2+" m",(t[2]+t[6])/2+" "+(t[3]+t[7])/2+" l","S");return[t[0],t[2],t[7],t[3]]}})}}else this.data.popupRef=null}}class StampAnnotation extends MarkupAnnotation{#T;constructor(e){super(e);this.data.annotationType=K;this.#T=this.data.hasOwnCanvas=this.data.noRotate;this.data.isEditable=!this.data.noHTML;this.data.noHTML=!1}mustBeViewedWhenEditing(e,t=null){if(e){if(!this.data.isEditable)return!1;this.#T=this.data.hasOwnCanvas;this.data.hasOwnCanvas=!0;return!0}this.data.hasOwnCanvas=this.#T;return!t?.has(this.data.id)}static async createImage(e,t){const{width:i,height:a}=e,s=new OffscreenCanvas(i,a),r=s.getContext("2d",{alpha:!0});r.drawImage(e,0,0);const n=r.getImageData(0,0,i,a).data,g=new Uint32Array(n.buffer),o=g.some(FeatureTest.isLittleEndian?e=>e>>>24!=255:e=>255!=(255&e));if(o){r.fillStyle="white";r.fillRect(0,0,i,a);r.drawImage(e,0,0)}const c=s.convertToBlob({type:"image/jpeg",quality:1}).then((e=>e.arrayBuffer())),C=Name.get("XObject"),h=Name.get("Image"),l=new Dict(t);l.set("Type",C);l.set("Subtype",h);l.set("BitsPerComponent",8);l.set("ColorSpace",Name.get("DeviceRGB"));l.set("Filter",Name.get("DCTDecode"));l.set("BBox",[0,0,i,a]);l.set("Width",i);l.set("Height",a);let Q=null;if(o){const e=new Uint8Array(g.length);if(FeatureTest.isLittleEndian)for(let t=0,i=g.length;t>>24;else for(let t=0,i=g.length;t=0&&r<=1?r:null}}function decodeString(e){try{return stringToUTF8String(e)}catch(t){warn(`UTF-8 decoding failed: "${t}".`);return e}}class DatasetXMLParser extends SimpleXMLParser{constructor(e){super(e);this.node=null}onEndElement(e){const t=super.onEndElement(e);if(t&&"xfa:datasets"===e){this.node=t;throw new Error("Aborting DatasetXMLParser.")}}}class DatasetReader{constructor(e){if(e.datasets)this.node=new SimpleXMLParser({hasAttributes:!0}).parseFromString(e.datasets).documentElement;else{const t=new DatasetXMLParser({hasAttributes:!0});try{t.parseFromString(e["xdp:xdp"])}catch{}this.node=t.node}}getValue(e){if(!this.node||!e)return"";const t=this.node.searchNode(parseXFAPath(e),0);if(!t)return"";const i=t.firstChild;return"value"===i?.nodeName?t.children.map((e=>decodeString(e.textContent))):decodeString(t.textContent)}}class XRef{#q=null;constructor(e,t){this.stream=e;this.pdfManager=t;this.entries=[];this._xrefStms=new Set;this._cacheMap=new Map;this._pendingRefs=new RefSet;this._newPersistentRefNum=null;this._newTemporaryRefNum=null;this._persistentRefsCache=null}getNewPersistentRef(e){null===this._newPersistentRefNum&&(this._newPersistentRefNum=this.entries.length||1);const t=this._newPersistentRefNum++;this._cacheMap.set(t,e);return Ref.get(t,0)}getNewTemporaryRef(){if(null===this._newTemporaryRefNum){this._newTemporaryRefNum=this.entries.length||1;if(this._newPersistentRefNum){this._persistentRefsCache=new Map;for(let e=this._newTemporaryRefNum;e0;){const[n,g]=r;if(!Number.isInteger(n)||!Number.isInteger(g))throw new FormatError(`Invalid XRef range fields: ${n}, ${g}`);if(!Number.isInteger(i)||!Number.isInteger(a)||!Number.isInteger(s))throw new FormatError(`Invalid XRef entry fields length: ${n}, ${g}`);for(let r=t.entryNum;r=e.length);){i+=String.fromCharCode(a);a=e[t]}return i}function skipUntil(e,t,i){const a=i.length,s=e.length;let r=0;for(;t=a)break;t++;r++}return r}const e=/\b(endobj|\d+\s+\d+\s+obj|xref|trailer\s*<<)\b/g,t=/\b(startxref|\d+\s+\d+\s+obj)\b/g,i=/^(\d+)\s+(\d+)\s+obj\b/,a=new Uint8Array([116,114,97,105,108,101,114]),s=new Uint8Array([115,116,97,114,116,120,114,101,102]),r=new Uint8Array([47,88,82,101,102]);this.entries.length=0;this._cacheMap.clear();const n=this.stream;n.pos=0;const g=n.getBytes(),o=bytesToString(g),c=g.length;let C=n.start;const h=[],l=[];for(;C=c)break;Q=g[C]}while(10!==Q&&13!==Q);continue}const E=readToken(g,C);let u;if(E.startsWith("xref")&&(4===E.length||/\s/.test(E[4]))){C+=skipUntil(g,C,a);h.push(C);C+=skipUntil(g,C,s)}else if(u=i.exec(E)){const t=0|u[1],i=0|u[2],a=C+E.length;let s,h=!1;if(this.entries[t]){if(this.entries[t].gen===i)try{new Parser({lexer:new Lexer(n.makeSubStream(a))}).getObj();h=!0}catch(e){e instanceof ParserEOFException?warn(`indexObjects -- checking object (${E}): "${e}".`):h=!0}}else h=!0;h&&(this.entries[t]={offset:C-n.start,gen:i,uncompressed:!0});e.lastIndex=a;const Q=e.exec(o);if(Q){s=e.lastIndex+1-C;if("endobj"!==Q[1]){warn(`indexObjects: Found "${Q[1]}" inside of another "obj", caused by missing "endobj" -- trying to recover.`);s-=Q[1].length+1}}else s=c-C;const d=g.subarray(C,C+s),f=skipUntil(d,0,r);if(f0?Math.max(...this._xrefStms):null)}getEntry(e){const t=this.entries[e];return t&&!t.free&&t.offset?t:null}fetchIfRef(e,t=!1){return e instanceof Ref?this.fetch(e,t):e}fetch(e,t=!1){if(!(e instanceof Ref))throw new Error("ref object is not a reference");const i=e.num,a=this._cacheMap.get(i);if(void 0!==a){a instanceof Dict&&!a.objId&&(a.objId=e.toString());return a}let s=this.getEntry(i);if(null===s){this._cacheMap.set(i,s);return s}if(this._pendingRefs.has(e)){this._pendingRefs.remove(e);warn(`Ignoring circular reference: ${e}.`);return yt}this._pendingRefs.put(e);try{s=s.uncompressed?this.fetchUncompressed(e,s,t):this.fetchCompressed(e,s,t);this._pendingRefs.remove(e)}catch(t){this._pendingRefs.remove(e);throw t}s instanceof Dict?s.objId=e.toString():s instanceof BaseStream&&(s.dict.objId=e.toString());return s}fetchUncompressed(e,t,i=!1){const a=e.gen;let s=e.num;if(t.gen!==a){const r=`Inconsistent generation in XRef: ${e}`;if(this._generationFallback&&t.gen0&&t[3]-t[1]>0)return t;warn(`Empty, or invalid, /${e} entry.`)}return null}get mediaBox(){return shadow(this,"mediaBox",this._getBoundingBox("MediaBox")||og)}get cropBox(){return shadow(this,"cropBox",this._getBoundingBox("CropBox")||this.mediaBox)}get userUnit(){let e=this.pageDict.get("UserUnit");("number"!=typeof e||e<=0)&&(e=1);return shadow(this,"userUnit",e)}get view(){const{cropBox:e,mediaBox:t}=this;if(e!==t&&!isArrayEqual(e,t)){const i=Util.intersect(e,t);if(i&&i[2]-i[0]>0&&i[3]-i[1]>0)return shadow(this,"view",i);warn("Empty /CropBox and /MediaBox intersection.")}return shadow(this,"view",t)}get rotate(){let e=this._getInheritableProperty("Rotate")||0;e%90!=0?e=0:e>=360?e%=360:e<0&&(e=(e%360+360)%360);return shadow(this,"rotate",e)}_onSubStreamError(e,t){if(!this.evaluatorOptions.ignoreErrors)throw e;warn(`getContentStream - ignoring sub-stream (${t}): "${e}".`)}getContentStream(){return this.pdfManager.ensure(this,"content").then((e=>e instanceof BaseStream?e:Array.isArray(e)?new StreamsSequenceStream(e,this._onSubStreamError.bind(this)):new NullStream))}get xfaData(){return shadow(this,"xfaData",this.xfaFactory?{bbox:this.xfaFactory.getBoundingBox(this.pageIndex)}:null)}async#O(e,t,i){const a=[];for(const s of e)if(s.id){const e=Ref.fromString(s.id);if(!e){warn(`A non-linked annotation cannot be modified: ${s.id}`);continue}if(s.deleted){t.put(e,e);if(s.popupRef){const e=Ref.fromString(s.popupRef);e&&t.put(e,e)}continue}i?.put(e);s.ref=e;a.push(this.xref.fetchAsync(e).then((e=>{e instanceof Dict&&(s.oldAnnotation=e.clone())}),(()=>{warn(`Cannot fetch \`oldAnnotation\` for: ${e}.`)})));delete s.id}await Promise.all(a)}async saveNewAnnotations(e,t,i,a){if(this.xfaFactory)throw new Error("XFA: Cannot save new annotations.");const s=new PartialEvaluator({xref:this.xref,handler:e,pageIndex:this.pageIndex,idFactory:this._localIdFactory,fontCache:this.fontCache,builtInCMapCache:this.builtInCMapCache,standardFontDataCache:this.standardFontDataCache,globalImageCache:this.globalImageCache,systemFontCache:this.systemFontCache,options:this.evaluatorOptions}),r=new RefSetCache,n=new RefSet;await this.#O(i,r,n);const g=this.pageDict,o=this.annotations.filter((e=>!(e instanceof Ref&&r.has(e)))),c=await AnnotationFactory.saveNewAnnotations(s,t,i,a);for(const{ref:e}of c.annotations)e instanceof Ref&&!n.has(e)&&o.push(e);const C=g.get("Annots");g.set("Annots",o);const h=[];await writeObject(this.ref,g,h,this.xref);C&&g.set("Annots",C);const l=c.dependencies;l.push({ref:this.ref,data:h.join("")},...c.annotations);for(const e of r)l.push({ref:e,data:null});return l}save(e,t,i){const a=new PartialEvaluator({xref:this.xref,handler:e,pageIndex:this.pageIndex,idFactory:this._localIdFactory,fontCache:this.fontCache,builtInCMapCache:this.builtInCMapCache,standardFontDataCache:this.standardFontDataCache,globalImageCache:this.globalImageCache,systemFontCache:this.systemFontCache,options:this.evaluatorOptions});return this._parsedAnnotations.then((function(e){const s=[];for(const r of e)s.push(r.save(a,t,i).catch((function(e){warn(`save - ignoring annotation data during "${t.name}" task: "${e}".`);return null})));return Promise.all(s).then((function(e){return e.filter((e=>!!e))}))}))}loadResources(e){this.resourcesPromise||=this.pdfManager.ensure(this,"resources");return this.resourcesPromise.then((()=>new ObjectLoader(this.resources,e,this.xref).load()))}getOperatorList({handler:e,sink:t,task:i,intent:a,cacheKey:s,annotationStorage:r=null,modifiedIds:n=null}){const C=this.getContentStream(),E=this.loadResources(["ColorSpace","ExtGState","Font","Pattern","Properties","Shading","XObject"]),d=new PartialEvaluator({xref:this.xref,handler:e,pageIndex:this.pageIndex,idFactory:this._localIdFactory,fontCache:this.fontCache,builtInCMapCache:this.builtInCMapCache,standardFontDataCache:this.standardFontDataCache,globalImageCache:this.globalImageCache,systemFontCache:this.systemFontCache,options:this.evaluatorOptions}),f=this.xfaFactory?null:getNewAnnotationsMap(r),p=f?.get(this.pageIndex);let m=Promise.resolve(null),y=null;if(p){const e=this.pdfManager.ensureDoc("annotationGlobals");let t;const a=new Set;for(const{bitmapId:e,bitmap:t}of p)!e||t||a.has(e)||a.add(e);const{isOffscreenCanvasSupported:s}=this.evaluatorOptions;if(a.size>0){const e=p.slice();for(const[t,i]of r)t.startsWith(u)&&i.bitmap&&a.has(i.bitmapId)&&e.push(i);t=AnnotationFactory.generateImages(e,this.xref,s)}else t=AnnotationFactory.generateImages(p,this.xref,s);y=new RefSet;m=Promise.all([e,this.#O(p,y,null)]).then((([e])=>e?AnnotationFactory.printNewAnnotations(e,d,i,p,t):null))}const w=Promise.all([C,E]).then((([r])=>{const n=new OperatorList(a,t);e.send("StartRenderPage",{transparency:d.hasBlendModes(this.resources,this.nonBlendModesSet),pageIndex:this.pageIndex,cacheKey:s});return d.getOperatorList({stream:r,task:i,resources:this.resources,operatorList:n}).then((function(){return n}))}));return Promise.all([w,this._parsedAnnotations,m]).then((function([e,t,s]){if(s){t=t.filter((e=>!(e.ref&&y.has(e.ref))));for(let e=0,i=s.length;ee.ref&&isRefsEqual(e.ref,a.refToReplace)));if(r>=0){t.splice(r,1,a);s.splice(e--,1);i--}}}t=t.concat(s)}if(0===t.length||a&l){e.flush(!0);return{length:e.totalLength}}const C=!!(a&h),E=!!(a&Q),u=!!(a&g),f=!!(a&o),p=!!(a&c),m=[];for(const e of t)(u||f&&e.mustBeViewed(r,C)&&e.mustBeViewedWhenEditing(E,n)||p&&e.mustBePrinted(r))&&m.push(e.getOperatorList(d,i,a,r).catch((function(e){warn(`getOperatorList - ignoring annotation data during "${i.name}" task: "${e}".`);return{opList:null,separateForm:!1,separateCanvas:!1}})));return Promise.all(m).then((function(t){let i=!1,a=!1;for(const{opList:s,separateForm:r,separateCanvas:n}of t){e.addOpList(s);i||=r;a||=n}e.flush(!0,{form:i,canvas:a});return{length:e.totalLength}}))}))}async extractTextContent({handler:e,task:t,includeMarkedContent:i,disableNormalization:a,sink:s}){const r=this.getContentStream(),n=this.loadResources(["ExtGState","Font","Properties","XObject"]),g=this.pdfManager.ensureCatalog("lang"),[o,,c]=await Promise.all([r,n,g]);return new PartialEvaluator({xref:this.xref,handler:e,pageIndex:this.pageIndex,idFactory:this._localIdFactory,fontCache:this.fontCache,builtInCMapCache:this.builtInCMapCache,standardFontDataCache:this.standardFontDataCache,globalImageCache:this.globalImageCache,systemFontCache:this.systemFontCache,options:this.evaluatorOptions}).getTextContent({stream:o,task:t,resources:this.resources,includeMarkedContent:i,disableNormalization:a,sink:s,viewBox:this.view,lang:c})}async getStructTree(){const e=await this.pdfManager.ensureCatalog("structTreeRoot");if(!e)return null;await this._parsedAnnotations;return(await this.pdfManager.ensure(this,"_parseStructTree",[e])).serializable}_parseStructTree(e){const t=new StructTreePage(e,this.pageDict);t.parse(this.ref);return t}async getAnnotationsData(e,t,i){const a=await this._parsedAnnotations;if(0===a.length)return a;const s=[],r=[];let n;const C=!!(i&g),h=!!(i&o),l=!!(i&c);for(const i of a){const a=C||h&&i.viewable;(a||l&&i.printable)&&s.push(i.data);if(i.hasTextContent&&a){n||=new PartialEvaluator({xref:this.xref,handler:e,pageIndex:this.pageIndex,idFactory:this._localIdFactory,fontCache:this.fontCache,builtInCMapCache:this.builtInCMapCache,standardFontDataCache:this.standardFontDataCache,globalImageCache:this.globalImageCache,systemFontCache:this.systemFontCache,options:this.evaluatorOptions});r.push(i.extractTextContent(n,t,[-1/0,-1/0,1/0,1/0]).catch((function(e){warn(`getAnnotationsData - ignoring textContent during "${t.name}" task: "${e}".`)})))}}await Promise.all(r);return s}get annotations(){const e=this._getInheritableProperty("Annots");return shadow(this,"annotations",Array.isArray(e)?e:[])}get _parsedAnnotations(){return shadow(this,"_parsedAnnotations",this.pdfManager.ensure(this,"annotations").then((async e=>{if(0===e.length)return e;const[t,i]=await Promise.all([this.pdfManager.ensureDoc("annotationGlobals"),this.pdfManager.ensureDoc("fieldObjects")]);if(!t)return[];const a=i?.orphanFields,s=[];for(const i of e)s.push(AnnotationFactory.create(this.xref,i,t,this._localIdFactory,!1,a,this.ref).catch((function(e){warn(`_parsedAnnotations: "${e}".`);return null})));const r=[];let n,g;for(const e of await Promise.all(s))e&&(e instanceof WidgetAnnotation?(g||=[]).push(e):e instanceof PopupAnnotation?(n||=[]).push(e):r.push(e));g&&r.push(...g);n&&r.push(...n);return r})))}get jsActions(){return shadow(this,"jsActions",collectActions(this.xref,this.pageDict,pA))}}const Ig=new Uint8Array([37,80,68,70,45]),cg=new Uint8Array([115,116,97,114,116,120,114,101,102]),Cg=new Uint8Array([101,110,100,111,98,106]);function find(e,t,i=1024,a=!1){const s=t.length,r=e.peekBytes(i),n=r.length-s;if(n<=0)return!1;if(a){const i=s-1;let a=r.length-1;for(;a>=i;){let n=0;for(;n=s){e.pos+=a-i;return!0}a--}}else{let i=0;for(;i<=n;){let a=0;for(;a=s){e.pos+=i;return!0}i++}}return!1}class PDFDocument{constructor(e,t){if(t.length<=0)throw new InvalidPDFException("The PDF file is empty, i.e. its size is zero bytes.");this.pdfManager=e;this.stream=t;this.xref=new XRef(t,e);this._pagePromises=new Map;this._version=null;const i={font:0};this._globalIdFactory=class{static getDocId(){return`g_${e.docId}`}static createFontId(){return"f"+ ++i.font}static createObjId(){unreachable("Abstract method `createObjId` called.")}static getPageObjId(){unreachable("Abstract method `getPageObjId` called.")}}}parse(e){this.xref.parse(e);this.catalog=new Catalog(this.pdfManager,this.xref)}get linearization(){let e=null;try{e=Linearization.create(this.stream)}catch(e){if(e instanceof MissingDataException)throw e;info(e)}return shadow(this,"linearization",e)}get startXRef(){const e=this.stream;let t=0;if(this.linearization){e.reset();if(find(e,Cg)){e.skip(6);let i=e.peekByte();for(;isWhiteSpace(i);){e.pos++;i=e.peekByte()}t=e.pos-e.start}}else{const i=1024,a=cg.length;let s=!1,r=e.end;for(;!s&&r>0;){r-=i-a;r<0&&(r=0);e.pos=r;s=find(e,cg,i,!0)}if(s){e.skip(9);let i;do{i=e.getByte()}while(isWhiteSpace(i));let a="";for(;i>=32&&i<=57;){a+=String.fromCharCode(i);i=e.getByte()}t=parseInt(a,10);isNaN(t)&&(t=0)}}return shadow(this,"startXRef",t)}checkHeader(){const e=this.stream;e.reset();if(!find(e,Ig))return;e.moveStart();e.skip(Ig.length);let t,i="";for(;(t=e.getByte())>32&&i.length<7;)i+=String.fromCharCode(t);kt.test(i)?this._version=i:warn(`Invalid PDF header version: ${i}`)}parseStartXRef(){this.xref.setStartXRef(this.startXRef)}get numPages(){let e=0;e=this.catalog.hasActualNumPages?this.catalog.numPages:this.xfaFactory?this.xfaFactory.getNumPages():this.linearization?this.linearization.numPages:this.catalog.numPages;return shadow(this,"numPages",e)}_hasOnlyDocumentSignatures(e,t=0){return!!Array.isArray(e)&&e.every((e=>{if(!((e=this.xref.fetchIfRef(e))instanceof Dict))return!1;if(e.has("Kids")){if(++t>10){warn("_hasOnlyDocumentSignatures: maximum recursion depth reached");return!1}return this._hasOnlyDocumentSignatures(e.get("Kids"),t)}const i=isName(e.get("FT"),"Sig"),a=e.get("Rect"),s=Array.isArray(a)&&a.every((e=>0===e));return i&&s}))}get _xfaStreams(){const e=this.catalog.acroForm;if(!e)return null;const t=e.get("XFA"),i={"xdp:xdp":"",template:"",datasets:"",config:"",connectionSet:"",localeSet:"",stylesheet:"","/xdp:xdp":""};if(t instanceof BaseStream&&!t.isEmpty){i["xdp:xdp"]=t;return i}if(!Array.isArray(t)||0===t.length)return null;for(let e=0,a=t.length;e{h.set(e,t)}));const l=[];for(const[e,i]of h){const s=i.get("FontDescriptor");if(!(s instanceof Dict))continue;let r=s.get("FontFamily");r=r.replaceAll(/[ ]+(\d)/g,"$1");const n={fontFamily:r,fontWeight:s.get("FontWeight"),italicAngle:-s.get("ItalicAngle")};validateCSSFont(n)&&l.push(g.handleSetFont(a,[Name.get(e),1],null,o,t,C,null,n).catch((function(e){warn(`loadXfaFonts: "${e}".`);return null})))}await Promise.all(l);const Q=this.xfaFactory.setFonts(c);if(!Q)return;n.ignoreErrors=!0;l.length=0;c.length=0;const E=new Set;for(const e of Q)getXfaFontName(`${e}-Regular`)||E.add(e);E.size&&Q.push("PdfJS-Fallback");for(const e of Q)if(!E.has(e))for(const i of[{name:"Regular",fontWeight:400,italicAngle:0},{name:"Bold",fontWeight:700,italicAngle:0},{name:"Italic",fontWeight:400,italicAngle:12},{name:"BoldItalic",fontWeight:700,italicAngle:12}]){const s=`${e}-${i.name}`,r=getXfaFontDict(s);l.push(g.handleSetFont(a,[Name.get(s),1],null,o,t,C,r,{fontFamily:e,fontWeight:i.fontWeight,italicAngle:i.italicAngle}).catch((function(e){warn(`loadXfaFonts: "${e}".`);return null})))}await Promise.all(l);this.xfaFactory.appendFonts(c,E)}async serializeXfaData(e){return this.xfaFactory?this.xfaFactory.serializeData(e):null}get version(){return this.catalog.version||this._version}get formInfo(){const e={hasFields:!1,hasAcroForm:!1,hasXfa:!1,hasSignatures:!1},t=this.catalog.acroForm;if(!t)return shadow(this,"formInfo",e);try{const i=t.get("Fields"),a=Array.isArray(i)&&i.length>0;e.hasFields=a;const s=t.get("XFA");e.hasXfa=Array.isArray(s)&&s.length>0||s instanceof BaseStream&&!s.isEmpty;const r=!!(1&t.get("SigFlags")),n=r&&this._hasOnlyDocumentSignatures(i);e.hasAcroForm=a&&!n;e.hasSignatures=r}catch(e){if(e instanceof MissingDataException)throw e;warn(`Cannot fetch form information: "${e}".`)}return shadow(this,"formInfo",e)}get documentInfo(){const e={PDFFormatVersion:this.version,Language:this.catalog.lang,EncryptFilterName:this.xref.encrypt?this.xref.encrypt.filterName:null,IsLinearized:!!this.linearization,IsAcroFormPresent:this.formInfo.hasAcroForm,IsXFAPresent:this.formInfo.hasXfa,IsCollectionPresent:!!this.catalog.collection,IsSignaturesPresent:this.formInfo.hasSignatures};let t;try{t=this.xref.trailer.get("Info")}catch(e){if(e instanceof MissingDataException)throw e;info("The document information dictionary is invalid.")}if(!(t instanceof Dict))return shadow(this,"documentInfo",e);for(const i of t.getKeys()){const a=t.get(i);switch(i){case"Title":case"Author":case"Subject":case"Keywords":case"Creator":case"Producer":case"CreationDate":case"ModDate":if("string"==typeof a){e[i]=stringToPDFString(a);continue}break;case"Trapped":if(a instanceof Name){e[i]=a;continue}break;default:let t;switch(typeof a){case"string":t=stringToPDFString(a);break;case"number":case"boolean":t=a;break;default:a instanceof Name&&(t=a)}if(void 0===t){warn(`Bad value, for custom key "${i}", in Info: ${a}.`);continue}e.Custom||(e.Custom=Object.create(null));e.Custom[i]=t;continue}warn(`Bad value, for key "${i}", in Info: ${a}.`)}return shadow(this,"documentInfo",e)}get fingerprints(){function validate(e){return"string"==typeof e&&e.length>0&&"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"!==e}function hexString(e){const t=[];for(const i of e){const e=i.toString(16);t.push(e.padStart(2,"0"))}return t.join("")}const e=this.xref.trailer.get("ID");let t,i;if(Array.isArray(e)&&validate(e[0])){t=stringToBytes(e[0]);e[1]!==e[0]&&validate(e[1])&&(i=stringToBytes(e[1]))}else t=Ks(this.stream.getByteRange(0,1024),0,1024);return shadow(this,"fingerprints",[hexString(t),i?hexString(i):null])}async _getLinearizationPage(e){const{catalog:t,linearization:i,xref:a}=this,s=Ref.get(i.objectNumberFirst,0);try{const e=await a.fetchAsync(s);if(e instanceof Dict){let i=e.getRaw("Type");i instanceof Ref&&(i=await a.fetchAsync(i));if(isName(i,"Page")||!e.has("Type")&&!e.has("Kids")&&e.has("Contents")){t.pageKidsCountCache.has(s)||t.pageKidsCountCache.put(s,1);t.pageIndexCache.has(s)||t.pageIndexCache.put(s,0);return[e,s]}}throw new FormatError("The Linearization dictionary doesn't point to a valid Page dictionary.")}catch(i){warn(`_getLinearizationPage: "${i.message}".`);return t.getPageDict(e)}}getPage(e){const t=this._pagePromises.get(e);if(t)return t;const{catalog:i,linearization:a,xfaFactory:s}=this;let r;r=s?Promise.resolve([Dict.empty,null]):a?.pageFirst===e?this._getLinearizationPage(e):i.getPageDict(e);r=r.then((([t,a])=>new Page({pdfManager:this.pdfManager,xref:this.xref,pageIndex:e,pageDict:t,ref:a,globalIdFactory:this._globalIdFactory,fontCache:i.fontCache,builtInCMapCache:i.builtInCMapCache,standardFontDataCache:i.standardFontDataCache,globalImageCache:i.globalImageCache,systemFontCache:i.systemFontCache,nonBlendModesSet:i.nonBlendModesSet,xfaFactory:s})));this._pagePromises.set(e,r);return r}async checkFirstPage(e=!1){if(!e)try{await this.getPage(0)}catch(e){if(e instanceof XRefEntryException){this._pagePromises.delete(0);await this.cleanup();throw new XRefParseException}}}async checkLastPage(e=!1){const{catalog:t,pdfManager:i}=this;t.setActualNumPages();let a;try{await Promise.all([i.ensureDoc("xfaFactory"),i.ensureDoc("linearization"),i.ensureCatalog("numPages")]);if(this.xfaFactory)return;a=this.linearization?this.linearization.numPages:t.numPages;if(!Number.isInteger(a))throw new FormatError("Page count is not an integer.");if(a<=1)return;await this.getPage(a-1)}catch(s){this._pagePromises.delete(a-1);await this.cleanup();if(s instanceof XRefEntryException&&!e)throw new XRefParseException;warn(`checkLastPage - invalid /Pages tree /Count: ${a}.`);let r;try{r=await t.getAllPageDicts(e)}catch(i){if(i instanceof XRefEntryException&&!e)throw new XRefParseException;t.setActualNumPages(1);return}for(const[e,[a,s]]of r){let r;if(a instanceof Error){r=Promise.reject(a);r.catch((()=>{}))}else r=Promise.resolve(new Page({pdfManager:i,xref:this.xref,pageIndex:e,pageDict:a,ref:s,globalIdFactory:this._globalIdFactory,fontCache:t.fontCache,builtInCMapCache:t.builtInCMapCache,standardFontDataCache:t.standardFontDataCache,globalImageCache:t.globalImageCache,systemFontCache:t.systemFontCache,nonBlendModesSet:t.nonBlendModesSet,xfaFactory:null}));this._pagePromises.set(e,r)}t.setActualNumPages(r.size)}}fontFallback(e,t){return this.catalog.fontFallback(e,t)}async cleanup(e=!1){return this.catalog?this.catalog.cleanup(e):clearGlobalCaches()}async#P(e,t,i,a,s,r,n){const{xref:g}=this;if(!(i instanceof Ref)||r.has(i))return;r.put(i);const o=await g.fetchAsync(i);if(!(o instanceof Dict))return;if(o.has("T")){const t=stringToPDFString(await o.getAsync("T"));e=""===e?t:`${e}.${t}`}else{let i=o;for(;;){i=i.getRaw("Parent")||t;if(i instanceof Ref){if(r.has(i))break;i=await g.fetchAsync(i)}if(!(i instanceof Dict))break;if(i.has("T")){const t=stringToPDFString(await i.getAsync("T"));e=""===e?t:`${e}.${t}`;break}}}t&&!o.has("Parent")&&isName(o.get("Subtype"),"Widget")&&n.put(i,t);a.has(e)||a.set(e,[]);a.get(e).push(AnnotationFactory.create(g,i,s,null,!0,n,null).then((e=>e?.getFieldObject())).catch((function(e){warn(`#collectFieldObjects: "${e}".`);return null})));if(!o.has("Kids"))return;const c=await o.getAsync("Kids");if(Array.isArray(c))for(const t of c)await this.#P(e,i,t,a,s,r,n)}get fieldObjects(){if(!this.formInfo.hasFields)return shadow(this,"fieldObjects",Promise.resolve(null));return shadow(this,"fieldObjects",Promise.all([this.pdfManager.ensureDoc("annotationGlobals"),this.pdfManager.ensureCatalog("acroForm")]).then((async([e,t])=>{if(!e)return null;const i=new RefSet,a=Object.create(null),s=new Map,r=new RefSetCache;for(const a of await t.getAsync("Fields"))await this.#P("",null,a,s,e,i,r);const n=[];for(const[e,t]of s)n.push(Promise.all(t).then((t=>{(t=t.filter((e=>!!e))).length>0&&(a[e]=t)})));await Promise.all(n);return{allFields:a,orphanFields:r}})))}get hasJSActions(){return shadow(this,"hasJSActions",this.pdfManager.ensureDoc("_parseHasJSActions"))}async _parseHasJSActions(){const[e,t]=await Promise.all([this.pdfManager.ensureCatalog("jsActions"),this.pdfManager.ensureDoc("fieldObjects")]);return!!e||!!t&&Object.values(t.allFields).some((e=>e.some((e=>null!==e.actions))))}get calculationOrderIds(){const e=this.catalog.acroForm;if(!e?.has("CO"))return shadow(this,"calculationOrderIds",null);const t=e.get("CO");if(!Array.isArray(t)||0===t.length)return shadow(this,"calculationOrderIds",null);const i=[];for(const e of t)e instanceof Ref&&i.push(e.toString());return 0===i.length?shadow(this,"calculationOrderIds",null):shadow(this,"calculationOrderIds",i)}get annotationGlobals(){return shadow(this,"annotationGlobals",AnnotationFactory.createGlobals(this.pdfManager))}}class BasePdfManager{constructor(e){this._docBaseUrl=function parseDocBaseUrl(e){if(e){const t=createValidAbsoluteUrl(e);if(t)return t.href;warn(`Invalid absolute docBaseUrl: "${e}".`)}return null}(e.docBaseUrl);this._docId=e.docId;this._password=e.password;this.enableXfa=e.enableXfa;e.evaluatorOptions.isOffscreenCanvasSupported&&=FeatureTest.isOffscreenCanvasSupported;this.evaluatorOptions=Object.freeze(e.evaluatorOptions)}get docId(){return this._docId}get password(){return this._password}get docBaseUrl(){return this._docBaseUrl}get catalog(){return this.pdfDocument.catalog}ensureDoc(e,t){return this.ensure(this.pdfDocument,e,t)}ensureXRef(e,t){return this.ensure(this.pdfDocument.xref,e,t)}ensureCatalog(e,t){return this.ensure(this.pdfDocument.catalog,e,t)}getPage(e){return this.pdfDocument.getPage(e)}fontFallback(e,t){return this.pdfDocument.fontFallback(e,t)}loadXfaFonts(e,t){return this.pdfDocument.loadXfaFonts(e,t)}loadXfaImages(){return this.pdfDocument.loadXfaImages()}serializeXfaData(e){return this.pdfDocument.serializeXfaData(e)}cleanup(e=!1){return this.pdfDocument.cleanup(e)}async ensure(e,t,i){unreachable("Abstract method `ensure` called")}requestRange(e,t){unreachable("Abstract method `requestRange` called")}requestLoadedStream(e=!1){unreachable("Abstract method `requestLoadedStream` called")}sendProgressiveData(e){unreachable("Abstract method `sendProgressiveData` called")}updatePassword(e){this._password=e}terminate(e){unreachable("Abstract method `terminate` called")}}class LocalPdfManager extends BasePdfManager{constructor(e){super(e);const t=new Stream(e.source);this.pdfDocument=new PDFDocument(this,t);this._loadedStreamPromise=Promise.resolve(t)}async ensure(e,t,i){const a=e[t];return"function"==typeof a?a.apply(e,i):a}requestRange(e,t){return Promise.resolve()}requestLoadedStream(e=!1){return this._loadedStreamPromise}terminate(e){}}class NetworkPdfManager extends BasePdfManager{constructor(e){super(e);this.streamManager=new ChunkedStreamManager(e.source,{msgHandler:e.handler,length:e.length,disableAutoFetch:e.disableAutoFetch,rangeChunkSize:e.rangeChunkSize});this.pdfDocument=new PDFDocument(this,this.streamManager.getStream())}async ensure(e,t,i){try{const a=e[t];return"function"==typeof a?a.apply(e,i):a}catch(a){if(!(a instanceof MissingDataException))throw a;await this.requestRange(a.begin,a.end);return this.ensure(e,t,i)}}requestRange(e,t){return this.streamManager.requestRange(e,t)}requestLoadedStream(e=!1){return this.streamManager.requestAllChunks(e)}sendProgressiveData(e){this.streamManager.onReceiveData({chunk:e})}terminate(e){this.streamManager.abort(e)}}const hg=1,Bg=2,lg=1,Qg=2,Eg=3,ug=4,dg=5,fg=6,pg=7,mg=8;function wrapReason(e){e instanceof Error||"object"==typeof e&&null!==e||unreachable('wrapReason: Expected "reason" to be a (possibly cloned) Error.');switch(e.name){case"AbortException":return new AbortException(e.message);case"MissingPDFException":return new MissingPDFException(e.message);case"PasswordException":return new PasswordException(e.message,e.code);case"UnexpectedResponseException":return new UnexpectedResponseException(e.message,e.status);case"UnknownErrorException":return new UnknownErrorException(e.message,e.details);default:return new UnknownErrorException(e.message,e.toString())}}class MessageHandler{constructor(e,t,i){this.sourceName=e;this.targetName=t;this.comObj=i;this.callbackId=1;this.streamId=1;this.streamSinks=Object.create(null);this.streamControllers=Object.create(null);this.callbackCapabilities=Object.create(null);this.actionHandler=Object.create(null);this._onComObjOnMessage=e=>{const t=e.data;if(t.targetName!==this.sourceName)return;if(t.stream){this.#W(t);return}if(t.callback){const e=t.callbackId,i=this.callbackCapabilities[e];if(!i)throw new Error(`Cannot resolve callback ${e}`);delete this.callbackCapabilities[e];if(t.callback===hg)i.resolve(t.data);else{if(t.callback!==Bg)throw new Error("Unexpected callback case");i.reject(wrapReason(t.reason))}return}const a=this.actionHandler[t.action];if(!a)throw new Error(`Unknown action from worker: ${t.action}`);if(t.callbackId){const e=this.sourceName,s=t.sourceName;new Promise((function(e){e(a(t.data))})).then((function(a){i.postMessage({sourceName:e,targetName:s,callback:hg,callbackId:t.callbackId,data:a})}),(function(a){i.postMessage({sourceName:e,targetName:s,callback:Bg,callbackId:t.callbackId,reason:wrapReason(a)})}))}else t.streamId?this.#j(t):a(t.data)};i.addEventListener("message",this._onComObjOnMessage)}on(e,t){const i=this.actionHandler;if(i[e])throw new Error(`There is already an actionName called "${e}"`);i[e]=t}send(e,t,i){this.comObj.postMessage({sourceName:this.sourceName,targetName:this.targetName,action:e,data:t},i)}sendWithPromise(e,t,i){const a=this.callbackId++,s=Promise.withResolvers();this.callbackCapabilities[a]=s;try{this.comObj.postMessage({sourceName:this.sourceName,targetName:this.targetName,action:e,callbackId:a,data:t},i)}catch(e){s.reject(e)}return s.promise}sendWithStream(e,t,i,a){const s=this.streamId++,r=this.sourceName,n=this.targetName,g=this.comObj;return new ReadableStream({start:i=>{const o=Promise.withResolvers();this.streamControllers[s]={controller:i,startCall:o,pullCall:null,cancelCall:null,isClosed:!1};g.postMessage({sourceName:r,targetName:n,action:e,streamId:s,data:t,desiredSize:i.desiredSize},a);return o.promise},pull:e=>{const t=Promise.withResolvers();this.streamControllers[s].pullCall=t;g.postMessage({sourceName:r,targetName:n,stream:fg,streamId:s,desiredSize:e.desiredSize});return t.promise},cancel:e=>{assert(e instanceof Error,"cancel must have a valid reason");const t=Promise.withResolvers();this.streamControllers[s].cancelCall=t;this.streamControllers[s].isClosed=!0;g.postMessage({sourceName:r,targetName:n,stream:lg,streamId:s,reason:wrapReason(e)});return t.promise}},i)}#j(e){const t=e.streamId,i=this.sourceName,a=e.sourceName,s=this.comObj,r=this,n=this.actionHandler[e.action],g={enqueue(e,r=1,n){if(this.isCancelled)return;const g=this.desiredSize;this.desiredSize-=r;if(g>0&&this.desiredSize<=0){this.sinkCapability=Promise.withResolvers();this.ready=this.sinkCapability.promise}s.postMessage({sourceName:i,targetName:a,stream:ug,streamId:t,chunk:e},n)},close(){if(!this.isCancelled){this.isCancelled=!0;s.postMessage({sourceName:i,targetName:a,stream:Eg,streamId:t});delete r.streamSinks[t]}},error(e){assert(e instanceof Error,"error must have a valid reason");if(!this.isCancelled){this.isCancelled=!0;s.postMessage({sourceName:i,targetName:a,stream:dg,streamId:t,reason:wrapReason(e)})}},sinkCapability:Promise.withResolvers(),onPull:null,onCancel:null,isCancelled:!1,desiredSize:e.desiredSize,ready:null};g.sinkCapability.resolve();g.ready=g.sinkCapability.promise;this.streamSinks[t]=g;new Promise((function(t){t(n(e.data,g))})).then((function(){s.postMessage({sourceName:i,targetName:a,stream:mg,streamId:t,success:!0})}),(function(e){s.postMessage({sourceName:i,targetName:a,stream:mg,streamId:t,reason:wrapReason(e)})}))}#W(e){const t=e.streamId,i=this.sourceName,a=e.sourceName,s=this.comObj,r=this.streamControllers[t],n=this.streamSinks[t];switch(e.stream){case mg:e.success?r.startCall.resolve():r.startCall.reject(wrapReason(e.reason));break;case pg:e.success?r.pullCall.resolve():r.pullCall.reject(wrapReason(e.reason));break;case fg:if(!n){s.postMessage({sourceName:i,targetName:a,stream:pg,streamId:t,success:!0});break}n.desiredSize<=0&&e.desiredSize>0&&n.sinkCapability.resolve();n.desiredSize=e.desiredSize;new Promise((function(e){e(n.onPull?.())})).then((function(){s.postMessage({sourceName:i,targetName:a,stream:pg,streamId:t,success:!0})}),(function(e){s.postMessage({sourceName:i,targetName:a,stream:pg,streamId:t,reason:wrapReason(e)})}));break;case ug:assert(r,"enqueue should have stream controller");if(r.isClosed)break;r.controller.enqueue(e.chunk);break;case Eg:assert(r,"close should have stream controller");if(r.isClosed)break;r.isClosed=!0;r.controller.close();this.#X(r,t);break;case dg:assert(r,"error should have stream controller");r.controller.error(wrapReason(e.reason));this.#X(r,t);break;case Qg:e.success?r.cancelCall.resolve():r.cancelCall.reject(wrapReason(e.reason));this.#X(r,t);break;case lg:if(!n)break;new Promise((function(t){t(n.onCancel?.(wrapReason(e.reason)))})).then((function(){s.postMessage({sourceName:i,targetName:a,stream:Qg,streamId:t,success:!0})}),(function(e){s.postMessage({sourceName:i,targetName:a,stream:Qg,streamId:t,reason:wrapReason(e)})}));n.sinkCapability.reject(wrapReason(e.reason));n.isCancelled=!0;delete this.streamSinks[t];break;default:throw new Error("Unexpected stream case")}}async#X(e,t){await Promise.allSettled([e.startCall?.promise,e.pullCall?.promise,e.cancelCall?.promise]);delete this.streamControllers[t]}destroy(){this.comObj.removeEventListener("message",this._onComObjOnMessage)}}class PDFWorkerStream{constructor(e){this._msgHandler=e;this._contentLength=null;this._fullRequestReader=null;this._rangeRequestReaders=[]}getFullReader(){assert(!this._fullRequestReader,"PDFWorkerStream.getFullReader can only be called once.");this._fullRequestReader=new PDFWorkerStreamReader(this._msgHandler);return this._fullRequestReader}getRangeReader(e,t){const i=new PDFWorkerStreamRangeReader(e,t,this._msgHandler);this._rangeRequestReaders.push(i);return i}cancelAllRequests(e){this._fullRequestReader?.cancel(e);for(const t of this._rangeRequestReaders.slice(0))t.cancel(e)}}class PDFWorkerStreamReader{constructor(e){this._msgHandler=e;this.onProgress=null;this._contentLength=null;this._isRangeSupported=!1;this._isStreamingSupported=!1;const t=this._msgHandler.sendWithStream("GetReader");this._reader=t.getReader();this._headersReady=this._msgHandler.sendWithPromise("ReaderHeadersReady").then((e=>{this._isStreamingSupported=e.isStreamingSupported;this._isRangeSupported=e.isRangeSupported;this._contentLength=e.contentLength}))}get headersReady(){return this._headersReady}get contentLength(){return this._contentLength}get isStreamingSupported(){return this._isStreamingSupported}get isRangeSupported(){return this._isRangeSupported}async read(){const{value:e,done:t}=await this._reader.read();return t?{value:void 0,done:!0}:{value:e.buffer,done:!1}}cancel(e){this._reader.cancel(e)}}class PDFWorkerStreamRangeReader{constructor(e,t,i){this._msgHandler=i;this.onProgress=null;const a=this._msgHandler.sendWithStream("GetRangeReader",{begin:e,end:t});this._reader=a.getReader()}get isStreamingSupported(){return!1}async read(){const{value:e,done:t}=await this._reader.read();return t?{value:void 0,done:!0}:{value:e.buffer,done:!1}}cancel(e){this._reader.cancel(e)}}class WorkerTask{constructor(e){this.name=e;this.terminated=!1;this._capability=Promise.withResolvers()}get finished(){return this._capability.promise}finish(){this._capability.resolve()}terminate(){this.terminated=!0}ensureNotTerminated(){if(this.terminated)throw new Error("Worker task was terminated")}}class WorkerMessageHandler{static setup(e,t){let i=!1;e.on("test",(function(t){if(!i){i=!0;e.send("test",t instanceof Uint8Array)}}));e.on("configure",(function(e){!function setVerbosityLevel(e){Number.isInteger(e)&&(gt=e)}(e.verbosity)}));e.on("GetDocRequest",(function(e){return WorkerMessageHandler.createDocumentHandler(e,t)}))}static createDocumentHandler(e,t){let i,a=!1,s=null;const r=new Set,n=getVerbosityLevel(),{docId:g,apiVersion:o}=e,c="4.7.76";if(o!==c)throw new Error(`The API version "${o}" does not match the Worker version "${c}".`);const C=[];for(const e in[])C.push(e);if(C.length)throw new Error("The `Array.prototype` contains unexpected enumerable properties: "+C.join(", ")+"; thus breaking e.g. `for...in` iteration of `Array`s.");const h=g+"_worker";let l=new MessageHandler(h,g,t);function ensureNotTerminated(){if(a)throw new Error("Worker was terminated")}function startWorkerTask(e){r.add(e)}function finishWorkerTask(e){e.finish();r.delete(e)}async function loadDocument(e){await i.ensureDoc("checkHeader");await i.ensureDoc("parseStartXRef");await i.ensureDoc("parse",[e]);await i.ensureDoc("checkFirstPage",[e]);await i.ensureDoc("checkLastPage",[e]);const t=await i.ensureDoc("isPureXfa");if(t){const e=new WorkerTask("loadXfaFonts");startWorkerTask(e);await Promise.all([i.loadXfaFonts(l,e).catch((e=>{})).then((()=>finishWorkerTask(e))),i.loadXfaImages()])}const[a,s]=await Promise.all([i.ensureDoc("numPages"),i.ensureDoc("fingerprints")]);return{numPages:a,fingerprints:s,htmlForXfa:t?await i.ensureDoc("htmlForXfa"):null}}function getPdfManager({data:e,password:t,disableAutoFetch:i,rangeChunkSize:a,length:r,docBaseUrl:n,enableXfa:o,evaluatorOptions:c}){const C={source:null,disableAutoFetch:i,docBaseUrl:n,docId:g,enableXfa:o,evaluatorOptions:c,handler:l,length:r,password:t,rangeChunkSize:a},h=Promise.withResolvers();let Q;if(e){try{C.source=e;Q=new LocalPdfManager(C);h.resolve(Q)}catch(e){h.reject(e)}return h.promise}let E,u=[];try{E=new PDFWorkerStream(l)}catch(e){h.reject(e);return h.promise}const d=E.getFullReader();d.headersReady.then((function(){if(d.isRangeSupported){C.source=E;C.length=d.contentLength;C.disableAutoFetch||=d.isStreamingSupported;Q=new NetworkPdfManager(C);for(const e of u)Q.sendProgressiveData(e);u=[];h.resolve(Q);s=null}})).catch((function(e){h.reject(e);s=null}));let f=0;new Promise((function(e,t){const readChunk=function({value:e,done:i}){try{ensureNotTerminated();if(i){Q||function(){const e=arrayBuffersToBytes(u);r&&e.length!==r&&warn("reported HTTP length is different from actual");try{C.source=e;Q=new LocalPdfManager(C);h.resolve(Q)}catch(e){h.reject(e)}u=[]}();s=null;return}f+=e.byteLength;d.isStreamingSupported||l.send("DocProgress",{loaded:f,total:Math.max(f,d.contentLength||0)});Q?Q.sendProgressiveData(e):u.push(e);d.read().then(readChunk,t)}catch(e){t(e)}};d.read().then(readChunk,t)})).catch((function(e){h.reject(e);s=null}));s=function(e){E.cancelAllRequests(e)};return h.promise}l.on("GetPage",(function(e){return i.getPage(e.pageIndex).then((function(e){return Promise.all([i.ensure(e,"rotate"),i.ensure(e,"ref"),i.ensure(e,"userUnit"),i.ensure(e,"view")]).then((function([e,t,i,a]){return{rotate:e,ref:t,refStr:t?.toString()??null,userUnit:i,view:a}}))}))}));l.on("GetPageIndex",(function(e){const t=Ref.get(e.num,e.gen);return i.ensureCatalog("getPageIndex",[t])}));l.on("GetDestinations",(function(e){return i.ensureCatalog("destinations")}));l.on("GetDestination",(function(e){return i.ensureCatalog("getDestination",[e.id])}));l.on("GetPageLabels",(function(e){return i.ensureCatalog("pageLabels")}));l.on("GetPageLayout",(function(e){return i.ensureCatalog("pageLayout")}));l.on("GetPageMode",(function(e){return i.ensureCatalog("pageMode")}));l.on("GetViewerPreferences",(function(e){return i.ensureCatalog("viewerPreferences")}));l.on("GetOpenAction",(function(e){return i.ensureCatalog("openAction")}));l.on("GetAttachments",(function(e){return i.ensureCatalog("attachments")}));l.on("GetDocJSActions",(function(e){return i.ensureCatalog("jsActions")}));l.on("GetPageJSActions",(function({pageIndex:e}){return i.getPage(e).then((function(e){return i.ensure(e,"jsActions")}))}));l.on("GetOutline",(function(e){return i.ensureCatalog("documentOutline")}));l.on("GetOptionalContentConfig",(function(e){return i.ensureCatalog("optionalContentConfig")}));l.on("GetPermissions",(function(e){return i.ensureCatalog("permissions")}));l.on("GetMetadata",(function(e){return Promise.all([i.ensureDoc("documentInfo"),i.ensureCatalog("metadata")])}));l.on("GetMarkInfo",(function(e){return i.ensureCatalog("markInfo")}));l.on("GetData",(function(e){return i.requestLoadedStream().then((function(e){return e.bytes}))}));l.on("GetAnnotations",(function({pageIndex:e,intent:t}){return i.getPage(e).then((function(i){const a=new WorkerTask(`GetAnnotations: page ${e}`);startWorkerTask(a);return i.getAnnotationsData(l,a,t).then((e=>{finishWorkerTask(a);return e}),(e=>{finishWorkerTask(a);throw e}))}))}));l.on("GetFieldObjects",(function(e){return i.ensureDoc("fieldObjects").then((e=>e?.allFields||null))}));l.on("HasJSActions",(function(e){return i.ensureDoc("hasJSActions")}));l.on("GetCalculationOrderIds",(function(e){return i.ensureDoc("calculationOrderIds")}));l.on("SaveDocument",(async function({isPureXfa:e,numPages:t,annotationStorage:a,filename:s}){const r=[i.requestLoadedStream(),i.ensureCatalog("acroForm"),i.ensureCatalog("acroFormRef"),i.ensureDoc("startXRef"),i.ensureDoc("xref"),i.ensureDoc("linearization"),i.ensureCatalog("structTreeRoot")],n=[],g=e?null:getNewAnnotationsMap(a),[o,c,C,h,Q,E,u]=await Promise.all(r),d=Q.trailer.getRaw("Root")||null;let f;if(g){u?await u.canUpdateStructTree({pdfManager:i,xref:Q,newAnnotationsByPage:g})&&(f=u):await StructTreeRoot.canCreateStructureTree({catalogRef:d,pdfManager:i,newAnnotationsByPage:g})&&(f=null);const e=AnnotationFactory.generateImages(a.values(),Q,i.evaluatorOptions.isOffscreenCanvasSupported),t=void 0===f?n:[];for(const[a,s]of g)t.push(i.getPage(a).then((t=>{const i=new WorkerTask(`Save (editor): page ${a}`);return t.saveNewAnnotations(l,i,s,e).finally((function(){finishWorkerTask(i)}))})));null===f?n.push(Promise.all(t).then((async e=>{await StructTreeRoot.createStructureTree({newAnnotationsByPage:g,xref:Q,catalogRef:d,pdfManager:i,newRefs:e});return e}))):f&&n.push(Promise.all(t).then((async e=>{await f.updateStructureTree({newAnnotationsByPage:g,pdfManager:i,newRefs:e});return e})))}if(e)n.push(i.serializeXfaData(a));else for(let e=0;ee.needAppearances)),D=c instanceof Dict&&c.get("XFA")||null;let b=null,F=!1;if(Array.isArray(D)){for(let e=0,t=D.length;e{"string"==typeof i&&(e[t]=stringToPDFString(i))}));S={rootRef:d,encryptRef:Q.trailer.getRaw("Encrypt")||null,newRef:Q.getNewTemporaryRef(),infoRef:Q.trailer.getRaw("Info")||null,info:e,fileIds:Q.trailer.get("ID")||null,startXRef:E?h:Q.lastXRefStreamPos??h,filename:s}}return incrementalUpdate({originalData:o.bytes,xrefInfo:S,newRefs:m,xref:Q,hasXfa:!!D,xfaDatasetsRef:b,hasXfaDatasetsEntry:F,needAppearances:w,acroFormRef:C,acroForm:c,xfaData:y,useXrefStream:isDict(Q.topDict,"XRef")}).finally((()=>{Q.resetNewTemporaryRef()}))}));l.on("GetOperatorList",(function(e,t){const a=e.pageIndex;i.getPage(a).then((function(i){const s=new WorkerTask(`GetOperatorList: page ${a}`);startWorkerTask(s);const r=n>=mA.INFOS?Date.now():0;i.getOperatorList({handler:l,sink:t,task:s,intent:e.intent,cacheKey:e.cacheKey,annotationStorage:e.annotationStorage,modifiedIds:e.modifiedIds}).then((function(e){finishWorkerTask(s);r&&info(`page=${a+1} - getOperatorList: time=${Date.now()-r}ms, len=${e.length}`);t.close()}),(function(e){finishWorkerTask(s);s.terminated||t.error(e)}))}))}));l.on("GetTextContent",(function(e,t){const{pageIndex:a,includeMarkedContent:s,disableNormalization:r}=e;i.getPage(a).then((function(e){const i=new WorkerTask("GetTextContent: page "+a);startWorkerTask(i);const g=n>=mA.INFOS?Date.now():0;e.extractTextContent({handler:l,task:i,sink:t,includeMarkedContent:s,disableNormalization:r}).then((function(){finishWorkerTask(i);g&&info(`page=${a+1} - getTextContent: time=`+(Date.now()-g)+"ms");t.close()}),(function(e){finishWorkerTask(i);i.terminated||t.error(e)}))}))}));l.on("GetStructTree",(function(e){return i.getPage(e.pageIndex).then((function(e){return i.ensure(e,"getStructTree")}))}));l.on("FontFallback",(function(e){return i.fontFallback(e.id,l)}));l.on("Cleanup",(function(e){return i.cleanup(!0)}));l.on("Terminate",(function(e){a=!0;const t=[];if(i){i.terminate(new AbortException("Worker was terminated."));const e=i.cleanup();t.push(e);i=null}else clearGlobalCaches();s&&s(new AbortException("Worker was terminated."));for(const e of r){t.push(e.finished);e.terminate()}return Promise.all(t).then((function(){l.destroy();l=null}))}));l.on("Ready",(function(t){!function setupDoc(e){function onSuccess(e){ensureNotTerminated();l.send("GetDoc",{pdfInfo:e})}function onFailure(e){ensureNotTerminated();if(e instanceof PasswordException){const t=new WorkerTask(`PasswordException: response ${e.code}`);startWorkerTask(t);l.sendWithPromise("PasswordRequest",e).then((function({password:e}){finishWorkerTask(t);i.updatePassword(e);pdfManagerReady()})).catch((function(){finishWorkerTask(t);l.send("DocException",e)}))}else e instanceof InvalidPDFException||e instanceof MissingPDFException||e instanceof UnexpectedResponseException||e instanceof UnknownErrorException?l.send("DocException",e):l.send("DocException",new UnknownErrorException(e.message,e.toString()))}function pdfManagerReady(){ensureNotTerminated();loadDocument(!1).then(onSuccess,(function(e){ensureNotTerminated();e instanceof XRefParseException?i.requestLoadedStream().then((function(){ensureNotTerminated();loadDocument(!0).then(onSuccess,onFailure)})):onFailure(e)}))}ensureNotTerminated();getPdfManager(e).then((function(e){if(a){e.terminate(new AbortException("Worker was terminated."));throw new Error("Worker was terminated")}i=e;i.requestLoadedStream(!0).then((e=>{l.send("DataLoaded",{length:e.bytes.byteLength})}))})).then(pdfManagerReady,onFailure)}(e);e=null}));return h}static initializeFromPort(e){const t=new MessageHandler("worker","main",e);WorkerMessageHandler.setup(t,e);t.send("ready",null)}}"undefined"==typeof window&&!t&&"undefined"!=typeof self&&function isMessagePort(e){return"function"==typeof e.postMessage&&"onmessage"in e}(self)&&WorkerMessageHandler.initializeFromPort(self);var yg=__webpack_exports__.WorkerMessageHandler;export{yg as WorkerMessageHandler}; \ No newline at end of file diff --git a/jiuguan2025cc/public/lib/polyfill.js b/jiuguan2025cc/public/lib/polyfill.js new file mode 100644 index 0000000000000000000000000000000000000000..cef73b4e59bef16d614e1dee6c42a1ba84e4eea7 --- /dev/null +++ b/jiuguan2025cc/public/lib/polyfill.js @@ -0,0 +1,19 @@ +// Polyfills for old Safari versions +if (!Object.hasOwn) { + Object.hasOwn = function (obj, prop) { return obj.hasOwnProperty(prop); } +} + +if (!Array.prototype.findLastIndex) { + Array.prototype.findLastIndex = function (callback, thisArg) { + for (let i = this.length - 1; i >= 0; i--) { + if (callback.call(thisArg, this[i], i, this)) return i; + } + return -1; + }; +} + +if (!Array.prototype.toSorted) { + Array.prototype.toSorted = function (compareFunction) { + return this.slice().sort(compareFunction); + }; +} diff --git a/jiuguan2025cc/public/lib/select2-search-placeholder.js b/jiuguan2025cc/public/lib/select2-search-placeholder.js new file mode 100644 index 0000000000000000000000000000000000000000..88ac6e397013a0e5839f4d512e3e4ddd07fb40e9 --- /dev/null +++ b/jiuguan2025cc/public/lib/select2-search-placeholder.js @@ -0,0 +1,25 @@ +(function($) { + + var Defaults = $.fn.select2.amd.require('select2/defaults'); + + $.extend(Defaults.defaults, { + searchInputPlaceholder: '', + searchInputCssClass: '', + }); + + var SearchDropdown = $.fn.select2.amd.require('select2/dropdown/search'); + + var _renderSearchDropdown = SearchDropdown.prototype.render; + + SearchDropdown.prototype.render = function(decorated) { + + // invoke parent method + var $rendered = _renderSearchDropdown.apply(this, Array.prototype.slice.apply(arguments)); + + this.$search.attr('placeholder', this.options.get('searchInputPlaceholder')); + this.$search.addClass(this.options.get('searchInputCssClass')); + + return $rendered; + }; + +})(window.jQuery); diff --git a/jiuguan2025cc/public/lib/select2.min.js b/jiuguan2025cc/public/lib/select2.min.js new file mode 100644 index 0000000000000000000000000000000000000000..cc9a83f1e2c258b3039b7a7d6b1245c74137950e --- /dev/null +++ b/jiuguan2025cc/public/lib/select2.min.js @@ -0,0 +1,2 @@ +/*! Select2 4.1.0-rc.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ +!function(n){"function"==typeof define&&define.amd?define(["jquery"],n):"object"==typeof module&&module.exports?module.exports=function(e,t){return void 0===t&&(t="undefined"!=typeof window?require("jquery"):require("jquery")(e)),n(t),t}:n(jQuery)}(function(t){var e,n,s,p,r,o,h,f,g,m,y,v,i,a,_,s=((u=t&&t.fn&&t.fn.select2&&t.fn.select2.amd?t.fn.select2.amd:u)&&u.requirejs||(u?n=u:u={},g={},m={},y={},v={},i=Object.prototype.hasOwnProperty,a=[].slice,_=/\.js$/,h=function(e,t){var n,s,i=c(e),r=i[0],t=t[1];return e=i[1],r&&(n=x(r=l(r,t))),r?e=n&&n.normalize?n.normalize(e,(s=t,function(e){return l(e,s)})):l(e,t):(r=(i=c(e=l(e,t)))[0],e=i[1],r&&(n=x(r))),{f:r?r+"!"+e:e,n:e,pr:r,p:n}},f={require:function(e){return w(e)},exports:function(e){var t=g[e];return void 0!==t?t:g[e]={}},module:function(e){return{id:e,uri:"",exports:g[e],config:(t=e,function(){return y&&y.config&&y.config[t]||{}})};var t}},r=function(e,t,n,s){var i,r,o,a,l,c=[],u=typeof n,d=A(s=s||e);if("undefined"==u||"function"==u){for(t=!t.length&&n.length?["require","exports","module"]:t,a=0;a":">",'"':""","'":"'","/":"/"};return"string"!=typeof e?e:String(e).replace(/[&<>"'\/\\]/g,function(e){return t[e]})},s.__cache={};var n=0;return s.GetUniqueElementId=function(e){var t=e.getAttribute("data-select2-id");return null!=t||(t=e.id?"select2-data-"+e.id:"select2-data-"+(++n).toString()+"-"+s.generateChars(4),e.setAttribute("data-select2-id",t)),t},s.StoreData=function(e,t,n){e=s.GetUniqueElementId(e);s.__cache[e]||(s.__cache[e]={}),s.__cache[e][t]=n},s.GetData=function(e,t){var n=s.GetUniqueElementId(e);return t?s.__cache[n]&&null!=s.__cache[n][t]?s.__cache[n][t]:r(e).data(t):s.__cache[n]},s.RemoveData=function(e){var t=s.GetUniqueElementId(e);null!=s.__cache[t]&&delete s.__cache[t],e.removeAttribute("data-select2-id")},s.copyNonInternalCssClasses=function(e,t){var n=(n=e.getAttribute("class").trim().split(/\s+/)).filter(function(e){return 0===e.indexOf("select2-")}),t=(t=t.getAttribute("class").trim().split(/\s+/)).filter(function(e){return 0!==e.indexOf("select2-")}),t=n.concat(t);e.setAttribute("class",t.join(" "))},s}),u.define("select2/results",["jquery","./utils"],function(d,p){function s(e,t,n){this.$element=e,this.data=n,this.options=t,s.__super__.constructor.call(this)}return p.Extend(s,p.Observable),s.prototype.render=function(){var e=d('
      ');return this.options.get("multiple")&&e.attr("aria-multiselectable","true"),this.$results=e},s.prototype.clear=function(){this.$results.empty()},s.prototype.displayMessage=function(e){var t=this.options.get("escapeMarkup");this.clear(),this.hideLoading();var n=d(''),s=this.options.get("translations").get(e.message);n.append(t(s(e.args))),n[0].className+=" select2-results__message",this.$results.append(n)},s.prototype.hideMessages=function(){this.$results.find(".select2-results__message").remove()},s.prototype.append=function(e){this.hideLoading();var t=[];if(null!=e.results&&0!==e.results.length){e.results=this.sort(e.results);for(var n=0;n
    ",{class:"select2-results__options select2-results__options--nested",role:"none"});i.append(l),o.append(a),o.append(i)}else this.template(e,t);return p.StoreData(t,"data",e),t},s.prototype.bind=function(t,e){var i=this,n=t.id+"-results";this.$results.attr("id",n),t.on("results:all",function(e){i.clear(),i.append(e.data),t.isOpen()&&(i.setClasses(),i.highlightFirstItem())}),t.on("results:append",function(e){i.append(e.data),t.isOpen()&&i.setClasses()}),t.on("query",function(e){i.hideMessages(),i.showLoading(e)}),t.on("select",function(){t.isOpen()&&(i.setClasses(),i.options.get("scrollAfterSelect")&&i.highlightFirstItem())}),t.on("unselect",function(){t.isOpen()&&(i.setClasses(),i.options.get("scrollAfterSelect")&&i.highlightFirstItem())}),t.on("open",function(){i.$results.attr("aria-expanded","true"),i.$results.attr("aria-hidden","false"),i.setClasses(),i.ensureHighlightVisible()}),t.on("close",function(){i.$results.attr("aria-expanded","false"),i.$results.attr("aria-hidden","true"),i.$results.removeAttr("aria-activedescendant")}),t.on("results:toggle",function(){var e=i.getHighlightedResults();0!==e.length&&e.trigger("mouseup")}),t.on("results:select",function(){var e,t=i.getHighlightedResults();0!==t.length&&(e=p.GetData(t[0],"data"),t.hasClass("select2-results__option--selected")?i.trigger("close",{}):i.trigger("select",{data:e}))}),t.on("results:previous",function(){var e,t=i.getHighlightedResults(),n=i.$results.find(".select2-results__option--selectable"),s=n.index(t);s<=0||(e=s-1,0===t.length&&(e=0),(s=n.eq(e)).trigger("mouseenter"),t=i.$results.offset().top,n=s.offset().top,s=i.$results.scrollTop()+(n-t),0===e?i.$results.scrollTop(0):n-t<0&&i.$results.scrollTop(s))}),t.on("results:next",function(){var e,t=i.getHighlightedResults(),n=i.$results.find(".select2-results__option--selectable"),s=n.index(t)+1;s>=n.length||((e=n.eq(s)).trigger("mouseenter"),t=i.$results.offset().top+i.$results.outerHeight(!1),n=e.offset().top+e.outerHeight(!1),e=i.$results.scrollTop()+n-t,0===s?i.$results.scrollTop(0):tthis.$results.outerHeight()||s<0)&&this.$results.scrollTop(n))},s.prototype.template=function(e,t){var n=this.options.get("templateResult"),s=this.options.get("escapeMarkup"),e=n(e,t);null==e?t.style.display="none":"string"==typeof e?t.innerHTML=s(e):d(t).append(e)},s}),u.define("select2/keys",[],function(){return{BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46}}),u.define("select2/selection/base",["jquery","../utils","../keys"],function(n,s,i){function r(e,t){this.$element=e,this.options=t,r.__super__.constructor.call(this)}return s.Extend(r,s.Observable),r.prototype.render=function(){var e=n('');return this._tabindex=0,null!=s.GetData(this.$element[0],"old-tabindex")?this._tabindex=s.GetData(this.$element[0],"old-tabindex"):null!=this.$element.attr("tabindex")&&(this._tabindex=this.$element.attr("tabindex")),e.attr("title",this.$element.attr("title")),e.attr("tabindex",this._tabindex),e.attr("aria-disabled","false"),this.$selection=e},r.prototype.bind=function(e,t){var n=this,s=e.id+"-results";this.container=e,this.$selection.on("focus",function(e){n.trigger("focus",e)}),this.$selection.on("blur",function(e){n._handleBlur(e)}),this.$selection.on("keydown",function(e){n.trigger("keypress",e),e.which===i.SPACE&&e.preventDefault()}),e.on("results:focus",function(e){n.$selection.attr("aria-activedescendant",e.data._resultId)}),e.on("selection:update",function(e){n.update(e.data)}),e.on("open",function(){n.$selection.attr("aria-expanded","true"),n.$selection.attr("aria-owns",s),n._attachCloseHandler(e)}),e.on("close",function(){n.$selection.attr("aria-expanded","false"),n.$selection.removeAttr("aria-activedescendant"),n.$selection.removeAttr("aria-owns"),n.$selection.trigger("focus"),n._detachCloseHandler(e)}),e.on("enable",function(){n.$selection.attr("tabindex",n._tabindex),n.$selection.attr("aria-disabled","false")}),e.on("disable",function(){n.$selection.attr("tabindex","-1"),n.$selection.attr("aria-disabled","true")})},r.prototype._handleBlur=function(e){var t=this;window.setTimeout(function(){document.activeElement==t.$selection[0]||n.contains(t.$selection[0],document.activeElement)||t.trigger("blur",e)},1)},r.prototype._attachCloseHandler=function(e){n(document.body).on("mousedown.select2."+e.id,function(e){var t=n(e.target).closest(".select2");n(".select2.select2-container--open").each(function(){this!=t[0]&&s.GetData(this,"element").select2("close")})})},r.prototype._detachCloseHandler=function(e){n(document.body).off("mousedown.select2."+e.id)},r.prototype.position=function(e,t){t.find(".selection").append(e)},r.prototype.destroy=function(){this._detachCloseHandler(this.container)},r.prototype.update=function(e){throw new Error("The `update` method must be defined in child classes.")},r.prototype.isEnabled=function(){return!this.isDisabled()},r.prototype.isDisabled=function(){return this.options.get("disabled")},r}),u.define("select2/selection/single",["jquery","./base","../utils","../keys"],function(e,t,n,s){function i(){i.__super__.constructor.apply(this,arguments)}return n.Extend(i,t),i.prototype.render=function(){var e=i.__super__.render.call(this);return e[0].classList.add("select2-selection--single"),e.html(''),e},i.prototype.bind=function(t,e){var n=this;i.__super__.bind.apply(this,arguments);var s=t.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",s).attr("role","textbox").attr("aria-readonly","true"),this.$selection.attr("aria-labelledby",s),this.$selection.attr("aria-controls",s),this.$selection.on("mousedown",function(e){1===e.which&&n.trigger("toggle",{originalEvent:e})}),this.$selection.on("focus",function(e){}),this.$selection.on("blur",function(e){}),t.on("focus",function(e){t.isOpen()||n.$selection.trigger("focus")})},i.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},i.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},i.prototype.selectionContainer=function(){return e("")},i.prototype.update=function(e){var t,n;0!==e.length?(n=e[0],t=this.$selection.find(".select2-selection__rendered"),e=this.display(n,t),t.empty().append(e),(n=n.title||n.text)?t.attr("title",n):t.removeAttr("title")):this.clear()},i}),u.define("select2/selection/multiple",["jquery","./base","../utils"],function(i,e,c){function r(e,t){r.__super__.constructor.apply(this,arguments)}return c.Extend(r,e),r.prototype.render=function(){var e=r.__super__.render.call(this);return e[0].classList.add("select2-selection--multiple"),e.html('
      '),e},r.prototype.bind=function(e,t){var n=this;r.__super__.bind.apply(this,arguments);var s=e.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",s),this.$selection.on("click",function(e){n.trigger("toggle",{originalEvent:e})}),this.$selection.on("click",".select2-selection__choice__remove",function(e){var t;n.isDisabled()||(t=i(this).parent(),t=c.GetData(t[0],"data"),n.trigger("unselect",{originalEvent:e,data:t}))}),this.$selection.on("keydown",".select2-selection__choice__remove",function(e){n.isDisabled()||e.stopPropagation()})},r.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},r.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},r.prototype.selectionContainer=function(){return i('
    • ')},r.prototype.update=function(e){if(this.clear(),0!==e.length){for(var t=[],n=this.$selection.find(".select2-selection__rendered").attr("id")+"-choice-",s=0;s')).attr("title",s()),e.attr("aria-label",s()),e.attr("aria-describedby",n),a.StoreData(e[0],"data",t),this.$selection.prepend(e),this.$selection[0].classList.add("select2-selection--clearable"))},e}),u.define("select2/selection/search",["jquery","../utils","../keys"],function(s,a,l){function e(e,t,n){e.call(this,t,n)}return e.prototype.render=function(e){var t=this.options.get("translations").get("search"),n=s('');this.$searchContainer=n,this.$search=n.find("textarea"),this.$search.prop("autocomplete",this.options.get("autocomplete")),this.$search.attr("aria-label",t());e=e.call(this);return this._transferTabIndex(),e.append(this.$searchContainer),e},e.prototype.bind=function(e,t,n){var s=this,i=t.id+"-results",r=t.id+"-container";e.call(this,t,n),s.$search.attr("aria-describedby",r),t.on("open",function(){s.$search.attr("aria-controls",i),s.$search.trigger("focus")}),t.on("close",function(){s.$search.val(""),s.resizeSearch(),s.$search.removeAttr("aria-controls"),s.$search.removeAttr("aria-activedescendant"),s.$search.trigger("focus")}),t.on("enable",function(){s.$search.prop("disabled",!1),s._transferTabIndex()}),t.on("disable",function(){s.$search.prop("disabled",!0)}),t.on("focus",function(e){s.$search.trigger("focus")}),t.on("results:focus",function(e){e.data._resultId?s.$search.attr("aria-activedescendant",e.data._resultId):s.$search.removeAttr("aria-activedescendant")}),this.$selection.on("focusin",".select2-search--inline",function(e){s.trigger("focus",e)}),this.$selection.on("focusout",".select2-search--inline",function(e){s._handleBlur(e)}),this.$selection.on("keydown",".select2-search--inline",function(e){var t;e.stopPropagation(),s.trigger("keypress",e),s._keyUpPrevented=e.isDefaultPrevented(),e.which!==l.BACKSPACE||""!==s.$search.val()||0<(t=s.$selection.find(".select2-selection__choice").last()).length&&(t=a.GetData(t[0],"data"),s.searchRemoveChoice(t),e.preventDefault())}),this.$selection.on("click",".select2-search--inline",function(e){s.$search.val()&&e.stopPropagation()});var t=document.documentMode,o=t&&t<=11;this.$selection.on("input.searchcheck",".select2-search--inline",function(e){o?s.$selection.off("input.search input.searchcheck"):s.$selection.off("keyup.search")}),this.$selection.on("keyup.search input.search",".select2-search--inline",function(e){var t;o&&"input"===e.type?s.$selection.off("input.search input.searchcheck"):(t=e.which)!=l.SHIFT&&t!=l.CTRL&&t!=l.ALT&&t!=l.TAB&&s.handleSearch(e)})},e.prototype._transferTabIndex=function(e){this.$search.attr("tabindex",this.$selection.attr("tabindex")),this.$selection.attr("tabindex","-1")},e.prototype.createPlaceholder=function(e,t){this.$search.attr("placeholder",t.text)},e.prototype.update=function(e,t){var n=this.$search[0]==document.activeElement;this.$search.attr("placeholder",""),e.call(this,t),this.resizeSearch(),n&&this.$search.trigger("focus")},e.prototype.handleSearch=function(){var e;this.resizeSearch(),this._keyUpPrevented||(e=this.$search.val(),this.trigger("query",{term:e})),this._keyUpPrevented=!1},e.prototype.searchRemoveChoice=function(e,t){this.trigger("unselect",{data:t}),this.$search.val(t.text),this.handleSearch()},e.prototype.resizeSearch=function(){this.$search.css("width","25px");var e="100%";""===this.$search.attr("placeholder")&&(e=.75*(this.$search.val().length+1)+"em"),this.$search.css("width",e)},e}),u.define("select2/selection/selectionCss",["../utils"],function(n){function e(){}return e.prototype.render=function(e){var t=e.call(this),e=this.options.get("selectionCssClass")||"";return-1!==e.indexOf(":all:")&&(e=e.replace(":all:",""),n.copyNonInternalCssClasses(t[0],this.$element[0])),t.addClass(e),t},e}),u.define("select2/selection/eventRelay",["jquery"],function(o){function e(){}return e.prototype.bind=function(e,t,n){var s=this,i=["open","opening","close","closing","select","selecting","unselect","unselecting","clear","clearing"],r=["opening","closing","selecting","unselecting","clearing"];e.call(this,t,n),t.on("*",function(e,t){var n;-1!==i.indexOf(e)&&(t=t||{},n=o.Event("select2:"+e,{params:t}),s.$element.trigger(n),-1!==r.indexOf(e)&&(t.prevented=n.isDefaultPrevented()))})},e}),u.define("select2/translation",["jquery","require"],function(t,n){function s(e){this.dict=e||{}}return s.prototype.all=function(){return this.dict},s.prototype.get=function(e){return this.dict[e]},s.prototype.extend=function(e){this.dict=t.extend({},e.all(),this.dict)},s._cache={},s.loadPath=function(e){var t;return e in s._cache||(t=n(e),s._cache[e]=t),new s(s._cache[e])},s}),u.define("select2/diacritics",[],function(){return{"Ⓐ":"A","A":"A","À":"A","Á":"A","Â":"A","Ầ":"A","Ấ":"A","Ẫ":"A","Ẩ":"A","Ã":"A","Ā":"A","Ă":"A","Ằ":"A","Ắ":"A","Ẵ":"A","Ẳ":"A","Ȧ":"A","Ǡ":"A","Ä":"A","Ǟ":"A","Ả":"A","Å":"A","Ǻ":"A","Ǎ":"A","Ȁ":"A","Ȃ":"A","Ạ":"A","Ậ":"A","Ặ":"A","Ḁ":"A","Ą":"A","Ⱥ":"A","Ɐ":"A","Ꜳ":"AA","Æ":"AE","Ǽ":"AE","Ǣ":"AE","Ꜵ":"AO","Ꜷ":"AU","Ꜹ":"AV","Ꜻ":"AV","Ꜽ":"AY","Ⓑ":"B","B":"B","Ḃ":"B","Ḅ":"B","Ḇ":"B","Ƀ":"B","Ƃ":"B","Ɓ":"B","Ⓒ":"C","C":"C","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","Ç":"C","Ḉ":"C","Ƈ":"C","Ȼ":"C","Ꜿ":"C","Ⓓ":"D","D":"D","Ḋ":"D","Ď":"D","Ḍ":"D","Ḑ":"D","Ḓ":"D","Ḏ":"D","Đ":"D","Ƌ":"D","Ɗ":"D","Ɖ":"D","Ꝺ":"D","DZ":"DZ","DŽ":"DZ","Dz":"Dz","Dž":"Dz","Ⓔ":"E","E":"E","È":"E","É":"E","Ê":"E","Ề":"E","Ế":"E","Ễ":"E","Ể":"E","Ẽ":"E","Ē":"E","Ḕ":"E","Ḗ":"E","Ĕ":"E","Ė":"E","Ë":"E","Ẻ":"E","Ě":"E","Ȅ":"E","Ȇ":"E","Ẹ":"E","Ệ":"E","Ȩ":"E","Ḝ":"E","Ę":"E","Ḙ":"E","Ḛ":"E","Ɛ":"E","Ǝ":"E","Ⓕ":"F","F":"F","Ḟ":"F","Ƒ":"F","Ꝼ":"F","Ⓖ":"G","G":"G","Ǵ":"G","Ĝ":"G","Ḡ":"G","Ğ":"G","Ġ":"G","Ǧ":"G","Ģ":"G","Ǥ":"G","Ɠ":"G","Ꞡ":"G","Ᵹ":"G","Ꝿ":"G","Ⓗ":"H","H":"H","Ĥ":"H","Ḣ":"H","Ḧ":"H","Ȟ":"H","Ḥ":"H","Ḩ":"H","Ḫ":"H","Ħ":"H","Ⱨ":"H","Ⱶ":"H","Ɥ":"H","Ⓘ":"I","I":"I","Ì":"I","Í":"I","Î":"I","Ĩ":"I","Ī":"I","Ĭ":"I","İ":"I","Ï":"I","Ḯ":"I","Ỉ":"I","Ǐ":"I","Ȉ":"I","Ȋ":"I","Ị":"I","Į":"I","Ḭ":"I","Ɨ":"I","Ⓙ":"J","J":"J","Ĵ":"J","Ɉ":"J","Ⓚ":"K","K":"K","Ḱ":"K","Ǩ":"K","Ḳ":"K","Ķ":"K","Ḵ":"K","Ƙ":"K","Ⱪ":"K","Ꝁ":"K","Ꝃ":"K","Ꝅ":"K","Ꞣ":"K","Ⓛ":"L","L":"L","Ŀ":"L","Ĺ":"L","Ľ":"L","Ḷ":"L","Ḹ":"L","Ļ":"L","Ḽ":"L","Ḻ":"L","Ł":"L","Ƚ":"L","Ɫ":"L","Ⱡ":"L","Ꝉ":"L","Ꝇ":"L","Ꞁ":"L","LJ":"LJ","Lj":"Lj","Ⓜ":"M","M":"M","Ḿ":"M","Ṁ":"M","Ṃ":"M","Ɱ":"M","Ɯ":"M","Ⓝ":"N","N":"N","Ǹ":"N","Ń":"N","Ñ":"N","Ṅ":"N","Ň":"N","Ṇ":"N","Ņ":"N","Ṋ":"N","Ṉ":"N","Ƞ":"N","Ɲ":"N","Ꞑ":"N","Ꞥ":"N","NJ":"NJ","Nj":"Nj","Ⓞ":"O","O":"O","Ò":"O","Ó":"O","Ô":"O","Ồ":"O","Ố":"O","Ỗ":"O","Ổ":"O","Õ":"O","Ṍ":"O","Ȭ":"O","Ṏ":"O","Ō":"O","Ṑ":"O","Ṓ":"O","Ŏ":"O","Ȯ":"O","Ȱ":"O","Ö":"O","Ȫ":"O","Ỏ":"O","Ő":"O","Ǒ":"O","Ȍ":"O","Ȏ":"O","Ơ":"O","Ờ":"O","Ớ":"O","Ỡ":"O","Ở":"O","Ợ":"O","Ọ":"O","Ộ":"O","Ǫ":"O","Ǭ":"O","Ø":"O","Ǿ":"O","Ɔ":"O","Ɵ":"O","Ꝋ":"O","Ꝍ":"O","Œ":"OE","Ƣ":"OI","Ꝏ":"OO","Ȣ":"OU","Ⓟ":"P","P":"P","Ṕ":"P","Ṗ":"P","Ƥ":"P","Ᵽ":"P","Ꝑ":"P","Ꝓ":"P","Ꝕ":"P","Ⓠ":"Q","Q":"Q","Ꝗ":"Q","Ꝙ":"Q","Ɋ":"Q","Ⓡ":"R","R":"R","Ŕ":"R","Ṙ":"R","Ř":"R","Ȑ":"R","Ȓ":"R","Ṛ":"R","Ṝ":"R","Ŗ":"R","Ṟ":"R","Ɍ":"R","Ɽ":"R","Ꝛ":"R","Ꞧ":"R","Ꞃ":"R","Ⓢ":"S","S":"S","ẞ":"S","Ś":"S","Ṥ":"S","Ŝ":"S","Ṡ":"S","Š":"S","Ṧ":"S","Ṣ":"S","Ṩ":"S","Ș":"S","Ş":"S","Ȿ":"S","Ꞩ":"S","Ꞅ":"S","Ⓣ":"T","T":"T","Ṫ":"T","Ť":"T","Ṭ":"T","Ț":"T","Ţ":"T","Ṱ":"T","Ṯ":"T","Ŧ":"T","Ƭ":"T","Ʈ":"T","Ⱦ":"T","Ꞇ":"T","Ꜩ":"TZ","Ⓤ":"U","U":"U","Ù":"U","Ú":"U","Û":"U","Ũ":"U","Ṹ":"U","Ū":"U","Ṻ":"U","Ŭ":"U","Ü":"U","Ǜ":"U","Ǘ":"U","Ǖ":"U","Ǚ":"U","Ủ":"U","Ů":"U","Ű":"U","Ǔ":"U","Ȕ":"U","Ȗ":"U","Ư":"U","Ừ":"U","Ứ":"U","Ữ":"U","Ử":"U","Ự":"U","Ụ":"U","Ṳ":"U","Ų":"U","Ṷ":"U","Ṵ":"U","Ʉ":"U","Ⓥ":"V","V":"V","Ṽ":"V","Ṿ":"V","Ʋ":"V","Ꝟ":"V","Ʌ":"V","Ꝡ":"VY","Ⓦ":"W","W":"W","Ẁ":"W","Ẃ":"W","Ŵ":"W","Ẇ":"W","Ẅ":"W","Ẉ":"W","Ⱳ":"W","Ⓧ":"X","X":"X","Ẋ":"X","Ẍ":"X","Ⓨ":"Y","Y":"Y","Ỳ":"Y","Ý":"Y","Ŷ":"Y","Ỹ":"Y","Ȳ":"Y","Ẏ":"Y","Ÿ":"Y","Ỷ":"Y","Ỵ":"Y","Ƴ":"Y","Ɏ":"Y","Ỿ":"Y","Ⓩ":"Z","Z":"Z","Ź":"Z","Ẑ":"Z","Ż":"Z","Ž":"Z","Ẓ":"Z","Ẕ":"Z","Ƶ":"Z","Ȥ":"Z","Ɀ":"Z","Ⱬ":"Z","Ꝣ":"Z","ⓐ":"a","a":"a","ẚ":"a","à":"a","á":"a","â":"a","ầ":"a","ấ":"a","ẫ":"a","ẩ":"a","ã":"a","ā":"a","ă":"a","ằ":"a","ắ":"a","ẵ":"a","ẳ":"a","ȧ":"a","ǡ":"a","ä":"a","ǟ":"a","ả":"a","å":"a","ǻ":"a","ǎ":"a","ȁ":"a","ȃ":"a","ạ":"a","ậ":"a","ặ":"a","ḁ":"a","ą":"a","ⱥ":"a","ɐ":"a","ꜳ":"aa","æ":"ae","ǽ":"ae","ǣ":"ae","ꜵ":"ao","ꜷ":"au","ꜹ":"av","ꜻ":"av","ꜽ":"ay","ⓑ":"b","b":"b","ḃ":"b","ḅ":"b","ḇ":"b","ƀ":"b","ƃ":"b","ɓ":"b","ⓒ":"c","c":"c","ć":"c","ĉ":"c","ċ":"c","č":"c","ç":"c","ḉ":"c","ƈ":"c","ȼ":"c","ꜿ":"c","ↄ":"c","ⓓ":"d","d":"d","ḋ":"d","ď":"d","ḍ":"d","ḑ":"d","ḓ":"d","ḏ":"d","đ":"d","ƌ":"d","ɖ":"d","ɗ":"d","ꝺ":"d","dz":"dz","dž":"dz","ⓔ":"e","e":"e","è":"e","é":"e","ê":"e","ề":"e","ế":"e","ễ":"e","ể":"e","ẽ":"e","ē":"e","ḕ":"e","ḗ":"e","ĕ":"e","ė":"e","ë":"e","ẻ":"e","ě":"e","ȅ":"e","ȇ":"e","ẹ":"e","ệ":"e","ȩ":"e","ḝ":"e","ę":"e","ḙ":"e","ḛ":"e","ɇ":"e","ɛ":"e","ǝ":"e","ⓕ":"f","f":"f","ḟ":"f","ƒ":"f","ꝼ":"f","ⓖ":"g","g":"g","ǵ":"g","ĝ":"g","ḡ":"g","ğ":"g","ġ":"g","ǧ":"g","ģ":"g","ǥ":"g","ɠ":"g","ꞡ":"g","ᵹ":"g","ꝿ":"g","ⓗ":"h","h":"h","ĥ":"h","ḣ":"h","ḧ":"h","ȟ":"h","ḥ":"h","ḩ":"h","ḫ":"h","ẖ":"h","ħ":"h","ⱨ":"h","ⱶ":"h","ɥ":"h","ƕ":"hv","ⓘ":"i","i":"i","ì":"i","í":"i","î":"i","ĩ":"i","ī":"i","ĭ":"i","ï":"i","ḯ":"i","ỉ":"i","ǐ":"i","ȉ":"i","ȋ":"i","ị":"i","į":"i","ḭ":"i","ɨ":"i","ı":"i","ⓙ":"j","j":"j","ĵ":"j","ǰ":"j","ɉ":"j","ⓚ":"k","k":"k","ḱ":"k","ǩ":"k","ḳ":"k","ķ":"k","ḵ":"k","ƙ":"k","ⱪ":"k","ꝁ":"k","ꝃ":"k","ꝅ":"k","ꞣ":"k","ⓛ":"l","l":"l","ŀ":"l","ĺ":"l","ľ":"l","ḷ":"l","ḹ":"l","ļ":"l","ḽ":"l","ḻ":"l","ſ":"l","ł":"l","ƚ":"l","ɫ":"l","ⱡ":"l","ꝉ":"l","ꞁ":"l","ꝇ":"l","lj":"lj","ⓜ":"m","m":"m","ḿ":"m","ṁ":"m","ṃ":"m","ɱ":"m","ɯ":"m","ⓝ":"n","n":"n","ǹ":"n","ń":"n","ñ":"n","ṅ":"n","ň":"n","ṇ":"n","ņ":"n","ṋ":"n","ṉ":"n","ƞ":"n","ɲ":"n","ʼn":"n","ꞑ":"n","ꞥ":"n","nj":"nj","ⓞ":"o","o":"o","ò":"o","ó":"o","ô":"o","ồ":"o","ố":"o","ỗ":"o","ổ":"o","õ":"o","ṍ":"o","ȭ":"o","ṏ":"o","ō":"o","ṑ":"o","ṓ":"o","ŏ":"o","ȯ":"o","ȱ":"o","ö":"o","ȫ":"o","ỏ":"o","ő":"o","ǒ":"o","ȍ":"o","ȏ":"o","ơ":"o","ờ":"o","ớ":"o","ỡ":"o","ở":"o","ợ":"o","ọ":"o","ộ":"o","ǫ":"o","ǭ":"o","ø":"o","ǿ":"o","ɔ":"o","ꝋ":"o","ꝍ":"o","ɵ":"o","œ":"oe","ƣ":"oi","ȣ":"ou","ꝏ":"oo","ⓟ":"p","p":"p","ṕ":"p","ṗ":"p","ƥ":"p","ᵽ":"p","ꝑ":"p","ꝓ":"p","ꝕ":"p","ⓠ":"q","q":"q","ɋ":"q","ꝗ":"q","ꝙ":"q","ⓡ":"r","r":"r","ŕ":"r","ṙ":"r","ř":"r","ȑ":"r","ȓ":"r","ṛ":"r","ṝ":"r","ŗ":"r","ṟ":"r","ɍ":"r","ɽ":"r","ꝛ":"r","ꞧ":"r","ꞃ":"r","ⓢ":"s","s":"s","ß":"s","ś":"s","ṥ":"s","ŝ":"s","ṡ":"s","š":"s","ṧ":"s","ṣ":"s","ṩ":"s","ș":"s","ş":"s","ȿ":"s","ꞩ":"s","ꞅ":"s","ẛ":"s","ⓣ":"t","t":"t","ṫ":"t","ẗ":"t","ť":"t","ṭ":"t","ț":"t","ţ":"t","ṱ":"t","ṯ":"t","ŧ":"t","ƭ":"t","ʈ":"t","ⱦ":"t","ꞇ":"t","ꜩ":"tz","ⓤ":"u","u":"u","ù":"u","ú":"u","û":"u","ũ":"u","ṹ":"u","ū":"u","ṻ":"u","ŭ":"u","ü":"u","ǜ":"u","ǘ":"u","ǖ":"u","ǚ":"u","ủ":"u","ů":"u","ű":"u","ǔ":"u","ȕ":"u","ȗ":"u","ư":"u","ừ":"u","ứ":"u","ữ":"u","ử":"u","ự":"u","ụ":"u","ṳ":"u","ų":"u","ṷ":"u","ṵ":"u","ʉ":"u","ⓥ":"v","v":"v","ṽ":"v","ṿ":"v","ʋ":"v","ꝟ":"v","ʌ":"v","ꝡ":"vy","ⓦ":"w","w":"w","ẁ":"w","ẃ":"w","ŵ":"w","ẇ":"w","ẅ":"w","ẘ":"w","ẉ":"w","ⱳ":"w","ⓧ":"x","x":"x","ẋ":"x","ẍ":"x","ⓨ":"y","y":"y","ỳ":"y","ý":"y","ŷ":"y","ỹ":"y","ȳ":"y","ẏ":"y","ÿ":"y","ỷ":"y","ẙ":"y","ỵ":"y","ƴ":"y","ɏ":"y","ỿ":"y","ⓩ":"z","z":"z","ź":"z","ẑ":"z","ż":"z","ž":"z","ẓ":"z","ẕ":"z","ƶ":"z","ȥ":"z","ɀ":"z","ⱬ":"z","ꝣ":"z","Ά":"Α","Έ":"Ε","Ή":"Η","Ί":"Ι","Ϊ":"Ι","Ό":"Ο","Ύ":"Υ","Ϋ":"Υ","Ώ":"Ω","ά":"α","έ":"ε","ή":"η","ί":"ι","ϊ":"ι","ΐ":"ι","ό":"ο","ύ":"υ","ϋ":"υ","ΰ":"υ","ώ":"ω","ς":"σ","’":"'"}}),u.define("select2/data/base",["../utils"],function(n){function s(e,t){s.__super__.constructor.call(this)}return n.Extend(s,n.Observable),s.prototype.current=function(e){throw new Error("The `current` method must be defined in child classes.")},s.prototype.query=function(e,t){throw new Error("The `query` method must be defined in child classes.")},s.prototype.bind=function(e,t){},s.prototype.destroy=function(){},s.prototype.generateResultId=function(e,t){e=e.id+"-result-";return e+=n.generateChars(4),null!=t.id?e+="-"+t.id.toString():e+="-"+n.generateChars(4),e},s}),u.define("select2/data/select",["./base","../utils","jquery"],function(e,a,l){function n(e,t){this.$element=e,this.options=t,n.__super__.constructor.call(this)}return a.Extend(n,e),n.prototype.current=function(e){var t=this;e(Array.prototype.map.call(this.$element[0].querySelectorAll(":checked"),function(e){return t.item(l(e))}))},n.prototype.select=function(i){var e,r=this;if(i.selected=!0,null!=i.element&&"option"===i.element.tagName.toLowerCase())return i.element.selected=!0,void this.$element.trigger("input").trigger("change");this.$element.prop("multiple")?this.current(function(e){var t=[];(i=[i]).push.apply(i,e);for(var n=0;nthis.maximumInputLength?this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:t.term,params:t}}):e.call(this,t,n)},e}),u.define("select2/data/maximumSelectionLength",[],function(){function e(e,t,n){this.maximumSelectionLength=n.get("maximumSelectionLength"),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var s=this;e.call(this,t,n),t.on("select",function(){s._checkIfMaximumSelected()})},e.prototype.query=function(e,t,n){var s=this;this._checkIfMaximumSelected(function(){e.call(s,t,n)})},e.prototype._checkIfMaximumSelected=function(e,t){var n=this;this.current(function(e){e=null!=e?e.length:0;0=n.maximumSelectionLength?n.trigger("results:message",{message:"maximumSelected",args:{maximum:n.maximumSelectionLength}}):t&&t()})},e}),u.define("select2/dropdown",["jquery","./utils"],function(t,e){function n(e,t){this.$element=e,this.options=t,n.__super__.constructor.call(this)}return e.Extend(n,e.Observable),n.prototype.render=function(){var e=t('');return e.attr("dir",this.options.get("dir")),this.$dropdown=e},n.prototype.bind=function(){},n.prototype.position=function(e,t){},n.prototype.destroy=function(){this.$dropdown.remove()},n}),u.define("select2/dropdown/search",["jquery"],function(r){function e(){}return e.prototype.render=function(e){var t=e.call(this),n=this.options.get("translations").get("search"),e=r('');return this.$searchContainer=e,this.$search=e.find("input"),this.$search.prop("autocomplete",this.options.get("autocomplete")),this.$search.attr("aria-label",n()),t.prepend(e),t},e.prototype.bind=function(e,t,n){var s=this,i=t.id+"-results";e.call(this,t,n),this.$search.on("keydown",function(e){s.trigger("keypress",e),s._keyUpPrevented=e.isDefaultPrevented()}),this.$search.on("input",function(e){r(this).off("keyup")}),this.$search.on("keyup input",function(e){s.handleSearch(e)}),t.on("open",function(){s.$search.attr("tabindex",0),s.$search.attr("aria-controls",i),s.$search.trigger("focus"),window.setTimeout(function(){s.$search.trigger("focus")},0)}),t.on("close",function(){s.$search.attr("tabindex",-1),s.$search.removeAttr("aria-controls"),s.$search.removeAttr("aria-activedescendant"),s.$search.val(""),s.$search.trigger("blur")}),t.on("focus",function(){t.isOpen()||s.$search.trigger("focus")}),t.on("results:all",function(e){null!=e.query.term&&""!==e.query.term||(s.showSearch(e)?s.$searchContainer[0].classList.remove("select2-search--hide"):s.$searchContainer[0].classList.add("select2-search--hide"))}),t.on("results:focus",function(e){e.data._resultId?s.$search.attr("aria-activedescendant",e.data._resultId):s.$search.removeAttr("aria-activedescendant")})},e.prototype.handleSearch=function(e){var t;this._keyUpPrevented||(t=this.$search.val(),this.trigger("query",{term:t})),this._keyUpPrevented=!1},e.prototype.showSearch=function(e,t){return!0},e}),u.define("select2/dropdown/hidePlaceholder",[],function(){function e(e,t,n,s){this.placeholder=this.normalizePlaceholder(n.get("placeholder")),e.call(this,t,n,s)}return e.prototype.append=function(e,t){t.results=this.removePlaceholder(t.results),e.call(this,t)},e.prototype.normalizePlaceholder=function(e,t){return t="string"==typeof t?{id:"",text:t}:t},e.prototype.removePlaceholder=function(e,t){for(var n=t.slice(0),s=t.length-1;0<=s;s--){var i=t[s];this.placeholder.id===i.id&&n.splice(s,1)}return n},e}),u.define("select2/dropdown/infiniteScroll",["jquery"],function(n){function e(e,t,n,s){this.lastParams={},e.call(this,t,n,s),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return e.prototype.append=function(e,t){this.$loadingMore.remove(),this.loading=!1,e.call(this,t),this.showLoadingMore(t)&&(this.$results.append(this.$loadingMore),this.loadMoreIfNeeded())},e.prototype.bind=function(e,t,n){var s=this;e.call(this,t,n),t.on("query",function(e){s.lastParams=e,s.loading=!0}),t.on("query:append",function(e){s.lastParams=e,s.loading=!0}),this.$results.on("scroll",this.loadMoreIfNeeded.bind(this))},e.prototype.loadMoreIfNeeded=function(){var e=n.contains(document.documentElement,this.$loadingMore[0]);!this.loading&&e&&(e=this.$results.offset().top+this.$results.outerHeight(!1),this.$loadingMore.offset().top+this.$loadingMore.outerHeight(!1)<=e+50&&this.loadMore())},e.prototype.loadMore=function(){this.loading=!0;var e=n.extend({},{page:1},this.lastParams);e.page++,this.trigger("query:append",e)},e.prototype.showLoadingMore=function(e,t){return t.pagination&&t.pagination.more},e.prototype.createLoadingMore=function(){var e=n('
    • '),t=this.options.get("translations").get("loadingMore");return e.html(t(this.lastParams)),e},e}),u.define("select2/dropdown/attachBody",["jquery","../utils"],function(u,o){function e(e,t,n){this.$dropdownParent=u(n.get("dropdownParent")||document.body),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var s=this;e.call(this,t,n),t.on("open",function(){s._showDropdown(),s._attachPositioningHandler(t),s._bindContainerResultHandlers(t)}),t.on("close",function(){s._hideDropdown(),s._detachPositioningHandler(t)}),this.$dropdownContainer.on("mousedown",function(e){e.stopPropagation()})},e.prototype.destroy=function(e){e.call(this),this.$dropdownContainer.remove()},e.prototype.position=function(e,t,n){t.attr("class",n.attr("class")),t[0].classList.remove("select2"),t[0].classList.add("select2-container--open"),t.css({position:"absolute",top:-999999}),this.$container=n},e.prototype.render=function(e){var t=u(""),e=e.call(this);return t.append(e),this.$dropdownContainer=t},e.prototype._hideDropdown=function(e){this.$dropdownContainer.detach()},e.prototype._bindContainerResultHandlers=function(e,t){var n;this._containerResultsHandlersBound||(n=this,t.on("results:all",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:append",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:message",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("select",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("unselect",function(){n._positionDropdown(),n._resizeDropdown()}),this._containerResultsHandlersBound=!0)},e.prototype._attachPositioningHandler=function(e,t){var n=this,s="scroll.select2."+t.id,i="resize.select2."+t.id,r="orientationchange.select2."+t.id,t=this.$container.parents().filter(o.hasScroll);t.each(function(){o.StoreData(this,"select2-scroll-position",{x:u(this).scrollLeft(),y:u(this).scrollTop()})}),t.on(s,function(e){var t=o.GetData(this,"select2-scroll-position");u(this).scrollTop(t.y)}),u(window).on(s+" "+i+" "+r,function(e){n._positionDropdown(),n._resizeDropdown()})},e.prototype._detachPositioningHandler=function(e,t){var n="scroll.select2."+t.id,s="resize.select2."+t.id,t="orientationchange.select2."+t.id;this.$container.parents().filter(o.hasScroll).off(n),u(window).off(n+" "+s+" "+t)},e.prototype._positionDropdown=function(){var e=u(window),t=this.$dropdown[0].classList.contains("select2-dropdown--above"),n=this.$dropdown[0].classList.contains("select2-dropdown--below"),s=null,i=this.$container.offset();i.bottom=i.top+this.$container.outerHeight(!1);var r={height:this.$container.outerHeight(!1)};r.top=i.top,r.bottom=i.top+r.height;var o=this.$dropdown.outerHeight(!1),a=e.scrollTop(),l=e.scrollTop()+e.height(),c=ai.bottom+o,a={left:i.left,top:r.bottom},l=this.$dropdownParent;"static"===l.css("position")&&(l=l.offsetParent());i={top:0,left:0};(u.contains(document.body,l[0])||l[0].isConnected)&&(i=l.offset()),a.top-=i.top,a.left-=i.left,t||n||(s="below"),e||!c||t?!c&&e&&t&&(s="below"):s="above",("above"==s||t&&"below"!==s)&&(a.top=r.top-i.top-o),null!=s&&(this.$dropdown[0].classList.remove("select2-dropdown--below"),this.$dropdown[0].classList.remove("select2-dropdown--above"),this.$dropdown[0].classList.add("select2-dropdown--"+s),this.$container[0].classList.remove("select2-container--below"),this.$container[0].classList.remove("select2-container--above"),this.$container[0].classList.add("select2-container--"+s)),this.$dropdownContainer.css(a)},e.prototype._resizeDropdown=function(){var e={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(e.minWidth=e.width,e.position="relative",e.width="auto"),this.$dropdown.css(e)},e.prototype._showDropdown=function(e){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},e}),u.define("select2/dropdown/minimumResultsForSearch",[],function(){function e(e,t,n,s){this.minimumResultsForSearch=n.get("minimumResultsForSearch"),this.minimumResultsForSearch<0&&(this.minimumResultsForSearch=1/0),e.call(this,t,n,s)}return e.prototype.showSearch=function(e,t){return!(function e(t){for(var n=0,s=0;s');return e.attr("dir",this.options.get("dir")),this.$container=e,this.$container[0].classList.add("select2-container--"+this.options.get("theme")),r.StoreData(e[0],"element",this.$element),e},o}),u.define("jquery-mousewheel",["jquery"],function(e){return e}),u.define("jquery.select2",["jquery","jquery-mousewheel","./select2/core","./select2/defaults","./select2/utils"],function(i,e,r,t,o){var a;return null==i.fn.select2&&(a=["open","close","destroy"],i.fn.select2=function(t){if("object"==typeof(t=t||{}))return this.each(function(){var e=i.extend(!0,{},t);new r(i(this),e)}),this;if("string"!=typeof t)throw new Error("Invalid arguments for Select2: "+t);var n,s=Array.prototype.slice.call(arguments,1);return this.each(function(){var e=o.GetData(this,"select2");null==e&&window.console&&console.error&&console.error("The select2('"+t+"') method was called on an element that is not using Select2."),n=e[t].apply(e,s)}),-1 { + const as = (out, index) => { + $.set(index, out); + return out; + }; + + const unpair = index => { + if ($.has(index)) + return $.get(index); + + const [type, value] = _[index]; + switch (type) { + case PRIMITIVE: + case VOID: + return as(value, index); + case ARRAY: { + const arr = as([], index); + for (const index of value) + arr.push(unpair(index)); + return arr; + } + case OBJECT: { + const object = as({}, index); + for (const [key, index] of value) + object[unpair(key)] = unpair(index); + return object; + } + case DATE: + return as(new Date(value), index); + case REGEXP: { + const {source, flags} = value; + return as(new RegExp(source, flags), index); + } + case MAP: { + const map = as(new Map, index); + for (const [key, index] of value) + map.set(unpair(key), unpair(index)); + return map; + } + case SET: { + const set = as(new Set, index); + for (const index of value) + set.add(unpair(index)); + return set; + } + case ERROR: { + const {name, message} = value; + return as(new env[name](message), index); + } + case BIGINT: + return as(BigInt(value), index); + case 'BigInt': + return as(Object(BigInt(value)), index); + } + return as(new env[type](value), index); + }; + + return unpair; +}; + +/** + * @typedef {Array} Record a type representation + */ + +/** + * Returns a deserialized value from a serialized array of Records. + * @param {Record[]} serialized a previously serialized value. + * @returns {any} + */ +export const deserialize = serialized => deserializer(new Map, serialized)(0); diff --git a/jiuguan2025cc/public/lib/structured-clone/index.js b/jiuguan2025cc/public/lib/structured-clone/index.js new file mode 100644 index 0000000000000000000000000000000000000000..d3b47479adfc55679022b9098fa0b968fed8d818 --- /dev/null +++ b/jiuguan2025cc/public/lib/structured-clone/index.js @@ -0,0 +1,25 @@ +import {deserialize} from './deserialize.js'; +import {serialize} from './serialize.js'; + +/** + * @typedef {Array} Record a type representation + */ + +/** + * Returns an array of serialized Records. + * @param {any} any a serializable value. + * @param {{transfer?: any[], json?: boolean, lossy?: boolean}?} options an object with + * a transfer option (ignored when polyfilled) and/or non standard fields that + * fallback to the polyfill if present. + * @returns {Record[]} + */ +export default typeof structuredClone === "function" ? + /* c8 ignore start */ + (any, options) => ( + options && ('json' in options || 'lossy' in options) ? + deserialize(serialize(any, options)) : structuredClone(any) + ) : + (any, options) => deserialize(serialize(any, options)); + /* c8 ignore stop */ + +export {deserialize, serialize}; diff --git a/jiuguan2025cc/public/lib/structured-clone/json.js b/jiuguan2025cc/public/lib/structured-clone/json.js new file mode 100644 index 0000000000000000000000000000000000000000..23eb95222d1a318faba1bffcd907b5038405ae38 --- /dev/null +++ b/jiuguan2025cc/public/lib/structured-clone/json.js @@ -0,0 +1,21 @@ +/*! (c) Andrea Giammarchi - ISC */ + +import {deserialize} from './deserialize.js'; +import {serialize} from './serialize.js'; + +const {parse: $parse, stringify: $stringify} = JSON; +const options = {json: true, lossy: true}; + +/** + * Revive a previously stringified structured clone. + * @param {string} str previously stringified data as string. + * @returns {any} whatever was previously stringified as clone. + */ +export const parse = str => deserialize($parse(str)); + +/** + * Represent a structured clone value as string. + * @param {any} any some clone-able value to stringify. + * @returns {string} the value stringified. + */ +export const stringify = any => $stringify(serialize(any, options)); diff --git a/jiuguan2025cc/public/lib/structured-clone/monkey-patch.js b/jiuguan2025cc/public/lib/structured-clone/monkey-patch.js new file mode 100644 index 0000000000000000000000000000000000000000..8489dc8921f2617a10f601b7b7a9e6c88dbcf11f --- /dev/null +++ b/jiuguan2025cc/public/lib/structured-clone/monkey-patch.js @@ -0,0 +1,6 @@ +import structuredClone from './index.js'; + +if (!("structuredClone" in globalThis)) { + console.debug("Monkey-patching structuredClone"); + globalThis.structuredClone = structuredClone; +} diff --git a/jiuguan2025cc/public/lib/structured-clone/serialize.js b/jiuguan2025cc/public/lib/structured-clone/serialize.js new file mode 100644 index 0000000000000000000000000000000000000000..8e098ddca777a7e96adce18bef6488e70ed2b8aa --- /dev/null +++ b/jiuguan2025cc/public/lib/structured-clone/serialize.js @@ -0,0 +1,161 @@ +import { + VOID, PRIMITIVE, + ARRAY, OBJECT, + DATE, REGEXP, MAP, SET, + ERROR, BIGINT +} from './types.js'; + +const EMPTY = ''; + +const {toString} = {}; +const {keys} = Object; + +const typeOf = value => { + const type = typeof value; + if (type !== 'object' || !value) + return [PRIMITIVE, type]; + + const asString = toString.call(value).slice(8, -1); + switch (asString) { + case 'Array': + return [ARRAY, EMPTY]; + case 'Object': + return [OBJECT, EMPTY]; + case 'Date': + return [DATE, EMPTY]; + case 'RegExp': + return [REGEXP, EMPTY]; + case 'Map': + return [MAP, EMPTY]; + case 'Set': + return [SET, EMPTY]; + } + + if (asString.includes('Array')) + return [ARRAY, asString]; + + if (asString.includes('Error')) + return [ERROR, asString]; + + return [OBJECT, asString]; +}; + +const shouldSkip = ([TYPE, type]) => ( + TYPE === PRIMITIVE && + (type === 'function' || type === 'symbol') +); + +const serializer = (strict, json, $, _) => { + + const as = (out, value) => { + const index = _.push(out) - 1; + $.set(value, index); + return index; + }; + + const pair = value => { + if ($.has(value)) + return $.get(value); + + let [TYPE, type] = typeOf(value); + switch (TYPE) { + case PRIMITIVE: { + let entry = value; + switch (type) { + case 'bigint': + TYPE = BIGINT; + entry = value.toString(); + break; + case 'function': + case 'symbol': + if (strict) + throw new TypeError('unable to serialize ' + type); + entry = null; + break; + case 'undefined': + return as([VOID], value); + } + return as([TYPE, entry], value); + } + case ARRAY: { + if (type) + return as([type, [...value]], value); + + const arr = []; + const index = as([TYPE, arr], value); + for (const entry of value) + arr.push(pair(entry)); + return index; + } + case OBJECT: { + if (type) { + switch (type) { + case 'BigInt': + return as([type, value.toString()], value); + case 'Boolean': + case 'Number': + case 'String': + return as([type, value.valueOf()], value); + } + } + + if (json && ('toJSON' in value)) + return pair(value.toJSON()); + + const entries = []; + const index = as([TYPE, entries], value); + for (const key of keys(value)) { + if (strict || !shouldSkip(typeOf(value[key]))) + entries.push([pair(key), pair(value[key])]); + } + return index; + } + case DATE: + return as([TYPE, value.toISOString()], value); + case REGEXP: { + const {source, flags} = value; + return as([TYPE, {source, flags}], value); + } + case MAP: { + const entries = []; + const index = as([TYPE, entries], value); + for (const [key, entry] of value) { + if (strict || !(shouldSkip(typeOf(key)) || shouldSkip(typeOf(entry)))) + entries.push([pair(key), pair(entry)]); + } + return index; + } + case SET: { + const entries = []; + const index = as([TYPE, entries], value); + for (const entry of value) { + if (strict || !shouldSkip(typeOf(entry))) + entries.push(pair(entry)); + } + return index; + } + } + + const {message} = value; + return as([TYPE, {name: type, message}], value); + }; + + return pair; +}; + +/** + * @typedef {Array} Record a type representation + */ + +/** + * Returns an array of serialized Records. + * @param {any} value a serializable value. + * @param {{json?: boolean, lossy?: boolean}?} options an object with a `lossy` or `json` property that, + * if `true`, will not throw errors on incompatible types, and behave more + * like JSON stringify would behave. Symbol and Function will be discarded. + * @returns {Record[]} + */ + export const serialize = (value, {json, lossy} = {}) => { + const _ = []; + return serializer(!(json || lossy), !!json, new Map, _)(value), _; +}; diff --git a/jiuguan2025cc/public/lib/structured-clone/types.js b/jiuguan2025cc/public/lib/structured-clone/types.js new file mode 100644 index 0000000000000000000000000000000000000000..50e60ca067667f4df09393a3898137f0c933604e --- /dev/null +++ b/jiuguan2025cc/public/lib/structured-clone/types.js @@ -0,0 +1,11 @@ +export const VOID = -1; +export const PRIMITIVE = 0; +export const ARRAY = 1; +export const OBJECT = 2; +export const DATE = 3; +export const REGEXP = 4; +export const MAP = 5; +export const SET = 6; +export const ERROR = 7; +export const BIGINT = 8; +// export const SYMBOL = 9; diff --git a/jiuguan2025cc/public/lib/swiped-events.js b/jiuguan2025cc/public/lib/swiped-events.js new file mode 100644 index 0000000000000000000000000000000000000000..b38054aba49b209aed676431113605b90efd67e1 --- /dev/null +++ b/jiuguan2025cc/public/lib/swiped-events.js @@ -0,0 +1,165 @@ +/*! + * swiped-events.js - v@version@ + * Pure JavaScript swipe events + * https://github.com/john-doherty/swiped-events + * @inspiration https://stackoverflow.com/questions/16348031/disable-scrolling-when-touch-moving-certain-element + * @author John Doherty + * @license MIT + */ +(function (window, document) { + + 'use strict'; + + // patch CustomEvent to allow constructor creation (IE/Chrome) + if (typeof window.CustomEvent !== 'function') { + + window.CustomEvent = function (event, params) { + + params = params || { bubbles: false, cancelable: false, detail: undefined }; + + var evt = document.createEvent('CustomEvent'); + evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); + return evt; + }; + + window.CustomEvent.prototype = window.Event.prototype; + } + + document.addEventListener('touchstart', handleTouchStart, false); + document.addEventListener('touchmove', handleTouchMove, false); + document.addEventListener('touchend', handleTouchEnd, false); + + var xDown = null; + var yDown = null; + var xDiff = null; + var yDiff = null; + var timeDown = null; + var startEl = null; + + /** + * Fires swiped event if swipe detected on touchend + * @param {object} e - browser event object + * @returns {void} + */ + function handleTouchEnd(e) { + + // if the user released on a different target, cancel! + if (startEl !== e.target) return; + + var swipeThreshold = parseInt(getNearestAttribute(startEl, 'data-swipe-threshold', '20'), 10); // default 20 units + var swipeUnit = getNearestAttribute(startEl, 'data-swipe-unit', 'px'); // default px + var swipeTimeout = parseInt(getNearestAttribute(startEl, 'data-swipe-timeout', '500'), 10); // default 500ms + var timeDiff = Date.now() - timeDown; + var eventType = ''; + var changedTouches = e.changedTouches || e.touches || []; + + if (swipeUnit === 'vh') { + swipeThreshold = Math.round((swipeThreshold / 100) * document.documentElement.clientHeight); // get percentage of viewport height in pixels + } + if (swipeUnit === 'vw') { + swipeThreshold = Math.round((swipeThreshold / 100) * document.documentElement.clientWidth); // get percentage of viewport height in pixels + } + + if (Math.abs(xDiff) > Math.abs(yDiff)) { // most significant + if (Math.abs(xDiff) > swipeThreshold && timeDiff < swipeTimeout) { + if (xDiff > 0) { + eventType = 'swiped-left'; + } + else { + eventType = 'swiped-right'; + } + } + } + else if (Math.abs(yDiff) > swipeThreshold && timeDiff < swipeTimeout) { + if (yDiff > 0) { + eventType = 'swiped-up'; + } + else { + eventType = 'swiped-down'; + } + } + + if (eventType !== '') { + + var eventData = { + dir: eventType.replace(/swiped-/, ''), + touchType: (changedTouches[0] || {}).touchType || 'direct', + xStart: parseInt(xDown, 10), + xEnd: parseInt((changedTouches[0] || {}).clientX || -1, 10), + yStart: parseInt(yDown, 10), + yEnd: parseInt((changedTouches[0] || {}).clientY || -1, 10) + }; + + // fire `swiped` event event on the element that started the swipe + startEl.dispatchEvent(new CustomEvent('swiped', { bubbles: true, cancelable: true, detail: eventData })); + + // fire `swiped-dir` event on the element that started the swipe + startEl.dispatchEvent(new CustomEvent(eventType, { bubbles: true, cancelable: true, detail: eventData })); + } + + // reset values + xDown = null; + yDown = null; + timeDown = null; + } + + /** + * Records current location on touchstart event + * @param {object} e - browser event object + * @returns {void} + */ + function handleTouchStart(e) { + + // if the element has data-swipe-ignore="true" we stop listening for swipe events + if (e.target.getAttribute('data-swipe-ignore') === 'true') return; + + startEl = e.target; + + timeDown = Date.now(); + xDown = e.touches[0].clientX; + yDown = e.touches[0].clientY; + xDiff = 0; + yDiff = 0; + } + + /** + * Records location diff in px on touchmove event + * @param {object} e - browser event object + * @returns {void} + */ + function handleTouchMove(e) { + + if (!xDown || !yDown) return; + + var xUp = e.touches[0].clientX; + var yUp = e.touches[0].clientY; + + xDiff = xDown - xUp; + yDiff = yDown - yUp; + } + + /** + * Gets attribute off HTML element or nearest parent + * @param {object} el - HTML element to retrieve attribute from + * @param {string} attributeName - name of the attribute + * @param {any} defaultValue - default value to return if no match found + * @returns {any} attribute value or defaultValue + */ + function getNearestAttribute(el, attributeName, defaultValue) { + + // walk up the dom tree looking for attributeName + while (el && el !== document.documentElement) { + + var attributeValue = el.getAttribute(attributeName); + + if (attributeValue) { + return attributeValue; + } + + el = el.parentNode; + } + + return defaultValue; + } + +}(window, document)); diff --git a/jiuguan2025cc/public/lib/toastr.js.map b/jiuguan2025cc/public/lib/toastr.js.map new file mode 100644 index 0000000000000000000000000000000000000000..07b5237f9f2ab9aca9d26cccba1d9b1403db498a --- /dev/null +++ b/jiuguan2025cc/public/lib/toastr.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["toastr.js"],"names":["define","$","error","message","title","optionsOverride","notify","type","toastType","iconClass","getOptions","iconClasses","getContainer","options","create","$container","containerId","length","createContainer","info","subscribe","callback","listener","success","warning","clear","$toastElement","clearOptions","clearToast","clearContainer","remove","removeToast","children","toastsToClear","i","force","hideMethod","duration","hideDuration","easing","hideEasing","complete","attr","addClass","positionClass","appendTo","target","getDefaults","tapToDismiss","toastClass","debug","showMethod","showDuration","showEasing","onShown","undefined","onHidden","closeMethod","closeDuration","closeEasing","closeOnHover","extendedTimeOut","timeOut","titleClass","messageClass","escapeHtml","closeHtml","closeClass","newestOnTop","preventDuplicates","progressBar","progressClass","rtl","publish","args","map","source","replace","personalizeToast","setIcon","setTitle","setMessage","setCloseButton","setProgressBar","setRTL","setSequence","setAria","ariaValue","handleEvents","hover","stickAround","delayedHideToast","onclick","click","hideToast","closeButton","$closeElement","event","stopPropagation","cancelBubble","onCloseClick","displayToast","hide","intervalId","setTimeout","maxHideTime","parseFloat","hideEta","Date","getTime","setInterval","updateProgress","prepend","append","suffix","$titleElement","$messageElement","$progressElement","shouldExit","previousToast","override","method","clearTimeout","response","state","endTime","stop","percentage","width","extend","toastId","startTime","console","log","toastr","is","version","amd","deps","factory","module","exports","require","window","jQuery"],"mappings":"CAaC,SAAUA,GACPA,GAAQ,UAAW,SAAUC,GACzB,MAAO,YA8BH,QAASC,GAAMC,EAASC,EAAOC,GAC3B,MAAOC,IACHC,KAAMC,EAAUN,MAChBO,UAAWC,IAAaC,YAAYT,MACpCC,QAASA,EACTE,gBAAiBA,EACjBD,MAAOA,IAIf,QAASQ,GAAaC,EAASC,GAG3B,MAFKD,KAAWA,EAAUH,KAC1BK,EAAad,EAAE,IAAMY,EAAQG,aACzBD,EAAWE,OACJF,GAEPD,IACAC,EAAaG,EAAgBL,IAE1BE,GAGX,QAASI,GAAKhB,EAASC,EAAOC,GAC1B,MAAOC,IACHC,KAAMC,EAAUW,KAChBV,UAAWC,IAAaC,YAAYQ,KACpChB,QAASA,EACTE,gBAAiBA,EACjBD,MAAOA,IAIf,QAASgB,GAAUC,GACfC,EAAWD,EAGf,QAASE,GAAQpB,EAASC,EAAOC,GAC7B,MAAOC,IACHC,KAAMC,EAAUe,QAChBd,UAAWC,IAAaC,YAAYY,QACpCpB,QAASA,EACTE,gBAAiBA,EACjBD,MAAOA,IAIf,QAASoB,GAAQrB,EAASC,EAAOC,GAC7B,MAAOC,IACHC,KAAMC,EAAUgB,QAChBf,UAAWC,IAAaC,YAAYa,QACpCrB,QAASA,EACTE,gBAAiBA,EACjBD,MAAOA,IAIf,QAASqB,GAAMC,EAAeC,GAC1B,GAAId,GAAUH,GACTK,IAAcH,EAAaC,GAC3Be,EAAWF,EAAeb,EAASc,IACpCE,EAAehB,GAIvB,QAASiB,GAAOJ,GACZ,GAAIb,GAAUH,GAEd,OADKK,IAAcH,EAAaC,GAC5Ba,GAAuD,IAAtCzB,EAAE,SAAUyB,GAAeT,WAC5Cc,GAAYL,QAGZX,EAAWiB,WAAWf,QACtBF,EAAWe,UAMnB,QAASD,GAAgBhB,GAErB,IAAK,GADDoB,GAAgBlB,EAAWiB,WACtBE,EAAID,EAAchB,OAAS,EAAGiB,GAAK,EAAGA,IAC3CN,EAAW3B,EAAEgC,EAAcC,IAAKrB,GAIxC,QAASe,GAAYF,EAAeb,EAASc,GACzC,GAAIQ,MAAQR,IAAgBA,EAAaQ,QAAQR,EAAaQ,KAC9D,UAAIT,IAAkBS,GAA+C,IAAtClC,EAAE,SAAUyB,GAAeT,UACtDS,EAAcb,EAAQuB,aAClBC,SAAUxB,EAAQyB,aAClBC,OAAQ1B,EAAQ2B,WAChBC,SAAU,WAAcV,EAAYL,OAEjC,GAKf,QAASR,GAAgBL,GAMrB,MALAE,GAAad,EAAE,UACVyC,KAAK,KAAM7B,EAAQG,aACnB2B,SAAS9B,EAAQ+B,eAEtB7B,EAAW8B,SAAS5C,EAAEY,EAAQiC,SACvB/B,EAGX,QAASgC,KACL,OACIC,cAAc,EACdC,WAAY,QACZjC,YAAa,kBACbkC,OAAO,EAEPC,WAAY,SACZC,aAAc,IACdC,WAAY,QACZC,QAASC,OACTnB,WAAY,UACZE,aAAc,IACdE,WAAY,QACZgB,SAAUD,OACVE,aAAa,EACbC,eAAe,EACfC,aAAa,EACbC,cAAc,EAEdC,gBAAiB,IACjBlD,aACIT,MAAO,cACPiB,KAAM,aACNI,QAAS,gBACTC,QAAS,iBAEbf,UAAW,aACXmC,cAAe,kBACfkB,QAAS,IACTC,WAAY,cACZC,aAAc,gBACdC,YAAY,EACZnB,OAAQ,OACRoB,UAAW,yCACXC,WAAY,qBACZC,aAAa,EACbC,mBAAmB,EACnBC,aAAa,EACbC,cAAe,iBACfC,KAAK,GAIb,QAASC,GAAQC,GACRpD,GACLA,EAASoD,GAGb,QAASpE,GAAOqE,GAgDZ,QAASV,GAAWW,GAKhB,MAJc,OAAVA,IACAA,EAAS,IAGNA,EACFC,QAAQ,KAAM,SACdA,QAAQ,KAAM,UACdA,QAAQ,KAAM,SACdA,QAAQ,KAAM,QACdA,QAAQ,KAAM,QAGvB,QAASC,KACLC,IACAC,IACAC,IACAC,IACAC,IACAC,IACAC,IACAC,IAGJ,QAASA,KACL,GAAIC,GAAY,EAChB,QAAQZ,EAAIlE,WACR,IAAK,gBACL,IAAK,aACD8E,EAAa,QACb,MACJ,SACIA,EAAY,YAEpB7D,EAAcgB,KAAK,YAAa6C,GAGpC,QAASC,KACD3E,EAAQ+C,cACRlC,EAAc+D,MAAMC,EAAaC,IAGhC9E,EAAQ+E,SAAW/E,EAAQmC,cAC5BtB,EAAcmE,MAAMC,GAGpBjF,EAAQkF,aAAeC,GACvBA,EAAcH,MAAM,SAAUI,GACtBA,EAAMC,gBACND,EAAMC,kBACwB3C,SAAvB0C,EAAME,cAA8BF,EAAME,gBAAiB,IAClEF,EAAME,cAAe,GAGrBtF,EAAQuF,cACRvF,EAAQuF,aAAaH,GAGzBH,GAAU,KAIdjF,EAAQ+E,SACRlE,EAAcmE,MAAM,SAAUI,GAC1BpF,EAAQ+E,QAAQK,GAChBH,MAKZ,QAASO,KACL3E,EAAc4E,OAEd5E,EAAcb,EAAQsC,aACjBd,SAAUxB,EAAQuC,aAAcb,OAAQ1B,EAAQwC,WAAYZ,SAAU5B,EAAQyC,UAG/EzC,EAAQiD,QAAU,IAClByC,EAAaC,WAAWV,EAAWjF,EAAQiD,SAC3CQ,EAAYmC,YAAcC,WAAW7F,EAAQiD,SAC7CQ,EAAYqC,SAAU,GAAIC,OAAOC,UAAYvC,EAAYmC,YACrD5F,EAAQyD,cACRA,EAAYiC,WAAaO,YAAYC,EAAgB,MAKjE,QAAShC,KACDJ,EAAIlE,WACJiB,EAAciB,SAAS9B,EAAQoC,YAAYN,SAASlC,GAI5D,QAAS4E,KACDxE,EAAQuD,YACRrD,EAAWiG,QAAQtF,GAEnBX,EAAWkG,OAAOvF,GAI1B,QAASsD,KACL,GAAIL,EAAIvE,MAAO,CACX,GAAI8G,GAASvC,EAAIvE,KACbS,GAAQoD,aACRiD,EAASjD,EAAWU,EAAIvE,QAE5B+G,EAAcF,OAAOC,GAAQvE,SAAS9B,EAAQkD,YAC9CrC,EAAcuF,OAAOE,IAI7B,QAASlC,KACL,GAAIN,EAAIxE,QAAS,CACb,GAAI+G,GAASvC,EAAIxE,OACbU,GAAQoD,aACRiD,EAASjD,EAAWU,EAAIxE,UAE5BiH,EAAgBH,OAAOC,GAAQvE,SAAS9B,EAAQmD,cAChDtC,EAAcuF,OAAOG,IAI7B,QAASlC,KACDrE,EAAQkF,cACRC,EAAcrD,SAAS9B,EAAQsD,YAAYzB,KAAK,OAAQ,UACxDhB,EAAcsF,QAAQhB,IAI9B,QAASb,KACDtE,EAAQyD,cACR+C,EAAiB1E,SAAS9B,EAAQ0D,eAClC7C,EAAcsF,QAAQK,IAI9B,QAASjC,KACDvE,EAAQ2D,KACR9C,EAAciB,SAAS,OAI/B,QAAS2E,GAAWzG,EAAS8D,GACzB,GAAI9D,EAAQwD,kBAAmB,CAC3B,GAAIM,EAAIxE,UAAYoH,EAChB,OAAO,CAEPA,GAAgB5C,EAAIxE,QAG5B,OAAO,EAGX,QAAS2F,GAAU0B,GACf,GAAIC,GAASD,GAAY3G,EAAQ4C,eAAgB,EAAQ5C,EAAQ4C,YAAc5C,EAAQuB,WACnFC,EAAWmF,GAAY3G,EAAQ6C,iBAAkB,EACjD7C,EAAQ6C,cAAgB7C,EAAQyB,aAChCC,EAASiF,GAAY3G,EAAQ8C,eAAgB,EAAQ9C,EAAQ8C,YAAc9C,EAAQ2B,UACvF,KAAIvC,EAAE,SAAUyB,GAAeT,QAAWuG,EAI1C,MADAE,cAAapD,EAAYiC,YAClB7E,EAAc+F,IACjBpF,SAAUA,EACVE,OAAQA,EACRE,SAAU,WACNV,EAAYL,GACZgG,aAAanB,GACT1F,EAAQ2C,UAA+B,WAAnBmE,EAASC,OAC7B/G,EAAQ2C,WAEZmE,EAASC,MAAQ,SACjBD,EAASE,QAAU,GAAIjB,MACvBnC,EAAQkD,MAKpB,QAAShC,MACD9E,EAAQiD,QAAU,GAAKjD,EAAQgD,gBAAkB,KACjD0C,EAAaC,WAAWV,EAAWjF,EAAQgD,iBAC3CS,EAAYmC,YAAcC,WAAW7F,EAAQgD,iBAC7CS,EAAYqC,SAAU,GAAIC,OAAOC,UAAYvC,EAAYmC,aAIjE,QAASf,KACLgC,aAAanB,GACbjC,EAAYqC,QAAU,EACtBjF,EAAcoG,MAAK,GAAM,GAAMjH,EAAQsC,aAClCd,SAAUxB,EAAQuC,aAAcb,OAAQ1B,EAAQwC,aAIzD,QAAS0D,KACL,GAAIgB,IAAezD,EAAYqC,SAAW,GAAIC,OAAOC,WAAcvC,EAAYmC,YAAe,GAC9FY,GAAiBW,MAAMD,EAAa,KApPxC,GAAIlH,GAAUH,IACVD,EAAYkE,EAAIlE,WAAaI,EAAQJ,SAOzC,IALqC,mBAAzBkE,GAAmB,kBAC3B9D,EAAUZ,EAAEgI,OAAOpH,EAAS8D,EAAItE,iBAChCI,EAAYkE,EAAItE,gBAAgBI,WAAaA,IAG7C6G,EAAWzG,EAAS8D,GAAxB,CAEAuD,IAEAnH,EAAaH,EAAaC,GAAS,EAEnC,IAAI0F,GAAa,KACb7E,EAAgBzB,EAAE,UAClBkH,EAAgBlH,EAAE,UAClBmH,EAAkBnH,EAAE,UACpBoH,EAAmBpH,EAAE,UACrB+F,EAAgB/F,EAAEY,EAAQqD,WAC1BI,GACAiC,WAAY,KACZI,QAAS,KACTF,YAAa,MAEbkB,GACAO,QAASA,EACTN,MAAO,UACPO,UAAW,GAAIvB,MACf/F,QAASA,EACT8D,IAAKA,EAeT,OAZAG,KAEAuB,IAEAb,IAEAf,EAAQkD,GAEJ9G,EAAQqC,OAASkF,SACjBA,QAAQC,IAAIV,GAGTjG,GA2MX,QAAShB,KACL,MAAOT,GAAEgI,UAAWlF,IAAeuF,EAAOzH,SAG9C,QAASkB,GAAYL,GACZX,IAAcA,EAAaH,KAC5Bc,EAAc6G,GAAG,cAGrB7G,EAAcI,SACdJ,EAAgB,KACqB,IAAjCX,EAAWiB,WAAWf,SACtBF,EAAWe,SACXyF,EAAgBhE,SA/bxB,GAAIxC,GACAO,EAsBAiG,EArBAW,EAAU,EACV1H,GACAN,MAAO,QACPiB,KAAM,OACNI,QAAS,UACTC,QAAS,WAGT8G,GACA7G,MAAOA,EACPK,OAAQA,EACR5B,MAAOA,EACPU,aAAcA,EACdO,KAAMA,EACNN,WACAO,UAAWA,EACXG,QAASA,EACTiH,QAAS,QACThH,QAASA,EAKb,OAAO8G,SA4aC,kBAAXtI,SAAyBA,OAAOyI,IAAMzI,OAAS,SAAU0I,EAAMC,GAC9C,mBAAXC,SAA0BA,OAAOC,QACxCD,OAAOC,QAAUF,EAAQG,QAAQ,WAEjCC,OAAOT,OAASK,EAAQI,OAAOC","file":"toastr.js","sourcesContent":["/*\n * Toastr\n * Copyright 2012-2015\n * Authors: John Papa, Hans Fjällemark, and Tim Ferrell.\n * All Rights Reserved.\n * Use, reproduction, distribution, and modification of this code is subject to the terms and\n * conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php\n *\n * ARIA Support: Greta Krafsig\n *\n * Project: https://github.com/CodeSeven/toastr\n */\n/* global define */\n(function (define) {\n define(['jquery'], function ($) {\n return (function () {\n var $container;\n var listener;\n var toastId = 0;\n var toastType = {\n error: 'error',\n info: 'info',\n success: 'success',\n warning: 'warning'\n };\n\n var toastr = {\n clear: clear,\n remove: remove,\n error: error,\n getContainer: getContainer,\n info: info,\n options: {},\n subscribe: subscribe,\n success: success,\n version: '2.1.3',\n warning: warning\n };\n\n var previousToast;\n\n return toastr;\n\n ////////////////\n\n function error(message, title, optionsOverride) {\n return notify({\n type: toastType.error,\n iconClass: getOptions().iconClasses.error,\n message: message,\n optionsOverride: optionsOverride,\n title: title\n });\n }\n\n function getContainer(options, create) {\n if (!options) { options = getOptions(); }\n $container = $('#' + options.containerId);\n if ($container.length) {\n return $container;\n }\n if (create) {\n $container = createContainer(options);\n }\n return $container;\n }\n\n function info(message, title, optionsOverride) {\n return notify({\n type: toastType.info,\n iconClass: getOptions().iconClasses.info,\n message: message,\n optionsOverride: optionsOverride,\n title: title\n });\n }\n\n function subscribe(callback) {\n listener = callback;\n }\n\n function success(message, title, optionsOverride) {\n return notify({\n type: toastType.success,\n iconClass: getOptions().iconClasses.success,\n message: message,\n optionsOverride: optionsOverride,\n title: title\n });\n }\n\n function warning(message, title, optionsOverride) {\n return notify({\n type: toastType.warning,\n iconClass: getOptions().iconClasses.warning,\n message: message,\n optionsOverride: optionsOverride,\n title: title\n });\n }\n\n function clear($toastElement, clearOptions) {\n var options = getOptions();\n if (!$container) { getContainer(options); }\n if (!clearToast($toastElement, options, clearOptions)) {\n clearContainer(options);\n }\n }\n\n function remove($toastElement) {\n var options = getOptions();\n if (!$container) { getContainer(options); }\n if ($toastElement && $(':focus', $toastElement).length === 0) {\n removeToast($toastElement);\n return;\n }\n if ($container.children().length) {\n $container.remove();\n }\n }\n\n // internal functions\n\n function clearContainer (options) {\n var toastsToClear = $container.children();\n for (var i = toastsToClear.length - 1; i >= 0; i--) {\n clearToast($(toastsToClear[i]), options);\n }\n }\n\n function clearToast ($toastElement, options, clearOptions) {\n var force = clearOptions && clearOptions.force ? clearOptions.force : false;\n if ($toastElement && (force || $(':focus', $toastElement).length === 0)) {\n $toastElement[options.hideMethod]({\n duration: options.hideDuration,\n easing: options.hideEasing,\n complete: function () { removeToast($toastElement); }\n });\n return true;\n }\n return false;\n }\n\n function createContainer(options) {\n $container = $('
      ')\n .attr('id', options.containerId)\n .addClass(options.positionClass);\n\n $container.appendTo($(options.target));\n return $container;\n }\n\n function getDefaults() {\n return {\n tapToDismiss: true,\n toastClass: 'toast',\n containerId: 'toast-container',\n debug: false,\n\n showMethod: 'fadeIn', //fadeIn, slideDown, and show are built into jQuery\n showDuration: 300,\n showEasing: 'swing', //swing and linear are built into jQuery\n onShown: undefined,\n hideMethod: 'fadeOut',\n hideDuration: 1000,\n hideEasing: 'swing',\n onHidden: undefined,\n closeMethod: false,\n closeDuration: false,\n closeEasing: false,\n closeOnHover: true,\n\n extendedTimeOut: 1000,\n iconClasses: {\n error: 'toast-error',\n info: 'toast-info',\n success: 'toast-success',\n warning: 'toast-warning'\n },\n iconClass: 'toast-info',\n positionClass: 'toast-top-right',\n timeOut: 5000, // Set timeOut and extendedTimeOut to 0 to make it sticky\n titleClass: 'toast-title',\n messageClass: 'toast-message',\n escapeHtml: false,\n target: 'body',\n closeHtml: '',\n closeClass: 'toast-close-button',\n newestOnTop: true,\n preventDuplicates: false,\n progressBar: false,\n progressClass: 'toast-progress',\n rtl: false\n };\n }\n\n function publish(args) {\n if (!listener) { return; }\n listener(args);\n }\n\n function notify(map) {\n var options = getOptions();\n var iconClass = map.iconClass || options.iconClass;\n\n if (typeof (map.optionsOverride) !== 'undefined') {\n options = $.extend(options, map.optionsOverride);\n iconClass = map.optionsOverride.iconClass || iconClass;\n }\n\n if (shouldExit(options, map)) { return; }\n\n toastId++;\n\n $container = getContainer(options, true);\n\n var intervalId = null;\n var $toastElement = $('
      ');\n var $titleElement = $('
      ');\n var $messageElement = $('
      ');\n var $progressElement = $('
      ');\n var $closeElement = $(options.closeHtml);\n var progressBar = {\n intervalId: null,\n hideEta: null,\n maxHideTime: null\n };\n var response = {\n toastId: toastId,\n state: 'visible',\n startTime: new Date(),\n options: options,\n map: map\n };\n\n personalizeToast();\n\n displayToast();\n\n handleEvents();\n\n publish(response);\n\n if (options.debug && console) {\n console.log(response);\n }\n\n return $toastElement;\n\n function escapeHtml(source) {\n if (source == null) {\n source = '';\n }\n\n return source\n .replace(/&/g, '&')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n .replace(//g, '>');\n }\n\n function personalizeToast() {\n setIcon();\n setTitle();\n setMessage();\n setCloseButton();\n setProgressBar();\n setRTL();\n setSequence();\n setAria();\n }\n\n function setAria() {\n var ariaValue = '';\n switch (map.iconClass) {\n case 'toast-success':\n case 'toast-info':\n ariaValue = 'polite';\n break;\n default:\n ariaValue = 'assertive';\n }\n $toastElement.attr('aria-live', ariaValue);\n }\n\n function handleEvents() {\n if (options.closeOnHover) {\n $toastElement.hover(stickAround, delayedHideToast);\n }\n\n if (!options.onclick && options.tapToDismiss) {\n $toastElement.click(hideToast);\n }\n\n if (options.closeButton && $closeElement) {\n $closeElement.click(function (event) {\n if (event.stopPropagation) {\n event.stopPropagation();\n } else if (event.cancelBubble !== undefined && event.cancelBubble !== true) {\n event.cancelBubble = true;\n }\n\n if (options.onCloseClick) {\n options.onCloseClick(event);\n }\n\n hideToast(true);\n });\n }\n\n if (options.onclick) {\n $toastElement.click(function (event) {\n options.onclick(event);\n hideToast();\n });\n }\n }\n\n function displayToast() {\n $toastElement.hide();\n\n $toastElement[options.showMethod](\n {duration: options.showDuration, easing: options.showEasing, complete: options.onShown}\n );\n\n if (options.timeOut > 0) {\n intervalId = setTimeout(hideToast, options.timeOut);\n progressBar.maxHideTime = parseFloat(options.timeOut);\n progressBar.hideEta = new Date().getTime() + progressBar.maxHideTime;\n if (options.progressBar) {\n progressBar.intervalId = setInterval(updateProgress, 10);\n }\n }\n }\n\n function setIcon() {\n if (map.iconClass) {\n $toastElement.addClass(options.toastClass).addClass(iconClass);\n }\n }\n\n function setSequence() {\n if (options.newestOnTop) {\n $container.prepend($toastElement);\n } else {\n $container.append($toastElement);\n }\n }\n\n function setTitle() {\n if (map.title) {\n var suffix = map.title;\n if (options.escapeHtml) {\n suffix = escapeHtml(map.title);\n }\n $titleElement.append(suffix).addClass(options.titleClass);\n $toastElement.append($titleElement);\n }\n }\n\n function setMessage() {\n if (map.message) {\n var suffix = map.message;\n if (options.escapeHtml) {\n suffix = escapeHtml(map.message);\n }\n $messageElement.append(suffix).addClass(options.messageClass);\n $toastElement.append($messageElement);\n }\n }\n\n function setCloseButton() {\n if (options.closeButton) {\n $closeElement.addClass(options.closeClass).attr('role', 'button');\n $toastElement.prepend($closeElement);\n }\n }\n\n function setProgressBar() {\n if (options.progressBar) {\n $progressElement.addClass(options.progressClass);\n $toastElement.prepend($progressElement);\n }\n }\n\n function setRTL() {\n if (options.rtl) {\n $toastElement.addClass('rtl');\n }\n }\n\n function shouldExit(options, map) {\n if (options.preventDuplicates) {\n if (map.message === previousToast) {\n return true;\n } else {\n previousToast = map.message;\n }\n }\n return false;\n }\n\n function hideToast(override) {\n var method = override && options.closeMethod !== false ? options.closeMethod : options.hideMethod;\n var duration = override && options.closeDuration !== false ?\n options.closeDuration : options.hideDuration;\n var easing = override && options.closeEasing !== false ? options.closeEasing : options.hideEasing;\n if ($(':focus', $toastElement).length && !override) {\n return;\n }\n clearTimeout(progressBar.intervalId);\n return $toastElement[method]({\n duration: duration,\n easing: easing,\n complete: function () {\n removeToast($toastElement);\n clearTimeout(intervalId);\n if (options.onHidden && response.state !== 'hidden') {\n options.onHidden();\n }\n response.state = 'hidden';\n response.endTime = new Date();\n publish(response);\n }\n });\n }\n\n function delayedHideToast() {\n if (options.timeOut > 0 || options.extendedTimeOut > 0) {\n intervalId = setTimeout(hideToast, options.extendedTimeOut);\n progressBar.maxHideTime = parseFloat(options.extendedTimeOut);\n progressBar.hideEta = new Date().getTime() + progressBar.maxHideTime;\n }\n }\n\n function stickAround() {\n clearTimeout(intervalId);\n progressBar.hideEta = 0;\n $toastElement.stop(true, true)[options.showMethod](\n {duration: options.showDuration, easing: options.showEasing}\n );\n }\n\n function updateProgress() {\n var percentage = ((progressBar.hideEta - (new Date().getTime())) / progressBar.maxHideTime) * 100;\n $progressElement.width(percentage + '%');\n }\n }\n\n function getOptions() {\n return $.extend({}, getDefaults(), toastr.options);\n }\n\n function removeToast($toastElement) {\n if (!$container) { $container = getContainer(); }\n if ($toastElement.is(':visible')) {\n return;\n }\n $toastElement.remove();\n $toastElement = null;\n if ($container.children().length === 0) {\n $container.remove();\n previousToast = undefined;\n }\n }\n\n })();\n });\n}(typeof define === 'function' && define.amd ? define : function (deps, factory) {\n if (typeof module !== 'undefined' && module.exports) { //Node\n module.exports = factory(require('jquery'));\n } else {\n window.toastr = factory(window.jQuery);\n }\n}));\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/jiuguan2025cc/public/lib/toastr.min.js b/jiuguan2025cc/public/lib/toastr.min.js new file mode 100644 index 0000000000000000000000000000000000000000..4b5f34a0591d318d514c69879b319174dc317dcf --- /dev/null +++ b/jiuguan2025cc/public/lib/toastr.min.js @@ -0,0 +1,7 @@ +/* + * Note that this is toastr v2.1.3, the "latest" version in url has no more maintenance, + * please go to https://cdnjs.com/libraries/toastr.js and pick a certain version you want to use, + * make sure you copy the url from the website since the url may change between versions. + * */ +!function(e){e(["jquery"],function(e){return function(){function t(e,t,n){return g({type:O.error,iconClass:m().iconClasses.error,message:e,optionsOverride:n,title:t})}function n(t,n){return t||(t=m()),v=e("#"+t.containerId),v.length?v:(n&&(v=d(t)),v)}function o(e,t,n){return g({type:O.info,iconClass:m().iconClasses.info,message:e,optionsOverride:n,title:t})}function s(e){C=e}function i(e,t,n){return g({type:O.success,iconClass:m().iconClasses.success,message:e,optionsOverride:n,title:t})}function a(e,t,n){return g({type:O.warning,iconClass:m().iconClasses.warning,message:e,optionsOverride:n,title:t})}function r(e,t){var o=m();v||n(o),u(e,o,t)||l(o)}function c(t){var o=m();return v||n(o),t&&0===e(":focus",t).length?void h(t):void(v.children().length&&v.remove())}function l(t){for(var n=v.children(),o=n.length-1;o>=0;o--)u(e(n[o]),t)}function u(t,n,o){var s=!(!o||!o.force)&&o.force;return!(!t||!s&&0!==e(":focus",t).length)&&(t[n.hideMethod]({duration:n.hideDuration,easing:n.hideEasing,complete:function(){h(t)}}),!0)}function d(t){return v=e("
      ").attr("id",t.containerId).addClass(t.positionClass),v.appendTo(e(t.target)),v}function p(){return{tapToDismiss:!0,toastClass:"toast",containerId:"toast-container",debug:!1,showMethod:"fadeIn",showDuration:300,showEasing:"swing",onShown:void 0,hideMethod:"fadeOut",hideDuration:1e3,hideEasing:"swing",onHidden:void 0,closeMethod:!1,closeDuration:!1,closeEasing:!1,closeOnHover:!0,extendedTimeOut:1e3,iconClasses:{error:"toast-error",info:"toast-info",success:"toast-success",warning:"toast-warning"},iconClass:"toast-info",positionClass:"toast-top-right",timeOut:5e3,titleClass:"toast-title",messageClass:"toast-message",escapeHtml:!1,target:"body",closeHtml:'',closeClass:"toast-close-button",newestOnTop:!0,preventDuplicates:!1,progressBar:!1,progressClass:"toast-progress",rtl:!1}}function f(e){C&&C(e)}function g(t){function o(e){return null==e&&(e=""),e.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">")}function s(){c(),u(),d(),p(),g(),C(),l(),i()}function i(){var e="";switch(t.iconClass){case"toast-success":case"toast-info":e="polite";break;default:e="assertive"}I.attr("aria-live",e)}function a(){E.closeOnHover&&I.hover(H,D),!E.onclick&&E.tapToDismiss&&I.click(b),E.closeButton&&j&&j.click(function(e){e.stopPropagation?e.stopPropagation():void 0!==e.cancelBubble&&e.cancelBubble!==!0&&(e.cancelBubble=!0),E.onCloseClick&&E.onCloseClick(e),b(!0)}),E.onclick&&I.click(function(e){E.onclick(e),b()})}function r(){I.hide(),I[E.showMethod]({duration:E.showDuration,easing:E.showEasing,complete:E.onShown}),E.timeOut>0&&(k=setTimeout(b,E.timeOut),F.maxHideTime=parseFloat(E.timeOut),F.hideEta=(new Date).getTime()+F.maxHideTime,E.progressBar&&(F.intervalId=setInterval(x,10)))}function c(){t.iconClass&&I.addClass(E.toastClass).addClass(y)}function l(){E.newestOnTop?v.prepend(I):v.append(I)}function u(){if(t.title){var e=t.title;E.escapeHtml&&(e=o(t.title)),M.append(e).addClass(E.titleClass),I.append(M)}}function d(){if(t.message){var e=t.message;E.escapeHtml&&(e=o(t.message)),B.append(e).addClass(E.messageClass),I.append(B)}}function p(){E.closeButton&&(j.addClass(E.closeClass).attr("role","button"),I.prepend(j))}function g(){E.progressBar&&(q.addClass(E.progressClass),I.prepend(q))}function C(){E.rtl&&I.addClass("rtl")}function O(e,t){if(e.preventDuplicates){if(t.message===w)return!0;w=t.message}return!1}function b(t){var n=t&&E.closeMethod!==!1?E.closeMethod:E.hideMethod,o=t&&E.closeDuration!==!1?E.closeDuration:E.hideDuration,s=t&&E.closeEasing!==!1?E.closeEasing:E.hideEasing;if(!e(":focus",I).length||t)return clearTimeout(F.intervalId),I[n]({duration:o,easing:s,complete:function(){h(I),clearTimeout(k),E.onHidden&&"hidden"!==P.state&&E.onHidden(),P.state="hidden",P.endTime=new Date,f(P)}})}function D(){(E.timeOut>0||E.extendedTimeOut>0)&&(k=setTimeout(b,E.extendedTimeOut),F.maxHideTime=parseFloat(E.extendedTimeOut),F.hideEta=(new Date).getTime()+F.maxHideTime)}function H(){clearTimeout(k),F.hideEta=0,I.stop(!0,!0)[E.showMethod]({duration:E.showDuration,easing:E.showEasing})}function x(){var e=(F.hideEta-(new Date).getTime())/F.maxHideTime*100;q.width(e+"%")}var E=m(),y=t.iconClass||E.iconClass;if("undefined"!=typeof t.optionsOverride&&(E=e.extend(E,t.optionsOverride),y=t.optionsOverride.iconClass||y),!O(E,t)){T++,v=n(E,!0);var k=null,I=e("
      "),M=e("
      "),B=e("
      "),q=e("
      "),j=e(E.closeHtml),F={intervalId:null,hideEta:null,maxHideTime:null},P={toastId:T,state:"visible",startTime:new Date,options:E,map:t};return s(),r(),a(),f(P),E.debug&&console&&console.log(P),I}}function m(){return e.extend({},p(),b.options)}function h(e){v||(v=n()),e.is(":visible")||(e.remove(),e=null,0===v.children().length&&(v.remove(),w=void 0))}var v,C,w,T=0,O={error:"error",info:"info",success:"success",warning:"warning"},b={clear:r,remove:c,error:t,getContainer:n,info:o,options:{},subscribe:s,success:i,version:"2.1.3",warning:a};return b}()})}("function"==typeof define&&define.amd?define:function(e,t){"undefined"!=typeof module&&module.exports?module.exports=t(require("jquery")):window.toastr=t(window.jQuery)}); +//# sourceMappingURL=toastr.js.map diff --git a/jiuguan2025cc/public/lib/toolcool-color-picker.js b/jiuguan2025cc/public/lib/toolcool-color-picker.js new file mode 100644 index 0000000000000000000000000000000000000000..54d7a751e1482ef2d2b26ae23b95ee9f0b59c809 --- /dev/null +++ b/jiuguan2025cc/public/lib/toolcool-color-picker.js @@ -0,0 +1,87 @@ +/* +Tool Cool Color Picker +Version: 1.0.14 +Documentation: https://github.com/mzusin/toolcool-color-picker +Author: Miriam Zusin +License: MIT License +*/ +(()=>{var Mt=Object.defineProperty;var kt=(o,e,t)=>e in o?Mt(o,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[e]=t;var h=(o,e,t)=>(kt(o,typeof e!="symbol"?e+"":e,t),t);var ot=":root{--tool-cool-color-picker-btn-bg:#fff;--tool-cool-color-picker-btn-border-color:#cecece;--tool-cool-color-picker-btn-border-color-inner:#626262;--tool-cool-color-picker-btn-border-radius:.25rem;--tool-cool-color-picker-btn-border-radius-inner:0}.color-picker{position:relative}.button{width:3rem;height:1.5rem;padding:.25rem;background:var(--tool-cool-color-picker-btn-bg,#fff);border-radius:var(--tool-cool-color-picker-btn-border-radius,0.25rem);border-width:1px;border-style:solid;border-color:var(--tool-cool-color-picker-btn-border-color,#cecece);cursor:pointer;box-sizing:border-box}.button-color{display:block;width:100%;height:100%;border-width:1px;border-style:solid;border-color:var(--tool-cool-color-picker-btn-border-color-inner,#626262);background:#000;box-sizing:border-box;border-radius:var(--tool-cool-color-picker-btn-border-radius-inner,0)}";var it=":root{--tool-cool-color-picker-popup-bg:#fff;--tool-cool-color-picker-popup-border-color:#cecece;--tool-cool-color-picker-popup-width:214px}.popup{position:absolute;left:0;top:calc(100% - 1px);z-index:50;width:var(--tool-cool-color-picker-popup-width,214px);box-shadow:0 1px 3px 0 rgba(0,0,0,0.1),0 1px 2px -1px rgba(0,0,0,0.1);padding:.5rem;background:var(--tool-cool-color-picker-popup-bg,#fff);border-width:1px;border-style:solid;border-color:var(--tool-cool-color-picker-popup-border-color,#cecece);border-radius:.25rem}.popup.right{right:0;left:auto}";var rt=".saturation{touch-action:none;overflow:hidden;width:100%;height:9rem;position:relative}.box{width:100%;height:100%;position:absolute}.white{background:linear-gradient(90deg,#fff,hsla(0,0%,100%,0))}.black{background:linear-gradient(0,#000,transparent)}.pointer{top:34.902%;left:18.6747%;cursor:pointer;position:absolute;outline:0}.handler{box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgb(0,0,0,0.3),0 0 1px 2px rgb(0,0,0,0.4);-webkit-transform:translate(-2px,-2px);transform:translate(-2px,-2px);border-radius:100%;width:.25rem;height:.25rem;outline:0}";var p="tc-hsv-changed",f="tc-hue-changed",m="tc-alpha-changed",D="tc-button-clicked",nt=o=>{!o||document.dispatchEvent(new CustomEvent(D,{detail:{cid:o}}))},M=(o,e)=>{!o||document.dispatchEvent(new CustomEvent(m,{detail:{a:e,cid:o}}))},b=(o,e,t,i)=>{!o||document.dispatchEvent(new CustomEvent(p,{detail:{h:e,s:t,v:i,cid:o}}))},st=(o,e)=>{!o||document.dispatchEvent(new CustomEvent(f,{detail:{h:e,cid:o}}))};function u(o,e){St(o)&&(o="100%");var t=Tt(o);return o=e===360?o:Math.min(e,Math.max(0,parseFloat(o))),t&&(o=parseInt(String(o*e),10)/100),Math.abs(o-e)<1e-6?1:(e===360?o=(o<0?o%e+e:o%e)/parseFloat(String(e)):o=o%e/parseFloat(String(e)),o)}function k(o){return Math.min(1,Math.max(0,o))}function St(o){return typeof o=="string"&&o.indexOf(".")!==-1&&parseFloat(o)===1}function Tt(o){return typeof o=="string"&&o.indexOf("%")!==-1}function _(o){return o=parseFloat(o),(isNaN(o)||o<0||o>1)&&(o=1),o}function L(o){return o<=1?"".concat(Number(o)*100,"%"):o}function C(o){return o.length===1?"0"+o:String(o)}function at(o,e,t){return{r:u(o,255)*255,g:u(e,255)*255,b:u(t,255)*255}}function U(o,e,t){o=u(o,255),e=u(e,255),t=u(t,255);var i=Math.max(o,e,t),r=Math.min(o,e,t),n=0,s=0,a=(i+r)/2;if(i===r)s=0,n=0;else{var d=i-r;switch(s=a>.5?d/(2-i-r):d/(i+r),i){case o:n=(e-t)/d+(e1&&(t-=1),t<1/6?o+(e-o)*(6*t):t<1/2?e:t<2/3?o+(e-o)*(2/3-t)*6:o}function ht(o,e,t){var i,r,n;if(o=u(o,360),e=u(e,100),t=u(t,100),e===0)r=t,n=t,i=t;else{var s=t<.5?t*(1+e):t+e-t*e,a=2*t-s;i=O(a,s,o+1/3),r=O(a,s,o),n=O(a,s,o-1/3)}return{r:i*255,g:r*255,b:n*255}}function N(o,e,t){o=u(o,255),e=u(e,255),t=u(t,255);var i=Math.max(o,e,t),r=Math.min(o,e,t),n=0,s=i,a=i-r,d=i===0?0:a/i;if(i===r)n=0;else{switch(i){case o:n=(e-t)/a+(e>16,g:(o&65280)>>8,b:o&255}}var A={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",goldenrod:"#daa520",gold:"#ffd700",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavenderblush:"#fff0f5",lavender:"#e6e6fa",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"};function ct(o){var e={r:0,g:0,b:0},t=1,i=null,r=null,n=null,s=!1,a=!1;return typeof o=="string"&&(o=Pt(o)),typeof o=="object"&&(E(o.r)&&E(o.g)&&E(o.b)?(e=at(o.r,o.g,o.b),s=!0,a=String(o.r).substr(-1)==="%"?"prgb":"rgb"):E(o.h)&&E(o.s)&&E(o.v)?(i=L(o.s),r=L(o.v),e=lt(o.h,i,r),s=!0,a="hsv"):E(o.h)&&E(o.s)&&E(o.l)&&(i=L(o.s),n=L(o.l),e=ht(o.h,i,n),s=!0,a="hsl"),Object.prototype.hasOwnProperty.call(o,"a")&&(t=o.a)),t=_(t),{ok:s,format:o.format||a,r:Math.min(255,Math.max(e.r,0)),g:Math.min(255,Math.max(e.g,0)),b:Math.min(255,Math.max(e.b,0)),a:t}}var Dt="[-\\+]?\\d+%?",_t="[-\\+]?\\d*\\.\\d+%?",y="(?:".concat(_t,")|(?:").concat(Dt,")"),G="[\\s|\\(]+(".concat(y,")[,|\\s]+(").concat(y,")[,|\\s]+(").concat(y,")\\s*\\)?"),F="[\\s|\\(]+(".concat(y,")[,|\\s]+(").concat(y,")[,|\\s]+(").concat(y,")[,|\\s]+(").concat(y,")\\s*\\)?"),v={CSS_UNIT:new RegExp(y),rgb:new RegExp("rgb"+G),rgba:new RegExp("rgba"+F),hsl:new RegExp("hsl"+G),hsla:new RegExp("hsla"+F),hsv:new RegExp("hsv"+G),hsva:new RegExp("hsva"+F),hex3:/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex6:/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,hex4:/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex8:/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/};function Pt(o){if(o=o.trim().toLowerCase(),o.length===0)return!1;var e=!1;if(A[o])o=A[o],e=!0;else if(o==="transparent")return{r:0,g:0,b:0,a:0,format:"name"};var t=v.rgb.exec(o);return t?{r:t[1],g:t[2],b:t[3]}:(t=v.rgba.exec(o),t?{r:t[1],g:t[2],b:t[3],a:t[4]}:(t=v.hsl.exec(o),t?{h:t[1],s:t[2],l:t[3]}:(t=v.hsla.exec(o),t?{h:t[1],s:t[2],l:t[3],a:t[4]}:(t=v.hsv.exec(o),t?{h:t[1],s:t[2],v:t[3]}:(t=v.hsva.exec(o),t?{h:t[1],s:t[2],v:t[3],a:t[4]}:(t=v.hex8.exec(o),t?{r:g(t[1]),g:g(t[2]),b:g(t[3]),a:V(t[4]),format:e?"name":"hex8"}:(t=v.hex6.exec(o),t?{r:g(t[1]),g:g(t[2]),b:g(t[3]),format:e?"name":"hex"}:(t=v.hex4.exec(o),t?{r:g(t[1]+t[1]),g:g(t[2]+t[2]),b:g(t[3]+t[3]),a:V(t[4]+t[4]),format:e?"name":"hex8"}:(t=v.hex3.exec(o),t?{r:g(t[1]+t[1]),g:g(t[2]+t[2]),b:g(t[3]+t[3]),format:e?"name":"hex"}:!1)))))))))}function E(o){return Boolean(v.CSS_UNIT.exec(String(o)))}var l=function(){function o(e,t){e===void 0&&(e=""),t===void 0&&(t={});var i;if(e instanceof o)return e;typeof e=="number"&&(e=ut(e)),this.originalInput=e;var r=ct(e);this.originalInput=e,this.r=r.r,this.g=r.g,this.b=r.b,this.a=r.a,this.roundA=Math.round(100*this.a)/100,this.format=(i=t.format)!==null&&i!==void 0?i:r.format,this.gradientType=t.gradientType,this.r<1&&(this.r=Math.round(this.r)),this.g<1&&(this.g=Math.round(this.g)),this.b<1&&(this.b=Math.round(this.b)),this.isValid=r.ok}return o.prototype.isDark=function(){return this.getBrightness()<128},o.prototype.isLight=function(){return!this.isDark()},o.prototype.getBrightness=function(){var e=this.toRgb();return(e.r*299+e.g*587+e.b*114)/1e3},o.prototype.getLuminance=function(){var e=this.toRgb(),t,i,r,n=e.r/255,s=e.g/255,a=e.b/255;return n<=.03928?t=n/12.92:t=Math.pow((n+.055)/1.055,2.4),s<=.03928?i=s/12.92:i=Math.pow((s+.055)/1.055,2.4),a<=.03928?r=a/12.92:r=Math.pow((a+.055)/1.055,2.4),.2126*t+.7152*i+.0722*r},o.prototype.getAlpha=function(){return this.a},o.prototype.setAlpha=function(e){return this.a=_(e),this.roundA=Math.round(100*this.a)/100,this},o.prototype.toHsv=function(){var e=N(this.r,this.g,this.b);return{h:e.h*360,s:e.s,v:e.v,a:this.a}},o.prototype.toHsvString=function(){var e=N(this.r,this.g,this.b),t=Math.round(e.h*360),i=Math.round(e.s*100),r=Math.round(e.v*100);return this.a===1?"hsv(".concat(t,", ").concat(i,"%, ").concat(r,"%)"):"hsva(".concat(t,", ").concat(i,"%, ").concat(r,"%, ").concat(this.roundA,")")},o.prototype.toHsl=function(){var e=U(this.r,this.g,this.b);return{h:e.h*360,s:e.s,l:e.l,a:this.a}},o.prototype.toHslString=function(){var e=U(this.r,this.g,this.b),t=Math.round(e.h*360),i=Math.round(e.s*100),r=Math.round(e.l*100);return this.a===1?"hsl(".concat(t,", ").concat(i,"%, ").concat(r,"%)"):"hsla(".concat(t,", ").concat(i,"%, ").concat(r,"%, ").concat(this.roundA,")")},o.prototype.toHex=function(e){return e===void 0&&(e=!1),K(this.r,this.g,this.b,e)},o.prototype.toHexString=function(e){return e===void 0&&(e=!1),"#"+this.toHex(e)},o.prototype.toHex8=function(e){return e===void 0&&(e=!1),dt(this.r,this.g,this.b,this.a,e)},o.prototype.toHex8String=function(e){return e===void 0&&(e=!1),"#"+this.toHex8(e)},o.prototype.toRgb=function(){return{r:Math.round(this.r),g:Math.round(this.g),b:Math.round(this.b),a:this.a}},o.prototype.toRgbString=function(){var e=Math.round(this.r),t=Math.round(this.g),i=Math.round(this.b);return this.a===1?"rgb(".concat(e,", ").concat(t,", ").concat(i,")"):"rgba(".concat(e,", ").concat(t,", ").concat(i,", ").concat(this.roundA,")")},o.prototype.toPercentageRgb=function(){var e=function(t){return"".concat(Math.round(u(t,255)*100),"%")};return{r:e(this.r),g:e(this.g),b:e(this.b),a:this.a}},o.prototype.toPercentageRgbString=function(){var e=function(t){return Math.round(u(t,255)*100)};return this.a===1?"rgb(".concat(e(this.r),"%, ").concat(e(this.g),"%, ").concat(e(this.b),"%)"):"rgba(".concat(e(this.r),"%, ").concat(e(this.g),"%, ").concat(e(this.b),"%, ").concat(this.roundA,")")},o.prototype.toName=function(){if(this.a===0)return"transparent";if(this.a<1)return!1;for(var e="#"+K(this.r,this.g,this.b,!1),t=0,i=Object.entries(A);t=0,n=!t&&r&&(e.startsWith("hex")||e==="name");return n?e==="name"&&this.a===0?this.toName():this.toRgbString():(e==="rgb"&&(i=this.toRgbString()),e==="prgb"&&(i=this.toPercentageRgbString()),(e==="hex"||e==="hex6")&&(i=this.toHexString()),e==="hex3"&&(i=this.toHexString(!0)),e==="hex4"&&(i=this.toHex8String(!0)),e==="hex8"&&(i=this.toHex8String()),e==="name"&&(i=this.toName()),e==="hsl"&&(i=this.toHslString()),e==="hsv"&&(i=this.toHsvString()),i||this.toHexString())},o.prototype.toNumber=function(){return(Math.round(this.r)<<16)+(Math.round(this.g)<<8)+Math.round(this.b)},o.prototype.clone=function(){return new o(this.toString())},o.prototype.lighten=function(e){e===void 0&&(e=10);var t=this.toHsl();return t.l+=e/100,t.l=k(t.l),new o(t)},o.prototype.brighten=function(e){e===void 0&&(e=10);var t=this.toRgb();return t.r=Math.max(0,Math.min(255,t.r-Math.round(255*-(e/100)))),t.g=Math.max(0,Math.min(255,t.g-Math.round(255*-(e/100)))),t.b=Math.max(0,Math.min(255,t.b-Math.round(255*-(e/100)))),new o(t)},o.prototype.darken=function(e){e===void 0&&(e=10);var t=this.toHsl();return t.l-=e/100,t.l=k(t.l),new o(t)},o.prototype.tint=function(e){return e===void 0&&(e=10),this.mix("white",e)},o.prototype.shade=function(e){return e===void 0&&(e=10),this.mix("black",e)},o.prototype.desaturate=function(e){e===void 0&&(e=10);var t=this.toHsl();return t.s-=e/100,t.s=k(t.s),new o(t)},o.prototype.saturate=function(e){e===void 0&&(e=10);var t=this.toHsl();return t.s+=e/100,t.s=k(t.s),new o(t)},o.prototype.greyscale=function(){return this.desaturate(100)},o.prototype.spin=function(e){var t=this.toHsl(),i=(t.h+e)%360;return t.h=i<0?360+i:i,new o(t)},o.prototype.mix=function(e,t){t===void 0&&(t=50);var i=this.toRgb(),r=new o(e).toRgb(),n=t/100,s={r:(r.r-i.r)*n+i.r,g:(r.g-i.g)*n+i.g,b:(r.b-i.b)*n+i.b,a:(r.a-i.a)*n+i.a};return new o(s)},o.prototype.analogous=function(e,t){e===void 0&&(e=6),t===void 0&&(t=30);var i=this.toHsl(),r=360/t,n=[this];for(i.h=(i.h-(r*e>>1)+720)%360;--e;)i.h=(i.h+r)%360,n.push(new o(i));return n},o.prototype.complement=function(){var e=this.toHsl();return e.h=(e.h+180)%360,new o(e)},o.prototype.monochromatic=function(e){e===void 0&&(e=6);for(var t=this.toHsv(),i=t.h,r=t.s,n=t.v,s=[],a=1/e;e--;)s.push(new o({h:i,s:r,v:n})),n=(n+a)%1;return s},o.prototype.splitcomplement=function(){var e=this.toHsl(),t=e.h;return[this,new o({h:(t+72)%360,s:e.s,l:e.l}),new o({h:(t+216)%360,s:e.s,l:e.l})]},o.prototype.onBackground=function(e){var t=this.toRgb(),i=new o(e).toRgb();return new o({r:i.r+(t.r-i.r)*t.a,g:i.g+(t.g-i.g)*t.a,b:i.b+(t.b-i.b)*t.a})},o.prototype.triad=function(){return this.polyad(3)},o.prototype.tetrad=function(){return this.polyad(4)},o.prototype.polyad=function(e){for(var t=this.toHsl(),i=t.h,r=[this],n=360/e,s=1;sMath.random().toString(16).slice(2),P=o=>Math.round((o+Number.EPSILON)*100)/100;var H=.01,q=o=>(o<0&&(o=0),o>360&&(o=360),`hsl(${Math.round(o)}, 100%, 50%)`),z=o=>{let e=o.toRgb();return`linear-gradient(to right, rgba(${e.r},${e.g},${e.b}, 0) 0%, rgba(${e.r},${e.g},${e.b}, 1) 100%)`},S=o=>{let e=o.toRgb();return`rgba(${e.r}, ${e.g}, ${e.b}, ${P(e.a)})`},pt=o=>{let e=o.toHsl();return`hsla(${Math.round(e.h)}, ${Math.round(e.s*100)}%, ${Math.round(e.l*100)}%, ${P(e.a)})`},gt=o=>{let e=o.toHsv();return`hsva(${Math.round(e.h)}, ${Math.round(e.s*100)}%, ${Math.round(e.v*100)}%, ${P(e.a)})`},W=o=>(o<0&&(o=0),o>1&&(o=1),`${(-(o*100)+100).toFixed(2)}%`),X=o=>(o<0&&(o=0),o>1&&(o=1),`${(o*100).toFixed(2)}%`),T=o=>{o<0&&(o=0),o>360&&(o=360);let e=o*100/360,t=Math.round(e*100)/100;return t<0&&(t=0),t>100&&(t=100),t},B=o=>360*o/100,I=o=>{let e=Number(o)||0;return e=Math.round(e),e=Math.max(0,e),e=Math.min(255,e),e},ft=o=>{let e=Number(o)||100;return e=Math.round(e),e=Math.max(0,e),e=Math.min(100,e),e},c=o=>{let e=new l(o||"#000");return e.setAlpha(e.getAlpha()),e};var j=class extends HTMLElement{constructor(){super();h(this,"cid");h(this,"$saturation");h(this,"$color");h(this,"$pointer");h(this,"hue",0);h(this,"saturation",0);h(this,"value",0);this.attachShadow({mode:"open"}),this.onMouseDown=this.onMouseDown.bind(this),this.onMouseUp=this.onMouseUp.bind(this),this.onChange=this.onChange.bind(this),this.onPointerKeyDown=this.onPointerKeyDown.bind(this),this.hsvChanged=this.hsvChanged.bind(this),this.hueChanged=this.hueChanged.bind(this)}static get observedAttributes(){return["color"]}render(t=!0){this.$pointer&&(this.$pointer.style.left=X(this.saturation),this.$pointer.style.top=W(this.value)),this.$color&&this.$color.setAttribute("style",`background: ${q(this.hue)}`),t&&b(this.cid,this.hue,this.saturation,this.value)}onChange(t){if(!this.$saturation)return;let{width:i,height:r,left:n,top:s}=this.$saturation.getBoundingClientRect();if(i===0||r===0)return;let a=typeof t.clientX=="number"?t.clientX:t.touches[0].clientX,d=typeof t.clientY=="number"?t.clientY:t.touches[0].clientY,w=Math.min(Math.max(0,a-n),i),x=Math.min(Math.max(0,d-s),r);this.saturation=w/i,this.value=1-x/r,this.render()}onPointerKeyDown(t){switch(t.key){case"ArrowLeft":{this.saturation=Math.max(0,this.saturation-H),this.render();break}case"ArrowRight":{this.saturation=Math.min(1,this.saturation+H),this.render();break}case"ArrowUp":{this.value=Math.min(1,this.value+H),this.render();break}case"ArrowDown":{t.preventDefault(),this.value=Math.max(0,this.value-H),this.render();break}}}onMouseDown(t){t.preventDefault&&t.preventDefault(),this.onChange(t),window.addEventListener("mousemove",this.onChange),window.addEventListener("mouseup",this.onMouseUp),window.setTimeout(()=>{var i;(i=this.$pointer)==null||i.focus()},0)}onMouseUp(){window.removeEventListener("mousemove",this.onChange),window.removeEventListener("mouseup",this.onChange)}hsvChanged(t){if(!t||!t.detail||!t.detail.cid||t.detail.cid!==this.cid)return;let i=!1;this.hue!==t.detail.h&&(this.hue=t.detail.h,i=!0),this.saturation!==t.detail.s&&(this.saturation=t.detail.s,i=!0),this.value!==t.detail.v&&(this.value=t.detail.v,i=!0),i&&this.render(!1)}hueChanged(t){!t||!t.detail||!t.detail.cid||t.detail.cid===this.cid&&(this.hue=t.detail.h,this.render())}connectedCallback(){var s,a,d,w,x;if(!this.shadowRoot)return;this.cid=this.getAttribute("cid")||"";let i=c(this.getAttribute("color")).toHsv();this.hue=i.h,this.saturation=i.s,this.value=i.v;let r=W(this.value),n=X(this.saturation);this.shadowRoot.innerHTML=` + +
      +
      +
      +
      + +
      +
      +
      +
      +
      +
      + `,this.$saturation=this.shadowRoot.querySelector(".saturation"),this.$color=this.shadowRoot.querySelector(".box"),this.$pointer=this.shadowRoot.querySelector(".pointer"),(s=this.$pointer)==null||s.addEventListener("keydown",this.onPointerKeyDown),(a=this.$saturation)==null||a.addEventListener("mousedown",this.onMouseDown),(d=this.$saturation)==null||d.addEventListener("mouseup",this.onMouseUp),(w=this.$saturation)==null||w.addEventListener("touchmove",this.onChange),(x=this.$saturation)==null||x.addEventListener("touchstart",this.onChange),document.addEventListener(p,this.hsvChanged),document.addEventListener(f,this.hueChanged)}disconnectedCallback(){var t,i,r,n,s;(t=this.$saturation)==null||t.removeEventListener("mousedown",this.onMouseDown),(i=this.$saturation)==null||i.removeEventListener("mouseup",this.onMouseUp),(r=this.$saturation)==null||r.removeEventListener("touchmove",this.onChange),(n=this.$saturation)==null||n.removeEventListener("touchstart",this.onChange),(s=this.$pointer)==null||s.removeEventListener("keydown",this.onPointerKeyDown),document.removeEventListener(p,this.hsvChanged),document.removeEventListener(f,this.hueChanged)}attributeChangedCallback(t,i,r){let s=c(r).toHsv();this.hue=s.h,this.saturation=s.s,this.value=s.v,this.render(!1)}},bt=j;var vt=".hue{overflow:hidden;height:.625rem;margin-bottom:.25rem;margin-top:.25rem;position:relative}.box{width:100%;height:100%;position:absolute}.hue-v{background:linear-gradient(0,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red)}.hue-h{background:linear-gradient(90deg,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red);width:100%;height:100%;position:relative}.pointer-box{left:87%;position:absolute;outline:0}.handler{background:#fff;box-shadow:0 0 2px rgb(0 0 0 / 60%);box-sizing:border-box;border:1px solid hsla(0,0%,88%,.5);height:8px;margin-top:1px;-webkit-transform:translateX(-4px);transform:translateX(-4px);width:8px;cursor:pointer;outline:0}.pointer-box:focus .handler{border:2px solid hsla(0,0%,88%,1)}";var Y=class extends HTMLElement{constructor(){super();h(this,"cid");h(this,"$hue");h(this,"$pointer");h(this,"hue",0);this.attachShadow({mode:"open"}),this.onMouseDown=this.onMouseDown.bind(this),this.onMouseUp=this.onMouseUp.bind(this),this.onChange=this.onChange.bind(this),this.onKeyDown=this.onKeyDown.bind(this),this.hsvChanged=this.hsvChanged.bind(this)}static get observedAttributes(){return["color"]}render(){this.$pointer&&(this.$pointer.style.left=`${T(this.hue)}%`),st(this.cid,this.hue)}hsvChanged(t){!t||!t.detail||!t.detail.cid||t.detail.cid===this.cid&&this.hue!==t.detail.h&&(this.hue=t.detail.h,this.render())}onChange(t){if(!this.$hue)return;t.preventDefault&&t.preventDefault();let{width:i,left:r}=this.$hue.getBoundingClientRect();if(i===0)return;let n=typeof t.clientX=="number"?t.clientX:t.touches[0].clientX,s=Math.min(Math.max(0,n-r),i),a=Math.min(Math.max(0,Math.round(s*100/i)),100);this.hue=B(a),this.render()}onKeyDown(t){var i;switch((i=this.$pointer)==null||i.focus(),t.key){case"ArrowLeft":{let r=T(this.hue);r=Math.max(0,r-1),this.hue=B(r),this.render();break}case"ArrowRight":{let r=T(this.hue);r=Math.min(100,r+1),this.hue=B(r),this.render();break}}}onMouseDown(t){t.preventDefault&&t.preventDefault(),this.onChange(t),window.addEventListener("mousemove",this.onChange),window.addEventListener("mouseup",this.onMouseUp),window.setTimeout(()=>{var i;(i=this.$pointer)==null||i.focus()},0)}onMouseUp(){window.removeEventListener("mousemove",this.onChange),window.removeEventListener("mouseup",this.onChange)}connectedCallback(){var i,r,n,s,a;if(!this.shadowRoot)return;this.cid=this.getAttribute("cid")||"";let t=c(this.getAttribute("color"));this.hue=t.toHsv().h,this.shadowRoot.innerHTML=` + +
      +
      +
      +
      +
      + +
      +
      +
      +
      +
      +
      +
      + `,this.$hue=this.shadowRoot.querySelector(".hue"),this.$pointer=this.shadowRoot.querySelector(".pointer-box"),(i=this.$hue)==null||i.addEventListener("mousedown",this.onMouseDown),(r=this.$hue)==null||r.addEventListener("mouseup",this.onMouseUp),(n=this.$hue)==null||n.addEventListener("touchmove",this.onChange),(s=this.$hue)==null||s.addEventListener("touchstart",this.onChange),(a=this.$pointer)==null||a.addEventListener("keydown",this.onKeyDown),document.addEventListener(p,this.hsvChanged)}disconnectedCallback(){var t,i,r,n,s;(t=this.$hue)==null||t.removeEventListener("mousedown",this.onMouseDown),(i=this.$hue)==null||i.removeEventListener("mouseup",this.onMouseUp),(r=this.$hue)==null||r.removeEventListener("touchmove",this.onChange),(n=this.$hue)==null||n.removeEventListener("touchstart",this.onChange),(s=this.$pointer)==null||s.removeEventListener("keydown",this.onKeyDown),document.removeEventListener(p,this.hsvChanged)}attributeChangedCallback(t,i,r){let s=c(r).toHsv();this.hue=s.h,this.render()}},mt=Y;var wt=".alpha{overflow:hidden;height:.625rem;position:relative;background:#fff}.box{width:100%;height:100%;position:absolute}.transparent-bg{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAADFJREFUOE9jZGBgEGHAD97gk2YcNYBhmIQBgWSAP52AwoAQwJvQRg1gACckQoC2gQgAIF8IscwEtKYAAAAASUVORK5CYII=);overflow:hidden}.pointer-box{left:100%;position:absolute;outline:0}.handler{background:#fff;box-shadow:0 0 2px rgb(0 0 0 / 60%);box-sizing:border-box;border:1px solid hsla(0,0%,88%,.5);height:8px;margin-top:1px;-webkit-transform:translateX(-4px);transform:translateX(-4px);width:8px;cursor:pointer;outline:0}.alpha-pointer-box:focus .alpha-pointer-handler{border:2px solid hsla(0,0%,88%,1)}";var Q=class extends HTMLElement{constructor(){super();h(this,"cid");h(this,"$alpha");h(this,"$color");h(this,"$pointer");h(this,"alpha",1);h(this,"hue",0);h(this,"saturation",0);h(this,"value",0);this.attachShadow({mode:"open"}),this.onMouseDown=this.onMouseDown.bind(this),this.onMouseUp=this.onMouseUp.bind(this),this.onChange=this.onChange.bind(this),this.onKeyDown=this.onKeyDown.bind(this),this.hsvChanged=this.hsvChanged.bind(this),this.hueChanged=this.hueChanged.bind(this),this.alphaChanged=this.alphaChanged.bind(this)}static get observedAttributes(){return["color"]}render(t=!0){if(this.$pointer&&(this.$pointer.style.left=`${this.alpha*100}%`),this.$color){let i=new l({h:this.hue,s:this.saturation,v:this.value,a:this.alpha});this.$color.style.background=z(i)}t&&M(this.cid,this.alpha)}onChange(t){if(!this.$alpha)return;t.preventDefault&&t.preventDefault();let{width:i,left:r}=this.$alpha.getBoundingClientRect();if(i===0)return;let n=typeof t.clientX=="number"?t.clientX:t.touches[0].clientX,s=Math.min(Math.max(0,n-r),i),a=Math.min(Math.max(0,s*100/i),100);this.alpha=a/100,this.render()}onKeyDown(t){var i;switch((i=this.$pointer)==null||i.focus(),t.key){case"ArrowLeft":{let r=this.alpha*100;r=Math.max(0,r-1),this.alpha=r/100,this.render();break}case"ArrowRight":{let r=this.alpha*100;r=Math.min(100,r+1),this.alpha=r/100,this.render();break}}}hsvChanged(t){!t||!t.detail||!t.detail.cid||t.detail.cid===this.cid&&(this.saturation=t.detail.h,this.hue=t.detail.s,this.value=t.detail.v,this.render(!1))}hueChanged(t){!t||!t.detail||!t.detail.cid||t.detail.cid===this.cid&&(this.hue=t.detail.h,this.render(!1))}alphaChanged(t){!t||!t.detail||!t.detail.cid||t.detail.cid===this.cid&&this.alpha!==t.detail.a&&(this.alpha=t.detail.a,this.render())}onMouseDown(t){t.preventDefault&&t.preventDefault(),this.onChange(t),window.addEventListener("mousemove",this.onChange),window.addEventListener("mouseup",this.onMouseUp),window.setTimeout(()=>{var i;(i=this.$pointer)==null||i.focus()},0)}onMouseUp(){window.removeEventListener("mousemove",this.onChange),window.removeEventListener("mouseup",this.onChange)}connectedCallback(){var r,n,s,a,d;if(!this.shadowRoot)return;this.cid=this.getAttribute("cid")||"";let t=c(this.getAttribute("color")),i=t.toHsv();this.alpha=i.a,this.hue=i.h,this.saturation=i.s,this.value=i.v,this.shadowRoot.innerHTML=` + +
      +
      +
      +
      + +
      +
      +
      +
      +
      +
      +
      + `,this.$alpha=this.shadowRoot.querySelector(".alpha"),this.$color=this.shadowRoot.querySelector(".color-bg"),this.$pointer=this.shadowRoot.querySelector(".pointer-box"),(r=this.$alpha)==null||r.addEventListener("mousedown",this.onMouseDown),(n=this.$alpha)==null||n.addEventListener("mouseup",this.onMouseUp),(s=this.$alpha)==null||s.addEventListener("touchmove",this.onChange),(a=this.$alpha)==null||a.addEventListener("touchstart",this.onChange),(d=this.$pointer)==null||d.addEventListener("keydown",this.onKeyDown),document.addEventListener(p,this.hsvChanged),document.addEventListener(f,this.hueChanged),document.addEventListener(m,this.alphaChanged)}disconnectedCallback(){var t,i,r,n,s;(t=this.$alpha)==null||t.removeEventListener("mousedown",this.onMouseDown),(i=this.$alpha)==null||i.removeEventListener("mouseup",this.onMouseUp),(r=this.$alpha)==null||r.removeEventListener("touchmove",this.onChange),(n=this.$alpha)==null||n.removeEventListener("touchstart",this.onChange),(s=this.$pointer)==null||s.removeEventListener("keydown",this.onKeyDown),document.removeEventListener(p,this.hsvChanged),document.removeEventListener(f,this.hueChanged),document.removeEventListener(m,this.alphaChanged)}attributeChangedCallback(t,i,r){let s=c(r).toHsv();this.alpha=s.a,this.hue=s.h,this.saturation=s.s,this.value=s.v,this.render()}},xt=Q;var Et=":root{--tool-cool-color-picker-field-border-color:#cecece;--tool-cool-color-picker-field-label-color:#000}.fields{font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Noto Sans,Liberation Sans,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-size:11px;grid-template-columns:60px 35px 35px 35px 34px;text-align:center;display:grid;gap:.25rem;margin-top:.25rem;color:var(--tool-cool-color-picker-field-label-color,#000)}.fields input{background:#fff;border-width:1px;border-style:solid;border-color:var(--tool-cool-color-picker-field-border-color,#cecece);padding:1px 3px;border-radius:2px;color:#000;font-family:inherit;font-size:100%;line-height:inherit;margin:0;box-sizing:border-box}";var J=class extends HTMLElement{constructor(){super();h(this,"cid");h(this,"color",new l("#000"));h(this,"$hex");h(this,"$r");h(this,"$g");h(this,"$b");h(this,"$a");h(this,"hex","");h(this,"r",0);h(this,"g",0);h(this,"b",0);h(this,"a",1);this.attachShadow({mode:"open"}),this.hsvChanged=this.hsvChanged.bind(this),this.hueChanged=this.hueChanged.bind(this),this.alphaChanged=this.alphaChanged.bind(this),this.onHexChange=this.onHexChange.bind(this),this.render=this.render.bind(this),this.onRedChange=this.onRedChange.bind(this),this.onGreenChange=this.onGreenChange.bind(this),this.onBlueChange=this.onBlueChange.bind(this),this.onAlphaChange=this.onAlphaChange.bind(this),this.onRedKeyDown=this.onRedKeyDown.bind(this),this.onBlueKeyDown=this.onBlueKeyDown.bind(this),this.onGreenKeyDown=this.onGreenKeyDown.bind(this),this.onAlphaKeyDown=this.onAlphaKeyDown.bind(this)}static get observedAttributes(){return["color"]}hueChanged(t){if(!t||!t.detail||!t.detail.cid||t.detail.cid!==this.cid)return;let i=this.color.toHsv();this.color=new l({h:Number(t.detail.h),s:i.s,v:i.v,a:i.a}),this.render()}alphaChanged(t){if(!t||!t.detail||!t.detail.cid||t.detail.cid!==this.cid)return;let i=this.color.toRgb();i.a=t.detail.a,this.color=new l(i),this.render()}hsvChanged(t){!t||!t.detail||!t.detail.cid||t.detail.cid===this.cid&&(this.color=new l({h:t.detail.h,s:t.detail.s,v:t.detail.v,a:this.color.toHsv().a}),this.render())}render(){var i,r,n,s,a;let t=this.color.toRgb();this.r=t.r,this.g=t.g,this.b=t.b,this.a=t.a,this.hex=this.color.toHex(),this.$hex&&((i=this.shadowRoot)==null?void 0:i.activeElement)!==this.$hex&&(this.$hex.value=this.hex.toUpperCase()),this.$r&&((r=this.shadowRoot)==null?void 0:r.activeElement)!==this.$r&&(this.$r.value=this.r.toString()),this.$g&&((n=this.shadowRoot)==null?void 0:n.activeElement)!==this.$g&&(this.$g.value=this.g.toString()),this.$b&&((s=this.shadowRoot)==null?void 0:s.activeElement)!==this.$b&&(this.$b.value=this.b.toString()),this.$a&&((a=this.shadowRoot)==null?void 0:a.activeElement)!==this.$a&&(this.$a.value=Math.round(this.a*100).toString())}onFieldKeyDown(t,i){var n,s;let r=this.color.toRgb();switch(t.key){case"ArrowUp":{if(i==="r"){this.r=Math.min(255,r.r+1),r.r=this.r;let a=new l(r).toHsv();b(this.cid,a.h,a.s,a.v),this.$r.value=this.r.toString(),this.render()}if(i==="g"){this.g=Math.min(255,r.g+1),r.g=this.g;let a=new l(r).toHsv();b(this.cid,a.h,a.s,a.v),this.$g.value=this.g.toString(),this.render()}if(i==="b"){this.b=Math.min(255,r.b+1),r.b=this.b;let a=new l(r).toHsv();b(this.cid,a.h,a.s,a.v),this.$b.value=this.b.toString(),this.render()}if(i==="a"){this.a=Math.min(100,this.a+.01),this.$a.value=Math.round(this.a*100).toString();let a=this.color.toRgb();a.a=this.a,this.color=new l(a),this.render(),M(this.cid,this.a)}break}case"ArrowDown":{if(i==="r"){this.r=Math.max(0,r.r-1),r.r=this.r;let a=new l(r).toHsv();b(this.cid,a.h,a.s,a.v),this.$r.value=this.r.toString(),this.render()}if(i==="g"){this.g=Math.max(0,r.g-1),r.g=this.g;let a=new l(r).toHsv();b(this.cid,a.h,a.s,a.v),this.$g.value=this.g.toString(),this.render()}if(i==="b"){this.b=Math.max(0,r.b-1),r.b=this.b;let a=new l(r).toHsv();b(this.cid,a.h,a.s,a.v),this.$b.value=this.b.toString(),this.render()}if(i==="a"){this.a=Math.max(0,this.a-.01),this.$a.value=Math.round(this.a*100).toString();let a=this.color.toRgb();a.a=this.a,this.color=new l(a),this.render(),M(this.cid,this.a)}break}case"Escape":{(n=this.shadowRoot)!=null&&n.activeElement&&this.shadowRoot.activeElement.blur(),this.render();break}case"Enter":{(s=this.shadowRoot)!=null&&s.activeElement&&this.shadowRoot.activeElement.blur(),this.render();break}}}onRedKeyDown(t){this.onFieldKeyDown(t,"r")}onGreenKeyDown(t){this.onFieldKeyDown(t,"g")}onBlueKeyDown(t){this.onFieldKeyDown(t,"b")}onAlphaKeyDown(t){this.onFieldKeyDown(t,"a")}onHexChange(t){let i=t.target;if(i.value.length!==6)return;let r=new l(`#${i.value}`);if(r.isValid){this.color=r;let n=this.color.toHsv();b(this.cid,n.h,n.s,n.v)}}onRedChange(t){let i=t.target,r=I(i.value);if(r.toString()===i.value){let n=this.color.toRgb();n.r=r;let s=new l(n).toHsv();b(this.cid,s.h,s.s,s.v)}}onGreenChange(t){let i=t.target,r=I(i.value);if(r.toString()===i.value){let n=this.color.toRgb();n.g=r;let s=new l(n).toHsv();b(this.cid,s.h,s.s,s.v)}}onBlueChange(t){let i=t.target,r=I(i.value);if(r.toString()===i.value){let n=this.color.toRgb();n.b=r;let s=new l(n).toHsv();b(this.cid,s.h,s.s,s.v)}}onAlphaChange(t){let i=t.target,r=ft(i.value);r.toString()===i.value&&M(this.cid,r/100)}connectedCallback(){if(!this.shadowRoot)return;this.cid=this.getAttribute("cid")||"",this.color=c(this.getAttribute("color"));let t=this.color.toRgb();this.r=t.r,this.g=t.g,this.b=t.b,this.a=t.a,this.hex=this.color.toHex();let i=$(),r=$(),n=$(),s=$(),a=$();this.shadowRoot.innerHTML=` + +
      + + + + + + + + + + + +
      + `,this.$hex=this.shadowRoot.getElementById(`hex-${i}`),this.$r=this.shadowRoot.getElementById(`r-${r}`),this.$g=this.shadowRoot.getElementById(`g-${n}`),this.$b=this.shadowRoot.getElementById(`b-${s}`),this.$a=this.shadowRoot.getElementById(`a-${a}`),document.addEventListener(p,this.hsvChanged),document.addEventListener(f,this.hueChanged),document.addEventListener(m,this.alphaChanged),this.$hex.addEventListener("input",this.onHexChange),this.$r.addEventListener("input",this.onRedChange),this.$g.addEventListener("input",this.onGreenChange),this.$b.addEventListener("input",this.onBlueChange),this.$a.addEventListener("input",this.onAlphaChange),this.$hex.addEventListener("blur",this.render),this.$r.addEventListener("blur",this.render),this.$g.addEventListener("blur",this.render),this.$b.addEventListener("blur",this.render),this.$a.addEventListener("blur",this.render),this.$r.addEventListener("keydown",this.onRedKeyDown),this.$g.addEventListener("keydown",this.onGreenKeyDown),this.$b.addEventListener("keydown",this.onBlueKeyDown),this.$a.addEventListener("keydown",this.onAlphaKeyDown)}disconnectedCallback(){document.removeEventListener(p,this.hsvChanged),document.removeEventListener(f,this.hueChanged),document.removeEventListener(m,this.alphaChanged),this.$hex.removeEventListener("input",this.onHexChange),this.$r.removeEventListener("input",this.onRedChange),this.$g.removeEventListener("input",this.onGreenChange),this.$b.removeEventListener("input",this.onBlueChange),this.$a.removeEventListener("input",this.onAlphaChange),this.$hex.removeEventListener("blur",this.render),this.$r.removeEventListener("blur",this.render),this.$g.removeEventListener("blur",this.render),this.$b.removeEventListener("blur",this.render),this.$a.removeEventListener("blur",this.render),this.$r.removeEventListener("keydown",this.onRedKeyDown),this.$g.removeEventListener("keydown",this.onGreenKeyDown),this.$b.removeEventListener("keydown",this.onBlueKeyDown),this.$a.removeEventListener("keydown",this.onAlphaKeyDown)}attributeChangedCallback(t,i,r){this.color=c(r),this.render()}},Ct=J;var Z=class extends HTMLElement{constructor(){super();h(this,"cid");h(this,"popupPosition","left");h(this,"$popup");h(this,"color","#000");customElements.get("toolcool-color-picker-saturation")||customElements.define("toolcool-color-picker-saturation",bt),customElements.get("toolcool-color-picker-hue")||customElements.define("toolcool-color-picker-hue",mt),customElements.get("toolcool-color-picker-alpha")||customElements.define("toolcool-color-picker-alpha",xt),customElements.get("toolcool-color-picker-fields")||customElements.define("toolcool-color-picker-fields",Ct),this.cid=this.getAttribute("cid")||"",this.prevent=this.prevent.bind(this),this.attachShadow({mode:"open"})}static get observedAttributes(){return["color","popup-position"]}prevent(t){t.stopPropagation()}connectedCallback(){var t,i;!this.shadowRoot||(this.color=this.getAttribute("color")||"#000",this.popupPosition=this.getAttribute("popup-position")||"left",this.shadowRoot.innerHTML=` + + + `,this.$popup=this.shadowRoot.querySelector(".popup"),(t=this.$popup)==null||t.addEventListener("mousedown",this.prevent),(i=this.$popup)==null||i.classList.toggle("right",this.popupPosition==="right"))}disconnectedCallback(){var t;(t=this.$popup)==null||t.removeEventListener("mousedown",this.prevent)}attributeChangedCallback(t,i,r){var n,s,a,d;if(t==="popup-position"&&(this.popupPosition=r,this.$popup&&this.$popup.classList.toggle("right",this.popupPosition==="right")),t==="color"){this.color=r;let w=(n=this.shadowRoot)==null?void 0:n.querySelector("toolcool-color-picker-saturation"),x=(s=this.shadowRoot)==null?void 0:s.querySelector("toolcool-color-picker-hue"),R=(a=this.shadowRoot)==null?void 0:a.querySelector("toolcool-color-picker-alpha"),et=(d=this.shadowRoot)==null?void 0:d.querySelector("toolcool-color-picker-fields");w&&w.setAttribute("color",this.color),x&&x.setAttribute("color",this.color),R&&R.setAttribute("color",this.color),et&&et.setAttribute("color",this.color)}}},yt=Z;var Ut={sm:"0.875rem",md:"1.2rem",lg:"1.5rem",xl:"2.25rem","2xl":"3rem","3xl":"3.75rem","4xl":"4.5rem"},tt=class extends HTMLElement{constructor(){super();h(this,"cid");h(this,"$button");h(this,"$buttonColor");h(this,"$popupBox");h(this,"stateDefaults",{isPopupVisible:!1,popupPosition:"left",initialColor:new l("#000"),color:new l("#000"),buttonWidth:null,buttonHeight:null,buttonPadding:null});h(this,"state");this.cid=$(),customElements.get("toolcool-color-picker-popup")||customElements.define("toolcool-color-picker-popup",yt),this.attachShadow({mode:"open"}),this.toggle=this.toggle.bind(this),this.onKeyDown=this.onKeyDown.bind(this),this.clickedOutside=this.clickedOutside.bind(this),this.stopPropagation=this.stopPropagation.bind(this),this.hsvChanged=this.hsvChanged.bind(this),this.hueChanged=this.hueChanged.bind(this),this.alphaChanged=this.alphaChanged.bind(this),this.buttonClicked=this.buttonClicked.bind(this),this.formatButtonSize=this.formatButtonSize.bind(this),this.initState()}static get observedAttributes(){return["color","popup-position","button-width","button-height","button-padding"]}set color(t){this.state.color=new l(t)}get color(){return this.state.color}get hex(){return this.state.color.toHexString().toUpperCase()}get hex8(){return this.state.color.toHex8String().toUpperCase()}get rgb(){return this.state.color.toRgbString()}get rgba(){return S(this.state.color)}get hsl(){return this.state.color.toHslString()}get hsla(){return pt(this.state.color)}get hsv(){return this.state.color.toHsvString()}get hsva(){return gt(this.state.color)}get opened(){return this.state.isPopupVisible}set opened(t){this.state.isPopupVisible=t}initState(){let t=this;this.state=new Proxy(t.stateDefaults,{set(i,r,n,s){return i[r]=n,r==="isPopupVisible"&&t.onPopupVisibilityChange(),r==="popupPosition"&&t.onPopupPosChange(),r==="initialColor"&&t.onInitialColorChange(),r==="color"&&t.onColorChange(),(r==="buttonWidth"||r==="buttonHeight"||r==="buttonPadding")&&t.setButtonSize(),!0}})}onPopupVisibilityChange(){!this.$popupBox||(this.$popupBox.innerHTML=this.state.isPopupVisible?``:"")}onPopupPosChange(){if(!this.$popupBox)return;let t=this.$popupBox.querySelector("toolcool-color-picker-popup");!t||t.setAttribute("popup-position",this.state.popupPosition)}onInitialColorChange(){var r;let t=S(this.state.color);this.$buttonColor&&(this.$buttonColor.style.backgroundColor=t);let i=(r=this.shadowRoot)==null?void 0:r.querySelector("toolcool-color-picker-popup");i&&i.setAttribute("color",t)}setButtonSize(){!this.$button||(this.state.buttonWidth&&(this.$button.style.width=this.formatButtonSize(this.state.buttonWidth)),this.state.buttonHeight&&(this.$button.style.height=this.formatButtonSize(this.state.buttonHeight)),this.state.buttonPadding&&(this.$button.style.padding=this.state.buttonPadding))}onColorChange(){this.$buttonColor&&(this.$buttonColor.style.backgroundColor=S(this.state.color)),this.dispatchEvent(new CustomEvent("change",{detail:{hex:this.hex,hex8:this.hex8,rgb:this.rgb,rgba:this.rgba,hsl:this.hsl,hsla:this.hsla,hsv:this.hsv,hsva:this.hsva,color:this.color}}))}hsvChanged(t){!t||!t.detail||!t.detail.cid||t.detail.cid===this.cid&&(this.state.color=new l({h:t.detail.h,s:t.detail.s,v:t.detail.v,a:this.state.color.toHsv().a}))}hueChanged(t){if(!t||!t.detail||!t.detail.cid||t.detail.cid!==this.cid)return;let i=this.state.color.toHsv();this.state.color=new l({h:t.detail.h,s:i.s,v:i.v,a:i.a})}alphaChanged(t){if(!t||!t.detail||!t.detail.cid||t.detail.cid!==this.cid)return;let i=this.state.color.toRgb();i.a=t.detail.a,this.state.color=new l(i)}buttonClicked(t){!t||!t.detail||!t.detail.cid||t.detail.cid!==this.cid&&(this.state.isPopupVisible=!1)}clickedOutside(){this.state.isPopupVisible=!1}toggle(){let t=this.state.isPopupVisible;window.setTimeout(()=>{this.state.isPopupVisible=!t,nt(this.cid)},0)}onKeyDown(t){t.key==="Escape"&&(this.state.isPopupVisible=!1)}stopPropagation(t){t.stopPropagation()}formatButtonSize(t){var i;return(i=Ut[t])!=null?i:t}connectedCallback(){var t,i,r;!this.shadowRoot||(this.state.initialColor=c(this.getAttribute("color")),this.state.color=c(this.getAttribute("color")),this.state.popupPosition=this.getAttribute("popup-position")||"left",this.state.buttonWidth=this.getAttribute("button-width"),this.state.buttonHeight=this.getAttribute("button-height"),this.state.buttonPadding=this.getAttribute("button-padding"),this.shadowRoot.innerHTML=` + +
      + +
      +
      + `,this.$button=this.shadowRoot.querySelector(".button"),this.$buttonColor=this.shadowRoot.querySelector(".button-color"),(t=this.$button)==null||t.addEventListener("click",this.toggle),(i=this.$button)==null||i.addEventListener("keydown",this.onKeyDown),(r=this.$button)==null||r.addEventListener("mousedown",this.stopPropagation),this.$popupBox=this.shadowRoot.querySelector("[data-popup-box]"),this.setButtonSize(),document.addEventListener("mousedown",this.clickedOutside),document.addEventListener(p,this.hsvChanged),document.addEventListener(f,this.hueChanged),document.addEventListener(m,this.alphaChanged),document.addEventListener(D,this.buttonClicked))}disconnectedCallback(){var t,i,r;(t=this.$button)==null||t.removeEventListener("click",this.toggle),(i=this.$button)==null||i.removeEventListener("keydown",this.onKeyDown),(r=this.$button)==null||r.removeEventListener("mousedown",this.stopPropagation),document.removeEventListener("mousedown",this.clickedOutside),document.removeEventListener(p,this.hsvChanged),document.removeEventListener(f,this.hueChanged),document.removeEventListener(m,this.alphaChanged),document.removeEventListener(D,this.buttonClicked)}attributeChangedCallback(t){switch(t){case"color":{this.state.initialColor=c(this.getAttribute("color")),this.state.color=c(this.getAttribute("color")),this.onInitialColorChange();break}case"popup-position":{this.state.popupPosition=this.getAttribute("popup-position")||"left",this.onPopupPosChange();break}case"button-width":{this.state.buttonWidth=this.getAttribute("button-width"),this.setButtonSize();break}case"button-height":{this.state.buttonHeight=this.getAttribute("button-height"),this.setButtonSize();break}case"button-padding":{this.state.buttonPadding=this.getAttribute("button-padding"),this.setButtonSize();break}}}},$t=tt;customElements.get("toolcool-color-picker")||customElements.define("toolcool-color-picker",$t);})(); \ No newline at end of file diff --git a/jiuguan2025cc/public/locales/ar-sa.json b/jiuguan2025cc/public/locales/ar-sa.json new file mode 100644 index 0000000000000000000000000000000000000000..517b7ce7d9ed1949ac9c5679476a868bb29d1151 --- /dev/null +++ b/jiuguan2025cc/public/locales/ar-sa.json @@ -0,0 +1,1443 @@ +{ + "Favorite": "مفضل", + "Tag": "بطاقة شعار", + "Duplicate": "ينسخ", + "Persona": "شخصية", + "Delete": "حذف", + "AI Response Configuration": "تكوين الرد الذكاء الاصطناعي", + "AI Configuration panel will stay open": "لوحة تكوين الذكاء الاصطناعي ستبقى مفتوحة", + "clickslidertips": "انقر لإدخال القيم يدويًا.", + "MAD LAB MODE ON": "وضع MAD LAB قيد التشغيل", + "Documentation on sampling parameters": "وثائق حول معلمات العينات", + "kobldpresets": "الإعدادات المسبقة لـ Kobold", + "guikoboldaisettings": "إعدادات واجهة KoboldAI", + "Update current preset": "تحديث الإعداد الحالي", + "Save preset as": "حفظ الضبط المسبق باسم", + "Import preset": "استيراد الإعداد", + "Export preset": "تصدير الإعداد", + "Restore current preset": "استعادة الضبط الحالي", + "Delete the preset": "حذف الإعداد", + "novelaipresets": "الإعدادات المسبقة لـ NovelAI", + "Default": "افتراضي", + "openaipresets": "الإعدادات المسبقة لـ OpenAI", + "Text Completion presets": "الإعدادات لإكمال النص", + "AI Module": "وحدة الذكاء الصناعي", + "Changes the style of the generated text.": "تغيير نمط النص المولد.", + "No Module": "لا توجد وحدة", + "Instruct": "إرشاد", + "Prose Augmenter": "مُعزز النثر", + "Text Adventure": "مغامرة النص", + "response legth(tokens)": "طول الاستجابة (بعدد الاحرف او الرموز)", + "Streaming": "البث المباشر ل", + "Streaming_desc": "عرض الاستجابة لحظيا كما يتم إنشاؤها.", + "context size(tokens)": "حجم الاحرف (بعدد الاحرف او الرموز)", + "unlocked": "مفتوح", + "Only enable this if your model supports context sizes greater than 8192 tokens": "قم بتمكين هذا فقط إذا كانت نموذجك يدعم مقاطع السياق بأحجام أكبر من 8192 رمزًا.", + "Max prompt cost:": "أقصى تكلفة فورية:", + "Display the response bit by bit as it is generated.": "عرض الاستجابة بتدريج كما يتم إنشاؤها.", + "When this is off, responses will be displayed all at once when they are complete.": "عند إيقاف هذا الخيار، سيتم عرض الردود جميعها دفعة واحدة عند اكتمالها.", + "Temperature": "درجة الحرارة", + "rep.pen": "عقوبة الاعادة", + "Rep. Pen. Range.": "مدى عقوبة التكرار", + "Rep. Pen. Slope": "ميل العقوبة التكرار", + "Rep. Pen. Freq.": "تكرار عقوبة التكرار", + "Rep. Pen. Presence": "وجود عقوبة التكرار", + "TFS": "TFS", + "Phrase Repetition Penalty": "عقوبة تكرار العبارات", + "Off": "إيقاف", + "Very light": "خفيف جداً", + "Light": "خفيف", + "Medium": "متوسط", + "Aggressive": "عدواني", + "Very aggressive": "عدواني للغاية", + "Unlocked Context Size": "حجم السياق غير المقفل", + "Unrestricted maximum value for the context slider": "قيمة قصوى غير مقيدة السياق", + "Context Size (tokens)": "حجم السياق (الرموزاو الحروف)", + "Max Response Length (tokens)": "الحد الأقصى لطول الاستجابة (الرموز,الحرف)", + "Multiple swipes per generation": "الضربات الشديدة المتعددة لكل جيل", + "Enable OpenAI completion streaming": "تمكين بث الاكتمال من OpenAI", + "Frequency Penalty": "عقوبة التكرار", + "Presence Penalty": "عقوبة الوجود", + "Count Penalty": "عد ضربة جزاء", + "Top K": "أعلى K", + "Top P": "أعلى P", + "Repetition Penalty": "عقوبة التكرار", + "Min P": "مين ص", + "Top A": "أعلى A", + "Quick Prompts Edit": "تحرير التلميحات بسرعة", + "Main": "الرئيسية", + "NSFW": "NSFW", + "Jailbreak": "كسر الحجز", + "Utility Prompts": "تلميحات الأدوات", + "Impersonation prompt": "تعليمات التنكر", + "Restore default prompt": "استعادة التعليمة الافتراضية", + "Prompt that is used for Impersonation function": "التعليمات التي يتم استخدامها لوظيفة التنكر", + "World Info Format Template": "قالب تنسيق معلومات العالم", + "Restore default format": "استعادة التنسيق الافتراضي", + "Wraps activated World Info entries before inserting into the prompt.": "يلتف إدخالات معلومات العالم المنشَّطة قبل إدراجها في الموجه.", + "scenario_format_template_part_1": "يستخدم", + "scenario_format_template_part_2": "لتحديد المكان الذي يتم فيه إدراج المحتوى.", + "Scenario Format Template": "قالب تنسيق السيناريو", + "Personality Format Template": "قالب تنسيق الشخصية", + "Group Nudge Prompt Template": "قالب المطالبة بدفعة المجموعة", + "Sent at the end of the group chat history to force reply from a specific character.": "يتم إرساله في نهاية سجل الدردشة الجماعية لفرض الرد من شخصية معينة.", + "New Chat": "دردشة جديدة", + "Restore new chat prompt": "استعادة موجه الدردشة الجديد", + "Set at the beginning of the chat history to indicate that a new chat is about to start.": "قم بتعيينه في بداية سجل الدردشة للإشارة إلى أن محادثة جديدة على وشك البدء.", + "New Group Chat": "دردشة جماعية جديدة", + "Restore new group chat prompt": "استعادة المطالبة الافتراضية", + "Set at the beginning of the chat history to indicate that a new group chat is about to start.": "قم بالتعيين في بداية سجل الدردشة للإشارة إلى أن محادثة جماعية جديدة على وشك البدء.", + "New Example Chat": "مثال جديد للدردشة", + "Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.": "قم بتعيين أمثلة في بداية الحوار للإشارة إلى أن مثالًا جديدًا للدردشة على وشك البدء.", + "Continue nudge": "استمر في الدفع", + "Set at the end of the chat history when the continue button is pressed.": "يتم تعيينه في نهاية سجل الدردشة عند الضغط على زر المتابعة.", + "Replace empty message": "استبدال الرسالة الفارغة", + "Send this text instead of nothing when the text box is empty.": "إرسال هذا النص بدلاً من عدم وجود شيء عندما يكون مربع النص فارغًا.", + "Seed": "بذرة", + "Set to get deterministic results. Use -1 for random seed.": "اضبط للحصول على نتائج حتمية. استخدم -1 للبذور العشوائية.", + "Temperature controls the randomness in token selection": "درجة الحرارة تتحكم في العشوائية في اختيار الحروف:\n- درجة حرارة منخفضة (<1.0) تؤدي إلى نص أكثر ذكاءا، مع إعطاء الأولوية(للعبارات والكلمات) للرموز ذات الاحتمالية العالية.\n- درجة حرارة مرتفعة (>1.0) تزيد من الإبداع وتنوع الإخراج، مع منح الرموز(العبارات والكلمات) ذات الاحتمالية المنخفضة فرصًا أكبر.\nقم بتعيين القيمة 1.0 للاحتماليات الأصلية.", + "Top_K_desc": "القيمة العليا K تحدد الحد الأقصى لعدد الرموز العلوية التي يمكن اختيارها.", + "Top_P_desc": "القيمة العلوية P (المعروفة أيضًا باسم عينة النواة) تجمع بين جميع الرموز العلوية اللازمة لتحقيق نسبة مئوية معينة.\nبمعنى آخر، إذا كانت الرموز العلوية 2 تمثل 25٪، وكانت Top-P تساوي 0.50، يُعتبر فقط هذان الرمزان العلويان.\nقم بتعيين القيمة 1.0 للتعطيل.", + "Typical P": "قيمة P النموذجية", + "Typical_P_desc": "عينة القيمة النموذجية P تُعطي أولوية للرموز استنادًا إلى انحرافها عن الانحدار المتوسط للمجموعة.\nيتم الاحتفاظ بالرموز التي تكون احتماليتها التراكمية قريبة من العتبة المحددة (على سبيل المثال، 0.5)، مما يميز تلك التي تحتوي على متوسط معلوماتي.\nقم بتعيين القيمة 1.0 للتعطيل.", + "Min_P_desc": "القيمة الدنيا P تحدد الحد الأدنى الأساسي للإحتمال. يتم تحسينها استنادًا إلى إحتمالية الرمز العلوي.\nإذا كانت إحتمالية الرمز العلوي 80٪، وكانت القيمة الدنيا P - 0.1، فسيتم النظر في الرموز فقط بإحتمالية أعلى من 8٪.\nقم بتعيين القيمة 0 للتعطيل.", + "Top_A_desc": "القيمة العلوية A تحدد عتبة لاختيار الرموز استنادًا إلى مربع إحتمالية الرمز الأعلى.\nإذا كانت القيمة العلوية A تساوي 0.2، وكانت إحتمالية الرمز العلوي تساوي 50٪، فسيتم استبعاد الرموز بإحتمالية أقل من 5٪ (0.2 * 0.5^2).\nقم بتعيين القيمة 0 للتعطيل.", + "Tail_Free_Sampling_desc": "عينة خالية من الذيل (TFS) تبحث عن ذيل الرموز ذات الاحتمالية الصغيرة في التوزيع،\n من خلال تحليل معدل تغير إحتماليات الرموز باستخدام الإشتقاقات. يتم الاحتفاظ بالرموز حتى الحد (على سبيل المثال، 0.3)، استنادًا إلى المشتق الثاني الموحد.\nكلما اقترب من 0، زاد عدد الرموز المرفوضة. قم بتعيين القيمة 1.0 للتعطيل.", + "rep.pen range": "نطاق عقوبة الاعادة.", + "Mirostat": "ميروستات", + "Mode": "وضع", + "Mirostat_Mode_desc": "قيمة 0 تعطل Mirostat بالكامل. 1 مخصص لميروستات 1.0، و2 مخصص لميروستات 2.0", + "Tau": "تاو", + "Mirostat_Tau_desc": "يتحكم في تقلب مخرجات Mirostat", + "Eta": "إيتا", + "Mirostat_Eta_desc": "يتحكم في معدل التعلم من Mirostat", + "Ban EOS Token": "حظر رمز EOS", + "Ban_EOS_Token_desc": "حظر رمز نهاية التسلسل (EOS) باستخدام KoboldCpp (وربما أيضًا الرموز المميزة الأخرى مع KoboldAI).\rجيد لكتابة القصة، ولكن لا ينبغي استخدامه في وضع الدردشة والإرشاد.", + "GBNF Grammar": "قواعد اللغة الباكوسية", + "Type in the desired custom grammar": "اكتب القواعد اللغوية المخصصة المطلوبة", + "Samplers Order": "ترتيب الأمثلة", + "Samplers will be applied in a top-down order. Use with caution.": "سيتم تطبيق الأمثلة بترتيب من الأعلى إلى الأسفل. استخدم بحذر.", + "Tail Free Sampling": "عينة خالية من الذيل", + "Load koboldcpp order": "تحميل أمر koboldcpp", + "Preamble": "مقدمة", + "Use style tags to modify the writing style of the output.": "استخدم علامات النمط لتعديل نمط الكتابة النهائية.", + "Banned Tokens": "الرموز المحظورة", + "Sequences you don't want to appear in the output. One per line.": "تسلسلات لا تريد ظهورها في النتيجة. واحدة لكل سطر.", + "Logit Bias": "الانحياز في اللوجيت", + "Add": "إضافة", + "Helps to ban or reenforce the usage of certain words": "يساعد في حظر أو تعزيز استخدام بعض الكلمات", + "CFG Scale": "مقياس CFG", + "Negative Prompt": "استفسار سلبي", + "Add text here that would make the AI generate things you don't want in your outputs.": "أضف النص هنا الذي سيجعل الذكاء الصناعي يولد أشياء لا ترغب فيها في اخراجها.", + "Used if CFG Scale is unset globally, per chat or character": "يتم استخدامه إذا لم يتم تعيين مقياس CFG على نطاق عالمي، لكل محادثة أو شخصية.", + "Mirostat Tau": "تاو Mirostat", + "Mirostat LR": "ميروستات LR", + "Min Length": "الحد الأدنى للطول", + "Top K Sampling": "عينة أعلى K", + "Nucleus Sampling": "عينة النواة", + "Top A Sampling": "عينة أعلى A", + "CFG": "CFG", + "Neutralize Samplers": "تعطيل المحاكيات", + "Set all samplers to their neutral/disabled state.": "ضبط جميع المحاكيات على حالتها الطبيعية/معطلة.", + "Sampler Select": "تحديد العينات", + "Customize displayed samplers or add custom samplers.": "تخصيص عينات المعروضة أو إضافة عينات مخصصة.", + "Epsilon Cutoff": "قطع إبسيلون", + "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "القيمة العلوية الإبسيلون تعيين الحد الأدنى للإحتمالية حيث تستبعد الرموز أدناه من العينة.\nبالوحدات 1e-4؛ القيمة المناسبة هي 3.\nقم بتعيين 0 للتعطيل.", + "Eta Cutoff": "قطع إيتا", + "Eta_Cutoff_desc": "قيمة القطع Eta هي المعلمة الرئيسية لتقنية عينة إيتا الخاصة. بوحدات 1e-4 ؛ القيمة المعقولة هي 3. قم بتعيينها على 0 لتعطيلها. انظر ورقة بحث عينة الانقطاع كما يمكن تسميتها باسم تلميع نموذج اللغة من قبل هيويت وآخرين (2022) للحصول على تفاصيل.", + "rep.pen decay": "ممثل تسوس القلم", + "Encoder Rep. Pen.": "عقوبة تكرار المشفر", + "No Repeat Ngram Size": "حجم Ngram بدون تكرار", + "Skew": "انحراف", + "Max Tokens Second": "أقصى عدد من الرموز(الحروف) / الثانية", + "Smooth Sampling": "أخذ العينات على نحو سلس", + "Smooth_Sampling_desc": "يسمح لك باستخدام التحويلات التربيعية/المكعبية لضبط التوزيع. ستكون قيم عامل التجانس الأقل أكثر إبداعًا، وعادة ما تكون بين 0.2-0.3 هي النقطة المثالية (بافتراض أن المنحنى = 1). ستؤدي قيم منحنى التجانس الأعلى إلى جعل المنحنى أكثر انحدارًا، مما سيؤدي إلى معاقبة الاختيارات ذات الاحتمالية المنخفضة بشكل أكثر قوة. منحنى 1.0 يعادل استخدام عامل التجانس فقط.", + "Smoothing Factor": "عامل التنعيم", + "Smoothing Curve": "منحنى التنعيم", + "DRY_Repetition_Penalty_desc": "يعاقب DRY الرموز المميزة التي من شأنها تمديد نهاية الإدخال إلى تسلسل حدث مسبقًا في الإدخال. اضبط المضاعف على 0 لتعطيله.", + "DRY Repetition Penalty": "عقوبة التكرار الجاف", + "DRY_Multiplier_desc": "اضبط على القيمة > 0 لتمكين DRY. يتحكم في حجم العقوبة لأقصر تسلسل معاقب عليه.", + "Multiplier": "المضاعف", + "DRY_Base_desc": "يتحكم في مدى سرعة نمو العقوبة مع زيادة طول التسلسل.", + "Base": "قاعدة", + "DRY_Allowed_Length_desc": "أطول تسلسل يمكن تكراره دون عقوبة.", + "Allowed Length": "الطول المسموح به", + "Penalty Range": "نطاق العقوبة", + "DRY_Sequence_Breakers_desc": "الرموز المميزة التي لا تستمر مطابقة التسلسل عبرها. تم تحديده كقائمة مفصولة بفواصل من السلاسل المقتبسة.", + "Sequence Breakers": "قواطع التسلسل", + "JSON-serialized array of strings.": "مجموعة سلاسل JSON متسلسلة.", + "Dynamic Temperature": "درجة الحرارة الديناميكية", + "Scale Temperature dynamically per token, based on the variation of probabilities": "قيمة درجة الحرارة يتم تحديدها ديناميكيًا لكل رمز، استنادًا إلى التغيير في الإحتمالات.", + "Minimum Temp": "أقل درجة حرارة", + "Maximum Temp": "أعلى درجة حرارة", + "Exponent": "الأس", + "Mirostat (mode=1 is only for llama.cpp)": "(فقط عند استخدام llama.cpp)ميروستات", + "Mirostat_desc": "ميروستات هو جهاز ترموستات لصعوبة الإخراج. يعد ميروستات آلية لضبط صعوبة الإخراج لتحقيق الانسجام بين الإدخال والإخراج.", + "Mirostat Mode": "وضعية Mirostat", + "Variability parameter for Mirostat outputs": "معلمة التباين لإخراج Mirostat.", + "Mirostat Eta": "إيتا Mirostat", + "Learning rate of Mirostat": "معدل التعلم لـ Mirostat.", + "Beam search": "بحث الشعاع", + "Helpful tip coming soon.": "نصيحة مفيدة قريبا.", + "Number of Beams": "عدد الشعاع", + "Length Penalty": "عقوبة الطول", + "Early Stopping": "التوقف المبكر", + "Contrastive search": "البحث المتقابل", + "Penalty Alpha": "ألفا العقوبة", + "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "قوة شرط التنظيم للبحث التناقضي( بعد تعيين العينات المعززة بقوة إلى المجموعات من خلال تسمياتها الزائفة، يقوم التنظيم المتباين الخاص بنا بتحديث النموذج بحيث تقوم الميزات ذات التسميات الزائفة الواثقة بتجميع الميزات في نفس المجموعة، مع دفع الميزات في مجموعات مختلفة بعيدًا). قم بتعيين القيمة إلى 0 لتعطيل CS.", + "Do Sample": "عينة", + "Add BOS Token": "إضافة رمز BOS", + "Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative": "إضافة bos_token إلى بداية الجمل. يمكن أن يجعل تعطيل هذا الردود أكثر إبداعًا.", + "Ban the eos_token. This forces the model to never end the generation prematurely": "حظر رمز EOS. هذا يجبر النموذج على عدم إنهاء الاستجابة مبكرًا أبدًا", + "Ignore EOS Token": "تجاهل رمز EOS", + "Ignore the EOS Token even if it generates.": "تجاهل رمز EOS حتى لو تم إنشاؤه.", + "Skip Special Tokens": "تخطي الرموز الخاصة", + "Temperature Last": "درجة الحرارة الأخيرة", + "Temperature_Last_desc": "استخدم مُخرج درجة الحرارة في النهاية. هذا عادة ما يكون منطقياً.\nعند التشغيل: يتم أولاً اختيار مجموعة من الرموز المحتملة، ثم يتم تطبيق درجة الحرارة لتصحيح احتمالياتها النسبية (تقنيًا، اللوجيتات).\nعند التعطيل: يتم تطبيق درجة الحرارة أولاً لتصحيح الاحتماليات النسبية لكل الرموز، ثم يتم اختيار مجموعة من الرموز المحتملة من بينها.\nتعطيل درجة الحرارة في النهاية يزيد من احتماليات الرموز في ذيل التوزيع، مما يزيد من فرص الحصول على إجابات غير متناسقة.", + "Speculative Ngram": "نغرام المضاربة", + "Use a different speculative decoding method without a draft model": "استخدم طريقة مختلفة لفك التشفير التخميني بدون نموذج أولي.\rيفضل استخدام نموذج مسودة. ngram المضاربة ليست فعالة.", + "Spaces Between Special Tokens": "المسافات بين الرموز الخاصة", + "LLaMA / Mistral / Yi models only": "فقط لنماذج LLaMA / Mistral / Yi. تأكد من تحديد المحلل المناسب أولاً.\nسلاسل تود أن لا تظهر في النتائج.\nسلسلة واحدة في كل سطر. نص أو [معرفات الحروف].\nالعديد من الرموز يبدأ بفراغ. استخدم عداد الرموز إذا كنت غير متأكد.", + "Example: some text [42, 69, 1337]": "مثال:\nبعض النص\n[42، 69، 1337]", + "Classifier Free Guidance. More helpful tip coming soon": "إرشادات خالية . نصائح أكثر فائدة قريباً.", + "Scale": "مقياس", + "JSON Schema": "مخطط جيسون", + "Type in the desired JSON schema": "اكتب مخطط JSON المطلوب", + "Grammar String": "سلسلة القواعد", + "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "يعتمد GBNF أو EBNF على الواجهة الخلفية المستخدمة. إذا كنت تستخدم هذا يجب أن تعرف أي.", + "Top P & Min P": "أعلى ع وأدنى ص", + "Load default order": "تحميل الترتيب الافتراضي", + "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "llama.cpp فقط. تحديد ترتيب أخذ العينات. إذا لم يكن وضع Mirostat 0، فسيتم تجاهل ترتيب أخذ العينات.", + "Sampler Priority": "أولوية العينات", + "Ooba only. Determines the order of samplers.": "Ooba فقط في حالة استخدام ل. يحدد ترتيب العينات.", + "Character Names Behavior": "سلوك أسماء الشخصيات", + "Helps the model to associate messages with characters.": "يساعد النموذج على ربط الرسائل بالأحرف.", + "None": "لا شيء", + "character_names_default": "باستثناء المجموعات والشخصيات السابقة. بخلاف ذلك، تأكد من تقديم الأسماء في المطالبة.", + "Don't add character names.": "لا تضيف أسماء الشخصيات.", + "Completion": "كائن الإكمال", + "character_names_completion": "تنطبق القيود: فقط الحروف الأبجدية اللاتينية والأرقام والشرطات السفلية. لا يعمل مع جميع المصادر، ولا سيما: Claude وMistralAI وGoogle.", + "Add character names to completion objects.": "أضف أسماء الشخصيات إلى كائنات الإكمال.", + "Message Content": "محتوى الرسالة", + "Prepend character names to message contents.": "قم بإرفاق أسماء الأحرف بمحتويات الرسالة.", + "Continue Postfix": "متابعة بوستفيكس", + "The next chunk of the continued message will be appended using this as a separator.": "سيتم إلحاق الجزء التالي من الرسالة المستمرة باستخدام هذا كفاصل.", + "Space": "فضاء", + "Newline": "خط جديد", + "Double Newline": "الخط الجديد مزدوج", + "Wrap user messages in quotes before sending": "لف رسائل المستخدمين في علامات اقتباس قبل الإرسال", + "Wrap in Quotes": "وضع النص بين علامات اقتباس", + "Wrap entire user message in quotes before sending.": "ضع الرسالة بأكملها بين علامات اقتباس قبل الإرسال.", + "Leave off if you use quotes manually for speech.": "اتركها على وضع الايقاف إذا كنت تستخدم الاقتباسات يدويًا للكلام.", + "Continue prefill": "متابعة التعبئة المسبقة", + "Continue sends the last message as assistant role instead of system message with instruction.": "المتابعة ترسل الرسالة الأخيرة بدور المساعد بدلاً من رسالة النظام مع التعليمات.", + "Squash system messages": "ضغط رسائل النظام", + "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "يجمع الرسائل المتتالية للنظام في رسالة واحدة (باستثناء الحوارات المثالية). قد يحسن التتابع لبعض النماذج.", + "Enable function calling": "تمكين استدعاء الوظيفة", + "Send inline images": "إرسال الصور المضمنة", + "image_inlining_hint_1": "يرسل الصور في المطالبات إذا كان النموذج يدعمها (على سبيل المثال، GPT-4V، أو Claude 3، أو Lava 13B).\n استخدم ال", + "image_inlining_hint_2": "الإجراء على أي رسالة أو", + "image_inlining_hint_3": "القائمة لإرفاق ملف صورة للدردشة.", + "Inline Image Quality": "جودة الصورة المضمنة", + "openai_inline_image_quality_auto": "آلي", + "openai_inline_image_quality_low": "قليل", + "openai_inline_image_quality_high": "عالي", + "Use AI21 Tokenizer": "استخدم رمز AI21", + "Use the appropriate tokenizer for Jurassic models, which is more efficient than GPT's.": "استخدم الرمز المميز المناسب للنماذج الجوراسية، وهو أكثر كفاءة من GPT.", + "Use Google Tokenizer": "استخدم محلل النحوي من Google", + "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "استخدم المحلل النحوي المناسب لنماذج Google عبر واجهة برمجة التطبيقات الخاصة بهم. معالجة الإشارات الأولية بطيئة، ولكنها تقدم عداد رمز دقيق جدًا.", + "Use system prompt": "استخدام موجه النظام", + "(Gemini 1.5 Pro/Flash only)": "(جيميني 1.5 برو/فلاش فقط)", + "Merges_all_system_messages_desc_1": "يدمج كافة رسائل النظام حتى الرسالة الأولى ذات دور غير النظام، ويرسلها في ملف", + "Merges_all_system_messages_desc_2": "مجال.", + "Assistant Prefill": "تعبئة مسبقة للمساعد", + "Start Claude's answer with...": "ابدأ إجابة كلود بـ...", + "Assistant Impersonation Prefill": "مساعد انتحال الشخصية المسبقة", + "Use system prompt (Claude 2.1+ only)": "استخدام التعليمة النظامية (فقط كلود 2.1+)", + "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "إرسال التعليمة النظامية للنماذج المدعومة. إذا تم تعطيلها، يتم إضافة رسالة المستخدم إلى بداية التعليمة.", + "User first message": "الرسالة الأولى للمستخدم", + "Restore User first message": "استعادة الرسالة الأولى للمستخدم", + "Human message": "رسالة إنسانية وتعليمات وما إلى ذلك.\nلا يضيف شيئًا عندما يكون فارغًا، أي يتطلب موجهًا جديدًا بالدور \"مستخدم\".", + "New preset": "إعداد جديد", + "Delete preset": "حذف الإعداد", + "View / Edit bias preset": "عرض/تحرير الضبط المسبق للانحياز", + "Add bias entry": "إضافة إدخال للانحياز", + "Most tokens have a leading space.": "تحتوي معظم الرموز المميزة على مسافة بادئة.", + "API Connections": "اتصالات واجهة برمجة التطبيقات", + "Text Completion": "اكتمال النص", + "Chat Completion": "إكمال الدردشة", + "NovelAI": "NovelAI", + "AI Horde": "AI Horde", + "KoboldAI": "KoboldAI", + "Avoid sending sensitive information to the Horde.": "تجنب إرسال معلومات حساسة إلى الجماعة.", + "Review the Privacy statement": "مراجعة بيان الخصوصية", + "Register a Horde account for faster queue times": "سجّل حساب Horde لزمن انتظار أسرع في الطابور", + "Learn how to contribute your idle GPU cycles to the Horde": "تعلم كيفية المساهمة بدورات معالجة الرسومات الخاملة الخاصة بك في الهورد", + "Adjust context size to worker capabilities": "ضبط حجم السياق وفقًا لقدرات العاملين", + "Adjust response length to worker capabilities": "ضبط طول الاستجابة وفقًا لقدرات العاملين", + "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "يمكن المساعدة في الردود السيئة عن طريق وضع العمال الموافق عليهم فقط في قائمة الانتظار. قد يؤدي إلى بطء وقت الاستجابة.", + "Trusted workers only": "العاملون الموثوق بهم فقط", + "API key": "مفتاح API", + "Get it here:": "احصل عليه هنا:", + "Register": "سجّل", + "View my Kudos": "عرض (Kudos)", + "Enter": "أدخل", + "to use anonymous mode.": "لاستخدام الوضع المتخفي.", + "Clear your API key": "مسح مفتاح واجهة برمجة التطبيقات الخاص بك", + "For privacy reasons, your API key will be hidden after you reload the page.": "لأسباب خصوصية، سيتم إخفاء مفتاح API الخاص بك بعد إعادة تحميل الصفحة.", + "Models": "النماذج", + "Refresh models": "تحديث النماذج", + "-- Horde models not loaded --": "-- نماذج الجماعة غير محملة --", + "Not connected...": "غير متصل...", + "API url": "رابط API", + "Example: http://127.0.0.1:5000/api ": "مثال: http://127.0.0.1:5000/api", + "Connect": "الاتصال", + "Cancel": "إلغاء", + "Novel API key": "مفتاح API لـ NovelAI", + "Get your NovelAI API Key": "احصل على مفتاح API NovelAI الخاص بك", + "Enter it in the box below": "أدخله في المربع أدناه", + "Novel AI Model": "نموذج NovelAI", + "No connection...": "لا يوجد اتصال...", + "API Type": "نوع واجهة برمجة التطبيقات", + "Default (completions compatible)": "الافتراضي [متوافق مع OpenAI/الإكمالات: oobabooga، LM Studio، إلخ.]", + "TogetherAI API Key": "مفتاح API لـ TogetherAI", + "TogetherAI Model": "نموذج TogetherAI", + "-- Connect to the API --": "-- الاتصال بواجهة برمجة التطبيقات --", + "OpenRouter API Key": "مفتاح API لـ OpenRouter", + "Click Authorize below or get the key from": "انقر فوق تفويض أدناه أو احصل على المفتاح من", + "View Remaining Credits": "عرض الرصيد المتبقي", + "OpenRouter Model": "نموذج OpenRouter", + "Model Providers": "مقدمو النماذج", + "InfermaticAI API Key": "مفتاح واجهة برمجة تطبيقات InfermaticAI", + "InfermaticAI Model": "نموذج الذكاء الاصطناعي Infermatic", + "DreamGen API key": "مفتاح DreamGen API", + "DreamGen Model": "نموذج دريم جين", + "Mancer API key": "مفتاح API لـ Mancer", + "Mancer Model": "نموذج مانسر", + "Make sure you run it with": "تأكد من تشغيله مع", + "flag": "وضع علامة", + "API key (optional)": "مفتاح API (اختياري)", + "Server url": "رابط الخادم", + "Example: 127.0.0.1:5000": "مثال: 127.0.0.1:5000", + "Custom model (optional)": "نموذج مخصص (اختياري)", + "vllm-project/vllm": "vllm-project/vllm (وضع غلاف OpenAI API)", + "vLLM API key": "مفتاح واجهة برمجة التطبيقات vLLM", + "Example: 127.0.0.1:8000": "مثال: http://127.0.0.1:8000", + "vLLM Model": "نموذج vLLM", + "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (وضع التغليف لواجهة برمجة التطبيقات OpenAI)", + "Aphrodite API key": "مفتاح واجهة برمجة التطبيقات Aphrodite", + "Aphrodite Model": "نموذج أفروديت", + "ggerganov/llama.cpp": "ggerganov/llama.cpp (خادم إخراج)", + "Example: 127.0.0.1:8080": "مثال: 127.0.0.1:8080", + "Example: 127.0.0.1:11434": "مثال: 127.0.0.1:11434", + "Ollama Model": "نموذج Ollama", + "Download": "تحميل", + "Tabby API key": "مفتاح API لـ Tabby", + "koboldcpp API key (optional)": "مفتاح koboldcpp API (اختياري)", + "Example: 127.0.0.1:5001": "مثال: 127.0.0.1:5001", + "Authorize": "تفويض", + "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "احصل على رمز واجهة برمجة التطبيقات الخاص بك لموزع الاتصالات باستخدام تدفق OAuth. سيتم توجيهك إلى openrouter.ai", + "Bypass status check": "تجاوز فحص الحالة", + "Chat Completion Source": "مصدر استكمال الدردشة", + "Reverse Proxy": "الوكيل العكسي", + "Proxy Presets": "إعدادات الوكيل المسبقة", + "Saved addresses and passwords.": "العناوين وكلمات المرور المحفوظة.", + "Save Proxy": "حفظ الوكيل", + "Delete Proxy": "حذف الوكيل", + "Proxy Name": "اسم الوكيل", + "This will show up as your saved preset.": "سيظهر هذا كإعداد مسبق محفوظ لديك.", + "Proxy Server URL": "عنوان URL للخادم الوكيل", + "Alternative server URL (leave empty to use the default value).": "عنوان URL الخادم البديل (اتركه فارغًا لاستخدام القيمة الافتراضية).", + "Remove your real OAI API Key from the API panel BEFORE typing anything into this box": "قم بإزالة مفتاح API الخاص بـ OAI الحقيقي من لوحة الواجهة البرمجية قبل كتابة أي شيء في هذا المربع", + "We cannot provide support for problems encountered while using an unofficial OpenAI proxy": "لا يمكننا تقديم الدعم للمشاكل التي تواجهك أثناء استخدام بروكسي OpenAI غير الرسمي", + "Doesn't work? Try adding": "لا يعمل؟ حاول إضافة", + "at the end!": "في نهايةالمطاف!", + "Proxy Password": "كلمة مرور الوكيل", + "Will be used as a password for the proxy instead of API key.": "سيتم استخدامها ككلمة مرور للوكيل بدلاً من مفتاح API.", + "Peek a password": "نظرة خاطفة على كلمة المرور", + "OpenAI API key": "مفتاح API لـ OpenAI", + "View API Usage Metrics": "عرض مقاييس استخدام واجهة برمجة التطبيقات", + "Follow": "اتبع", + "these directions": "هذه التوجيهات", + "to get your OpenAI API key.": "للحصول على مفتاح API لـ OpenAI.", + "Use Proxy password field instead. This input will be ignored.": "استخدم حقل \"كلمة مرور الوكيل\" بدلاً من ذلك. سيتم تجاهل هذا الإدخال.", + "OpenAI Model": "نموذج OpenAI", + "Bypass API status check": "تجاوز فحص حالة واجهة برمجة التطبيقات", + "Show External models (provided by API)": "عرض النماذج الخارجية (المقدمة من قبل واجهة برمجة التطبيقات)", + "Get your key from": "احصل على مفتاحك من", + "Anthropic's developer console": "وحدة تحكم المطور في Anthropic", + "Claude Model": "نموذج Claude", + "Window AI Model": "نموذج Window AI", + "Model Order": "فرز نموذج OpenRouter", + "Alphabetically": "أبجديا", + "Price": "السعر (الأرخص)", + "Context Size": "حجم السياق", + "Group by vendors": "المجموعة حسب البائعين", + "Group by vendors Description": "ضع نماذج OpenAI في مجموعة واحدة، والنماذج الإنسانية في مجموعة أخرى، وما إلى ذلك. ويمكن دمجها مع الفرز.", + "Allow fallback routes": "السماح بمسارات الاحتياط", + "Allow fallback routes Description": "يختار النموذج البديل تلقائيًا إذا كان النموذج المحدد غير قادر على تلبية طلبك.", + "Scale API Key": "مفتاح API لـ Scale", + "Clear your cookie": "امسح ملف تعريف الارتباط الخاص بك", + "Alt Method": "طريقة بديلة", + "AI21 API Key": "مفتاح API لـ AI21", + "AI21 Model": "نموذج AI21", + "Google AI Studio API Key": "مفتاح واجهة برمجة تطبيقات Google AI Studio", + "Google Model": "نموذج جوجل", + "MistralAI API Key": "مفتاح واجهة برمجة التطبيقات MistralAI", + "MistralAI Model": "نموذج ميسترال آي آي", + "Groq API Key": "مفتاح Groq API", + "Groq Model": "نموذج جروك", + "Perplexity API Key": "مفتاح واجهة برمجة تطبيقات الحيرة", + "Perplexity Model": "نموذج الحيرة", + "Cohere API Key": "مفتاح واجهة برمجة التطبيقات Cohere", + "Cohere Model": "نموذج التماسك", + "Custom Endpoint (Base URL)": "نقطة النهاية المخصصة (عنوان URL الأساسي)", + "Custom API Key": "مفتاح واجهة برمجة التطبيقات المخصص", + "Available Models": "النماذج المتاحة", + "Prompt Post-Processing": "موجه بعد المعالجة", + "Applies additional processing to the prompt before sending it to the API.": "يطبق معالجة إضافية على الموجه قبل إرساله إلى واجهة برمجة التطبيقات.", + "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "تتحقق من اتصالك بواجهة برمجة التطبيقات من خلال إرسال رسالة اختبار قصيرة. كن على علم بأنك ستحصل على الفضل في ذلك!", + "Test Message": "رسالة اختبار", + "Auto-connect to Last Server": "الاتصال التلقائي بآخر خادم", + "Missing key": "❌المفتاح مفقود", + "Key saved": "✔️ تم حفظ المفتاح", + "View hidden API keys": "عرض مفاتيح واجهة برمجة التطبيقات المخفية", + "AI Response Formatting": "تنسيق رد الذكاء الاصطناعي", + "Advanced Formatting": "تنسيق متقدم", + "Context Template": "قالب السياق", + "Auto-select this preset for Instruct Mode": "تحديد هذا الإعداد تلقائياً لوضع التعليم", + "Story String": "سلسلة القصة", + "Example Separator": "فاصل المثال", + "Chat Start": "بداية الدردشة", + "Add Chat Start and Example Separator to a list of stopping strings.": "أضف بداية الدردشة وفاصل الأمثلة إلى قائمة سلاسل التوقف.", + "Use as Stop Strings": "استخدم كسلاسل التوقف", + "context_allow_jailbreak": "يتضمن كسر الحماية في نهاية المطالبة، إذا تم تحديده في بطاقة الشخصية و''Prefer Char. تم تمكين الهروب من السجن.\nلا يُنصح بهذا بالنسبة لنماذج إكمال النص، فقد يؤدي إلى نتائج سيئة.", + "Allow Jailbreak": "السماح بالجيلبريك", + "Context Order": "ترتيب السياق", + "Summary": "ملخص", + "Author's Note": "مذكرة المؤلف", + "Example Dialogues": "أمثلة للحوارات", + "Hint": "تَلمِيح:", + "In-Chat Position not affected": "تتأثر أوامر الملخص وملاحظات المؤلف فقط عندما لا يكون لديهم موضع محدد داخل الدردشة.", + "Instruct Mode": "وضع التعليم", + "Enabled": "مفعل", + "instruct_bind_to_context": "في حالة التمكين، سيتم تحديد قوالب السياق تلقائيًا بناءً على اسم قالب التعليمات المحدد أو حسب التفضيل.", + "Bind to Context": "ربط بالسياق", + "Presets": "الإعدادات المسبقة", + "Auto-select this preset on API connection": "تحديد هذا الإعداد تلقائياً عند الاتصال بواجهة برمجة التطبيقات", + "Activation Regex": "تنشيط Regex", + "Wrap Sequences with Newline": "لف السلاسل بسطر جديد", + "Replace Macro in Sequences": "استبدال الماكرو في التسلسلات", + "Skip Example Dialogues Formatting": "تخطي مثال تنسيق الحوار", + "Include Names": "تضمين الأسماء", + "Force for Groups and Personas": "فرض للمجموعات والشخصيات", + "System Prompt": "دعوة النظام", + "Instruct Mode Sequences": "سلاسل وضع التعليم", + "System Prompt Wrapping": "التفاف النظام الفوري", + "Inserted before a System prompt.": "تم إدراجه قبل مطالبة النظام.", + "System Prompt Prefix": "بادئة موجه النظام", + "Inserted after a System prompt.": "تم إدراجه بعد مطالبة النظام.", + "System Prompt Suffix": "لاحقة موجه النظام", + "Chat Messages Wrapping": "تغليف رسائل الدردشة", + "Inserted before a User message and as a last prompt line when impersonating.": "يتم إدراجه قبل رسالة المستخدم وكسطر مطالبة أخير عند انتحال الشخصية.", + "User Message Prefix": "بادئة رسالة المستخدم", + "Inserted after a User message.": "تم إدراجه بعد رسالة المستخدم.", + "User Message Suffix": "لاحقة رسالة المستخدم", + "Inserted before an Assistant message and as a last prompt line when generating an AI reply.": "يتم إدراجه قبل رسالة المساعد وكوسطر مطالبة أخير عند إنشاء رد الذكاء الاصطناعي.", + "Assistant Message Prefix": "بادئة رسالة المساعد", + "Inserted after an Assistant message.": "تم إدراجه بعد رسالة مساعد.", + "Assistant Message Suffix": "لاحقة رسالة المساعد", + "Inserted before a System (added by slash commands or extensions) message.": "تم إدراجه قبل رسالة النظام (المضافة بواسطة أوامر أو ملحقات الشرطة المائلة).", + "System Message Prefix": "بادئة رسالة النظام", + "Inserted after a System message.": "تم إدراجه بعد رسالة النظام.", + "System Message Suffix": "لاحقة رسالة النظام", + "If enabled, System Sequences will be the same as User Sequences.": "في حالة التمكين، ستكون تسلسلات النظام هي نفس تسلسلات المستخدم.", + "System same as User": "النظام نفس المستخدم", + "Misc. Sequences": "تسلسلات متنوعة", + "Inserted before the first Assistant's message.": "تم إدراجه قبل رسالة المساعد الأول.", + "First Assistant Prefix": "بادئة المساعد الأول", + "instruct_last_output_sequence": "يتم إدراجه قبل رسالة المساعد الأخيرة أو كسطر مطالبة أخير عند إنشاء رد AI (باستثناء دور محايد/نظام).", + "Last Assistant Prefix": "بادئة المساعد الأخيرة", + "Will be inserted as a last prompt line when using system/neutral generation.": "سيتم إدراجه كسطر مطالبة أخير عند استخدام إنشاء النظام/المحايد.", + "System Instruction Prefix": "بادئة تعليمات النظام", + "If a stop sequence is generated, everything past it will be removed from the output (inclusive).": "إذا تم إنشاء تسلسل توقف، فسيتم إزالة كل شيء بعده من الإخراج (شاملًا).", + "Stop Sequence": "توقف السلسلة", + "Will be inserted at the start of the chat history if it doesn't start with a User message.": "سيتم إدراجه في بداية سجل الدردشة إذا لم يبدأ برسالة مستخدم.", + "User Filler Message": "رسالة حشو المستخدم", + "Context Formatting": "تنسيق السياق", + "(Saved to Context Template)": "(يتم حفظه في قالب السياق)", + "Always add character's name to prompt": "إضافة دائمًا اسم الشخصية إلى الحديث", + "Generate only one line per request": "توليد سطر واحد فقط لكل طلب", + "Trim Incomplete Sentences": "تقليم الجمل غير المكتملة", + "Include Newline": "تضمين سطر جديد", + "Misc. Settings": "إعدادات متنوعة", + "Collapse Consecutive Newlines": "طي الأسطر الجديدة المتتالية", + "Trim spaces": "تقليم الفراغات", + "Tokenizer": "فاصل النصوص", + "Token Padding": "امتداد الرموز", + "Start Reply With": "بدء الرد مع", + "AI reply prefix": "بادئة رد الذكاء الاصطناعي", + "Show reply prefix in chat": "إظهار بادئة الرد في الدردشة", + "Non-markdown strings": "سلاسل غير Markdown", + "separate with commas w/o space between": "فصل بفواصل دون مسافة بينها", + "Custom Stopping Strings": "سلاسل توقف مخصصة", + "JSON serialized array of strings": "مصفوفة سلسلة JSON متسلسلة", + "Replace Macro in Stop Strings": "استبدال الماكرو في سلاسل التوقف المخصصة", + "Auto-Continue": "المتابعة التلقائية", + "Allow for Chat Completion APIs": "السماح بواجهات برمجة التطبيقات لإكمال الدردشة", + "Target length (tokens)": "الطول المستهدف (رموز)", + "World Info": "معلومات العالم", + "Locked = World Editor will stay open": "مقفول = محرر العالم سيبقى مفتوحاً", + "Worlds/Lorebooks": "العوالم/Lorebook-ات", + "Active World(s) for all chats": "العالم(أو العوالم) النشط(ة) لجميع الدردشات", + "-- World Info not found --": "-- معلومات العالم غير موجودة --", + "Global World Info/Lorebook activation settings": "إعدادات تفعيل معلومات العالم العالمي/Lorebook", + "Click to expand": "انقر فوق لتوسيع", + "Scan Depth": "عمق المسح", + "Context %": "نسبة السياق", + "Budget Cap": "حد الميزانية", + "(0 = disabled)": "(0 = معطل)", + "Scan chronologically until reached min entries or token budget.": "قم بالمسح بشكل زمني حتى الوصول إلى الحد الأدنى من الإدخالات أو ميزانية الرمز المميز.", + "Min Activations": "الحد الأدنى للتفعيلات", + "Max Depth": "أقصى عمق", + "(0 = unlimited, use budget)": "(0 = غير محدود، استخدم الميزانية)", + "Insertion Strategy": "استراتيجية الإدراج", + "Sorted Evenly": "ترتيب متساوي", + "Character Lore First": "سرد الشخصية أولاً", + "Global Lore First": "سرد العالم أولاً", + "Entries can activate other entries by mentioning their keywords": "يمكن للإدخالات تنشيط إدخالات أخرى عن طريق ذكر كلماتهم الرئيسية", + "Recursive Scan": "فحص متكرر", + "Lookup for the entry keys in the context will respect the case": "سيحترم البحث عن مفاتيح الإدخال في السياق الحالة", + "Case Sensitive": "حساس لحالة الأحرف", + "If the entry key consists of only one word, it would not be matched as part of other words": "إذا كانت مفتاح الإدخال يتكون من كلمة واحدة فلن يتم مطابقتها كجزء من كلمات أخرى", + "Match Whole Words": "مطابقة الكلمات الكاملة", + "Only the entries with the most number of key matches will be selected for Inclusion Group filtering": "سيتم تحديد الإدخالات التي تحتوي على أكبر عدد من تطابقات المفاتيح فقط لتصفية مجموعة التضمين", + "Use Group Scoring": "استخدم تسجيل المجموعة", + "Alert if your world info is greater than the allocated budget.": "تنبيه إذا كانت معلومات العالم الخاصة بك أكبر من الميزانية المخصصة.", + "Alert On Overflow": "تنبيه عند التجاوز", + "New": "جديد", + "or": "أو", + "--- Pick to Edit ---": "--- اختر للتحرير ---", + "Rename World Info": "إعادة تسمية معلومات العالم", + "Open all Entries": "فتح جميع الإدخالات", + "Close all Entries": "إغلاق جميع الإدخالات", + "New Entry": "إدخال جديد", + "Fill empty Memo/Titles with Keywords": "املأ الملاحظات / العناوين الفارغة بالكلمات الرئيسية", + "Import World Info": "استيراد معلومات العالم", + "Export World Info": "تصدير معلومات العالم", + "Duplicate World Info": "تكرار معلومات العالم", + "Delete World Info": "حذف معلومات العالم", + "Search...": "بحث...", + "Search": "يبحث", + "Priority": "أولوية", + "Custom": "مخصص", + "Title A-Z": "العنوان من أ-ي", + "Title Z-A": "العنوان من ي-أ", + "Tokens ↗": "الرموز ↗", + "Tokens ↘": "الرموز ↘", + "Depth ↗": "العمق ↗", + "Depth ↘": "العمق ↘", + "Order ↗": "الترتيب ↗", + "Order ↘": "الترتيب ↘", + "UID ↗": "معرف فريد ↗", + "UID ↘": "معرف فريد ↘", + "Trigger% ↗": "مشغل% ↗", + "Trigger% ↘": "مشغل% ↘", + "Refresh": "تحديث", + "User Settings": "إعدادات المستخدم", + "Simple": "بسيط", + "Advanced": "متقدم", + "UI Language": "لغة", + "Account": "حساب", + "Admin Panel": "لوحة الادارة", + "Logout": "تسجيل خروج", + "Search Settings": "إعدادات البحث", + "UI Theme": "مظهر واجهة المستخدم", + "Import a theme file": "استيراد ملف السمة", + "Export a theme file": "تصدير ملف موضوع", + "Delete a theme": "حذف موضوع", + "Update a theme file": "تحديث ملف السمة", + "Save as a new theme": "حفظ كسمة جديدة", + "Avatar Style:": "نمط الصورة الرمزية", + "Circle": "دائرة", + "Square": "مربع", + "Rectangle": "مستطيل", + "Chat Style:": "نمط الدردشة:", + "Flat": "مستوي\nفقاعات\nوثيقة", + "Bubbles": "فقاعات", + "Document": "وثيقة", + "Specify colors for your theme.": "تحديد الألوان للموضوع الخاص بك.", + "Theme Colors": "ألوان الموضوع", + "Main Text": "النص الرئيسي", + "Italics Text": "نص مائل", + "Underlined Text": "نص تحته خط", + "Quote Text": "نص الاقتباس", + "Shadow Color": "لون الظل", + "Chat Background": "خلفية الدردشة", + "UI Background": "خلفية الواجهة الرسومية", + "UI Border": "حدود الواجهة الرسومية", + "User Message Blur Tint": "تظليل رسالة المستخدم", + "AI Message Blur Tint": "تظليل رسالة الذكاء الاصطناعي", + "Chat Width": "عرض الدردشة", + "Width of the main chat window in % of screen width": "عرض نافذة الدردشة الرئيسية بنسبة % من عرض الشاشة", + "Font Scale": "مقياس الخط", + "Font size": "حجم الخط", + "Blur Strength": "قوة التمويه", + "Blur strength on UI panels.": "قوة التمويه على لوحات واجهة المستخدم.", + "Text Shadow Width": "عرض ظل النص", + "Strength of the text shadows": "قوة ظلال النص", + "Disables animations and transitions": "تعطيل الرسوم المتحركة والانتقالات", + "Reduced Motion": "تقليل الحركة", + "removes blur from window backgrounds": "إزالة الضبابية من خلفيات النوافذ لتسريع التقديم", + "No Blur Effect": "عدم وجود تأثير ضبابية", + "Remove text shadow effect": "إزالة تأثير الظل النصي", + "No Text Shadows": "عدم وجود ظلال للنص", + "Reduce chat height, and put a static sprite behind the chat window": "تقليل ارتفاع الدردشة ووضع صورة ثابتة خلف نافذة الدردشة", + "Waifu Mode": "وضع الوايفو", + "Always show the full list of the Message Actions context items for chat messages, instead of hiding them behind '...'": "إظهار دائمًا القائمة الكاملة لبنود سياق إجراءات الرسائل لرسائل الدردشة بدلاً من إخفائها خلف '...' ", + "Auto-Expand Message Actions": "توسيع إجراءات الرسالة تلقائيًا", + "Alternative UI for numeric sampling parameters with fewer steps": "واجهة مستخدم بديلة لمعلمات العينات الرقمية بعدد أقل من الخطوات", + "Zen Sliders": "منزلقات الزن", + "Entirely unrestrict all numeric sampling parameters": "رفع القيود عن جميع المعلمات الرقمية للعينات بالكامل", + "Mad Lab Mode": "وضع المختبر المجنون", + "Time the AI's message generation, and show the duration in the chat log": "توقيت إنتاج رسائل الذكاء الاصطناعي، وعرض المدة في سجل الدردشة", + "Message Timer": "مؤقت الرسالة", + "Show a timestamp for each message in the chat log": "إظهار الطابع الزمني لكل رسالة في سجل الدردشة", + "Chat Timestamps": "طوابع الزمن في الدردشة", + "Show an icon for the API that generated the message": "إظهار أيقونة للواجهة البرمجية التطبيقية التي أنشأت الرسالة", + "Model Icon": "أيقونة النموذج", + "Show sequential message numbers in the chat log": "إظهار أرقام الرسائل التسلسلية في سجل الدردشة", + "Message IDs": "معرفات الرسائل", + "Hide avatars in chat messages.": "إخفاء الصور الرمزية في رسائل الدردشة.", + "Hide Chat Avatars": "إخفاء الصور الرمزية للدردشة", + "Show the number of tokens in each message in the chat log": "عرض عدد الرموز في كل رسالة في سجل الدردشة", + "Show Message Token Count": "عرض عدد الرموز في الرسالة", + "Single-row message input area. Mobile only, no effect on PC": "منطقة إدخال رسالة بصف واحد. فقط للهواتف المحمولة، لا تؤثر على الكمبيوتر الشخصي", + "Compact Input Area (Mobile)": "منطقة إدخال مضغوطة (الهاتف المحمول)", + "In the Character Management panel, show quick selection buttons for favorited characters": "في لوحة إدارة الشخصيات، إظهار أزرار الاختيار السريع للشخصيات المفضلة", + "Characters Hotswap": "تبديل سريع للشخصيات", + "Enable magnification for zoomed avatar display.": "تمكين التكبير لعرض الصورة الرمزية المكبرة.", + "Avatar Hover Magnification": "الصورة الرمزية تحوم التكبير", + "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "لتمكين تأثير التكبير عند التمرير عند عرض الصورة الرمزية التي تم تكبيرها بعد النقر على صورة الصورة الرمزية في الدردشة.", + "Show tagged character folders in the character list": "عرض مجلدات الشخصيات الموسومة في قائمة الشخصيات", + "Tags as Folders": "الوسوم كمجلدات", + "Tags_as_Folders_desc": "التغيير الأخير: يجب وضع علامة على العلامات كمجلدات في قائمة إدارة العلامات لتظهر على هذا النحو. انقر هنا لعرضه.", + "Character Handling": "معالجة الشخصية", + "If set in the advanced character definitions, this field will be displayed in the characters list.": "إذا تم تعيينه في تعريفات الشخصيات المتقدمة، سيتم عرض هذا الحقل في قائمة الشخصيات.", + "Char List Subheader": "العنوان الفرعي لقائمة الأحرف", + "Character Version": "إصدار الشخصية", + "Created by": "تم إنشاؤه بواسطة", + "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "استخدام مطابقة غامضة، والبحث في الشخصيات في القائمة حسب جميع حقول البيانات، ليس فقط بواسطة جزء من الاسم", + "Advanced Character Search": "بحث متقدم عن الشخصيات", + "If checked and the character card contains a prompt override (System Prompt), use that instead": "إذا تم التحقق وكانت بطاقة الشخصية تحتوي على تجاوز للمطالبة (المطالبة النظامية)، استخدم ذلك بدلاً من ذلك", + "Prefer Character Card Prompt": "تفضيل التعليمات من بطاقة الشخصية", + "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "إذا تم التحقق وكانت بطاقة الشخصية تحتوي على تجاوز للكسر (تعليمات تاريخ المشاركة)، استخدم ذلك بدلاً من ذلك", + "Prefer Character Card Jailbreak": "تفضيل كسر الحصار من بطاقة الشخصية", + "never_resize_avatars_tooltip": "تجنب اقتصاص صور الأحرف المستوردة وتغيير حجمها. عند إيقاف التشغيل، قم بالقص/تغيير الحجم إلى 512 × 768.", + "Never resize avatars": "لا تغيير حجم الصور الرمزية أبدًا", + "Show actual file names on the disk, in the characters list display only": "عرض الأسماء الفعلية للملفات على القرص، في عرض قائمة الشخصيات فقط", + "Show avatar filenames": "عرض أسماء ملفات الصور الرمزية", + "Prompt to import embedded card tags on character import. Otherwise embedded tags are ignored": "طلب استيراد العلامات المضمنة في البطاقة عند استيراد الشخصية. في غير ذلك، تتم تجاهل العلامات المضمنة", + "Import Card Tags": "استيراد وسوم البطاقة", + "Hide character definitions from the editor panel behind a spoiler button": "إخفاء تعريفات الشخصيات من لوحة التحرير وراء زر التلميح", + "Spoiler Free Mode": "وضع خالٍ من حرق الاحداث", + "Miscellaneous": "متنوع", + "Reload and redraw the currently open chat": "إعادة تحميل وإعادة رسم الدردشة المفتوحة حاليًا", + "Reload Chat": "إعادة تحميل الدردشة", + "Debug Menu": "قائمة التصحيح", + "Smooth Streaming": "التدفق السلس", + "Experimental feature. May not work for all backends.": "الميزة التجريبية. قد لا تعمل مع جميع الواجهات الخلفية.", + "Slow": "بطيء", + "Fast": "سريع", + "Play a sound when a message generation finishes": "تشغيل صوت عند الانتهاء من إنشاء الرسالة", + "Message Sound": "صوت الرسالة", + "Only play a sound when ST's browser tab is unfocused": "تشغيل الصوت فقط عندما تكون علامة تبويب متصفح ST غير مركزة", + "Background Sound Only": "صوت الخلفية فقط", + "Reduce the formatting requirements on API URLs": "تقليل متطلبات التنسيق على عناوين URL الخاصة بالواجهة البرمجية التطبيقية", + "Relaxed API URLS": "عناوين URL لواجهة برمجة التطبيقات المرنة", + "Ask to import the World Info/Lorebook for every new character with embedded lorebook. If unchecked, a brief message will be shown instead": "اسأل لاستيراد معلومات العالم/دفتر السرد لكل شخصية جديدة مع دفتر سرد مضمن. إذا لم يتم التحقق، سيتم عرض رسالة موجزة بدلاً من ذلك", + "Lorebook Import Dialog": "مربع حوار استيراد كتاب المعرفة", + "Restore unsaved user input on page refresh": "استعادة الإدخالات غير المحفوظة للمستخدم عند تحديث الصفحة", + "Restore User Input": "استعادة إدخال المستخدم", + "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "السماح بإعادة تحديد موقع بعض عناصر واجهة المستخدم بسحبها. فقط للكمبيوتر، لا تؤثر على الهواتف المحمولة", + "Movable UI Panels": "لوحات واجهة المستخدم القابلة للتحريك", + "MovingUI preset. Predefined/saved draggable positions": "إعداد مسبق لواجهة المستخدم المتحركة. مواقع قابلة للسحب محددة/محفوظة مسبقًا", + "MUI Preset": "الإعداد المسبق لـ MUI:", + "Save movingUI changes to a new file": "حفظ التغييرات في واجهة المستخدم المتحركة في ملف جديد", + "Reset MovingUI panel sizes/locations.": "إعادة تعيين أحجام/مواقع لوحة MovingUI.", + "Apply a custom CSS style to all of the ST GUI": "تطبيق نمط CSS مخصص على كل واجهة ST", + "Custom CSS": "CSS مخصص", + "Expand the editor": "قم بتوسيع المحرر", + "Chat/Message Handling": "معالجة الدردشة/الرسائل", + "# Messages to Load": "# رسالة. للتحميل", + "The number of chat history messages to load before pagination.": "عدد رسائل سجل الدردشة التي يجب تحميلها قبل الترقيم الصفحي.", + "(0 = All)": "(0 = الكل)", + "Streaming FPS": "معدل الإطارات في البث", + "Update speed of streamed text.": "تحديث سرعة النص المتدفق.", + "Example Messages Behavior": "سلوك الرسائل المثالية", + "Gradual push-out": "طرد تدريجي", + "Always include examples": "تضمين الأمثلة دائمًا", + "Never include examples": "عدم تضمين الأمثلة أبدًا", + "Send on Enter": "إرسال عند الضغط على Enter", + "Disabled": "معطل", + "Automatic (PC)": "تلقائي (الكمبيوتر الشخصي)", + "Press Send to continue": "اضغط على 'إرسال' للمتابعة", + "Show a button in the input area to ask the AI to continue (extend) its last message": "عرض زر في منطقة الإدخال لطلب من الذكاء الاصطناعي المتابعة (تمديد) رسالته الأخيرة", + "Quick 'Continue' button": "زر 'متابعة' السريع", + "Show arrow buttons on the last in-chat message to generate alternative AI responses. Both PC and mobile": "عرض أزرار السهم على آخر رسالة في الدردشة لإنشاء ردود ذكاء اصطناعي بديلة. على الكمبيوتر الشخصي والهاتف المحمول", + "Swipes": "انزلاقات", + "Allow using swiping gestures on the last in-chat message to trigger swipe generation. Mobile only, no effect on PC": "السماح باستخدام إيماءات السحب على آخر رسالة في الدردشة لتشغيل إنشاء السحب. فقط على الهاتف المحمول، لا تؤثر على الكمبيوتر الشخصي", + "Gestures": "الإيماءات", + "Auto-load Last Chat": "تحميل الدردشة الأخيرة تلقائيًا", + "Auto-scroll Chat": "التمرير التلقائي للدردشة", + "Save edits to messages without confirmation as you type": "حفظ التحريرات في الرسائل دون تأكيد أثناء الكتابة", + "Auto-save Message Edits": "حفظ التعديلات التلقائي للرسائل", + "Confirm message deletion": "تأكيد حذف الرسالة", + "Auto-fix Markdown": "إصلاح Markdown تلقائيًا", + "Disallow embedded media from other domains in chat messages": "عدم السماح بالوسائط المضمنة من المجالات الأخرى في رسائل الدردشة.", + "Forbid External Media": "منع وسائط خارجية", + "Allow {{char}}: in bot messages": "السماح بـ {{char}}: في رسائل البوت", + "Allow {{user}}: in bot messages": "السماح بـ {{user}}: في رسائل البوت", + "Skip encoding and characters in message text, allowing a subset of HTML markup as well as Markdown": "تخطي الترميز للأحرف < و > في نص الرسالة، مما يسمح بمجموعة فرعية من العلامات التنسيقية HTML وكذلك Markdown", + "Show tags in responses": "عرض الوسوم في الردود", + "Allow AI messages in groups to contain lines spoken by other group members": "السماح لرسائل الذكاء الاصطناعي في المجموعات بأن تحتوي على أسطر يتحدثها أعضاء المجموعة الآخرين", + "Relax message trim in Groups": "تخفيف تقليم الرسائل في المجموعات", + "Log prompts to console": "تسجيل التعليمات إلى وحدة التحكم", + "Requests logprobs from the API for the Token Probabilities feature": "يطلب logprobs من الواجهة البرمجية التطبيقية لميزة الرموز الاحتمالية", + "Request token probabilities": "احتماليات طلب الرمز", + "Automatically reject and re-generate AI message based on configurable criteria": "رفض الرسالة التي تم إنشاؤها تلقائيًا وإعادة إنشاءها بناءً على معايير قابلة للتكوين", + "Auto-swipe": "السحب التلقائي", + "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "تمكين وظيفة السحب التلقائي. الإعدادات في هذا القسم تؤثر فقط عند تمكين السحب التلقائي", + "Minimum generated message length": "الحد الأدنى لطول الرسالة المولدة", + "If the generated message is shorter than these many characters, trigger an auto-swipe": "إذا كانت الرسالة المولدة أقصر من هذا، فتحريض السحب التلقائي", + "Blacklisted words": "الكلمات الممنوعة", + "words you dont want generated separated by comma ','": "الكلمات التي لا تريد توليدها مفصولة بفاصلة ','", + "Blacklisted word count to swipe": "عدد الكلمات الممنوعة للسحب", + "Minimum number of blacklisted words detected to trigger an auto-swipe": "الحد الأدنى لعدد الكلمات في القائمة السوداء المكتشفة لتشغيل السحب التلقائي.", + "AutoComplete Settings": "إعدادات الإكمال التلقائي", + "Automatically hide details": "إخفاء التفاصيل تلقائيًا", + "Determines how entries are found for autocomplete.": "تحديد كيفية العثور على الإدخالات للإكمال التلقائي.", + "Autocomplete Matching": "مطابقة", + "Starts with": "ابدا ب", + "Includes": "يشمل", + "Fuzzy": "أجعد", + "Sets the style of the autocomplete.": "يضبط نمط الإكمال التلقائي.", + "Autocomplete Style": "أسلوب", + "Follow Theme": "اتبع الموضوع", + "Dark": "مظلم", + "Sets the font size of the autocomplete.": "يضبط حجم الخط للإكمال التلقائي.", + "Sets the width of the autocomplete.": "يضبط عرض الإكمال التلقائي.", + "Autocomplete Width": "عرض", + "chat input box": "مربع إدخال الدردشة", + "entire chat width": "عرض الدردشة بالكامل", + "full window width": "عرض النافذة بالكامل", + "STscript Settings": "إعدادات ستسكريبت", + "Sets default flags for the STscript parser.": "يقوم بتعيين العلامات الافتراضية لمحلل STscript.", + "Parser Flags": "أعلام المحلل اللغوي", + "Switch to stricter escaping, allowing all delimiting characters to be escaped with a backslash, and backslashes to be escaped as well.": "قم بالتبديل إلى الهروب الأكثر صرامة، مما يسمح بالهروب من جميع الأحرف المحددة باستخدام شرطة مائلة عكسية، كما يمكن الهروب من الخطوط المائلة العكسية أيضًا.", + "STRICT_ESCAPING": "STRICT_ESCAPING", + "Replace all {{getvar::}} and {{getglobalvar::}} macros with scoped variables to avoid double macro substitution.": "استبدل كافة وحدات الماكرو {{getvar::}} و{{getglobalvar::}} بمتغيرات محددة النطاق لتجنب استبدال الماكرو المزدوج.", + "REPLACE_GETVAR": "REPLACE_GETVAR", + "Change Background Image": "تغيير صورة الخلفية", + "Filter": "تصفية", + "Automatically select a background based on the chat context": "تحديد خلفية تلقائيًا استنادًا إلى سياق الدردشة", + "Auto-select": "التحديد التلقائي", + "System Backgrounds": "خلفيات النظام", + "Chat Backgrounds": "خلفيات الدردشة", + "bg_chat_hint_1": "خلفيات الدردشة التي تم إنشاؤها باستخدام", + "bg_chat_hint_2": "سوف يظهر الامتداد هنا", + "Extensions": "امتدادات", + "Notify on extension updates": "الإخطار بالتحديثات الإضافية", + "Manage extensions": "إدارة الامتدادات", + "Import Extension From Git Repo": "استيراد الامتداد من مستودع Git", + "Install extension": "تثبيت الامتداد", + "Extras API:": "واجهة برمجة التطبيقات الإضافية:", + "Auto-connect": "الاتصال التلقائي", + "Extras API URL": "عنوان URL لواجهة برمجة التطبيقات الإضافية", + "Extras API key (optional)": "مفتاح API الإضافي (اختياري)", + "Persona Management": "إدارة الشخصية", + "How do I use this?": "كيف يمكنني استخدام هذا؟", + "Click for stats!": "انقر للحصول على الإحصائيات!", + "Usage Stats": "إحصائيات الاستخدام", + "Backup your personas to a file": "انسخ نسخة احتياطية من شخصياتك إلى ملف", + "Backup": "نسخة احتياطية", + "Restore your personas from a file": "استعادة شخصياتك من ملف", + "Restore": "استعادة", + "Create a dummy persona": "إنشاء شخصية وهمية", + "Create": "إنشاء", + "Toggle grid view": "تبديل عرض الشبكة", + "No persona description": "[بدون وصف]", + "Name": "الاسم", + "Enter your name": "أدخل اسمك", + "Click to set a new User Name": "انقر لتعيين اسم مستخدم جديد", + "Click to lock your selected persona to the current chat. Click again to remove the lock.": "انقر لتأمين الشخصية المحددة إلى الدردشة الحالية. انقر مرة أخرى لإزالة القفل.", + "Click to set user name for all messages": "انقر لتعيين اسم المستخدم لجميع الرسائل", + "Persona Description": "وصف الشخصية", + "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "مثال: [{{user}} هي فتاة على شكل قطة رومانية عمرها 28 عامًا.]", + "Tokens persona description": "الرموز", + "Position:": "الموضع:", + "In Story String / Prompt Manager": "في سلسلة القصة / إدارة التعليمات", + "Top of Author's Note": "أعلى ملاحظة المؤلف", + "Bottom of Author's Note": "أسفل ملاحظة المؤلف", + "In-chat @ Depth": "داخل الدردشة @ العمق", + "Depth:": "العمق:", + "Role:": "دور:", + "System": "نظام", + "User": "مستخدم", + "Assistant": "مساعد", + "Show notifications on switching personas": "إظهار الإشعارات عند التبديل بين الشخصيات", + "Character Management": "إدارة الشخصيات", + "Locked = Character Management panel will stay open": "مقفل = ستبقى لوحة إدارة الشخصيات مفتوحة", + "Select/Create Characters": "اختر / إنشاء الشخصيات", + "Favorite characters to add them to HotSwaps": "اختر الشخصيات المفضلة لإضافتها إلى HotSwaps", + "Token counts may be inaccurate and provided just for reference.": "قد تكون عدادات الرموز غير دقيقة وتُقدم فقط للإشارة.", + "Total tokens": "مجموع الرموز", + "Calculating...": "جارٍ الحساب...", + "Tokens": "الرموز", + "Permanent tokens": "الرموز الدائمة", + "Permanent": "دائم", + "About Token 'Limits'": "حول \"حدود\" الرمز المميز", + "Toggle character info panel": "تبديل لوحة معلومات الشخصية", + "Name this character": "اسم هذا الشخصية", + "extension_token_counter": "الرموز:", + "Click to select a new avatar for this character": "انقر لتحديد صورة رمزية جديدة لهذه الشخصية", + "Add to Favorites": "أضف إلى المفضلة", + "Advanced Definition": "تعريف متقدم", + "Character Lore": "قصة الشخصية", + "Chat Lore": "تقاليد الدردشة", + "Export and Download": "تصدير وتنزيل", + "Duplicate Character": "تكرار الشخصية", + "Create Character": "إنشاء شخصية", + "Delete Character": "حذف الشخصية", + "More...": "المزيد...", + "Link to World Info": "رابط لمعلومات العالم", + "Import Card Lore": "استيراد البطاقة السردية", + "Scenario Override": "تجاوز السيناريو", + "Convert to Persona": "تحويل إلى شخصية", + "Rename": "إعادة التسمية", + "Link to Source": "رابط إلى المصدر", + "Replace / Update": "استبدال / تحديث", + "Import Tags": "استيراد العلامات", + "Search / Create Tags": "البحث / إنشاء العلامات", + "View all tags": "عرض جميع العلامات", + "Creator's Notes": "ملاحظات الصانع", + "Show / Hide Description and First Message": "إظهار / إخفاء الوصف والرسالة الأولى", + "Character Description": "وصف الشخصية", + "Click to allow/forbid the use of external media for this character.": "انقر للسماح/منع استخدام الوسائط الخارجية لهذه الشخصية.", + "Ext. Media": "تحويلة. وسائط", + "Describe your character's physical and mental traits here.": "صف صفات شخصيتك الجسدية والعقلية هنا.", + "First message": "الرسالة الأولى", + "Click to set additional greeting messages": "انقر لتعيين رسائل تحية إضافية", + "Alt. Greetings": "بديل. تحيات", + "This will be the first message from the character that starts every chat.": "سيكون هذا أول رسالة من الشخصية التي تبدأ كل دردشة.", + "Group Controls": "ضوابط المجموعة", + "Chat Name (Optional)": "اسم المحادثة (اختياري)", + "Click to select a new avatar for this group": "انقر لتحديد صورة رمزية جديدة لهذه المجموعة", + "Group reply strategy": "استراتيجية الرد في المجموعة", + "Natural order": "الترتيب الطبيعي", + "List order": "ترتيب القائمة", + "Group generation handling mode": "وضع التعامل مع إنشاء المجموعة", + "Swap character cards": "مبادلة بطاقات الشخصية", + "Join character cards (exclude muted)": "الانضمام إلى بطاقات الشخصيات (استبعاد كتم الصوت)", + "Join character cards (include muted)": "انضم إلى بطاقات الشخصيات (بما في ذلك البطاقات الصامتة)", + "Inserted before each part of the joined fields.": "تم إدراجه قبل كل جزء من الحقول المرتبطة.", + "Join Prefix": "الانضمام إلى البادئة", + "When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and with the name of the part (e.g.: description, personality, scenario, etc.)": "عند تحديد \"الانضمام إلى بطاقات الأحرف\"، يتم ضم كافة الحقول الخاصة بالأحرف معًا.\rوهذا يعني أنه في سلسلة القصة على سبيل المثال، سيتم دمج جميع أوصاف الشخصيات في نص واحد كبير.\rإذا كنت تريد فصل هذه الحقول، فيمكنك تحديد بادئة أو لاحقة هنا.\r\rتدعم هذه القيمة وحدات الماكرو العادية وستستبدل أيضًا {{char}} باسم الحرف ذي الصلة و باسم الجزء (على سبيل المثال: الوصف، والشخصية، والسيناريو، وما إلى ذلك)", + "Inserted after each part of the joined fields.": "يتم إدراجه بعد كل جزء من الحقول المرتبطة.", + "Join Suffix": "انضم إلى لاحقة", + "Set a group chat scenario": "تعيين سيناريو للمحادثة الجماعية", + "Click to allow/forbid the use of external media for this group.": "انقر للسماح/منع استخدام الوسائط الخارجية لهذه المجموعة.", + "Restore collage avatar": "استعادة الصورة الرمزية للشخصية", + "Allow self responses": "السماح بالرد على الذات", + "Auto Mode": "الوضع التلقائي", + "Auto Mode delay": "تأخير الوضع التلقائي", + "Hide Muted Member Sprites": "إخفاء أعضاء Sprites المكتومة", + "Current Members": "الأعضاء الحاليين", + "Add Members": "إضافة أعضاء", + "Create New Character": "إنشاء شخصية جديدة", + "Import Character from File": "استيراد شخصية من ملف", + "Import content from external URL": "استيراد المحتوى من عنوان URL الخارجي", + "Create New Chat Group": "إنشاء مجموعة دردشة جديدة", + "Characters sorting order": "ترتيب فرز الشخصيات", + "A-Z": "أ-ي", + "Z-A": "ي-أ", + "Newest": "الأحدث", + "Oldest": "الأقدم", + "Favorites": "المفضلة", + "Recent": "الأخيرة", + "Most chats": "معظم الدردشات", + "Least chats": "أقل الدردشات", + "Most tokens": "معظم الرموز", + "Least tokens": "أقل الرموز", + "Random": "عشوائي", + "Toggle character grid view": "تبديل طريقة عرض الى شبكة للشخصيات", + "Bulk_edit_characters": "تحرير الشخصيات جميعها", + "Bulk select all characters": "تحديد كافة الشخصيات بالجملة", + "Bulk delete characters": "حذف الشخصيات جميعها", + "popup-button-save": "يحفظ", + "popup-button-yes": "نعم", + "popup-button-no": "لا", + "popup-button-cancel": "يلغي", + "popup-button-import": "يستورد", + "Advanced Definitions": "تعريفات متقدمة", + "Prompt Overrides": "التجاوزات السريعة", + "(For Chat Completion and Instruct Mode)": "(لاستكمال الدردشة ووضع التعليمات)", + "Insert {{original}} into either box to include the respective default prompt from system settings.": "أدخل {{original}} في أي مربع لتضمين التعليمات الافتراضية المعنية من إعدادات النظام.", + "Main Prompt": "التعليمات الرئيسية", + "Any contents here will replace the default Main Prompt used for this character. (v2 spec: system_prompt)": "سيحل أي محتوى هنا محل التعليمة الرئيسية الافتراضية المستخدمة لهذا الشخصية.", + "Any contents here will replace the default Jailbreak Prompt used for this character. (v2 spec: post_history_instructions)": "سيحل أي محتوى هنا محل التعليمة الافتراضية لكسر الحجز المستخدمة لهذا الشخصية.", + "Creator's Metadata (Not sent with the AI prompt)": "بيانات التعريف للمنشئ (لا يتم إرسالها مع التعليمات الذكية)", + "Creator's Metadata": "البيانات الوصفية للمنشئ", + "(Not sent with the AI Prompt)": "(لم يتم إرساله مع موجه الذكاء الاصطناعي)", + "Everything here is optional": "كل ما هو هنا اختياري", + "(Botmaker's name / Contact Info)": "اسم المطور / معلومات الاتصال", + "(If you want to track character versions)": "(إذا كنت ترغب في تتبع إصدارات الشخصية)", + "(Describe the bot, give use tips, or list the chat models it has been tested on. This will be displayed in the character list.)": "(صف الروبوت، وأعطي استخدام النصائح، أو قائمة النماذج الدردشة التي تم اختبارها. سيتم عرض هذا في قائمة الشخصيات.)", + "Tags to Embed": "العلامات المضمنة", + "(Write a comma-separated list of tags)": "(اكتب قائمة بفواصل مفصولة للعلامات)", + "Personality summary": "ملخص الشخصية", + "(A brief description of the personality)": "(وصف موجز للشخصية)", + "Scenario": "السيناريو", + "(Circumstances and context of the interaction)": "(الظروف والسياق للتفاعل)", + "Character's Note": "ملاحظة الشخصية", + "(Text to be inserted in-chat @ designated depth and role)": "(النص الذي سيتم إدراجه في الدردشة عند العمق والدور المحددين)", + "@ Depth": "@ العمق", + "Role": "دور", + "Talkativeness": "الكلام", + "How often the character speaks in group chats!": "كيفية تحدث الشخصية في محادثات المجموعة!", + "How often the character speaks in": "كم مرة تتحدث الشخصية في", + "group chats!": "الدردشات الجماعية!", + "Shy": "خجول", + "Normal": "عادي", + "Chatty": "محادث", + "Examples of dialogue": "أمثلة على الحوار", + "Important to set the character's writing style.": "مهم لتحديد نمط كتابة الشخصية.", + "(Examples of chat dialog. Begin each example with START on a new line.)": "(أمثلة على حوار الدردشة. ابدأ كل مثال بـ START في سطر جديد.)", + "Save": "حفظ", + "Chat History": "تاريخ الدردشة", + "Import Chat": "استيراد الدردشة", + "Copy to system backgrounds": "نسخ إلى خلفيات النظام", + "Rename background": "إعادة تسمية الخلفية", + "Lock": "قفل", + "Unlock": "الغاء القفل", + "Delete background": "حذف الخلفية", + "Chat Scenario Override": "تجاوز سيناريو الدردشة", + "Remove": "إزالة", + "Type here...": "اكتب هنا...", + "Chat Lorebook": "دردشة Lorebook ل", + "Chat Lorebook for": "دردشة Lorebook ل", + "chat_world_template_txt": "سيتم ربط معلومات العالم المحددة بهذه الدردشة. عند إنشاء رد AI،\n سيتم دمجه مع الإدخالات من كتب التراث العالمية والشخصية.", + "Select a World Info file for": "حدد ملف معلومات العالم لـ", + "Primary Lorebook": "سجل قصة أساسي", + "A selected World Info will be bound to this character as its own Lorebook.": "ستُرتبط معلومات العالم المحددة بهذه الشخصية كسجل قصة خاص بها.", + "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "عند إنشاء رد من الذكاء الاصطناعي، سيتم دمجه مع الإدخالات من محدد معلومات العالم العالمي.", + "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "سيقوم تصدير الشخصية أيضًا بتصدير ملف سجل القصة المحدد المضمن في البيانات JSON.", + "Additional Lorebooks": "سجلات قصص إضافية", + "Associate one or more auxillary Lorebooks with this character.": "ربط سجلات قصص إضافية واحدة أو أكثر مع هذه الشخصية.", + "NOTE: These choices are optional and won't be preserved on character export!": "ملاحظة: هذه الاختيارات اختيارية ولن تتم الاحتفاظ بها عند تصدير الشخصية!", + "Rename chat file": "إعادة تسمية ملف الدردشة", + "Export JSONL chat file": "تصدير ملف الدردشة بتنسيق JSONL", + "Download chat as plain text document": "تنزيل الدردشة كمستند نصي عادي", + "Delete chat file": "حذف ملف الدردشة", + "Use tag as folder": "وضع علامة كمجلد", + "Delete tag": "حذف العلامة", + "Entry Title/Memo": "عنوان الإدخال/المذكرة", + "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized❌ Disabled": "حالة دخول وي:\r🔵 ثابت\r🟢 عادي\r🔗 ناقل\r❌ معطل", + "WI_Entry_Status_Constant": "ثابت", + "WI_Entry_Status_Normal": "طبيعي", + "WI_Entry_Status_Vectorized": "متجه", + "WI_Entry_Status_Disabled": "عاجز", + "T_Position": "↑Char: قبل تحديدات الشخصية\n↓Char: بعد تحديدات الشخصية\n↑AN: قبل الملاحظات الخاصة بالمؤلف\n↓AN: بعد الملاحظات الخاصة بالمؤلف\n@D: على عمق", + "Before Char Defs": "↑تحديد الشخصية", + "After Char Defs": "↓تحديد الشخصية", + "Before EM": "↑ م", + "After EM": "↓م", + "Before AN": "↑AN", + "After AN": "↓AN", + "at Depth System": "@د ⚙️", + "at Depth User": "@د 👤", + "at Depth AI": "@د 🤖", + "Depth": "عمق", + "Order:": "الترتيب:", + "Order": "الترتيب:", + "Trigger %:": "مشغل ٪:", + "Probability": "احتمالا", + "Duplicate world info entry": "إدخال معلومات العالم المكررة", + "Delete world info entry": "حذف إدخال معلومات العالم", + "Comma separated (required)": "فاصلة مفصولة (مطلوب)", + "Primary Keywords": "الكلمات الأساسية", + "Keywords or Regexes": "الكلمات الرئيسية أو Regexes", + "Comma separated list": "قائمة مفصولة بفواصل", + "Switch to plaintext mode": "التبديل إلى وضع النص العادي", + "Logic": "منطق", + "AND ANY": "و ,أي شيء", + "AND ALL": "و,الجميع", + "NOT ALL": "ليس كل", + "NOT ANY": " لا , لأي شيء", + "(ignored if empty)": "(يتم تجاهله إذا كان فارغًا)", + "Optional Filter": "تصفية اختيارية", + "Keywords or Regexes (ignored if empty)": "الكلمات الرئيسية أو التعابير العادية (يتم تجاهلها إذا كانت فارغة)", + "Comma separated list (ignored if empty)": "قائمة مفصولة بفواصل (يتم تجاهلها إذا كانت فارغة)", + "Use global setting": "استخدام الإعداد العام", + "Case-Sensitive": "حساس لحالة الأحرف", + "Yes": "نعم", + "No": "لا", + "Can be used to automatically activate Quick Replies": "يمكن استخدامه لتنشيط الردود السريعة تلقائيًا", + "Automation ID": "معرف الأتمتة", + "( None )": "( لا أحد )", + "Content": "المحتوى", + "Exclude from recursion": "استبعاد من التكرار", + "Prevent further recursion (this entry will not activate others)": "منع المزيد من التكرار (هذا الإدخال لن ينشط الإدخالات الأخرى)", + "Delay until recursion (this entry can only be activated on recursive checking)": "التأخير حتى العودية (لا يمكن تفعيل هذا الإدخال إلا عند التحقق العودي)", + "What this keyword should mean to the AI, sent verbatim": "ما يجب أن يعني هذا الكلمة الرئيسية للذكاء الاصطناعي، ترسل حرفيًا", + "Filter to Character(s)": "تصفية إلى الشخصيات", + "Character Exclusion": "استبعاد الشخصيات", + "-- Characters not found --": "-- الشخصيات غير موجودة --", + "Inclusion Group": "مجموعة الإدراج", + "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "تضمن مجموعات التضمين تنشيط إدخال واحد فقط من المجموعة في المرة الواحدة، إذا تم تشغيل عدة إدخالات.\rيدعم مجموعات متعددة مفصولة بفواصل.\r\rالتوثيق: معلومات العالم - مجموعة الإدماج", + "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "إعطاء الأولوية لهذا الإدخال: عند تحديده، يتم إعطاء الأولوية لهذا الإدخال من بين جميع التحديدات.\rإذا تم تحديد الأولوية لأكثر من مجموعة، فسيتم اختيار \"الترتيب\" الأعلى.", + "Only one entry with the same label will be activated": "سيتم تنشيط مدخل واحد فقط بنفس العلامة", + "A relative likelihood of entry activation within the group": "احتمال نسبي لتفعيل الدخول داخل المجموعة", + "Group Weight": "وزن المجموعة", + "Selective": "انتقائي", + "Use Probability": "استخدم الاحتمالية", + "Add Memo": "إضافة مذكرة", + "Text or token ids": "نص أو [معرفات الرمز المميز]", + "close": "يغلق", + "prompt_manager_edit": "يحرر", + "prompt_manager_name": "اسم", + "A name for this prompt.": "اسم لهذه المطالبة.", + "To whom this message will be attributed.": "لمن ستنسب هذه الرسالة؟", + "AI Assistant": "مساعد الذكاء الاصطناعي", + "prompt_manager_position": "موضع", + "Injection position. Next to other prompts (relative) or in-chat (absolute).": "موضع الحقن. بجوار المطالبات الأخرى (نسبية) أو داخل الدردشة (مطلقة).", + "prompt_manager_relative": "نسبي", + "prompt_manager_depth": "عمق", + "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "عمق الحقن. 0 = بعد الرسالة الأخيرة، 1 = قبل الرسالة الأخيرة، الخ.", + "Prompt": "موضوع", + "The prompt to be sent.": "المطالبة ليتم إرسالها.", + "This prompt cannot be overridden by character cards, even if overrides are preferred.": "لا يمكن تجاوز هذه المطالبة بواسطة بطاقات الأحرف، حتى إذا كان التجاوزات مفضلاً.", + "prompt_manager_forbid_overrides": "منع التجاوزات", + "reset": "إعادة ضبط", + "save": "يحفظ", + "This message is invisible for the AI": "هذه الرسالة غير مرئية للذكاء الاصطناعي", + "Message Actions": "إجراءات الرسالة", + "Translate message": "ترجمة الرسالة", + "Generate Image": "إنشاء صورة", + "Narrate": "سرد", + "Exclude message from prompts": "استثناء الرسالة من التلميحات", + "Include message in prompts": "تضمين الرسالة في التلميحات", + "Embed file or image": "تضمين ملف أو صورة", + "Create checkpoint": "إنشاء نقطة تفتيش", + "Create Branch": "إنشاء فرع", + "Copy": "نسخ", + "Open checkpoint chat": "فتح دردشة نقطة التفتيش", + "Edit": "تعديل", + "Confirm": "تأكيد", + "Copy this message": "نسخ هذه الرسالة", + "Delete this message": "حذف هذه الرسالة", + "Move message up": "نقل الرسالة لأعلى", + "Move message down": "نقل الرسالة لأسفل", + "Enlarge": "تكبير", + "Welcome to SillyTavern!": "مرحبا بكم في SillyTavern!", + "welcome_message_part_1": "إقرأ ال", + "welcome_message_part_2": "التوثيق الرسمي", + "welcome_message_part_3": null, + "welcome_message_part_4": "يكتب", + "welcome_message_part_5": "في الدردشة للأوامر ووحدات الماكرو.", + "welcome_message_part_6": "انضم الي", + "Discord server": "خادم الخلاف", + "welcome_message_part_7": "للحصول على المعلومات والإعلانات.", + "SillyTavern is aimed at advanced users.": "يستهدف SillyTavern المستخدمين المتقدمين.", + "If you're new to this, enable the simplified UI mode below.": "إذا كنت جديدًا على هذا، فقم بتمكين وضع واجهة المستخدم المبسطة أدناه.", + "Change it later in the 'User Settings' panel.": "قم بتغييره لاحقًا في لوحة \"إعدادات المستخدم\".", + "Enable simple UI mode": "تمكين وضع واجهة المستخدم البسيطة", + "Looking for AI characters?": "هل تبحث عن شخصيات الذكاء الاصطناعي؟", + "onboarding_import": "يستورد", + "from supported sources or view": "من المصادر المدعومة أو العرض", + "Sample characters": "شخصيات عينة", + "Your Persona": "شخصيتك", + "Before you get started, you must select a persona name.": "قبل البدء، يجب عليك تحديد اسم شخصي.", + "welcome_message_part_8": "يمكن تغيير هذا في أي وقت عبر", + "welcome_message_part_9": "أيقونة.", + "Persona Name:": "اسم الشخصية:", + "Temporarily disable automatic replies from this character": "تعطيل الردود التلقائية مؤقتًا من هذه الشخصية", + "Enable automatic replies from this character": "تمكين الردود التلقائية من هذه الشخصية", + "Trigger a message from this character": "تفعيل رسالة من هذه الشخصية", + "Move up": "نقل لأعلى", + "Move down": "نقل لأسفل", + "View character card": "عرض بطاقة الشخصية", + "Remove from group": "إزالة من المجموعة", + "Add to group": "إضافة إلى المجموعة", + "Alternate Greetings": "تحية بديلة", + "Alternate_Greetings_desc": "سيتم عرضها كتمريرات سريعة على الرسالة الأولى عند بدء محادثة جديدة.\n يمكن لأعضاء المجموعة اختيار واحد منهم لبدء المحادثة.", + "Alternate Greetings Hint": "انقر فوق الزر للبدء!", + "(This will be the first message from the character that starts every chat)": "(سيكون هذا أول رسالة من الشخصية التي تبدأ كل دردشة)", + "Forbid Media Override explanation": "قدرة الشخصية/المجموعة الحالية على استخدام الوسائط الخارجية في المحادثات.", + "Forbid Media Override subtitle": "الوسائط: الصور ومقاطع الفيديو والصوت. خارجي: غير مستضاف على الخادم المحلي.", + "Always forbidden": "ممنوع دائما", + "Always allowed": "دائما مسموح", + "View contents": "عرض المحتويات", + "Remove the file": "قم بإزالة الملف", + "Unique to this chat": "فريدة من نوعها لهذه الدردشة", + "Checkpoints inherit the Note from their parent, and can be changed individually after that.": "ترث نقاط التفتيش الملاحظة من أصلها، ويمكن تغييرها بشكل فردي بعد ذلك.", + "Include in World Info Scanning": "تضمين في مسح المعلومات العالمية", + "Before Main Prompt / Story String": "قبل الموجه الرئيسي/سلسلة القصة", + "After Main Prompt / Story String": "بعد الموجه الرئيسي/سلسلة القصة", + "as": "مثل", + "Insertion Frequency": "تردد الإدراج", + "(0 = Disable, 1 = Always)": "(0 = تعطيل، 1 = دائمًا)", + "User inputs until next insertion:": "مدخلات المستخدم حتى الإدراج التالي:", + "Character Author's Note (Private)": "ملاحظة مؤلف الشخصية (خاصة)", + "Won't be shared with the character card on export.": "لن تتم مشاركتها مع بطاقة الشخصية عند التصدير.", + "Will be automatically added as the author's note for this character. Will be used in groups, but can't be modified when a group chat is open.": "ستتم إضافتها تلقائيًا كملاحظة المؤلف لهذه الشخصية. سيتم استخدامها في مجموعات، ولكن\n لا يمكن تعديلها عندما تكون الدردشة الجماعية مفتوحة.", + "Use character author's note": "استخدم ملاحظة مؤلف الشخصية", + "Replace Author's Note": "استبدال ملاحظة المؤلف", + "Default Author's Note": "ملاحظة المؤلف الافتراضية", + "Will be automatically added as the Author's Note for all new chats.": "سيتم إضافتها تلقائيًا كملاحظة المؤلف لجميع الدردشات الجديدة.", + "Chat CFG": "الدردشة سي إف جي", + "1 = disabled": "1 = معطل", + "write short replies, write replies using past tense": "كتابة ردود قصيرة، وكتابة الردود باستخدام الزمن الماضي", + "Positive Prompt": "موجه إيجابي", + "Use character CFG scales": "استخدم مقاييس الأحرف CFG", + "Character CFG": "حرف CFG", + "Will be automatically added as the CFG for this character.": "ستتم إضافتها تلقائيًا كـ CFG لهذه الشخصية.", + "Global CFG": "سي إف جي العالمية", + "Will be used as the default CFG options for every chat unless overridden.": "سيتم استخدامه كخيارات CFG الافتراضية لكل دردشة ما لم يتم تجاوزه.", + "CFG Prompt Cascading": "CFG المتتالية السريعة", + "Combine positive/negative prompts from other boxes.": "اجمع بين المطالبات الإيجابية والسلبية من الصناديق الأخرى.", + "For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string.": "على سبيل المثال، يؤدي تحديد مربعات الدردشة والعمومية والأحرف إلى دمج كافة المطالبات السلبية في سلسلة مفصولة بفواصل.", + "Always Include": "تضمين دائما", + "Chat Negatives": "سلبيات الدردشة", + "Character Negatives": "سلبيات الشخصية", + "Global Negatives": "السلبيات العالمية", + "Custom Separator:": "فاصل مخصص:", + "Insertion Depth:": "عمق الإدخال:", + "Token Probabilities": "احتمالات الرمز", + "Select a token to see alternatives considered by the AI.": "حدد رمزًا مميزًا لرؤية البدائل التي ينظر فيها الذكاء الاصطناعي.", + "Not connected to API!": "غير متصل بواجهة برمجة التطبيقات!", + "Type a message, or /? for help": "اكتب رسالة، أو /؟ للمساعدة", + "Continue script execution": "متابعة تنفيذ البرنامج النصي", + "Pause script execution": "إيقاف تنفيذ البرنامج النصي مؤقتًا", + "Abort script execution": "إحباط تنفيذ البرنامج النصي", + "Abort request": "إلغاء الطلب", + "Continue the last message": "متابعة الرسالة الأخيرة", + "Send a message": "إرسال رسالة", + "Close chat": "إغلاق الدردشة", + "Toggle Panels": "تبديل اللوحات", + "Back to parent chat": "العودة إلى الدردشة الأصلية", + "Save checkpoint": "حفظ نقطة التفتيش", + "Convert to group": "تحويل إلى مجموعة", + "Start new chat": "بدء دردشة جديدة", + "Manage chat files": "إدارة ملفات الدردشة", + "Delete messages": "حذف الرسائل", + "Regenerate": "إعادة توليد", + "Ask AI to write your message for you": "طلب من الذكاء الاصطناعي كتابة رسالتك لك", + "Impersonate": "تقمص الشخصية", + "Continue": "استمر", + "Bind user name to that avatar": "ربط اسم المستخدم بتلك الصورة الرمزية", + "Change persona image": "تغيير صورة الشخصية", + "Select this as default persona for the new chats.": "تحديد هذا كشخصية افتراضية للمحادثات الجديدة.", + "Delete persona": "حذف الشخصية", + "These characters are the winners of character design contests and have outstandable quality.": "هذه الشخصيات هي الفائزة في مسابقات تصميم الشخصيات وتتمتع بجودة رائعة.", + "Contest Winners": "الفائزين في المسابقة", + "These characters are the finalists of character design contests and have remarkable quality.": "هذه الشخصيات هي المتأهلين للتصفيات النهائية في مسابقات تصميم الشخصيات وتتمتع بجودة رائعة.", + "Featured Characters": "شخصيات مميزة", + "Attach a File": "إرفاق ملف", + "Open Data Bank": "بنك البيانات المفتوح", + "Enter a URL or the ID of a Fandom wiki page to scrape:": "أدخل عنوان URL أو معرف صفحة ويكي Fandom لجمعها:", + "Examples:": "أمثلة:", + "Example:": "مثال:", + "Single file": "ملف واحد", + "All articles will be concatenated into a single file.": "سيتم تجميع كافة المقالات في ملف واحد.", + "File per article": "ملف لكل مقالة", + "Each article will be saved as a separate file.": "لا ينصح. سيتم حفظ كل مقالة كملف منفصل.", + "Data Bank": "بنك المعلومات", + "These files will be available for extensions that support attachments (e.g. Vector Storage).": "ستكون هذه الملفات متاحة للملحقات التي تدعم المرفقات (مثل تخزين المتجهات).", + "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.": "أنواع الملفات المدعومة: نص عادي، PDF، Markdown، HTML، EPUB.", + "Drag and drop files here to upload.": "قم بسحب وإسقاط الملفات هنا للتحميل.", + "Date (Newest First)": "التاريخ (الأحدث أولاً)", + "Date (Oldest First)": "التاريخ (الأقدم أولاً)", + "Name (A-Z)": "الاسم (أ-ي)", + "Name (Z-A)": "الاسم (ي-أ)", + "Size (Smallest First)": "الحجم (الأصغر أولاً)", + "Size (Largest First)": "الحجم (الأكبر أولاً)", + "Bulk Edit": "تحرير بالجملة", + "Select All": "اختر الكل", + "Select None": "لا تختر شيء", + "Global Attachments": "المرفقات العالمية", + "These files are available for all characters in all chats.": "هذه الملفات متاحة لجميع الشخصيات في جميع الدردشات.", + "Character Attachments": "مرفقات الشخصيات", + "These files are available the current character in all chats they are in.": "تتوفر هذه الملفات بالحرف الحالي في جميع الدردشات الموجودة فيها.", + "Saved locally. Not exported.": "تم الحفظ محليًا. لم يتم تصديرها.", + "Chat Attachments": "مرفقات الدردشة", + "These files are available to all characters in the current chat.": "هذه الملفات متاحة لجميع الشخصيات في الدردشة الحالية.", + "Enter a base URL of the MediaWiki to scrape.": "أدخل عنوان URL الأساسي لـ MediaWiki المراد استخراجه.", + "Don't include the page name!": "لا تقم بتضمين اسم الصفحة!", + "Enter web URLs to scrape (one per line):": "أدخل عناوين URL للويب المراد استخراجها (واحد لكل سطر):", + "Enter a video URL to download its transcript.": "أدخل عنوان URL أو معرف الفيديو لتنزيل النص الخاص به.", + "Expression API": "محلي\nإضافات\nماجستير", + "ext_sum_with": "تلخيص مع:", + "ext_sum_main_api": "واجهة برمجة التطبيقات الرئيسية", + "ext_sum_current_summary": "الملخص الحالي:", + "ext_sum_restore_previous": "استعادة ما تقدم", + "ext_sum_memory_placeholder": "سيتم إنشاء الملخص هنا...", + "Trigger a summary update right now.": "تلخيص الآن", + "ext_sum_force_text": "تلخيص الآن", + "Disable automatic summary updates. While paused, the summary remains as-is. You can still force an update by pressing the Summarize now button (which is only available with the Main API).": "تعطيل التحديثات الموجزة التلقائية. أثناء الإيقاف المؤقت، يظل الملخص كما هو. لا يزال بإمكانك فرض التحديث بالضغط على زر تلخيص الآن (والذي يتوفر فقط مع واجهة برمجة التطبيقات الرئيسية).", + "ext_sum_pause": "يوقف", + "Omit World Info and Author's Note from text to be summarized. Only has an effect when using the Main API. The Extras API always omits WI/AN.": "حذف معلومات العالم وملاحظة المؤلف من النص المراد تلخيصه. يكون له تأثير فقط عند استخدام واجهة برمجة التطبيقات الرئيسية. تتجاهل واجهة برمجة تطبيقات Extras دائمًا شبكة WI/AN.", + "ext_sum_no_wi_an": "لا يوجد واي فاي/AN", + "ext_sum_settings_tip": "تحرير موجه التلخيص، وموضع الإدراج، وما إلى ذلك.", + "ext_sum_settings": "إعدادات الملخص", + "ext_sum_prompt_builder": "منشئ سريع", + "ext_sum_prompt_builder_1_desc": "سيقوم الامتداد ببناء المطالبة الخاصة به باستخدام الرسائل التي لم يتم تلخيصها بعد. حظر الدردشة حتى يتم إنشاء الملخص.", + "ext_sum_prompt_builder_1": "خام، حجب", + "ext_sum_prompt_builder_2_desc": "سيقوم الامتداد ببناء المطالبة الخاصة به باستخدام الرسائل التي لم يتم تلخيصها بعد. لا يمنع الدردشة أثناء إنشاء الملخص. لا تدعم جميع الواجهات الخلفية هذا الوضع.", + "ext_sum_prompt_builder_2": "خام وغير مانع", + "ext_sum_prompt_builder_3_desc": "سوف يستخدم الامتداد منشئ المطالبة الرئيسي العادي ويضيف طلب الملخص إليه باعتباره رسالة النظام الأخيرة.", + "ext_sum_prompt_builder_3": "كلاسيكي، مانع", + "Summary Prompt": "ملخص موجه", + "ext_sum_restore_default_prompt_tip": "استعادة المطالبة الافتراضية", + "ext_sum_prompt_placeholder": "سيتم إرسال هذا المطالبة إلى الذكاء الاصطناعي لطلب إنشاء الملخص. سيتم حل {{words}} إلى معلمة \"عدد الكلمات\".", + "ext_sum_target_length_1": "طول الملخص المستهدف", + "ext_sum_target_length_2": null, + "ext_sum_target_length_3": "كلمات)", + "ext_sum_api_response_length_1": "طول استجابة واجهة برمجة التطبيقات", + "ext_sum_api_response_length_2": null, + "ext_sum_api_response_length_3": "الرموز)", + "ext_sum_0_default": "0 = افتراضي", + "ext_sum_raw_max_msg": "[خام] الحد الأقصى للرسائل لكل طلب", + "ext_sum_0_unlimited": "0 = غير محدود", + "Update frequency": "تردد التحديث", + "ext_sum_update_every_messages_1": "تحديث كل", + "ext_sum_update_every_messages_2": "رسائل", + "ext_sum_0_disable": "0 = تعطيل", + "ext_sum_auto_adjust_desc": "حاول ضبط الفاصل الزمني تلقائيًا بناءً على مقاييس الدردشة.", + "ext_sum_update_every_words_1": "تحديث كل", + "ext_sum_update_every_words_2": "كلمات", + "ext_sum_both_sliders": "إذا لم يكن كلا شريطي التمرير صفرًا، فسيقوم كلاهما بتشغيل تحديثات موجزة على فترات زمنية خاصة بهما.", + "ext_sum_injection_template": "قالب الحقن", + "ext_sum_memory_template_placeholder": "{{summary}} سيتوافق مع محتويات الملخص الحالي.", + "ext_sum_injection_position": "موضع الحقن", + "How many messages before the current end of the chat.": "كم عدد الرسائل قبل النهاية الحالية للدردشة.", + "ext_regex_title": "التعبيرات العادية", + "ext_regex_new_global_script": "+ العالمية", + "ext_regex_new_scoped_script": "+ نطاق", + "ext_regex_import_script": "يستورد", + "ext_regex_global_scripts": "البرامج النصية العالمية", + "ext_regex_global_scripts_desc": "متاح لجميع الشخصيات. تم الحفظ في الإعدادات المحلية.", + "ext_regex_scoped_scripts": "البرامج النصية ذات النطاق", + "ext_regex_scoped_scripts_desc": "متاح فقط لهذه الشخصية. تم الحفظ في بيانات البطاقة.", + "Regex Editor": "محرر ريجكس", + "Test Mode": "وضع الاختبار", + "ext_regex_desc": "Regex هي أداة للبحث عن/استبدال السلاسل باستخدام التعبيرات العادية. إذا كنت تريد معرفة المزيد، فانقر فوق علامة الاستفهام بجوار العنوان.", + "Input": "مدخل", + "ext_regex_test_input_placeholder": "أكتب هنا...", + "Output": "انتاج |", + "ext_regex_output_placeholder": "فارغ", + "Script Name": "اسم البرنامج النصي", + "Find Regex": "ابحث عن Regex", + "Replace With": "استبدل ب", + "ext_regex_replace_string_placeholder": "استخدم {{match}} لتضمين النص المطابق من Find Regex أو $1، $2، وما إلى ذلك لمجموعات الالتقاط.", + "Trim Out": "تقليم خارج", + "ext_regex_trim_placeholder": "يقوم عالميًا بقص أي أجزاء غير مرغوب فيها من تطابق التعبير العادي قبل الاستبدال. افصل كل عنصر بإدخال.", + "ext_regex_affects": "يؤثر", + "ext_regex_user_input": "إدخال المستخدم", + "ext_regex_ai_output": "مخرجات الذكاء الاصطناعي", + "Slash Commands": "أوامر القطع", + "ext_regex_min_depth_desc": "عند تطبيقه على المطالبات أو العرض، فإنه يؤثر فقط على الرسائل التي لا يقل عمقها عن N من المستويات. 0 = الرسالة الأخيرة، 1 = الرسالة قبل الأخيرة، وما إلى ذلك. يحسب فقط إدخالات WI@Depth والرسائل القابلة للاستخدام، أي غير المخفية أو النظام.", + "Min Depth": "الحد الأدنى للعمق", + "ext_regex_min_depth_placeholder": "غير محدود", + "ext_regex_max_depth_desc": "عند تطبيقه على المطالبات أو العرض، فإنه يؤثر فقط على الرسائل التي لا يزيد عمقها عن مستويات N. 0 = الرسالة الأخيرة، 1 = الرسالة قبل الأخيرة، وما إلى ذلك. يحسب فقط إدخالات WI@Depth والرسائل القابلة للاستخدام، أي غير المخفية أو النظام.", + "ext_regex_other_options": "خيارات أخرى", + "Only Format Display": "عرض التنسيق فقط", + "ext_regex_only_format_prompt_desc": "لن يتغير سجل الدردشة، فقط المطالبة التي يتم إرسالها عند الطلب (عند الإنشاء).", + "Only Format Prompt (?)": "موجه التنسيق فقط", + "Run On Edit": "تشغيل عند التحرير", + "ext_regex_substitute_regex_desc": "استبدل {{وحدات الماكرو}} في Find Regex قبل تشغيله", + "Substitute Regex": "استبدال Regex", + "ext_regex_import_target": "استيراد إلى:", + "ext_regex_disable_script": "تعطيل البرنامج النصي", + "ext_regex_enable_script": "تمكين البرنامج النصي", + "ext_regex_edit_script": "تحرير البرنامج النصي", + "ext_regex_move_to_global": "الانتقال إلى البرامج النصية العالمية", + "ext_regex_move_to_scoped": "الانتقال إلى البرامج النصية ذات النطاق", + "ext_regex_export_script": "تصدير البرنامج النصي", + "ext_regex_delete_script": "حذف البرنامج النصي", + "Trigger Stable Diffusion": "الزناد نشر مستقر", + "sd_Yourself": "نفسك", + "sd_Your_Face": "وجهك", + "sd_Me": "أنا", + "sd_The_Whole_Story": "القصة الكاملة", + "sd_The_Last_Message": "الرسالة الاخيرة", + "sd_Raw_Last_Message": "الرسالة الأخيرة الخام", + "sd_Background": "خلفية", + "Image Generation": "توليد الصور", + "sd_refine_mode": "السماح بتحرير المطالبات يدويًا قبل إرسالها إلى واجهة برمجة تطبيقات الإنشاء", + "sd_refine_mode_txt": "تعديل المطالبات قبل التوليد", + "sd_interactive_mode": "قم بإنشاء الصور تلقائيًا عند إرسال رسائل مثل \"أرسل لي صورة قطة\".", + "sd_interactive_mode_txt": "الوضع التفاعلي", + "sd_multimodal_captioning": "استخدم التسميات التوضيحية متعددة الوسائط لإنشاء مطالبات لصور المستخدمين والشخصيات استنادًا إلى الصور الرمزية الخاصة بهم.", + "sd_multimodal_captioning_txt": "استخدم التسميات التوضيحية متعددة الوسائط للصور", + "sd_expand": "تمديد المطالبات تلقائيًا باستخدام نموذج إنشاء النص", + "sd_expand_txt": "مطالبات التحسين التلقائي", + "sd_snap": "طلبات إنشاء اللقطات باستخدام نسبة العرض إلى الارتفاع القسرية (الصور الشخصية والخلفيات) إلى أقرب دقة معروفة، مع محاولة الحفاظ على عدد البكسل المطلق (موصى به لـ SDXL).", + "sd_snap_txt": "التقاط الدقة المعدلة تلقائيًا", + "Source": "مصدر", + "sd_auto_url": "مثال: {{auto_url}}", + "Authentication (optional)": "المصادقة (اختياري)", + "Example: username:password": "مثال: اسم المستخدم: كلمة المرور", + "Important:": "مهم:", + "sd_auto_auth_warning_1": "قم بتشغيل SD Web UI باستخدام", + "sd_auto_auth_warning_2": "علَم! يجب أن يكون الخادم قابلاً للوصول من الجهاز المضيف SillyTavern.", + "sd_drawthings_url": "مثال: {{drawthings_url}}", + "sd_drawthings_auth_txt": "قم بتشغيل تطبيق DrawThings مع تمكين مفتاح HTTP API في واجهة المستخدم! يجب أن يكون الخادم قابلاً للوصول من الجهاز المضيف SillyTavern.", + "sd_vlad_url": "مثال: {{vlad_url}}", + "The server must be accessible from the SillyTavern host machine.": "يجب أن يكون الخادم قابلاً للوصول من الجهاز المضيف SillyTavern.", + "Hint: Save an API key in AI Horde API settings to use it here.": "تلميح: احفظ مفتاح API في إعدادات AI Horde API لاستخدامه هنا.", + "Allow NSFW images from Horde": "السماح بصور NSFW من Horde", + "Sanitize prompts (recommended)": "مطالبات التعقيم (مستحسن)", + "Automatically adjust generation parameters to ensure free image generations.": "قم بضبط معلمات الإنشاء تلقائيًا لضمان إنشاء صور مجانية.", + "Avoid spending Anlas": "تجنب إنفاق Anlas", + "Opus tier": "(طبقة التأليف)", + "View my Anlas": "عرض أنلاس الخاص بي", + "These settings only apply to DALL-E 3": "تنطبق هذه الإعدادات فقط على DALL-E 3", + "Image Style": "نمط الصورة", + "Image Quality": "جودة الصورة", + "Standard": "معيار", + "HD": "عالية الدقة", + "sd_comfy_url": "مثال: {{comfy_url}}", + "Open workflow editor": "افتح محرر سير العمل", + "Create new workflow": "إنشاء سير عمل جديد", + "Delete workflow": "حذف سير العمل", + "Enhance": "يحسن", + "Refine": "صقل", + "Decrisper": "ديكريسبر", + "Sampling steps": "خطوات أخذ العينات ()", + "Width": "عرض ()", + "Height": "ارتفاع ()", + "Resolution": "دقة", + "Model": "نموذج", + "Sampling method": "طريقة أخذ العينات", + "Karras (not all samplers supported)": "Karras (ليست جميع أجهزة أخذ العينات مدعومة)", + "SMEA versions of samplers are modified to perform better at high resolution.": "يتم تعديل إصدارات SMEA من أجهزة أخذ العينات لتقديم أداء أفضل بدقة عالية.", + "SMEA": "SMEA", + "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "غالبًا ما تؤدي متغيرات DYN الخاصة بأجهزة أخذ العينات SMEA إلى إنتاج أكثر تنوعًا، ولكنها قد تفشل في الدقة العالية جدًا.", + "DYN": "دين", + "Scheduler": "مجدول", + "Restore Faces": "استعادة الوجوه", + "Hires. Fix": "يستأجر. يصلح", + "Upscaler": "الراقي", + "Upscale by": "الراقي بواسطة", + "Denoising strength": "قوة إزالة الضوضاء", + "Hires steps (2nd pass)": "خطوات الاستئجار (الممر الثاني)", + "Preset for prompt prefix and negative prompt": "الإعداد المسبق للبادئة السريعة والموجه السلبي", + "Style": "أسلوب", + "Save style": "حفظ النمط", + "Delete style": "حذف النمط", + "Common prompt prefix": "بادئة المطالبة الشائعة", + "sd_prompt_prefix_placeholder": "استخدم {prompt} لتحديد المكان الذي سيتم فيه إدراج المطالبة التي تم إنشاؤها", + "Negative common prompt prefix": "بادئة المطالبة المشتركة السلبية", + "Character-specific prompt prefix": "بادئة المطالبة الخاصة بالحرف", + "Won't be used in groups.": "لن يتم استخدامها في مجموعات.", + "sd_character_prompt_placeholder": "أي خصائص تصف الشخصية المحددة حاليًا. ستتم إضافتها بعد بادئة المطالبة الشائعة.\nمثال: أنثى، عيون خضراء، شعر بني، قميص وردي", + "Character-specific negative prompt prefix": "بادئة موجه سلبية خاصة بالحرف", + "sd_character_negative_prompt_placeholder": "أي خصائص يجب ألا تظهر للشخصية المحددة. ستتم إضافتها بعد بادئة المطالبة العامة السلبية.\nمثال: المجوهرات والأحذية والنظارات", + "Shareable": "قابلة للمشاركة", + "Image Prompt Templates": "قوالب الصور السريعة", + "Vectors Model Warning": "يوصى بتطهير المتجهات عند تغيير النموذج أثناء الدردشة. وإلا فإنه سيؤدي إلى نتائج دون المستوى.", + "Translate files into English before processing": "ترجمة الملفات إلى اللغة الإنجليزية قبل المعالجة", + "Manager Users": "ادارة المستخدمين", + "New User": "مستخدم جديد", + "Status:": "حالة:", + "Created:": "مخلوق:", + "Display Name:": "اسم العرض:", + "User Handle:": "مقبض المستخدم:", + "Password:": "كلمة المرور:", + "Confirm Password:": "تأكيد كلمة المرور:", + "This will create a new subfolder...": "سيؤدي هذا إلى إنشاء مجلد فرعي جديد في الدليل /data/ مع مقبض المستخدم كاسم المجلد.", + "Current Password:": "كلمة السر الحالية:", + "New Password:": "كلمة المرور الجديدة:", + "Confirm New Password:": "تأكيد كلمة المرور الجديدة:", + "Debug Warning": "الوظائف في هذه الفئة مخصصة للمستخدمين المتقدمين فقط. لا تنقر على أي شيء إذا لم تكن متأكدًا من العواقب.", + "Execute": "ينفذ", + "Are you sure you want to delete this user?": "هل أنت متأكد أنك تريد حذف هذا المستخدم؟", + "Deleting:": "حذف:", + "Also wipe user data.": "امسح بيانات المستخدم أيضًا.", + "Warning:": "تحذير:", + "This action is irreversible.": "هذا الإجراء لا رجعة فيه.", + "Type the user's handle below to confirm:": "اكتب مقبض المستخدم أدناه للتأكيد:", + "Import Characters": "استيراد الشخصيات", + "Enter the URL of the content to import": "أدخل عنوان URL للمحتوى المراد استيراده", + "Supported sources:": "المصادر المدعومة:", + "char_import_1": "حرف Chub (رابط مباشر أو معرف)", + "char_import_example": "مثال:", + "char_import_2": "Chub Lorebook (رابط مباشر أو معرف)", + "char_import_3": "حرف JanitorAI (رابط مباشر أو UUID)", + "char_import_4": "حرف Pygmalion.chat (رابط مباشر أو UUID)", + "char_import_5": "حرف AICharacterCards.com (رابط مباشر أو معرف)", + "char_import_6": "رابط PNG المباشر (راجع", + "char_import_7": "للمضيفين المسموح بهم)", + "char_import_8": "شخصية RisuRealm (رابط مباشر)", + "Supports importing multiple characters.": "يدعم استيراد أحرف متعددة.", + "Write each URL or ID into a new line.": "اكتب كل عنوان URL أو معرف في سطر جديد.", + "Export for character": "تصدير للشخصية", + "Export prompts for this character, including their order.": "تصدير المطالبات لهذه الشخصية، بما في ذلك ترتيبها.", + "Export all": "تصدير الكل", + "Export all your prompts to a file": "تصدير كافة المطالبات الخاصة بك إلى ملف", + "Insert prompt": "إدراج تلميح", + "Delete prompt": "حذف التلميح", + "Import a prompt list": "استيراد قائمة التلميحات", + "Export this prompt list": "تصدير هذه القائمة من التلميحات", + "Reset current character": "إعادة تعيين الشخصية الحالية", + "New prompt": "تلميح جديد", + "Prompts": "تلميحات", + "Total Tokens:": "مجموع الرموز:", + "prompt_manager_tokens": "الرموز", + "Are you sure you want to reset your settings to factory defaults?": "هل أنت متأكد أنك تريد إعادة ضبط إعداداتك على إعدادات المصنع الافتراضية؟", + "Don't forget to save a snapshot of your settings before proceeding.": "لا تنس حفظ لقطة من إعداداتك قبل المتابعة.", + "Settings Snapshots": "لقطات الإعدادات", + "Record a snapshot of your current settings.": "سجل لقطة لإعداداتك الحالية.", + "Make a Snapshot": "قم بعمل لقطة", + "Restore this snapshot": "استعادة هذه اللقطة", + "Hi,": "أهلاً،", + "To enable multi-account features, restart the SillyTavern server with": "لتمكين ميزات الحسابات المتعددة، أعد تشغيل خادم SillyTavern باستخدام", + "set to true in the config.yaml file.": "تم ضبطه على true في ملف config.yaml.", + "Account Info": "معلومات الحساب", + "To change your user avatar, use the buttons below or select a default persona in the Persona Management menu.": "لتغيير الصورة الرمزية للمستخدم، استخدم الأزرار أدناه أو حدد شخصية افتراضية في قائمة إدارة الشخصية.", + "Set your custom avatar.": "قم بتعيين الصورة الرمزية المخصصة لك.", + "Remove your custom avatar.": "قم بإزالة الصورة الرمزية المخصصة الخاصة بك.", + "Handle:": "مقبض:", + "This account is password protected.": "هذا الحساب محمي بكلمة مرور.", + "This account is not password protected.": "هذا الحساب غير محمي بكلمة مرور.", + "Account Actions": "إجراءات الحساب", + "Change Password": "تغيير كلمة المرور", + "Manage your settings snapshots.": "إدارة لقطات الإعدادات الخاصة بك.", + "Download a complete backup of your user data.": "قم بتنزيل نسخة احتياطية كاملة لبيانات المستخدم الخاصة بك.", + "Download Backup": "تحميل النسخ الاحتياطي", + "Danger Zone": "منطقة الخطر", + "Reset your settings to factory defaults.": "إعادة تعيين إعداداتك إلى إعدادات المصنع الافتراضية.", + "Reset Settings": "اعادة الضبط", + "Wipe all user data and reset your account to factory settings.": "امسح جميع بيانات المستخدم وأعد ضبط حسابك على إعدادات المصنع.", + "Reset Everything": "إعادة ضبط كل شيء", + "Reset Code:": "إعادة تعيين الرمز:", + "Want to update?": "هل ترغب في التحديث؟", + "How to start chatting?": "كيف تبدأ في المحادثة؟", + "Click _space": "انقر", + "and select a": "وحدد أ", + "Chat API": "واجهة برمجة تطبيقات الدردشة", + "and pick a character.": "واختر شخصية.", + "You can browse a list of bundled characters in the": "يمكنك تصفح قائمة الأحرف المجمعة في ملف", + "Download Extensions & Assets": "تنزيل الإضافات والأصول", + "menu within": "القائمة داخل", + "Confused or lost?": "هل أنت مرتبك أو ضائع؟", + "click these icons!": "انقر على هذه الأيقونات!", + "in the chat bar": "في شريط الدردشة", + "SillyTavern Documentation Site": "موقع وثائق SillyTavern", + "Extras Installation Guide": "دليل تثبيت الإضافات", + "Still have questions?": "هل ما زالت لديك اسئلة؟", + "Join the SillyTavern Discord": "انضم إلى ديسكورد SillyTavern", + "Post a GitHub issue": "نشر مشكلة على GitHub", + "Contact the developers": "الاتصال بالمطورين" +} diff --git a/jiuguan2025cc/public/locales/de-de.json b/jiuguan2025cc/public/locales/de-de.json new file mode 100644 index 0000000000000000000000000000000000000000..c47c8c5423d4406013be6c2f65d05e75d7f4d33b --- /dev/null +++ b/jiuguan2025cc/public/locales/de-de.json @@ -0,0 +1,1443 @@ +{ + "Favorite": "Favorit", + "Tag": "Etikett", + "Duplicate": "Duplikat", + "Persona": "Persona", + "Delete": "Löschen", + "AI Response Configuration": "KI-Antwortkonfiguration", + "AI Configuration panel will stay open": "Das KI-Konfigurationsfeld bleibt geöffnet", + "clickslidertips": "Klick einfach drauf, um die Zahlen selber einzugeben.", + "MAD LAB MODE ON": "MAD LAB-MODUS EIN", + "Documentation on sampling parameters": "Dokumentation zu Abtastparametern", + "kobldpresets": "Kobold-Einstellungen von vorher", + "guikoboldaisettings": "KoboldAI-Einstellungen für das Menü", + "Update current preset": "Aktuelles Voreinstellung aktualisieren", + "Save preset as": "Voreinstellung speichern als", + "Import preset": "Voreinstellung importieren", + "Export preset": "Voreinstellung exportieren", + "Restore current preset": "Aktuelle Voreinstellung wiederherstellen", + "Delete the preset": "Die Voreinstellung löschen", + "novelaipresets": "NovelAI-Einstellungen von früher", + "Default": "Standard", + "openaipresets": "OpenAI-Einstellungen von vorher", + "Text Completion presets": "Voreinstellungen für Textvervollständigung", + "AI Module": "KI-Modul", + "Changes the style of the generated text.": "Ändert den Stil des generierten Textes.", + "No Module": "Kein Modul", + "Instruct": "Anweisen", + "Prose Augmenter": "Prosa-Erweiterer", + "Text Adventure": "Textabenteuer", + "response legth(tokens)": "Länge der Antwort (Tokens)", + "Streaming": "Streamen", + "Streaming_desc": "Zeige die Antwort Stück für Stück an, während sie generiert wird.", + "context size(tokens)": "Größe des Zusammenhangs (Tokens)", + "unlocked": "Freigeschaltet", + "Only enable this if your model supports context sizes greater than 8192 tokens": "Aktiviere dies nur, wenn dein Modell Kontextgrößen von mehr als 8192 Tokens unterstützt.", + "Max prompt cost:": "Maximale Sofortkosten:", + "Display the response bit by bit as it is generated.": "Zeige die Antwort Stück für Stück, während sie generiert wird.", + "When this is off, responses will be displayed all at once when they are complete.": "Wenn dies ausgeschaltet ist, werden Antworten angezeigt, sobald sie vollständig sind.", + "Temperature": "Temperatur", + "rep.pen": "Wiederholungsstrafe", + "Rep. Pen. Range.": "Wiederh. Strafe Bereich.", + "Rep. Pen. Slope": "Steigung der Wiederholungsstrafe", + "Rep. Pen. Freq.": "Wiederh. Strafe Häufigkeit.", + "Rep. Pen. Presence": "Wiederh. Strafe Anwesenheit", + "TFS": "TFS", + "Phrase Repetition Penalty": "Strafe für wiederholte Phrasen", + "Off": "Aus", + "Very light": "Sehr leicht", + "Light": "Leicht", + "Medium": "Mittel", + "Aggressive": "Aggressiv", + "Very aggressive": "Sehr aggressiv", + "Unlocked Context Size": "Entsperrte Kontextgröße", + "Unrestricted maximum value for the context slider": "Uneingeschränkter maximaler Wert für den Kontext-Schieberegler", + "Context Size (tokens)": "Größe des Zusammenhangs (Tokens)", + "Max Response Length (tokens)": "Maximale Antwortlänge (Tokens)", + "Multiple swipes per generation": "Mehrere Swipes pro Generation", + "Enable OpenAI completion streaming": "OpenAI-Vervollständigungsstreaming aktivieren", + "Frequency Penalty": "Frequenzstrafe", + "Presence Penalty": "Präsenzstrafe", + "Count Penalty": "Strafe zählen", + "Top K": "Top K", + "Top P": "Top P", + "Repetition Penalty": "Wiederholungsstrafe", + "Min P": "Mindestens P", + "Top A": "Top A", + "Quick Prompts Edit": "Schnelle Aufforderungen bearbeiten", + "Main": "Haupt", + "NSFW": "Nicht für die Arbeit geeignet", + "Jailbreak": "Ausbruch", + "Utility Prompts": "Hilfs-Prompts", + "Impersonation prompt": "Aufforderung zur Personifikation", + "Restore default prompt": "Standardprompt wiederherstellen", + "Prompt that is used for Impersonation function": "Aufforderung, die für die Funktion der Personifikation verwendet wird.", + "World Info Format Template": "Vorlage für das World Info-Format", + "Restore default format": "Standardformat wiederherstellen", + "Wraps activated World Info entries before inserting into the prompt.": "Umschließt aktivierte World Info-Einträge vor dem Einfügen in die Eingabeaufforderung.", + "scenario_format_template_part_1": "Verwenden", + "scenario_format_template_part_2": "um eine Stelle zu markieren, an der der Inhalt eingefügt wird.", + "Scenario Format Template": "Szenarioformatvorlage", + "Personality Format Template": "Vorlage für das Persönlichkeitsformat", + "Group Nudge Prompt Template": "Vorlage für die Gruppenanstoß-Eingabeaufforderung", + "Sent at the end of the group chat history to force reply from a specific character.": "Wird am Ende des Gruppenchatverlaufs gesendet, um eine Antwort von einem bestimmten Charakter zu erzwingen.", + "New Chat": "Neuer Chat", + "Restore new chat prompt": "Neue Chat-Eingabeaufforderung wiederherstellen", + "Set at the beginning of the chat history to indicate that a new chat is about to start.": "Wird am Anfang des Chatverlaufs gesetzt, um anzuzeigen, dass gerade ein neuer Chat beginnt.", + "New Group Chat": "Neuer Gruppenchat", + "Restore new group chat prompt": "Standardeingabeaufforderung wiederherstellen", + "Set at the beginning of the chat history to indicate that a new group chat is about to start.": "Wird am Anfang des Chatverlaufs gesetzt, um anzuzeigen, dass gerade ein neuer Gruppenchat beginnt.", + "New Example Chat": "Neuer Beispiel-Chat", + "Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.": "Wird zu Beginn von Dialogbeispielen gesetzt, um anzuzeigen, dass ein neuer Beispiel-Chat gestartet wird.", + "Continue nudge": "Weiter anstupsen", + "Set at the end of the chat history when the continue button is pressed.": "Wird am Ende des Chatverlaufs gesetzt, wenn die Schaltfläche „Weiter“ gedrückt wird.", + "Replace empty message": "Leere Nachricht ersetzen", + "Send this text instead of nothing when the text box is empty.": "Sende diesen Text, wenn das Textfeld leer ist, anstelle von nichts.", + "Seed": "Seed", + "Set to get deterministic results. Use -1 for random seed.": "Eingestellt, um deterministische Ergebnisse zu erhalten. Verwenden Sie -1 für den Zufallsstartwert.", + "Temperature controls the randomness in token selection": "Die Temperatur steuert die Zufälligkeit bei der Tokenauswahl:\n- Eine niedrige Temperatur (<1,0) führt zu intelligenterem Text, wobei häufig auftretende Tokens (Wörter oder Zeichen) priorisiert werden.\n- Eine hohe Temperatur (>1,0) erhöht die Kreativität und die Vielfalt der Ausgabe, wobei seltenere Tokens (Wörter oder Zeichen) eine größere Chance haben.\nStelle den Wert auf 1,0 für die Standardwahrscheinlichkeiten ein.", + "Top_K_desc": "Top K legt ein Limit für die obersten Tokens fest, die ausgewählt werden können.", + "Top_P_desc": "Top P (auch bekannt als Kernsampling) kombiniert alle erforderlichen obersten Tokens, um einen bestimmten Prozentsatz zu erreichen.\nAnders ausgedrückt, wenn die obersten 2 Tokens 25% ausmachen und Top P 0,50 beträgt, werden nur diese beiden obersten Tokens berücksichtigt.\nStelle den Wert auf 1,0, um dies zu deaktivieren.", + "Typical P": "Typisch P", + "Typical_P_desc": "Bei der typischen P-Stichprobe werden Tokens priorisiert, basierend auf ihrer Abweichung von der durchschnittlichen Entropie des Satzes.\nTokens mit einer kumulierten Wahrscheinlichkeit nahe am definierten Schwellenwert (z. B. 0,5) werden beibehalten, was darauf hinweist, dass sie einen mittleren Informationsgehalt haben.\nStelle den Wert auf 1,0, um dies zu deaktivieren.", + "Min_P_desc": "Min P legt eine Basismindestwahrscheinlichkeit fest. Diese wird basierend auf der Wahrscheinlichkeit des obersten Tokens optimiert.\nWenn die Wahrscheinlichkeit des obersten Tokens 80% beträgt und Min P 0,1 beträgt, werden nur Tokens mit einer Wahrscheinlichkeit von mehr als 8% berücksichtigt.\nStelle den Wert auf 0,0, um dies zu deaktivieren.", + "Top_A_desc": "Top A legt einen Schwellenwert für die Tokenauswahl basierend auf dem Quadrat der höchsten Tokenwahrscheinlichkeit fest.\nWenn Top A 0,2 beträgt und die Wahrscheinlichkeit des obersten Tokens 50% beträgt, werden Tokens mit einer Wahrscheinlichkeit von weniger als 5% ausgeschlossen (0,2 * 0,5^2).\nStelle den Wert auf 0,0, um dies zu deaktivieren.", + "Tail_Free_Sampling_desc": "Schwanzfreie Stichprobe (TFS) sucht nach schwach wahrscheinlichen Tokens in der Verteilung,\n indem sie die Änderungsrate der Tokenwahrscheinlichkeiten mithilfe von Derivaten analysiert. Tokens werden bis zu einer bestimmten Schwelle (z. B. 0,3) beibehalten, basierend auf der zweiten einheitlichen Ableitung.\nJe näher 0, desto mehr Tokens werden abgelehnt. Stelle den Wert auf 1,0, um dies zu deaktivieren.", + "rep.pen range": "Bereich der Wiederholungsstrafe", + "Mirostat": "Mirostat", + "Mode": "Modus", + "Mirostat_Mode_desc": "Ein Wert von 0 deaktiviert Mirostat vollständig. 1 steht für Mirostat 1.0 und 2 für Mirostat 2.0", + "Tau": "Tau", + "Mirostat_Tau_desc": "Steuert die Variabilität der Mirostat-Ausgaben", + "Eta": "Eta", + "Mirostat_Eta_desc": "Steuert die Lernrate von Mirostat", + "Ban EOS Token": "Verbiet das EOS-Token", + "Ban_EOS_Token_desc": "Verbot des End-of-Sequence (EOS)-Tokens mit KoboldCpp (und möglicherweise auch anderer Token mit KoboldAI). Gut zum Schreiben von Geschichten, sollte aber nicht für den Chat- und Anweisungsmodus verwendet werden.", + "GBNF Grammar": "GBNF-Grammatik", + "Type in the desired custom grammar": "Gib die gewünschte individuelle Grammatik ein.", + "Samplers Order": "Sampler-Reihenfolge", + "Samplers will be applied in a top-down order. Use with caution.": "Sampler werden in einer Top-Down-Reihenfolge angewendet. Benutzen Sie es mit Vorsicht.", + "Tail Free Sampling": "Schwanzfreie Stichprobe", + "Load koboldcpp order": "Laden Sie die Reihenfolge von koboldcpp", + "Preamble": "Vorwort", + "Use style tags to modify the writing style of the output.": "Verwende Stil-Tags, um den Schreibstil der Ausgabe zu ändern.", + "Banned Tokens": "Verbotene Tokens", + "Sequences you don't want to appear in the output. One per line.": "Sequenzen, die du nicht in der Ausgabe sehen möchtest. Eine pro Zeile.", + "Logit Bias": "Logit-Bias", + "Add": "Hinzufügen", + "Helps to ban or reenforce the usage of certain words": "Hilft dabei, die Verwendung bestimmter Wörter zu verbieten oder zu verstärken.", + "CFG Scale": "CFG-Skala", + "Negative Prompt": "Negatives Prompt", + "Add text here that would make the AI generate things you don't want in your outputs.": "Füge hier Text hinzu, der die KI dazu bringen würde, Dinge zu generieren, die du nicht in deinen Ausgaben haben möchtest.", + "Used if CFG Scale is unset globally, per chat or character": "Wird verwendet, wenn die CFG-Skalierung global, pro Chat oder pro Zeichen nicht festgelegt ist.", + "Mirostat Tau": "Mirostat Tau", + "Mirostat LR": "Mirostat LR", + "Min Length": "Minimale Länge", + "Top K Sampling": "Top K-Beprobung", + "Nucleus Sampling": "Nukleus-Beprobung", + "Top A Sampling": "Top A-Beprobung", + "CFG": "CFG", + "Neutralize Samplers": "Sampler neutralisieren", + "Set all samplers to their neutral/disabled state.": "Setze alle Sampler auf ihren neutralen/deaktivierten Zustand.", + "Sampler Select": "Sampler-Auswahl", + "Customize displayed samplers or add custom samplers.": "Passen Sie angezeigte Sampler an oder fügen Sie benutzerdefinierte Sampler hinzu.", + "Epsilon Cutoff": "Epsilon-Abschaltung", + "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "Epsilon-Cutoff legt einen Wahrscheinlichkeitsboden fest, unter dem Tokens vom Abtasten ausgeschlossen werden.\nIn Einheiten von 1e-4; der geeignete Wert ist 3.\nStelle 0,0 ein, um dies zu deaktivieren.", + "Eta Cutoff": "Eta-Abschaltung", + "Eta_Cutoff_desc": "Eta-Cutoff ist der Hauptparameter der speziellen Eta-Beprobungstechnik. In Einheiten von 1e-4; ein vernünftiger Wert ist 3. Auf 0 setzen, um zu deaktivieren. Siehe das Paper Truncation Sampling as Language Model Desmoothing von Hewitt et al. (2022) für Details.", + "rep.pen decay": "Rep Pen-Verfall", + "Encoder Rep. Pen.": "Encoder Wiederholungsstrafe.", + "No Repeat Ngram Size": "Keine Wiederholung Ngram-Größe", + "Skew": "Schiefe", + "Max Tokens Second": "Maximale Tokens pro Sekunde", + "Smooth Sampling": "Reibungsloses Sampling", + "Smooth_Sampling_desc": "Ermöglicht Ihnen, quadratische/kubische Transformationen zu verwenden, um die Verteilung anzupassen. Niedrigere Glättungsfaktorwerte sind kreativer, normalerweise liegt der Sweetspot zwischen 0,2 und 0,3 (vorausgesetzt, die Kurve ist = 1). Höhere Glättungskurvenwerte machen die Kurve steiler, was Entscheidungen mit geringer Wahrscheinlichkeit aggressiver bestraft. Eine Kurve von 1,0 entspricht der alleinigen Verwendung des Glättungsfaktors.", + "Smoothing Factor": "Glättungsfaktor", + "Smoothing Curve": "Glättungskurve", + "DRY_Repetition_Penalty_desc": "DRY bestraft Token, die das Ende der Eingabe in eine Sequenz verlängern würden, die zuvor in der Eingabe aufgetreten ist. Setzen Sie den Multiplikator auf 0, um dies zu deaktivieren.", + "DRY Repetition Penalty": "DRY Wiederholungsstrafe", + "DRY_Multiplier_desc": "Auf einen Wert > 0 setzen, um DRY zu aktivieren. Steuert die Stärke der Strafe für die kürzesten bestraften Sequenzen.", + "Multiplier": "Multiplikator", + "DRY_Base_desc": "Steuert, wie schnell die Strafe mit zunehmender Sequenzlänge wächst.", + "Base": "Base", + "DRY_Allowed_Length_desc": "Längste Sequenz, die ohne Strafe wiederholt werden kann.", + "Allowed Length": "Erlaubte Länge", + "Penalty Range": "Strafbereich", + "DRY_Sequence_Breakers_desc": "Token, bei denen die Sequenzübereinstimmung nicht fortgesetzt wird. Angegeben als durch Kommas getrennte Liste zitierter Zeichenfolgen.", + "Sequence Breakers": "Sequenzunterbrecher", + "JSON-serialized array of strings.": "JSON-serialisiertes Array von Zeichenfolgen.", + "Dynamic Temperature": "Dynamische Temperatur", + "Scale Temperature dynamically per token, based on the variation of probabilities": "Die Skalierung der Temperatur wird dynamisch pro Token festgelegt, basierend auf der Variation der Wahrscheinlichkeiten.", + "Minimum Temp": "Minimale Temperatur", + "Maximum Temp": "Maximale Temperatur", + "Exponent": "Exponent", + "Mirostat (mode=1 is only for llama.cpp)": "Mirostat (Modus=1 gilt nur für llama.cpp)", + "Mirostat_desc": "Mirostat ist ein Thermostat für die Ausgangsperplexität. Es ist ein Mechanismus zur Anpassung der Ausgangsschwierigkeit, um Konsistenz zwischen Eingabe und Ausgabe zu erreichen.", + "Mirostat Mode": "Mirostat-Modus", + "Variability parameter for Mirostat outputs": "Variabilitätsparameter für Mirostat-Ausgaben.", + "Mirostat Eta": "Mirostat Eta", + "Learning rate of Mirostat": "Lernrate von Mirostat.", + "Beam search": "Strahlensuche", + "Helpful tip coming soon.": "Hilfreicher Tipp folgt in Kürze.", + "Number of Beams": "Anzahl der Strahlen", + "Length Penalty": "Längenstrafe", + "Early Stopping": "Frühes Stoppen", + "Contrastive search": "Kontrastive Suche", + "Penalty Alpha": "Strafe Alpha", + "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "Stärke des Regularisierungsterms für den kontrastiven Suchvorgang. Setze ihn auf 0, um CS zu deaktivieren.", + "Do Sample": "Probier's aus", + "Add BOS Token": "Füge ein BOS-Token hinzu", + "Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative": "Füg das bos_token am Anfang der Aufforderungen hinzu. Wenn du das deaktivierst, können die Antworten kreativer werden.", + "Ban the eos_token. This forces the model to never end the generation prematurely": "Verbiet das eos_token. So wird das Modell gezwungen, die Generierung niemals vorzeitig zu beenden.", + "Ignore EOS Token": "EOS-Token ignorieren", + "Ignore the EOS Token even if it generates.": "Ignorieren Sie das EOS-Token, auch wenn es generiert wird.", + "Skip Special Tokens": "Spezielle Tokens überspringen", + "Temperature Last": "Letzte Temperatur", + "Temperature_Last_desc": "Benutz den Temperaturmuster zuletzt. Ist normalerweise sinnvoll.\nWenn aktiviert, werden zuerst eine Gruppe potenzieller Tokens ausgewählt und dann wird die Temperatur angewendet, um ihre relativen Wahrscheinlichkeiten (technisch: Logits) zu korrigieren.\nWenn deaktiviert, wird die Temperatur zuerst angewendet, um die relativen Wahrscheinlichkeiten für alle Tokens zu korrigieren, und dann wird eine Gruppe potenzieller Tokens daraus ausgewählt.\nDas Deaktivieren der Temperatur am Ende erhöht die Wahrscheinlichkeit von Tokens im Schwanz der Verteilung und erhöht die Wahrscheinlichkeit inkonsistenter Antworten.", + "Speculative Ngram": "Spekulatives Ngram", + "Use a different speculative decoding method without a draft model": "Verwenden Sie eine andere spekulative Dekodierungsmethode ohne Entwurfsmodell. Die Verwendung eines Entwurfsmodells ist vorzuziehen. Spekulatives N-Gramm ist nicht so effektiv.", + "Spaces Between Special Tokens": "Leerzeichen zwischen Sonderzeichen", + "LLaMA / Mistral / Yi models only": "Nur für LLaMA / Mistral / Yi-Modelle. Stelle sicher, dass du zuerst den richtigen Analyzer auswählst.\nStrings sollten nicht in den Ergebnissen erscheinen.\nEine Zeichenfolge pro Zeile. Text oder [Zeichenkennungen].\nViele Zeichen beginnen mit einem Leerzeichen. Verwende den Zeichenzähler, wenn du unsicher bist.", + "Example: some text [42, 69, 1337]": "Beispiel:\nEin bisschen Text\n[42, 69, 1337]", + "Classifier Free Guidance. More helpful tip coming soon": "Anleitung ohne Klassifizierer. Bald kommen weitere hilfreiche Tipps.", + "Scale": "Maßstab", + "JSON Schema": "JSON-Schema", + "Type in the desired JSON schema": "Geben Sie das gewünschte JSON-Schema ein", + "Grammar String": "Grammatikzeichenfolge", + "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF oder EBNF, hängt vom verwendeten Backend ab. Wenn Sie dieses verwenden, sollten Sie wissen, welches.", + "Top P & Min P": "Top P und Min P", + "Load default order": "Standardreihenfolge laden", + "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "Nur llama.cpp. Bestimmt die Reihenfolge der Sampler. Wenn der Mirostat-Modus nicht 0 ist, wird die Sampler-Reihenfolge ignoriert.", + "Sampler Priority": "Sampler-Priorität", + "Ooba only. Determines the order of samplers.": "Nur Ooba. Bestimmt die Reihenfolge der Sampler.", + "Character Names Behavior": "Charakternamen Verhalten", + "Helps the model to associate messages with characters.": "Hilft dem Modell, Nachrichten mit Zeichen zu verknüpfen.", + "None": "Keins", + "character_names_default": "Außer für Gruppen und frühere Personas. Andernfalls stellen Sie sicher, dass Sie in der Eingabeaufforderung Namen angeben.", + "Don't add character names.": "Fügen Sie keine Charakternamen hinzu.", + "Completion": "Vervollständigungsobjekt", + "character_names_completion": "Es gelten Einschränkungen: nur lateinische alphanumerische Zeichen und Unterstriche. Funktioniert nicht für alle Quellen, insbesondere: Claude, MistralAI, Google.", + "Add character names to completion objects.": "Fügen Sie den Vervollständigungsobjekten Charakternamen hinzu.", + "Message Content": "Nachrichteninhalt", + "Prepend character names to message contents.": "Stellen Sie dem Nachrichteninhalt die Zeichennamen voran.", + "Continue Postfix": "Weiter mit Postfix", + "The next chunk of the continued message will be appended using this as a separator.": "Der nächste Teil der Fortsetzungsnachricht wird mit diesem als Trennzeichen angehängt.", + "Space": "Raum", + "Newline": "Neue Zeile", + "Double Newline": "Doppelte Neue Zeile", + "Wrap user messages in quotes before sending": "Umschließt Benutzerbotschaften vor dem Senden mit Anführungszeichen", + "Wrap in Quotes": "In Anführungszeichen setzen", + "Wrap entire user message in quotes before sending.": "Umschließe die gesamte Benutzernachricht vor dem Senden in Anführungszeichen.", + "Leave off if you use quotes manually for speech.": "Lass es weg, wenn du Anführungszeichen manuell für die Sprache verwendest.", + "Continue prefill": "Mit dem Vorausfüllen fortfahren", + "Continue sends the last message as assistant role instead of system message with instruction.": "Mit dem Fortfahren wird die letzte Nachricht als Assistenzrolle gesendet, anstatt als Systemnachricht mit Anweisungen.", + "Squash system messages": "Systemnachrichten zusammenfassen", + "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Kombiniert aufeinanderfolgende Systemnachrichten zu einer (ausschließlich Beispiel-Dialoge ausgeschlossen). Kann die Kohärenz für einige Modelle verbessern.", + "Enable function calling": "Funktionsaufruf aktivieren", + "Send inline images": "Inline-Bilder senden", + "image_inlining_hint_1": "Sendet Bilder in Eingabeaufforderungen, wenn das Modell dies unterstützt (z. B. GPT-4V, Claude 3 oder Llava 13B).\nVerwenden Sie die", + "image_inlining_hint_2": "Aktion auf eine Nachricht oder die", + "image_inlining_hint_3": "Menü, um eine Bilddatei an den Chat anzuhängen.", + "Inline Image Quality": "Inline-Bildqualität", + "openai_inline_image_quality_auto": "Auto", + "openai_inline_image_quality_low": "Niedrig", + "openai_inline_image_quality_high": "Hoch", + "Use AI21 Tokenizer": "Verwenden Sie den AI21 Tokenizer", + "Use the appropriate tokenizer for Jurassic models, which is more efficient than GPT's.": "Verwenden Sie den entsprechenden Tokenizer für Jurassic-Modelle, der effizienter ist als der von GPT.", + "Use Google Tokenizer": "Google-Tokenizer verwenden", + "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "Verwenden Sie den geeigneten Tokenizer für Google-Modelle über deren API. Langsamere Prompt-Verarbeitung, bietet jedoch eine viel genauere Token-Zählung.", + "Use system prompt": "Systemaufforderung verwenden", + "(Gemini 1.5 Pro/Flash only)": "(nur Gemini 1.5 Pro/Flash)", + "Merges_all_system_messages_desc_1": "Führt alle Systemnachrichten bis zur ersten Nachricht mit einer Nicht-Systemrolle zusammen und sendet sie in einer", + "Merges_all_system_messages_desc_2": "Feld.", + "Assistant Prefill": "Assistenten-Vorausfüllung", + "Start Claude's answer with...": "Beginne Claudes Antwort mit...", + "Assistant Impersonation Prefill": "Identitätswechsel des Assistenten vorab ausfüllen", + "Use system prompt (Claude 2.1+ only)": "Systemprompt verwenden (nur Claude 2.1+)", + "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "Senden Sie die Systemaufforderung für unterstützte Modelle. Wenn deaktiviert, wird die Benutzernachricht am Anfang der Aufforderung hinzugefügt.", + "User first message": "Erste Nachricht des Benutzers", + "Restore User first message": "Erste Nachricht des Benutzers wiederherstellen", + "Human message": "Menschliche Nachricht, Anweisung usw.\nFügt nichts hinzu, wenn es leer ist, d. h. erfordert eine neue Eingabeaufforderung mit der Rolle „Benutzer“.", + "New preset": "Neue Voreinstellung", + "Delete preset": "Voreinstellung löschen", + "View / Edit bias preset": "Voreinstellung für Bias anzeigen / bearbeiten", + "Add bias entry": "Bias-Eintrag hinzufügen", + "Most tokens have a leading space.": "Die meisten Token haben ein führendes Leerzeichen.", + "API Connections": "API-Verbindungen", + "Text Completion": "Textvervollständigung", + "Chat Completion": "Chat-Abschluss", + "NovelAI": "NovelAI", + "AI Horde": "AI Horde", + "KoboldAI": "KoboldAI", + "Avoid sending sensitive information to the Horde.": "Vermeide das Senden sensibler Informationen an die Horde.", + "Review the Privacy statement": "Überprüfe die Datenschutzerklärung", + "Register a Horde account for faster queue times": "Registriere einen Horde-Account für kürzere Wartezeiten in der Warteschlange", + "Learn how to contribute your idle GPU cycles to the Horde": "Erfahren Sie, wie Sie Ihre ungenutzten GPU-Zyklen zum Horde beitragen können", + "Adjust context size to worker capabilities": "Passe die Kontextgröße an die Fähigkeiten des Arbeiters an", + "Adjust response length to worker capabilities": "Passe die Länge der Antwort an die Fähigkeiten des Arbeiters an", + "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "Kann bei schlechten Antworten helfen, indem nur die genehmigten Arbeiter in die Warteschlange gestellt werden. Kann die Reaktionszeit verlangsamen.", + "Trusted workers only": "Nur vertrauenswürdige Arbeiter", + "API key": "API-Schlüssel", + "Get it here:": "Hol es dir hier:", + "Register": "Registrieren", + "View my Kudos": "Meine Kudos anzeigen", + "Enter": "Eingeben", + "to use anonymous mode.": "um den anonymen Modus zu verwenden.", + "Clear your API key": "Lösche deinen API-Schlüssel", + "For privacy reasons, your API key will be hidden after you reload the page.": "Aus Datenschutzgründen wird Ihr API-Schlüssel nach dem Neuladen der Seite verborgen.", + "Models": "Modelle", + "Refresh models": "Modelle aktualisieren", + "-- Horde models not loaded --": "-- Horde-Modelle nicht geladen --", + "Not connected...": "Nicht verbunden...", + "API url": "API-URL", + "Example: http://127.0.0.1:5000/api ": "Beispiel: http://127.0.0.1:5000/api", + "Connect": "Verbinden", + "Cancel": "Abbrechen", + "Novel API key": "NovelAPI-Schlüssel", + "Get your NovelAI API Key": "Hol dir deinen NovelAI API-Schlüssel", + "Enter it in the box below": "Gib ihn im untenstehenden Feld ein", + "Novel AI Model": "Novel AI-Modell", + "No connection...": "Keine Verbindung...", + "API Type": "API-Typ", + "Default (completions compatible)": "Standard [OpenAI /completions-kompatibel: oobabooga, LM Studio usw.]", + "TogetherAI API Key": "TogetherAI API-Schlüssel", + "TogetherAI Model": "TogetherAI-Modell", + "-- Connect to the API --": "-- Mit der API verbinden --", + "OpenRouter API Key": "OpenRouter API-Schlüssel", + "Click Authorize below or get the key from": "Klicke unten auf Autorisieren oder hol dir den Schlüssel von", + "View Remaining Credits": "Verbleibende Gutschriften anzeigen", + "OpenRouter Model": "OpenRouter-Modell", + "Model Providers": "Modellanbieter", + "InfermaticAI API Key": "InfermaticAI API-Schlüssel", + "InfermaticAI Model": "InfermaticAI-Modell", + "DreamGen API key": "DreamGen API-Schlüssel", + "DreamGen Model": "DreamGen-Modell", + "Mancer API key": "Mancer API-Schlüssel", + "Mancer Model": "Mancer-Modell", + "Make sure you run it with": "Stelle sicher, dass du es ausführst mit", + "flag": "Flagge", + "API key (optional)": "API-Schlüssel (optional)", + "Server url": "Server-URL", + "Example: 127.0.0.1:5000": "Beispiel: 127.0.0.1:5000", + "Custom model (optional)": "Benutzerdefiniertes Modell (optional)", + "vllm-project/vllm": "vllm-project/vllm (OpenAI API-Wrappermodus)", + "vLLM API key": "vLLM-API-Schlüssel", + "Example: 127.0.0.1:8000": "Beispiel: http://127.0.0.1:8000", + "vLLM Model": "vLLM-Modell", + "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (Wrappermodus für OpenAI API)", + "Aphrodite API key": "Aphrodite API-Schlüssel", + "Aphrodite Model": "Aphrodite-Modell", + "ggerganov/llama.cpp": "ggerganov/llama.cpp (Output-Server)", + "Example: 127.0.0.1:8080": "Beispiel: 127.0.0.1:8080", + "Example: 127.0.0.1:11434": "Beispiel: 127.0.0.1:11434", + "Ollama Model": "Ollama-Modell", + "Download": "Herunterladen", + "Tabby API key": "Tabby API-Schlüssel", + "koboldcpp API key (optional)": "koboldcpp API-Schlüssel (optional)", + "Example: 127.0.0.1:5001": "Beispiel: 127.0.0.1:5001", + "Authorize": "Autorisieren", + "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Hole dein OpenRouter-API-Token mit OAuth-Fluss. Du wirst zu openrouter.ai weitergeleitet", + "Bypass status check": "Umgehe Statusüberprüfung", + "Chat Completion Source": "Quelle für Chat-Vervollständigung", + "Reverse Proxy": "Reverse-Proxy", + "Proxy Presets": "Proxy-Voreinstellungen", + "Saved addresses and passwords.": "Gespeicherte Adressen und Passwörter.", + "Save Proxy": "Proxy speichern", + "Delete Proxy": "Proxy löschen", + "Proxy Name": "Proxy-Name", + "This will show up as your saved preset.": "Dies wird als Ihre gespeicherte Voreinstellung angezeigt.", + "Proxy Server URL": "Proxy-Server-URL", + "Alternative server URL (leave empty to use the default value).": "Alternative Server-URL (lassen das Feld leer, um den Standardwert zu verwenden).", + "Remove your real OAI API Key from the API panel BEFORE typing anything into this box": "Entferne deinen echten OAI-API-Schlüssel aus dem API-Panel, BEVOR du etwas in dieses Feld eingibst.", + "We cannot provide support for problems encountered while using an unofficial OpenAI proxy": "Wir können keine Unterstützung für Probleme bieten, die bei der Verwendung eines inoffiziellen OpenAI-Proxys auftreten.", + "Doesn't work? Try adding": "Funktioniert nicht? Versuchen Sie hinzuzufügen", + "at the end!": "Am Ende!", + "Proxy Password": "Proxy-Passwort", + "Will be used as a password for the proxy instead of API key.": "Wird anstelle des API-Schlüssels als Kennwort für den Proxy verwendet.", + "Peek a password": "Einsehen eines Passworts", + "OpenAI API key": "OpenAI API-Schlüssel", + "View API Usage Metrics": "API-Nutzungsmetriken anzeigen", + "Follow": "Folgen", + "these directions": "diesen Anweisungen", + "to get your OpenAI API key.": "um deinen OpenAI-API-Schlüssel zu erhalten.", + "Use Proxy password field instead. This input will be ignored.": "Verwenden Sie stattdessen das Feld „Proxy-Passwort“. Diese Eingabe wird ignoriert.", + "OpenAI Model": "OpenAI-Modell", + "Bypass API status check": "Umgehe API-Statusüberprüfung", + "Show External models (provided by API)": "Externe Modelle anzeigen (bereitgestellt von API)", + "Get your key from": "Hol dir deinen Schlüssel von", + "Anthropic's developer console": "Anthropics Entwicklerkonsole", + "Claude Model": "Claude-Modell", + "Window AI Model": "Fenster AI-Modell", + "Model Order": "Sortierung des OpenRouter-Modells", + "Alphabetically": "Alphabetisch", + "Price": "Preis (am günstigsten)", + "Context Size": "Kontextgröße", + "Group by vendors": "Gruppieren nach Anbietern", + "Group by vendors Description": "Platzieren Sie OpenAI-Modelle in einer Gruppe, anthropogene Modelle in einer anderen Gruppe usw. Kann mit Sortierung kombiniert werden.", + "Allow fallback routes": "Fallback-Routen zulassen", + "Allow fallback routes Description": "Das alternative Modell wird automatisch ausgewählt, wenn das ausgewählte Modell Ihre Anfrage nicht erfüllen kann.", + "Scale API Key": "Scale API-Schlüssel", + "Clear your cookie": "Löschen Sie Ihre Cookies", + "Alt Method": "Alternative Methode", + "AI21 API Key": "AI21 API-Schlüssel", + "AI21 Model": "AI21-Modell", + "Google AI Studio API Key": "Google AI Studio API-Schlüssel", + "Google Model": "Google-Modell", + "MistralAI API Key": "MistralAI API-Schlüssel", + "MistralAI Model": "MistralAI-Modell", + "Groq API Key": "Groq API-Schlüssel", + "Groq Model": "Groq-Modell", + "Perplexity API Key": "Perplexity API-Schlüssel", + "Perplexity Model": "Perplexitätsmodell", + "Cohere API Key": "Cohere API-Schlüssel", + "Cohere Model": "Cohere-Modell", + "Custom Endpoint (Base URL)": "Benutzerdefinierter Endpunkt (Basis-URL)", + "Custom API Key": "Benutzerdefinierter API-Schlüssel", + "Available Models": "Verfügbare Modelle", + "Prompt Post-Processing": "Zeitnahe Nachbearbeitung", + "Applies additional processing to the prompt before sending it to the API.": "Wendet zusätzliche Verarbeitungsvorgänge auf die Eingabeaufforderung an, bevor sie an die API gesendet wird.", + "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "Überprüft deine API-Verbindung durch Senden einer kurzen Testnachricht. Sei dir bewusst, dass du dafür gutgeschrieben wirst!", + "Test Message": "Testnachricht", + "Auto-connect to Last Server": "Automatisch mit dem letzten Server verbinden", + "Missing key": "❌ Fehlender Schlüssel", + "Key saved": "✔️ Schlüssel gespeichert", + "View hidden API keys": "Versteckte API-Schlüssel anzeigen", + "AI Response Formatting": "KI-Antwortformatierung", + "Advanced Formatting": "Erweiterte Formatierung", + "Context Template": "Kontextvorlage", + "Auto-select this preset for Instruct Mode": "Diese Voreinstellung automatisch für den Anweisungsmodus auswählen", + "Story String": "Geschichtszeichenfolge", + "Example Separator": "Beispiel-Trennzeichen", + "Chat Start": "Chat-Start", + "Add Chat Start and Example Separator to a list of stopping strings.": "Fügen Sie einer Liste von Stoppzeichenfolgen „Chat-Start“ und „Beispieltrennzeichen“ hinzu.", + "Use as Stop Strings": "Verwende als Stoppzeichenfolgen", + "context_allow_jailbreak": "Schließt Jailbreak am Ende der Eingabeaufforderung ein, wenn dies in der Charakterkarte definiert ist UND „Charakter-Jailbreak bevorzugen“ aktiviert ist.\nDIES WIRD FÜR TEXTVERVOLLSTÄNDIGUNGSMODELLE NICHT EMPFOHLEN, KANN ZU SCHLECHTEN AUSGABEN FÜHREN.", + "Allow Jailbreak": "Jailbreak zulassen", + "Context Order": "Kontextreihenfolge", + "Summary": "Zusammenfassung", + "Author's Note": "Hinweis des Autors", + "Example Dialogues": "Beispieldialoge", + "Hint": "Hinweis:", + "In-Chat Position not affected": "Die Bestellungen für Zusammenfassungen und Autorennotizen sind nur dann betroffen, wenn für sie keine In-Chat-Position festgelegt ist.", + "Instruct Mode": "Anweisungsmodus", + "Enabled": "Aktiviert", + "instruct_bind_to_context": "Wenn aktiviert, werden Kontextvorlagen automatisch basierend auf dem ausgewählten Anweisungsvorlagennamen oder nach Präferenz ausgewählt.", + "Bind to Context": "An Kontext binden", + "Presets": "Voreinstellungen", + "Auto-select this preset on API connection": "Diese Voreinstellung automatisch bei API-Verbindung auswählen", + "Activation Regex": "Aktivierungsregex", + "Wrap Sequences with Newline": "Sequenzen mit Zeilenumbruch umschließen", + "Replace Macro in Sequences": "Makro in Sequenzen ersetzen", + "Skip Example Dialogues Formatting": "Formatierung der Beispiel-Dialoge überspringen", + "Include Names": "Namen einbeziehen", + "Force for Groups and Personas": "Erzwingen für Gruppen und Personen", + "System Prompt": "System-Prompt", + "Instruct Mode Sequences": "Anweisungsmodus-Sequenzen", + "System Prompt Wrapping": "Umbruch der Systemeingabeaufforderung", + "Inserted before a System prompt.": "Wird vor einer Systemaufforderung eingefügt.", + "System Prompt Prefix": "Präfix der Systemaufforderung", + "Inserted after a System prompt.": "Wird nach einer Systemaufforderung eingefügt.", + "System Prompt Suffix": "Systemaufforderungssuffix", + "Chat Messages Wrapping": "Umbruch von Chat-Nachrichten", + "Inserted before a User message and as a last prompt line when impersonating.": "Wird vor einer Benutzernachricht und als letzte Eingabeaufforderungszeile beim Identitätswechsel eingefügt.", + "User Message Prefix": "Benutzernachrichtenpräfix", + "Inserted after a User message.": "Wird nach einer Benutzernachricht eingefügt.", + "User Message Suffix": "Benutzernachrichtensuffix", + "Inserted before an Assistant message and as a last prompt line when generating an AI reply.": "Wird vor einer Assistentennachricht und als letzte Eingabeaufforderungszeile beim Generieren einer KI-Antwort eingefügt.", + "Assistant Message Prefix": "Assistenten-Nachrichtenpräfix", + "Inserted after an Assistant message.": "Wird nach einer Assistentennachricht eingefügt.", + "Assistant Message Suffix": "Assistentennachrichtensuffix", + "Inserted before a System (added by slash commands or extensions) message.": "Wird vor einer Systemnachricht (hinzugefügt durch Schrägstrichbefehle oder Erweiterungen) eingefügt.", + "System Message Prefix": "Systemnachrichtenpräfix", + "Inserted after a System message.": "Wird nach einer Systemnachricht eingefügt.", + "System Message Suffix": "Systemnachrichtensuffix", + "If enabled, System Sequences will be the same as User Sequences.": "Wenn aktiviert, sind die System-Sequenzen dieselben wie die Benutzer-Sequenzen.", + "System same as User": "System gleich Benutzer", + "Misc. Sequences": "Verschiedene Sequenzen", + "Inserted before the first Assistant's message.": "Wird vor der ersten Nachricht des Assistenten eingefügt.", + "First Assistant Prefix": "Präfix des ersten Assistenten", + "instruct_last_output_sequence": "Wird vor der letzten Nachricht des Assistenten oder als letzte Eingabeaufforderungszeile beim Generieren einer KI-Antwort eingefügt (außer bei einer neutralen/Systemrolle).", + "Last Assistant Prefix": "Präfix des letzten Assistenten", + "Will be inserted as a last prompt line when using system/neutral generation.": "Wird bei Verwendung der System-/Neutralgenerierung als letzte Eingabeaufforderungszeile eingefügt.", + "System Instruction Prefix": "Systemanweisungspräfix", + "If a stop sequence is generated, everything past it will be removed from the output (inclusive).": "Wenn eine Stoppsequenz generiert wird, wird alles danach (einschließlich) aus der Ausgabe entfernt.", + "Stop Sequence": "Stoppsequenz", + "Will be inserted at the start of the chat history if it doesn't start with a User message.": "Wird am Anfang des Chatverlaufs eingefügt, wenn dieser nicht mit einer Benutzernachricht beginnt.", + "User Filler Message": "Benutzer-Füllnachricht", + "Context Formatting": "Kontextformatierung", + "(Saved to Context Template)": "(Gespeichert in Kontextvorlage)", + "Always add character's name to prompt": "Füge immer den Namen des Charakters zur Eingabe hinzu", + "Generate only one line per request": "Generiere nur eine Zeile pro Anfrage", + "Trim Incomplete Sentences": "Unvollständige Sätze entfernen", + "Include Newline": "Zeilenumbruch einbeziehen", + "Misc. Settings": "Sonstige Einstellungen", + "Collapse Consecutive Newlines": "Aufeinanderfolgende neue Zeilen zusammenfalten", + "Trim spaces": "Leerzeichen entfernen", + "Tokenizer": "Tokenizer", + "Token Padding": "Token-Auffüllung", + "Start Reply With": "Antwort mit starten", + "AI reply prefix": "KI-Antwortpräfix", + "Show reply prefix in chat": "Antwortpräfix im Chat anzeigen", + "Non-markdown strings": "Nicht-Markdown-Strings", + "separate with commas w/o space between": "getrennt durch Kommas ohne Leerzeichen dazwischen", + "Custom Stopping Strings": "Benutzerdefinierte Stoppzeichenfolgen", + "JSON serialized array of strings": "JSON serialisierte Reihe von Zeichenfolgen", + "Replace Macro in Stop Strings": "Makro in benutzerdefinierten Stoppzeichenfolgen ersetzen", + "Auto-Continue": "Automatisch fortsetzen", + "Allow for Chat Completion APIs": "Erlaube Chat-Vervollständigungs-APIs", + "Target length (tokens)": "Ziel-Länge (Tokens)", + "World Info": "Weltinformation", + "Locked = World Editor will stay open": "Verriegelt = Welt-Editor bleibt geöffnet", + "Worlds/Lorebooks": "Welten/Lorebooks", + "Active World(s) for all chats": "Aktive Welt(en) für alle Chats", + "-- World Info not found --": "-- Weltinformation nicht gefunden --", + "Global World Info/Lorebook activation settings": "Global World Info/Lorebook Aktivierungseinstellungen", + "Click to expand": "Zum erweitern klicken", + "Scan Depth": "Scan-Tiefe", + "Context %": "Kontext %", + "Budget Cap": "Budgetgrenze", + "(0 = disabled)": "(0 = deaktiviert)", + "Scan chronologically until reached min entries or token budget.": "Chronologisch scannen, bis die Mindesteinträge oder das Token-Budget erreicht sind.", + "Min Activations": "Mindestanzahl Aktivierungen", + "Max Depth": "Maximale Tiefe", + "(0 = unlimited, use budget)": "(0 = unbegrenzt, Budget nutzen)", + "Insertion Strategy": "Einfügestrategie", + "Sorted Evenly": "Gleichmäßig sortiert", + "Character Lore First": "Charakter-Lore zuerst", + "Global Lore First": "Globale Lore zuerst", + "Entries can activate other entries by mentioning their keywords": "Einträge können andere Einträge aktivieren, indem sie ihre Schlüsselwörter erwähnen", + "Recursive Scan": "Rekursive Suche", + "Lookup for the entry keys in the context will respect the case": "Die Suche nach den Eintragsschlüsseln im Kontext wird die Groß- und Kleinschreibung berücksichtigen", + "Case Sensitive": "Groß-/Kleinschreibung beachten", + "If the entry key consists of only one word, it would not be matched as part of other words": "Wenn der Eintragsschlüssel nur aus einem Wort besteht, wird er nicht als Teil anderer Wörter abgeglichen", + "Match Whole Words": "Ganze Wörter abgleichen", + "Only the entries with the most number of key matches will be selected for Inclusion Group filtering": "Für die Einschlussgruppenfilterung werden nur die Einträge mit den meisten Schlüsselübereinstimmungen ausgewählt.", + "Use Group Scoring": "Gruppenwertung verwenden", + "Alert if your world info is greater than the allocated budget.": "Alarm, wenn Ihre Weltinformationen das zugewiesene Budget überschreiten.", + "Alert On Overflow": "Warnung bei Überlauf", + "New": "Neu", + "or": "oder", + "--- Pick to Edit ---": "--- Zum Bearbeiten auswählen ---", + "Rename World Info": "Weltinfo umbenennen", + "Open all Entries": "Alle Einträge öffnen", + "Close all Entries": "Alle Einträge schließen", + "New Entry": "Neuer Eintrag", + "Fill empty Memo/Titles with Keywords": "Leere Memo/Titel mit Schlüsselwörtern füllen", + "Import World Info": "Weltinfo importieren", + "Export World Info": "Weltinfo exportieren", + "Duplicate World Info": "Weltinfo duplizieren", + "Delete World Info": "Weltinfo löschen", + "Search...": "Suchen...", + "Search": "Suchen", + "Priority": "Priorität", + "Custom": "Benutzerdefiniert", + "Title A-Z": "Titel A-Z", + "Title Z-A": "Titel Z-A", + "Tokens ↗": "Token ↗", + "Tokens ↘": "Token ↘", + "Depth ↗": "Tiefe ↗", + "Depth ↘": "Tiefe ↘", + "Order ↗": "Reihenfolge ↗", + "Order ↘": "Reihenfolge ↘", + "UID ↗": "UID ↗", + "UID ↘": "UID ↘", + "Trigger% ↗": "Auslöser% ↗", + "Trigger% ↘": "Auslöser% ↘", + "Refresh": "Aktualisieren", + "User Settings": "Benutzereinstellungen", + "Simple": "Einfach", + "Advanced": "Fortgeschritten", + "UI Language": "UI-Sprache", + "Account": "Konto", + "Admin Panel": "Administrationsmenü", + "Logout": "Ausloggen", + "Search Settings": "Sucheinstellungen", + "UI Theme": "UI-Thema", + "Import a theme file": "Ein Design-Datei importieren", + "Export a theme file": "Ein Design-Datei exportieren", + "Delete a theme": "Löschen eines Designs", + "Update a theme file": "Ein Theme-Datei aktualisieren", + "Save as a new theme": "Als neues Theme speichern", + "Avatar Style:": "Avatar-Stil", + "Circle": "Kreis", + "Square": "Quadrat", + "Rectangle": "Rechteck", + "Chat Style:": "Chat-Stil:", + "Flat": "Flache\nBlasen\nDokument", + "Bubbles": "Blasen", + "Document": "Dokument", + "Specify colors for your theme.": "Geben Sie Farben für Ihr Design an.", + "Theme Colors": "Themenfarben", + "Main Text": "Haupttext", + "Italics Text": "Kursiver Text", + "Underlined Text": "Unterstrichener Text", + "Quote Text": "Zitattext", + "Shadow Color": "Schattenfarbe", + "Chat Background": "Chat-Hintergrund", + "UI Background": "UI-Hintergrund", + "UI Border": "UI-Rand", + "User Message Blur Tint": "Benutzer-Nachrichten-Blur-Tönung", + "AI Message Blur Tint": "KI-Nachrichten-Blur-Tönung", + "Chat Width": "Chat-Breite", + "Width of the main chat window in % of screen width": "Breite des Hauptchatfensters in % der Bildschirmbreite", + "Font Scale": "Schriftskalierung", + "Font size": "Schriftgröße", + "Blur Strength": "Unschärfestärke", + "Blur strength on UI panels.": "Unschärfestärke auf UI-Panels.", + "Text Shadow Width": "Textschattenbreite", + "Strength of the text shadows": "Stärke der Textschatten", + "Disables animations and transitions": "Deaktiviert Animationen und Übergänge", + "Reduced Motion": "Verringerte Bewegung", + "removes blur from window backgrounds": "Entfernt Unschärfe von Fensterhintergründen", + "No Blur Effect": "Kein Unschärfeeffekt", + "Remove text shadow effect": "Entferne den Textschatten-Effekt", + "No Text Shadows": "Keine Textschatten", + "Reduce chat height, and put a static sprite behind the chat window": "Verringere die Chat-Höhe und setze einen statischen Sprite hinter das Chat-Fenster", + "Waifu Mode": "Waifu-Modus", + "Always show the full list of the Message Actions context items for chat messages, instead of hiding them behind '...'": "Zeige immer die vollständige Liste der Nachrichtenaktionen-Kontextelemente für Chat-Nachrichten an, anstatt sie hinter '...' zu verstecken", + "Auto-Expand Message Actions": "Automatische Erweiterung von Nachrichtenaktionen", + "Alternative UI for numeric sampling parameters with fewer steps": "Alternative UI für numerische Probenparameter mit weniger Schritten", + "Zen Sliders": "Zen-Schieberegler", + "Entirely unrestrict all numeric sampling parameters": "Völlig alle numerischen Probenparameter freigeben", + "Mad Lab Mode": "Verrückter Labor-Modus", + "Time the AI's message generation, and show the duration in the chat log": "Zeit die Nachrichtengenerierung des KI und zeige die Dauer im Chat-Log", + "Message Timer": "Nachrichten-Timer", + "Show a timestamp for each message in the chat log": "Zeige einen Zeitstempel für jede Nachricht im Chat-Log", + "Chat Timestamps": "Chat-Zeitstempel", + "Show an icon for the API that generated the message": "Zeige ein Symbol für die API, die die Nachricht generiert hat", + "Model Icon": "Modell-Icon", + "Show sequential message numbers in the chat log": "Zeige aufeinanderfolgende Nachrichtennummern im Chat-Log", + "Message IDs": "Nachrichten-IDs", + "Hide avatars in chat messages.": "Avatare in Chatnachrichten verbergen.", + "Hide Chat Avatars": "Chat-Avatare ausblenden", + "Show the number of tokens in each message in the chat log": "Zeige die Anzahl der Tokens in jeder Nachricht im Chat-Log", + "Show Message Token Count": "Anzahl der Nachrichten-Token anzeigen", + "Single-row message input area. Mobile only, no effect on PC": "Einzeln Zeile Nachrichteneingabebereich. Nur auf Mobilgeräten, keine Auswirkungen auf PC", + "Compact Input Area (Mobile)": "Kompakter Eingabebereich (Mobil)", + "In the Character Management panel, show quick selection buttons for favorited characters": "Zeige im Charakter-Management-Panel Schnellauswahlknöpfe für favorisierte Charaktere", + "Characters Hotswap": "Charaktere Hotswap", + "Enable magnification for zoomed avatar display.": "Aktivieren Sie die Vergrößerung für die vergrößerte Avatar-Anzeige.", + "Avatar Hover Magnification": "Avatar-Hover-Vergrößerung", + "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "Aktiviert einen Vergrößerungseffekt beim Hovern, wenn Sie den gezoomten Avatar anzeigen, nachdem Sie im Chat auf das Bild eines Avatars geklickt haben.", + "Show tagged character folders in the character list": "Zeige markierte Charakterordner in der Charakterliste", + "Tags as Folders": "Tags als Ordner", + "Tags_as_Folders_desc": "Letzte Änderung: Tags müssen im Tag-Management-Menü als Ordner markiert sein, um als solche angezeigt zu werden. Klicken Sie hier, um es aufzurufen.", + "Character Handling": "Charakterbehandlung", + "If set in the advanced character definitions, this field will be displayed in the characters list.": "Wenn in den erweiterten Charakterdefinitionen festgelegt, wird dieses Feld in der Charakterliste angezeigt.", + "Char List Subheader": "Zeichenliste - Unterüberschrift", + "Character Version": "Charakterversion", + "Created by": "Erstellt von", + "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "Verwende Fuzzy-Matching und suche Charaktere in der Liste nach allen Datenfeldern, nicht nur nach einem Namens-Substring", + "Advanced Character Search": "Erweiterte Charakter-Suche", + "If checked and the character card contains a prompt override (System Prompt), use that instead": "Wenn aktiviert und die Charakterkarte eine Prompt-Überschreibung enthält (System-Prompt), verwende stattdessen diese", + "Prefer Character Card Prompt": "Bevorzuge Charakterkarten-Prompt", + "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Wenn aktiviert und die Charakterkarte eine Jailbreak-Überschreibung enthält (Post-History-Instruction), verwende stattdessen diese", + "Prefer Character Card Jailbreak": "Bevorzuge Charakterkarten-Jailbreak", + "never_resize_avatars_tooltip": "Vermeiden Sie das Zuschneiden und Ändern der Größe importierter Zeichenbilder. Wenn deaktiviert, wird die Größe auf 512 x 768 zugeschnitten/angepasst.", + "Never resize avatars": "Avatare niemals verkleinern", + "Show actual file names on the disk, in the characters list display only": "Zeige tatsächliche Dateinamen auf der Festplatte, nur in der Anzeige der Charakterliste", + "Show avatar filenames": "Avatar-Dateinamen anzeigen", + "Prompt to import embedded card tags on character import. Otherwise embedded tags are ignored": "Aufforderung zum Importieren eingebetteter Karten-Tags beim Importieren von Charakteren. Andernfalls werden eingebettete Tags ignoriert", + "Import Card Tags": "Karten-Tags importieren", + "Hide character definitions from the editor panel behind a spoiler button": "Verstecke Charakterdefinitionen im Editor-Panel hinter einem Spoiler-Button", + "Spoiler Free Mode": "Spoilerfreier Modus", + "Miscellaneous": "Verschiedenes", + "Reload and redraw the currently open chat": "Lade den aktuell geöffneten Chat neu und zeichne ihn neu", + "Reload Chat": "Chat neu laden", + "Debug Menu": "Debug-Menü", + "Smooth Streaming": "Reibungsloses Streaming", + "Experimental feature. May not work for all backends.": "Experimentelle Funktion. Funktioniert möglicherweise nicht für alle Backends.", + "Slow": "Langsam", + "Fast": "Schnell", + "Play a sound when a message generation finishes": "Spiele einen Ton, wenn die Nachrichtengenerierung abgeschlossen ist", + "Message Sound": "Nachrichtenklang", + "Only play a sound when ST's browser tab is unfocused": "Spiele nur einen Ton, wenn der Browser-Tab von ST nicht im Fokus ist", + "Background Sound Only": "Nur Hintergrundgeräusch", + "Reduce the formatting requirements on API URLs": "Reduziere die Formatierungsanforderungen für API-URLs", + "Relaxed API URLS": "Entspannte API-URLs", + "Ask to import the World Info/Lorebook for every new character with embedded lorebook. If unchecked, a brief message will be shown instead": "Frage nach dem Importieren von Weltinfos/Lorebooks für jeden neuen Charakter mit eingebettetem Lorebook. Wenn nicht ausgewählt, wird stattdessen eine kurze Nachricht angezeigt", + "Lorebook Import Dialog": "Lorebook-Import-Dialog", + "Restore unsaved user input on page refresh": "Stelle nicht gespeicherte Benutzereingaben beim Aktualisieren der Seite wieder her", + "Restore User Input": "Benutzereingabe wiederherstellen", + "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "Ermögliche das Neupositionieren bestimmter UI-Elemente durch Ziehen. Nur auf dem PC, keine Auswirkungen auf Mobilgeräte", + "Movable UI Panels": "Verschiebbare UI-Panel", + "MovingUI preset. Predefined/saved draggable positions": "MovingUI-Voreinstellung. Vordefinierte/gespeicherte verschiebbare Positionen", + "MUI Preset": "MUI-Voreinstellung", + "Save movingUI changes to a new file": "Speichere MovingUI-Änderungen in einer neuen Datei", + "Reset MovingUI panel sizes/locations.": "Setzen Sie die Größen/Positionen der MovingUI-Bedienfelder zurück.", + "Apply a custom CSS style to all of the ST GUI": "Wende einen benutzerdefinierten CSS-Stil auf die gesamte ST-Benutzeroberfläche an", + "Custom CSS": "Benutzerdefiniertes CSS", + "Expand the editor": "Erweitern Sie den Editor", + "Chat/Message Handling": "Chat-/Nachrichtenbehandlung", + "# Messages to Load": "# Zu ladende Nachricht", + "The number of chat history messages to load before pagination.": "Die Anzahl der Chatverlaufsnachrichten, die vor der Paginierung geladen werden sollen.", + "(0 = All)": "(0 = Alle)", + "Streaming FPS": "Streaming FPS", + "Update speed of streamed text.": "Aktualisierungsgeschwindigkeit des gestreamten Textes.", + "Example Messages Behavior": "Verhalten von Beispielnachrichten", + "Gradual push-out": "Allmähliches Herausschieben", + "Always include examples": "Immer Beispiele einbeziehen", + "Never include examples": "Nie Beispiele einbeziehen", + "Send on Enter": "Mit Enter senden", + "Disabled": "Deaktiviert", + "Automatic (PC)": "Automatisch (PC)", + "Press Send to continue": "Drücke Senden, um fortzufahren", + "Show a button in the input area to ask the AI to continue (extend) its last message": "Zeige einen Button im Eingabebereich, um die KI zu bitten, ihre letzte Nachricht fortzusetzen (zu erweitern)", + "Quick 'Continue' button": "Schnelle 'Weiter'-Schaltfläche", + "Show arrow buttons on the last in-chat message to generate alternative AI responses. Both PC and mobile": "Zeige Pfeilbuttons auf der letzten In-Chat-Nachricht, um alternative KI-Antworten zu generieren. Sowohl auf PC als auch auf Mobilgeräten", + "Swipes": "Wischgesten", + "Allow using swiping gestures on the last in-chat message to trigger swipe generation. Mobile only, no effect on PC": "Ermögliche das Verwenden von Wischgesten auf der letzten In-Chat-Nachricht, um die Wischgenerierung auszulösen. Nur auf Mobilgeräten, keine Auswirkungen auf PCs", + "Gestures": "Gesten", + "Auto-load Last Chat": "Letzten Chat automatisch laden", + "Auto-scroll Chat": "Chat automatisch scrollen", + "Save edits to messages without confirmation as you type": "Speichere Änderungen an Nachrichten ohne Bestätigung während du tippst", + "Auto-save Message Edits": "Nachrichtenänderungen automatisch speichern", + "Confirm message deletion": "Löschung der Nachricht bestätigen", + "Auto-fix Markdown": "Markdown automatisch reparieren", + "Disallow embedded media from other domains in chat messages": "Eingebettete Medien von anderen Domänen in Chat-Nachrichten nicht zulassen.", + "Forbid External Media": "Externe Medien verbieten", + "Allow {{char}}: in bot messages": "Erlaube {{char}}: in Bot-Nachrichten", + "Allow {{user}}: in bot messages": "Erlaube {{user}}: in Bot-Nachrichten", + "Skip encoding and characters in message text, allowing a subset of HTML markup as well as Markdown": "Überspringe die Codierung von und Zeichen im Nachrichtentext, was eine Teilmenge von HTML-Markup sowie Markdown zulässt", + "Show tags in responses": "Tags in Antworten anzeigen", + "Allow AI messages in groups to contain lines spoken by other group members": "Ermögliche es AI-Nachrichten in Gruppen, Zeilen zu enthalten, die von anderen Gruppenmitgliedern gesprochen wurden", + "Relax message trim in Groups": "Nachrichtenbeschnitt in Gruppen entspannen", + "Log prompts to console": "Protokolliere Aufforderungen in die Konsole", + "Requests logprobs from the API for the Token Probabilities feature": "Fordert Logprobs von der API für die Funktion Token-Wahrscheinlichkeiten an", + "Request token probabilities": "Token-Wahrscheinlichkeiten anfordern", + "Automatically reject and re-generate AI message based on configurable criteria": "Automatisch AI-Nachricht ablehnen und basierend auf konfigurierbaren Kriterien erneut generieren", + "Auto-swipe": "Automatisches Wischen", + "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Aktiviere die Auto-Wisch-Funktion. Einstellungen in diesem Abschnitt haben nur dann Auswirkungen, wenn das automatische Wischen aktiviert ist", + "Minimum generated message length": "Minimale generierte Nachrichtenlänge", + "If the generated message is shorter than these many characters, trigger an auto-swipe": "Wenn die generierte Nachricht kürzer ist als diese, löse automatisches Wischen aus", + "Blacklisted words": "Verbotene Wörter", + "words you dont want generated separated by comma ','": "Wörter, die du nicht generiert haben möchtest, durch Komma ',' getrennt", + "Blacklisted word count to swipe": "Anzahl der verbotenen Wörter, um zu wischen", + "Minimum number of blacklisted words detected to trigger an auto-swipe": "Mindestanzahl von erkannten verbotenen Wörtern, um eine automatische Wischbewegung auszulösen", + "AutoComplete Settings": "AutoVervollständigen-Einstellungen", + "Automatically hide details": "Details automatisch ausblenden", + "Determines how entries are found for autocomplete.": "Bestimmt, wie Einträge für die Autovervollständigung gefunden werden.", + "Autocomplete Matching": "Dazu passend", + "Starts with": "Beginnt mit", + "Includes": "Enthält", + "Fuzzy": "Unscharf", + "Sets the style of the autocomplete.": "Legt den Stil der automatischen Vervollständigung fest.", + "Autocomplete Style": "Stil", + "Follow Theme": "Thema folgen", + "Dark": "Dunkel", + "Sets the font size of the autocomplete.": "Legt die Schriftgröße der Autovervollständigung fest.", + "Sets the width of the autocomplete.": "Legt die Breite der Autovervollständigung fest.", + "Autocomplete Width": "Breite", + "chat input box": "Chat-Eingabefeld", + "entire chat width": "gesamte Chatbreite", + "full window width": "volle Fensterbreite", + "STscript Settings": "STscript-Einstellungen", + "Sets default flags for the STscript parser.": "Legt Standardflags für den STscript-Parser fest.", + "Parser Flags": "Parser-Flags", + "Switch to stricter escaping, allowing all delimiting characters to be escaped with a backslash, and backslashes to be escaped as well.": "Wechseln Sie zu einer strengeren Escape-Methode, bei der alle Trennzeichen mit einem Backslash und auch Backslashs mit einem Escape-Zeichen versehen werden können.", + "STRICT_ESCAPING": "STRENGES_ESCAPING", + "Replace all {{getvar::}} and {{getglobalvar::}} macros with scoped variables to avoid double macro substitution.": "Ersetzen Sie alle {{getvar::}}- und {{getglobalvar::}}-Makros durch gültige Variablen, um eine doppelte Makroersetzung zu vermeiden.", + "REPLACE_GETVAR": "REPLACE_GETVAR", + "Change Background Image": "Hintergrundbild ändern", + "Filter": "Filter", + "Automatically select a background based on the chat context": "Automatisch einen Hintergrund basierend auf dem Chatkontext auswählen", + "Auto-select": "Automatische Auswahl", + "System Backgrounds": "Systemhintergründe", + "Chat Backgrounds": "Chat-Hintergründe", + "bg_chat_hint_1": "Chat-Hintergründe generiert mit dem", + "bg_chat_hint_2": "Die Erweiterung wird hier angezeigt.", + "Extensions": "Erweiterungen", + "Notify on extension updates": "Benachrichtigen bei Erweiterungsaktualisierungen", + "Manage extensions": "Erweiterungen verwalten", + "Import Extension From Git Repo": "Erweiterung aus Git-Repository importieren", + "Install extension": "Erweiterung installieren", + "Extras API:": "Extras API:", + "Auto-connect": "Automatisch verbinden", + "Extras API URL": "Extras API URL", + "Extras API key (optional)": "Zusätzlicher API-Schlüssel (optional)", + "Persona Management": "Persönlichkeitsverwaltung", + "How do I use this?": "Wie benutze ich das?", + "Click for stats!": "Klick für Statistiken!", + "Usage Stats": "Nutzungsstatistiken", + "Backup your personas to a file": "Speicher deine Persönlichkeiten in einer Datei.", + "Backup": "Backup", + "Restore your personas from a file": "Stell deine Persönlichkeiten aus einer Datei wieder her.", + "Restore": "Wiederherstellen", + "Create a dummy persona": "Erstelle eine Dummy-Persona", + "Create": "Erstellen", + "Toggle grid view": "Rasteransicht umschalten", + "No persona description": "[Keine Beschreibung]", + "Name": "Name", + "Enter your name": "Gib deinen Namen ein", + "Click to set a new User Name": "Klicke, um einen neuen Benutzernamen festzulegen", + "Click to lock your selected persona to the current chat. Click again to remove the lock.": "Klicke, um deine ausgewählte Persona für den aktuellen Chat zu sperren. Klicke erneut, um die Sperre zu entfernen.", + "Click to set user name for all messages": "Klicke, um für alle Nachrichten einen Benutzernamen festzulegen", + "Persona Description": "Persönlichkeitsbeschreibung", + "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "Beispiel: [{{user}} ist ein 28-jähriges rumänisches Katzenmädchen.]", + "Tokens persona description": "Beschreibung der Tokens-Persona", + "Position:": "Position:", + "In Story String / Prompt Manager": "In Story-String / Prompt-Manager", + "Top of Author's Note": "Oberteil der Autorennotiz", + "Bottom of Author's Note": "Unterteil der Autorennotiz", + "In-chat @ Depth": "Im Chat @ Tiefe", + "Depth:": "Tiefe:", + "Role:": "Rolle:", + "System": "System", + "User": "Benutzer", + "Assistant": "Assistent", + "Show notifications on switching personas": "Benachrichtigungen beim Wechseln von Persönlichkeiten anzeigen", + "Character Management": "Charakterverwaltung", + "Locked = Character Management panel will stay open": "Verriegelt = Charakterverwaltungsfeld bleibt geöffnet", + "Select/Create Characters": "Charaktere auswählen/erstellen", + "Favorite characters to add them to HotSwaps": "Favoritencharaktere hinzufügen, um sie zu HotSwaps hinzuzufügen", + "Token counts may be inaccurate and provided just for reference.": "Token-Zählungen können ungenau sein und dienen nur zur Referenz.", + "Total tokens": "Token insgesamt", + "Calculating...": "Berechnung…", + "Tokens": "Tokens", + "Permanent tokens": "Permanente Token", + "Permanent": "Dauerhaft", + "About Token 'Limits'": "Über Token-Limits", + "Toggle character info panel": "Zeicheninformationsfeld umschalten", + "Name this character": "Gib diesem Charakter einen Namen", + "extension_token_counter": "Token:", + "Click to select a new avatar for this character": "Klicke, um einen neuen Avatar für diesen Charakter auszuwählen", + "Add to Favorites": "Zu Favoriten hinzufügen", + "Advanced Definition": "Erweiterte Definition", + "Character Lore": "Charakterhintergrund", + "Chat Lore": "Chat-Überlieferung", + "Export and Download": "Exportieren und Herunterladen", + "Duplicate Character": "Charakter duplizieren", + "Create Character": "Charakter erstellen", + "Delete Character": "Charakter löschen", + "More...": "Mehr...", + "Link to World Info": "Link zur Weltinfo", + "Import Card Lore": "Karten-Lore importieren", + "Scenario Override": "Szenarioüberschreibung", + "Convert to Persona": "In Persona konvertieren", + "Rename": "Umbenennen", + "Link to Source": "Link zur Quelle", + "Replace / Update": "Ersetzen / Aktualisieren", + "Import Tags": "Tags importieren", + "Search / Create Tags": "Tags suchen/erstellen", + "View all tags": "Alle Tags anzeigen", + "Creator's Notes": "Schöpfernotizen", + "Show / Hide Description and First Message": "Beschreibung und erste Nachricht anzeigen/verbergen", + "Character Description": "Charakterbeschreibung", + "Click to allow/forbid the use of external media for this character.": "Klicken Sie, um die Verwendung externer Medien für diesen Charakter zuzulassen/zu verbieten.", + "Ext. Media": "Ext. Medien", + "Describe your character's physical and mental traits here.": "Beschreibe hier die physischen und mentalen Eigenschaften deines Charakters.", + "First message": "Erste Nachricht", + "Click to set additional greeting messages": "Klicke, um zusätzliche Begrüßungsnachrichten festzulegen", + "Alt. Greetings": "Alt. Grüße", + "This will be the first message from the character that starts every chat.": "Dies wird die erste Nachricht des Charakters sein, die jeden Chat startet.", + "Group Controls": "Gruppensteuerung", + "Chat Name (Optional)": "Chatname (optional)", + "Click to select a new avatar for this group": "Klicke, um einen neuen Avatar für diese Gruppe auszuwählen", + "Group reply strategy": "Strategie für Gruppenantworten", + "Natural order": "Natürliche Reihenfolge", + "List order": "Listenreihenfolge", + "Group generation handling mode": "Gruppengenerierungs-Handhabungsmodus", + "Swap character cards": "Charakterkarten tauschen", + "Join character cards (exclude muted)": "Charakterkarten beitreten (Stummschaltung ausschließen)", + "Join character cards (include muted)": "Charakterkarten beitreten (auch stummgeschaltet)", + "Inserted before each part of the joined fields.": "Wird vor jedem Teil der verbundenen Felder eingefügt.", + "Join Prefix": "Präfix beitreten", + "When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and with the name of the part (e.g.: description, personality, scenario, etc.)": "Wenn „Charakterkarten zusammenfügen“ ausgewählt ist, werden alle entsprechenden Felder der Charaktere zusammengefügt. Das bedeutet, dass im Story-String beispielsweise alle Charakterbeschreibungen zu einem großen Text zusammengefügt werden. Wenn Sie möchten, dass diese Felder getrennt werden, können Sie hier ein Präfix oder Suffix definieren. Dieser Wert unterstützt normale Makros und ersetzt außerdem {{char}} durch den Namen des entsprechenden Charakters und durch den Namen des Teils (z. B.: Beschreibung, Persönlichkeit, Szenario usw.).", + "Inserted after each part of the joined fields.": "Wird nach jedem Teil der verbundenen Felder eingefügt.", + "Join Suffix": "Join-Suffix", + "Set a group chat scenario": "Setze ein Gruppenchat-Szenario", + "Click to allow/forbid the use of external media for this group.": "Klicken Sie, um die Verwendung externer Medien für diese Gruppe zuzulassen/zu verbieten.", + "Restore collage avatar": "Collage-Avatar wiederherstellen", + "Allow self responses": "Selbstantworten erlauben", + "Auto Mode": "Automatikmodus", + "Auto Mode delay": "Auto-Modus-Verzögerung", + "Hide Muted Member Sprites": "Stummgeschaltete Mitglieder-Sprites verbergen", + "Current Members": "Aktuelle Mitglieder", + "Add Members": "Mitglieder hinzufügen", + "Create New Character": "Neuen Charakter erstellen", + "Import Character from File": "Charakter aus Datei importieren", + "Import content from external URL": "Inhalt von externer URL importieren", + "Create New Chat Group": "Neue Chatgruppe erstellen", + "Characters sorting order": "Sortierreihenfolge der Charaktere", + "A-Z": "A-Z", + "Z-A": "Z-A", + "Newest": "Neueste", + "Oldest": "Älteste", + "Favorites": "Favoriten", + "Recent": "Neu", + "Most chats": "Meiste Chats", + "Least chats": "Wenigste Chats", + "Most tokens": "Die meisten Tokens", + "Least tokens": "Die wenigsten Tokens", + "Random": "Zufällig", + "Toggle character grid view": "Rasteransicht des Charakters umschalten", + "Bulk_edit_characters": "Massenbearbeitung von Charakteren", + "Bulk select all characters": "Massenauswahl aller Zeichen", + "Bulk delete characters": "Massenlöschung von Charakteren", + "popup-button-save": "Speichern", + "popup-button-yes": "Ja", + "popup-button-no": "NEIN", + "popup-button-cancel": "Stornieren", + "popup-button-import": "Importieren", + "Advanced Definitions": "Erweiterte Definitionen", + "Prompt Overrides": "Eingabeaufforderungsüberschreibungen", + "(For Chat Completion and Instruct Mode)": "(Für Chat-Abschluss und Anweisungsmodus)", + "Insert {{original}} into either box to include the respective default prompt from system settings.": "Füge {{original}} in eines der Felder ein, um den jeweiligen Standardprompt aus den Systemeinstellungen einzuschließen.", + "Main Prompt": "Haupt-Prompt", + "Any contents here will replace the default Main Prompt used for this character. (v2 spec: system_prompt)": "Alle Inhalte hier ersetzen den Standard-Haupt-Prompt, der für diesen Charakter verwendet wird. (v2 Spezifikation: system_prompt)", + "Any contents here will replace the default Jailbreak Prompt used for this character. (v2 spec: post_history_instructions)": "Alle Inhalte hier ersetzen den standardmäßigen Jailbreak-Prompt, der für diesen Charakter verwendet wird. (v2 Spezifikation: post_history_instructions)", + "Creator's Metadata (Not sent with the AI prompt)": "Metadaten des Erstellers (Nicht mit dem KI-Prompt gesendet)", + "Creator's Metadata": "Metadaten des Erstellers", + "(Not sent with the AI Prompt)": "(Nicht mit der KI-Eingabeaufforderung gesendet)", + "Everything here is optional": "Alles hier ist optional", + "(Botmaker's name / Contact Info)": "(Name des Bot-Erstellers / Kontaktinformationen)", + "(If you want to track character versions)": "(Wenn du Charakterversionen verfolgen möchtest)", + "(Describe the bot, give use tips, or list the chat models it has been tested on. This will be displayed in the character list.)": "(Beschreibe den Bot, gib Tipps zur Verwendung oder liste die Chatmodelle auf, auf denen er getestet wurde. Dies wird in der Charakterliste angezeigt.)", + "Tags to Embed": "Tags zum Einbetten", + "(Write a comma-separated list of tags)": "(Schreibe eine kommagetrennte Liste von Tags)", + "Personality summary": "Persönlichkeitszusammenfassung", + "(A brief description of the personality)": "(Eine kurze Beschreibung der Persönlichkeit)", + "Scenario": "Szenario", + "(Circumstances and context of the interaction)": "(Umstände und Kontext der Interaktion)", + "Character's Note": "Anmerkung des Charakters", + "(Text to be inserted in-chat @ designated depth and role)": "(Text wird im Chat in der angegebenen Tiefe und Rolle eingefügt)", + "@ Depth": "@ Tiefe", + "Role": "Rolle", + "Talkativeness": "Gesprächigkeit", + "How often the character speaks in group chats!": "Wie oft der Charakter in Gruppenchats spricht!", + "How often the character speaks in": "Wie oft spricht der Charakter in", + "group chats!": "Gruppenchats!", + "Shy": "Schüchtern", + "Normal": "Normal", + "Chatty": "Plaudernd", + "Examples of dialogue": "Beispiele für Dialog", + "Important to set the character's writing style.": "Wichtig, den Schreibstil des Charakters festzulegen.", + "(Examples of chat dialog. Begin each example with START on a new line.)": "(Beispiele für Chatdialoge. Beginne jedes Beispiel mit START in einer neuen Zeile.)", + "Save": "Speichern", + "Chat History": "Chat-Verlauf", + "Import Chat": "Chat importieren", + "Copy to system backgrounds": "In Systemhintergründe kopieren", + "Rename background": "Hintergrund umbenennen", + "Lock": "Sperren", + "Unlock": "Freischalten", + "Delete background": "Hintergrund löschen", + "Chat Scenario Override": "Chat-Szenario-Überschreibung", + "Remove": "Entfernen", + "Type here...": "Tippe hier...", + "Chat Lorebook": "Chat Lorebook für", + "Chat Lorebook for": "Chat Lorebook für", + "chat_world_template_txt": "Eine ausgewählte Weltinformation wird an diesen Chat gebunden. Beim Generieren einer KI-Antwort wird sie mit den Einträgen aus globalen und Charakter-Lorebooks kombiniert.", + "Select a World Info file for": "Wähle eine Weltinfo-Datei für", + "Primary Lorebook": "Primäres Geschichtenbuch", + "A selected World Info will be bound to this character as its own Lorebook.": "Eine ausgewählte Weltinfo wird diesem Charakter als sein eigenes Geschichtenbuch zugeordnet.", + "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "Beim Generieren einer KI-Antwort wird sie mit den Einträgen aus einem globalen Weltinfo-Selektor kombiniert.", + "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "Beim Exportieren eines Charakters wird auch die ausgewählte Geschichtenbuchdatei in den JSON-Daten exportiert.", + "Additional Lorebooks": "Zusätzliche Geschichtenbücher", + "Associate one or more auxillary Lorebooks with this character.": "Verknüpfe ein oder mehrere zusätzliche Geschichtenbücher mit diesem Charakter.", + "NOTE: These choices are optional and won't be preserved on character export!": "ACHTUNG: Diese Entscheidungen sind optional und werden beim Export des Charakters nicht beibehalten!", + "Rename chat file": "Chatdatei umbenennen", + "Export JSONL chat file": "JSONL-Chatdatei exportieren", + "Download chat as plain text document": "Chat als einfaches Textdokument herunterladen", + "Delete chat file": "Chatdatei löschen", + "Use tag as folder": "Als Ordner markieren", + "Delete tag": "Tag löschen", + "Entry Title/Memo": "Eintragstitel/Memo", + "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized❌ Disabled": "WI-Eintragstatus: 🔵 Konstant 🟢 Normal 🔗 Vektorisiert ❌ Deaktiviert", + "WI_Entry_Status_Constant": "Konstante", + "WI_Entry_Status_Normal": "Normal", + "WI_Entry_Status_Vectorized": "Vektorisiert", + "WI_Entry_Status_Disabled": "Deaktiviert", + "T_Position": "↑Char: vor Charakterdefinitionen\n↓Char: nach Charakterdefinitionen\n↑AN: vor Anmerkungen des Autors\n↓AN: nach Anmerkungen des Autors\n@D: bei Tiefe", + "Before Char Defs": "Vor Charakterdefinitionen", + "After Char Defs": "Nach Charakterdefinitionen", + "Before EM": "↑EM", + "After EM": "↓EM", + "Before AN": "Vor AN", + "After AN": "Nach AN", + "at Depth System": "@D ⚙️", + "at Depth User": "@D 👤", + "at Depth AI": "@D 🤖", + "Depth": "Tiefe", + "Order:": "Reihenfolge:", + "Order": "Reihenfolge:", + "Trigger %:": "Auslösen %:", + "Probability": "Wahrscheinlichkeit", + "Duplicate world info entry": "Doppelter Weltinfoeintrag", + "Delete world info entry": "Weltinfoeintrag löschen", + "Comma separated (required)": "Komma getrennt (erforderlich)", + "Primary Keywords": "Primäre Schlüsselwörter", + "Keywords or Regexes": "Schlüsselwörter oder reguläre Ausdrücke", + "Comma separated list": "Kommagetrennte Liste", + "Switch to plaintext mode": "In den Klartextmodus wechseln", + "Logic": "Logik", + "AND ANY": "UND JEDE", + "AND ALL": "UND ALLES", + "NOT ALL": "NICHT ALLES", + "NOT ANY": "NICHT JEDE", + "(ignored if empty)": "(wird ignoriert, wenn leer)", + "Optional Filter": "Optionaler Filter", + "Keywords or Regexes (ignored if empty)": "Schlüsselwörter oder reguläre Ausdrücke (werden ignoriert, wenn sie leer sind)", + "Comma separated list (ignored if empty)": "Durch Komma getrennte Liste (wird ignoriert, wenn sie leer ist)", + "Use global setting": "Globale Einstellung verwenden", + "Case-Sensitive": "Groß-/Kleinschreibung beachten", + "Yes": "Ja", + "No": "Nein", + "Can be used to automatically activate Quick Replies": "Kann verwendet werden, um Schnellantworten automatisch zu aktivieren", + "Automation ID": "Automatisierungs-ID", + "( None )": "( Keiner )", + "Content": "Inhalt", + "Exclude from recursion": "Aus Rekursion ausschließen", + "Prevent further recursion (this entry will not activate others)": "Weitere Rekursion verhindern (dieser Eintrag aktiviert keine anderen)", + "Delay until recursion (this entry can only be activated on recursive checking)": "Verzögerung bis zur Rekursion (dieser Eintrag kann nur bei rekursiver Prüfung aktiviert werden)", + "What this keyword should mean to the AI, sent verbatim": "Was dieses Schlüsselwort für die KI bedeuten soll, wörtlich gesendet", + "Filter to Character(s)": "Filtern auf Charakter(e)", + "Character Exclusion": "Charakterausschluss", + "-- Characters not found --": "-- Charaktere nicht gefunden --", + "Inclusion Group": "Einschlussgruppe", + "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "Inklusionsgruppen stellen sicher, dass immer nur ein Eintrag aus einer Gruppe aktiviert wird, wenn mehrere ausgelöst werden. Unterstützt mehrere durch Kommas getrennte Gruppen. Dokumentation: World Info - Inclusion Group", + "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "Diesen Eintrag priorisieren: Wenn diese Option aktiviert ist, wird dieser Eintrag aus allen Auswahlen priorisiert. Wenn mehrere priorisiert sind, wird der Eintrag mit der höchsten „Reihenfolge“ ausgewählt.", + "Only one entry with the same label will be activated": "Nur ein Eintrag mit demselben Label wird aktiviert", + "A relative likelihood of entry activation within the group": "Eine relative Wahrscheinlichkeit der Eintrittsaktivierung innerhalb der Gruppe", + "Group Weight": "Gruppengewicht", + "Selective": "Selektiv", + "Use Probability": "Wahrscheinlichkeit verwenden", + "Add Memo": "Memo hinzufügen", + "Text or token ids": "Text oder [Token-IDs]", + "close": "schließen", + "prompt_manager_edit": "Bearbeiten", + "prompt_manager_name": "Name", + "A name for this prompt.": "Ein Name für diese Eingabeaufforderung.", + "To whom this message will be attributed.": "Wem diese Nachricht zugeschrieben wird.", + "AI Assistant": "KI-Assistent", + "prompt_manager_position": "Position", + "Injection position. Next to other prompts (relative) or in-chat (absolute).": "Injektionsposition. Neben anderen Eingabeaufforderungen (relativ) oder im Chat (absolut).", + "prompt_manager_relative": "Relativ", + "prompt_manager_depth": "Tiefe", + "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "Injektionstiefe. 0 = nach der letzten Nachricht, 1 = vor der letzten Nachricht usw.", + "Prompt": "Aufforderung", + "The prompt to be sent.": "Die zu sendende Eingabeaufforderung.", + "This prompt cannot be overridden by character cards, even if overrides are preferred.": "Diese Eingabeaufforderung kann nicht durch Charakterkarten überschrieben werden, selbst wenn dies bevorzugt wird.", + "prompt_manager_forbid_overrides": "Überschreibungen verbieten", + "reset": "zurücksetzen", + "save": "speichern", + "This message is invisible for the AI": "Diese Nachricht ist für die KI unsichtbar", + "Message Actions": "Nachrichtenaktionen", + "Translate message": "Nachricht übersetzen", + "Generate Image": "Bild generieren", + "Narrate": "Erzählen", + "Exclude message from prompts": "Nachricht von Aufforderungen ausschließen", + "Include message in prompts": "Nachricht in Aufforderungen einschließen", + "Embed file or image": "Datei oder Bild einbetten", + "Create checkpoint": "Checkpoint erstellen", + "Create Branch": "Zweig erstellen", + "Copy": "Kopieren", + "Open checkpoint chat": "Checkpoint-Chat öffnen", + "Edit": "Bearbeiten", + "Confirm": "Bestätigen", + "Copy this message": "Diese Nachricht kopieren", + "Delete this message": "Diese Nachricht löschen", + "Move message up": "Nachricht nach oben verschieben", + "Move message down": "Nachricht nach unten verschieben", + "Enlarge": "Vergrößern", + "Welcome to SillyTavern!": "Willkommen bei SillyTavern!", + "welcome_message_part_1": "Lies das", + "welcome_message_part_2": "Offizielle Dokumentation", + "welcome_message_part_3": null, + "welcome_message_part_4": "Typ", + "welcome_message_part_5": "im Chat für Befehle und Makros.", + "welcome_message_part_6": "Werden Sie Mitglied der", + "Discord server": "Discord-Server", + "welcome_message_part_7": "für Informationen und Ankündigungen.", + "SillyTavern is aimed at advanced users.": "SillyTavern richtet sich an fortgeschrittene Benutzer.", + "If you're new to this, enable the simplified UI mode below.": "Wenn Sie damit noch nicht vertraut sind, aktivieren Sie unten den vereinfachten UI-Modus.", + "Change it later in the 'User Settings' panel.": "Ändern Sie es später im Bereich „Benutzereinstellungen“.", + "Enable simple UI mode": "Aktivieren Sie den einfachen UI-Modus", + "Looking for AI characters?": "Suchen Sie nach KI-Charakteren?", + "onboarding_import": "Importieren", + "from supported sources or view": "aus unterstützten Quellen oder anzeigen", + "Sample characters": "Beispielcharaktere", + "Your Persona": "Deine Persönlichkeit", + "Before you get started, you must select a persona name.": "Bevor Sie beginnen, müssen Sie einen Persona-Namen auswählen.", + "welcome_message_part_8": "Dies kann jederzeit geändert werden über die", + "welcome_message_part_9": "Symbol.", + "Persona Name:": "Personenname:", + "Temporarily disable automatic replies from this character": "Automatische Antworten dieses Charakters vorübergehend deaktivieren", + "Enable automatic replies from this character": "Automatische Antworten dieses Charakters aktivieren", + "Trigger a message from this character": "Eine Nachricht von diesem Charakter auslösen", + "Move up": "Nach oben verschieben", + "Move down": "Nach unten verschieben", + "View character card": "Charakterkarte anzeigen", + "Remove from group": "Aus Gruppe entfernen", + "Add to group": "Zur Gruppe hinzufügen", + "Alternate Greetings": "Alternative Grüße", + "Alternate_Greetings_desc": "Diese werden beim Starten eines neuen Chats als Wischbewegungen in der ersten Nachricht angezeigt.\nGruppenmitglieder können eine davon auswählen, um die Unterhaltung zu beginnen.", + "Alternate Greetings Hint": "Klicken Sie auf die Schaltfläche, um zu beginnen!", + "(This will be the first message from the character that starts every chat)": "(Dies wird die erste Nachricht des Charakters sein, die jeden Chat startet)", + "Forbid Media Override explanation": "Möglichkeit des aktuellen Charakters/der aktuellen Gruppe, externe Medien in Chats zu verwenden.", + "Forbid Media Override subtitle": "Medien: Bilder, Videos, Audio. Extern: nicht auf dem lokalen Server gehostet.", + "Always forbidden": "Immer verboten", + "Always allowed": "Immer erlaubt", + "View contents": "Inhalte anzeigen", + "Remove the file": "Entfernen Sie die Datei", + "Unique to this chat": "Einzigartig in diesem Chat", + "Checkpoints inherit the Note from their parent, and can be changed individually after that.": "Prüfpunkte erben die Notiz von ihrem übergeordneten Element und können danach einzeln geändert werden.", + "Include in World Info Scanning": "In World Info Scanning einbeziehen", + "Before Main Prompt / Story String": "Vor der Hauptaufforderung / Story-String", + "After Main Prompt / Story String": "Nach der Hauptaufforderung / Story-String", + "as": "als", + "Insertion Frequency": "Einfügungsfrequenz", + "(0 = Disable, 1 = Always)": "(0 = Deaktivieren, 1 = Immer)", + "User inputs until next insertion:": "Benutzereingaben bis zur nächsten Einfügung:", + "Character Author's Note (Private)": "Anmerkung des Charakterautors (privat)", + "Won't be shared with the character card on export.": "Wird beim Export nicht mit der Charakterkarte geteilt.", + "Will be automatically added as the author's note for this character. Will be used in groups, but can't be modified when a group chat is open.": "Wird automatisch als Autorennotiz für diesen Charakter hinzugefügt. Wird in Gruppen verwendet, kann aber nicht geändert werden, wenn ein Gruppenchat geöffnet ist.", + "Use character author's note": "Notiz des Charakterautors verwenden", + "Replace Author's Note": "Autornotiz ersetzen", + "Default Author's Note": "Standard-Autorennotiz", + "Will be automatically added as the Author's Note for all new chats.": "Wird automatisch als Autorennotiz für alle neuen Chats hinzugefügt.", + "Chat CFG": "Chat-CFG", + "1 = disabled": "1 = deaktiviert", + "write short replies, write replies using past tense": "kurze Antworten schreiben, Antworten in der Vergangenheitsform schreiben", + "Positive Prompt": "Positive Aufforderung", + "Use character CFG scales": "Verwenden Sie Zeichen-CFG-Skalen", + "Character CFG": "Charakter-CFG", + "Will be automatically added as the CFG for this character.": "Wird automatisch als CFG für diesen Charakter hinzugefügt.", + "Global CFG": "Globale CFG", + "Will be used as the default CFG options for every chat unless overridden.": "Wird als Standard-CFG-Option für jeden Chat verwendet, sofern sie nicht überschrieben wird.", + "CFG Prompt Cascading": "CFG-Eingabeaufforderung kaskadierend", + "Combine positive/negative prompts from other boxes.": "Kombinieren Sie positive/negative Eingabeaufforderungen aus anderen Feldern.", + "For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string.": "Wenn Sie beispielsweise die Kontrollkästchen „Chat“, „Global“ und „Zeichen“ aktivieren, werden alle negativen Eingabeaufforderungen in einer durch Kommas getrennten Zeichenfolge kombiniert.", + "Always Include": "Immer einschließen", + "Chat Negatives": "Chat-Negative", + "Character Negatives": "Negative Charaktere", + "Global Negatives": "Globale Negative", + "Custom Separator:": "Benutzerdefiniertes Trennzeichen:", + "Insertion Depth:": "Einstecktiefe:", + "Token Probabilities": "Token-Wahrscheinlichkeiten", + "Select a token to see alternatives considered by the AI.": "Wählen Sie ein Token aus, um die von der KI in Betracht gezogenen Alternativen anzuzeigen.", + "Not connected to API!": "Nicht mit der API verbunden!", + "Type a message, or /? for help": "Geben Sie eine Nachricht ein, oder /?, um Hilfe zu erhalten.", + "Continue script execution": "Skriptausführung fortsetzen", + "Pause script execution": "Skriptausführung anhalten", + "Abort script execution": "Skriptausführung abbrechen", + "Abort request": "Anfrage abbrechen", + "Continue the last message": "Mit der letzten Nachricht fortfahren", + "Send a message": "Eine Nachricht senden", + "Close chat": "Chat schließen", + "Toggle Panels": "Bedienfelder umschalten", + "Back to parent chat": "Zurück zum übergeordneten Chat", + "Save checkpoint": "Prüfpunkt speichern", + "Convert to group": "In Gruppe umwandeln", + "Start new chat": "Neuen Chat starten", + "Manage chat files": "Chatdateien verwalten", + "Delete messages": "Nachrichten löschen", + "Regenerate": "Regenerieren", + "Ask AI to write your message for you": "Bitten Sie die KI, Ihre Nachricht für Sie zu schreiben", + "Impersonate": "Imitieren", + "Continue": "Weiter", + "Bind user name to that avatar": "Benutzernamen an diesen Avatar binden", + "Change persona image": "Personenbild ändern", + "Select this as default persona for the new chats.": "Dies als Standard-Persona für die neuen Chats auswählen.", + "Delete persona": "Persona löschen", + "These characters are the winners of character design contests and have outstandable quality.": "Diese Charaktere sind die Gewinner von Charakterdesign-Wettbewerben und haben eine herausragende Qualität.", + "Contest Winners": "Gewinner des Wettbewerbs", + "These characters are the finalists of character design contests and have remarkable quality.": "Diese Charaktere sind die Finalisten von Charakterdesign-Wettbewerben und haben eine bemerkenswerte Qualität.", + "Featured Characters": "Ausgewählte Charaktere", + "Attach a File": "Eine Datei anhängen", + "Open Data Bank": "Offene Datenbank", + "Enter a URL or the ID of a Fandom wiki page to scrape:": "Geben Sie eine URL oder die ID einer Fandom-Wiki-Seite zum Scrapen ein:", + "Examples:": "Beispiele:", + "Example:": "Beispiel:", + "Single file": "Einzelne Datei", + "All articles will be concatenated into a single file.": "Alle Artikel werden zu einer einzigen Datei zusammengefasst.", + "File per article": "Datei pro Artikel", + "Each article will be saved as a separate file.": "Nicht empfohlen. Jeder Artikel wird als separate Datei gespeichert.", + "Data Bank": "Datenbank", + "These files will be available for extensions that support attachments (e.g. Vector Storage).": "Diese Dateien sind für Erweiterungen verfügbar, die Anhänge unterstützen (z. B. Vector Storage).", + "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.": "Unterstützte Dateitypen: Nur Text, PDF, Markdown, HTML, EPUB.", + "Drag and drop files here to upload.": "Ziehen Sie Dateien hierher, um sie hochzuladen.", + "Date (Newest First)": "Datum (Neueste zuerst)", + "Date (Oldest First)": "Datum (Älteste zuerst)", + "Name (A-Z)": "Name (A-Z)", + "Name (Z-A)": "Name (Z–A)", + "Size (Smallest First)": "Größe (Kleinste zuerst)", + "Size (Largest First)": "Größe (Größte zuerst)", + "Bulk Edit": "Bulk-Bearbeitung", + "Select All": "Wählen Sie Alle", + "Select None": "Nichts ausgewählt", + "Global Attachments": "Globale Anhänge", + "These files are available for all characters in all chats.": "Diese Dateien sind für alle Charaktere in allen Chats verfügbar.", + "Character Attachments": "Charakteranhänge", + "These files are available the current character in all chats they are in.": "Diese Dateien sind für den aktuellen Charakter in allen Chats verfügbar, in denen er sich befindet.", + "Saved locally. Not exported.": "Lokal gespeichert. Nicht exportiert.", + "Chat Attachments": "Chat-Anhänge", + "These files are available to all characters in the current chat.": "Diese Dateien stehen allen Charakteren im aktuellen Chat zur Verfügung.", + "Enter a base URL of the MediaWiki to scrape.": "Geben Sie eine Basis-URL des zu scrapenden MediaWiki ein.", + "Don't include the page name!": "Geben Sie den Seitennamen nicht an!", + "Enter web URLs to scrape (one per line):": "Geben Sie die zu scrapenden Web-URLs ein (eine pro Zeile):", + "Enter a video URL to download its transcript.": "Geben Sie eine Video-URL oder -ID ein, um das Transkript herunterzuladen.", + "Expression API": "Lokal\nExtras\nLLM", + "ext_sum_with": "Zusammenfassen mit:", + "ext_sum_main_api": "Haupt-API", + "ext_sum_current_summary": "Aktuelle Zusammenfassung:", + "ext_sum_restore_previous": "Vorheriges wiederherstellen", + "ext_sum_memory_placeholder": "Eine Zusammenfassung wird hier generiert...", + "Trigger a summary update right now.": "Jetzt zusammenfassen", + "ext_sum_force_text": "Jetzt zusammenfassen", + "Disable automatic summary updates. While paused, the summary remains as-is. You can still force an update by pressing the Summarize now button (which is only available with the Main API).": "Deaktivieren Sie automatische Zusammenfassungsaktualisierungen. Während der Pause bleibt die Zusammenfassung unverändert. Sie können dennoch eine Aktualisierung erzwingen, indem Sie auf die Schaltfläche „Jetzt zusammenfassen“ klicken (nur mit der Haupt-API verfügbar).", + "ext_sum_pause": "Pause", + "Omit World Info and Author's Note from text to be summarized. Only has an effect when using the Main API. The Extras API always omits WI/AN.": "Weltinfo und Anmerkung des Autors aus dem zusammenzufassenden Text weglassen. Hat nur Auswirkungen bei Verwendung der Haupt-API. Die Extras-API lässt WI/AN immer weg.", + "ext_sum_no_wi_an": "Kein WI/AN", + "ext_sum_settings_tip": "Bearbeiten Sie die Zusammenfassungsaufforderung, die Einfügeposition usw.", + "ext_sum_settings": "Zusammenfassungseinstellungen", + "ext_sum_prompt_builder": "Eingabeaufforderungsgenerator", + "ext_sum_prompt_builder_1_desc": "Die Erweiterung erstellt ihre eigene Eingabeaufforderung mit Nachrichten, die noch nicht zusammengefasst wurden. Blockiert den Chat, bis die Zusammenfassung generiert wurde.", + "ext_sum_prompt_builder_1": "Roh, blockierend", + "ext_sum_prompt_builder_2_desc": "Die Erweiterung erstellt ihre eigene Eingabeaufforderung mit Nachrichten, die noch nicht zusammengefasst wurden. Blockiert den Chat nicht, während die Zusammenfassung generiert wird. Nicht alle Backends unterstützen diesen Modus.", + "ext_sum_prompt_builder_2": "Roh, nicht blockierend", + "ext_sum_prompt_builder_3_desc": "Die Erweiterung verwendet den regulären Haupt-Prompt-Builder und fügt ihm die Zusammenfassungsanforderung als letzte Systemnachricht hinzu.", + "ext_sum_prompt_builder_3": "Klassisch, blockierend", + "Summary Prompt": "Zusammenfassungseingabeaufforderung", + "ext_sum_restore_default_prompt_tip": "Standardeingabeaufforderung wiederherstellen", + "ext_sum_prompt_placeholder": "Diese Eingabeaufforderung wird an AI gesendet, um die Erstellung der Zusammenfassung anzufordern. {{words}} wird in den Parameter „Anzahl der Wörter“ aufgelöst.", + "ext_sum_target_length_1": "Länge der Zielzusammenfassung", + "ext_sum_target_length_2": null, + "ext_sum_target_length_3": "Wörter)", + "ext_sum_api_response_length_1": "Länge der API-Antwort", + "ext_sum_api_response_length_2": null, + "ext_sum_api_response_length_3": "Token)", + "ext_sum_0_default": "0 = Standard", + "ext_sum_raw_max_msg": "[Raw] Max. Nachrichten pro Anfrage", + "ext_sum_0_unlimited": "0 = unbegrenzt", + "Update frequency": "Aktualisierungsfrequenz", + "ext_sum_update_every_messages_1": "Aktualisieren alle", + "ext_sum_update_every_messages_2": "Mitteilungen", + "ext_sum_0_disable": "0 = deaktivieren", + "ext_sum_auto_adjust_desc": "Versuchen Sie, das Intervall basierend auf den Chat-Metriken automatisch anzupassen.", + "ext_sum_update_every_words_1": "Aktualisieren alle", + "ext_sum_update_every_words_2": "Wörter", + "ext_sum_both_sliders": "Wenn beide Schieberegler ungleich Null sind, lösen beide in ihren jeweiligen Intervallen Zusammenfassungsaktualisierungen aus.", + "ext_sum_injection_template": "Injektionsvorlage", + "ext_sum_memory_template_placeholder": "{{summary}} wird zum aktuellen Zusammenfassungsinhalt aufgelöst.", + "ext_sum_injection_position": "Injektionsposition", + "How many messages before the current end of the chat.": "Wie viele Nachrichten bis zum aktuellen Ende des Chats.", + "ext_regex_title": "Regulärer Ausdruck", + "ext_regex_new_global_script": "+ Allgemein", + "ext_regex_new_scoped_script": "+ Umfang", + "ext_regex_import_script": "Importieren", + "ext_regex_global_scripts": "Globale Skripte", + "ext_regex_global_scripts_desc": "Für alle Charaktere verfügbar. In den lokalen Einstellungen gespeichert.", + "ext_regex_scoped_scripts": "Bereichsbezogene Skripte", + "ext_regex_scoped_scripts_desc": "Nur für diesen Charakter verfügbar. In den Kartendaten gespeichert.", + "Regex Editor": "Regex-Editor", + "Test Mode": "Testmodus", + "ext_regex_desc": "Regex ist ein Tool zum Suchen/Ersetzen von Zeichenfolgen mithilfe regulärer Ausdrücke. Wenn Sie mehr erfahren möchten, klicken Sie auf das ? neben dem Titel.", + "Input": "Eingang", + "ext_regex_test_input_placeholder": "Hier eingeben...", + "Output": "Ausgabe", + "ext_regex_output_placeholder": "Leer", + "Script Name": "Skriptname", + "Find Regex": "Regex suchen", + "Replace With": "Ersetzen mit", + "ext_regex_replace_string_placeholder": "Verwenden Sie {{match}}, um den übereinstimmenden Text aus dem Such-Regex oder $1, $2 usw. für Erfassungsgruppen einzuschließen.", + "Trim Out": "Ausschneiden", + "ext_regex_trim_placeholder": "Entfernt global alle unerwünschten Teile aus einer Regex-Übereinstimmung vor dem Ersetzen. Trennen Sie jedes Element durch eine Eingabetaste.", + "ext_regex_affects": "Auswirkungen", + "ext_regex_user_input": "Benutzereingabe", + "ext_regex_ai_output": "KI-Ausgabe", + "Slash Commands": "Schrägstrichbefehle", + "ext_regex_min_depth_desc": "Bei Anwendung auf Eingabeaufforderungen oder die Anzeige wirkt sich dies nur auf Nachrichten aus, die mindestens N Ebenen tief sind. 0 = letzte Nachricht, 1 = vorletzte Nachricht usw. Zählt nur WI-Einträge @Depth und verwendbare Nachrichten, d. h. nicht versteckte oder Systemnachrichten.", + "Min Depth": "Min. Tiefe", + "ext_regex_min_depth_placeholder": "Unbegrenzt", + "ext_regex_max_depth_desc": "Bei Anwendung auf Eingabeaufforderungen oder die Anzeige wirkt es sich nur auf Nachrichten aus, die nicht tiefer als N Ebenen liegen. 0 = letzte Nachricht, 1 = vorletzte Nachricht usw. Zählt nur WI-Einträge @Depth und verwendbare Nachrichten, d. h. nicht versteckte oder Systemnachrichten.", + "ext_regex_other_options": "Andere Optionen", + "Only Format Display": "Nur Formatanzeige", + "ext_regex_only_format_prompt_desc": "Der Chatverlauf ändert sich nicht, nur die Eingabeaufforderung beim Senden der Anfrage (bei der Generierung).", + "Only Format Prompt (?)": "Nur Formataufforderung", + "Run On Edit": "Ausführen beim Bearbeiten", + "ext_regex_substitute_regex_desc": "Ersetzen Sie {{macros}} in Find Regex, bevor Sie es ausführen", + "Substitute Regex": "Regex ersetzen", + "ext_regex_import_target": "Importieren nach:", + "ext_regex_disable_script": "Skript deaktivieren", + "ext_regex_enable_script": "Skript aktivieren", + "ext_regex_edit_script": "Skript bearbeiten", + "ext_regex_move_to_global": "Wechseln Sie zu globalen Skripten", + "ext_regex_move_to_scoped": "Wechseln Sie zu bereichsbezogenen Skripts", + "ext_regex_export_script": "Skript exportieren", + "ext_regex_delete_script": "Skript löschen", + "Trigger Stable Diffusion": "Stabile Diffusion auslösen", + "sd_Yourself": "Selbst", + "sd_Your_Face": "Dein Gesicht", + "sd_Me": "Mich", + "sd_The_Whole_Story": "Die ganze Geschichte", + "sd_The_Last_Message": "Die letzte Nachricht", + "sd_Raw_Last_Message": "Rohe letzte Nachricht", + "sd_Background": "Hintergrund", + "Image Generation": "Bildgenerierung", + "sd_refine_mode": "Erlaubt die manuelle Bearbeitung von Eingabeaufforderungen, bevor diese an die Generierungs-API gesendet werden", + "sd_refine_mode_txt": "Eingabeaufforderungen vor der Generierung bearbeiten", + "sd_interactive_mode": "Beim Senden von Nachrichten wie „Schicken Sie mir ein Bild von einer Katze“ werden automatisch Bilder generiert.", + "sd_interactive_mode_txt": "Interaktiver Modus", + "sd_multimodal_captioning": "Verwenden Sie multimodale Untertitel, um Eingabeaufforderungen für Benutzer- und Charakterporträts basierend auf ihren Avataren zu generieren.", + "sd_multimodal_captioning_txt": "Verwenden Sie multimodale Untertitel für Porträts", + "sd_expand": "Automatisches Erweitern von Eingabeaufforderungen mithilfe des Textgenerierungsmodells", + "sd_expand_txt": "Eingabeaufforderungen automatisch verbessern", + "sd_snap": "Snap-Generierungsanforderungen mit einem erzwungenen Seitenverhältnis (Porträts, Hintergründe) zur nächsten bekannten Auflösung, wobei versucht wird, die absolute Pixelanzahl beizubehalten (empfohlen für SDXL).", + "sd_snap_txt": "Snap automatisch angepasste Auflösungen", + "Source": "Quelle", + "sd_auto_url": "Beispiel: {{auto_url}}", + "Authentication (optional)": "Authentifizierung (optional)", + "Example: username:password": "Beispiel: Benutzername:Passwort", + "Important:": "Wichtig:", + "sd_auto_auth_warning_1": "Führen Sie die SD Web UI mit dem", + "sd_auto_auth_warning_2": "Flagge! Der Server muss vom SillyTavern-Hostcomputer aus erreichbar sein.", + "sd_drawthings_url": "Beispiel: {{drawthings_url}}", + "sd_drawthings_auth_txt": "Führen Sie die DrawThings-App mit aktiviertem HTTP-API-Schalter in der Benutzeroberfläche aus! Der Server muss vom SillyTavern-Hostcomputer aus zugänglich sein.", + "sd_vlad_url": "Beispiel: {{vlad_url}}", + "The server must be accessible from the SillyTavern host machine.": "Der Server muss vom SillyTavern-Hostcomputer aus zugänglich sein.", + "Hint: Save an API key in AI Horde API settings to use it here.": "Tipp: Speichern Sie einen API-Schlüssel in den AI Horde API-Einstellungen, um ihn hier zu verwenden.", + "Allow NSFW images from Horde": "NSFW-Bilder von Horde zulassen", + "Sanitize prompts (recommended)": "Eingabeaufforderungen bereinigen (empfohlen)", + "Automatically adjust generation parameters to ensure free image generations.": "Passen Sie die Generierungsparameter automatisch an, um eine freie Bildgenerierung zu gewährleisten.", + "Avoid spending Anlas": "Vermeiden Sie die Ausgabe von Anlas", + "Opus tier": "(Opus-Stufe)", + "View my Anlas": "Meine Anlas ansehen", + "These settings only apply to DALL-E 3": "Diese Einstellungen gelten nur für DALL-E 3", + "Image Style": "Bildstil", + "Image Quality": "Bildqualität", + "Standard": "Standard", + "HD": "HD", + "sd_comfy_url": "Beispiel: {{comfy_url}}", + "Open workflow editor": "Workflow-Editor öffnen", + "Create new workflow": "Neuen Workflow erstellen", + "Delete workflow": "Workflow löschen", + "Enhance": "Erweitern", + "Refine": "Verfeinern", + "Decrisper": "Entkrisper", + "Sampling steps": "Schritte zur Probenahme ()", + "Width": "Breite ()", + "Height": "Höhe ()", + "Resolution": "Auflösung", + "Model": "Modell", + "Sampling method": "Probenahmeverfahren", + "Karras (not all samplers supported)": "Karras (nicht alle Sampler werden unterstützt)", + "SMEA versions of samplers are modified to perform better at high resolution.": "SMEA-Versionen von Samplern werden modifiziert, um bei hoher Auflösung eine bessere Leistung zu erzielen.", + "SMEA": "KMU", + "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "DYN-Varianten von SMEA-Samplern führen häufig zu einer vielfältigeren Ausgabe, können aber bei sehr hohen Auflösungen versagen.", + "DYN": "DYN", + "Scheduler": "Planer", + "Restore Faces": "Gesichter wiederherstellen", + "Hires. Fix": "Einstellungen. Fix", + "Upscaler": "Upscaler", + "Upscale by": "Gehoben durch", + "Denoising strength": "Rauschunterdrückungsstärke", + "Hires steps (2nd pass)": "Hires-Schritte (2. Durchgang)", + "Preset for prompt prefix and negative prompt": "Vorgabe für Prompt-Präfix und Negativ-Prompt", + "Style": "Stil", + "Save style": "Stil speichern", + "Delete style": "Stil löschen", + "Common prompt prefix": "Allgemeines Eingabeaufforderungspräfix", + "sd_prompt_prefix_placeholder": "Verwenden Sie {prompt}, um anzugeben, wo die generierte Eingabeaufforderung eingefügt wird", + "Negative common prompt prefix": "Negatives allgemeines Eingabeaufforderungspräfix", + "Character-specific prompt prefix": "Zeichenspezifisches Eingabeaufforderungspräfix", + "Won't be used in groups.": "Wird nicht in Gruppen verwendet.", + "sd_character_prompt_placeholder": "Alle Merkmale, die den aktuell ausgewählten Charakter beschreiben. Werden nach einem gemeinsamen Eingabeaufforderungspräfix hinzugefügt.\nBeispiel: weiblich, grüne Augen, braune Haare, rosa Hemd", + "Character-specific negative prompt prefix": "Zeichenspezifisches negatives Eingabeaufforderungspräfix", + "sd_character_negative_prompt_placeholder": "Alle Merkmale, die für das ausgewählte Zeichen nicht erscheinen sollen. Werden nach einem negativen allgemeinen Eingabeaufforderungspräfix hinzugefügt.\nBeispiel: Schmuck, Schuhe, Brille", + "Shareable": "Teilbar", + "Image Prompt Templates": "Vorlagen für Bildaufforderungen", + "Vectors Model Warning": "Es wird empfohlen, Vektoren zu löschen, wenn das Modell während des Chats geändert wird. Andernfalls führt dies zu unterdurchschnittlichen Ergebnissen.", + "Translate files into English before processing": "Übersetzen Sie die Dateien vor der Verarbeitung ins Englische", + "Manager Users": "Benutzer verwalten", + "New User": "Neuer Benutzer", + "Status:": "Status:", + "Created:": "Erstellt:", + "Display Name:": "Anzeigename:", + "User Handle:": "Benutzername:", + "Password:": "Passwort:", + "Confirm Password:": "Bestätige das Passwort:", + "This will create a new subfolder...": "Dadurch wird im Verzeichnis /data/ ein neuer Unterordner mit dem Benutzerhandle als Ordnername erstellt.", + "Current Password:": "Aktuelles Passwort:", + "New Password:": "Neues Kennwort:", + "Confirm New Password:": "Bestätige neues Passwort:", + "Debug Warning": "Die Funktionen in dieser Kategorie sind nur für fortgeschrittene Benutzer. Klicken Sie nichts an, wenn Sie sich über die Folgen nicht im Klaren sind.", + "Execute": "Ausführen", + "Are you sure you want to delete this user?": "Möchten Sie diesen Benutzer wirklich löschen?", + "Deleting:": "Löschen:", + "Also wipe user data.": "Löschen Sie auch Benutzerdaten.", + "Warning:": "Warnung:", + "This action is irreversible.": "Diese Aktion ist irreversibel.", + "Type the user's handle below to confirm:": "Geben Sie zur Bestätigung unten den Benutzernamen ein:", + "Import Characters": "Zeichen importieren", + "Enter the URL of the content to import": "Geben Sie die URL des zu importierenden Inhalts ein", + "Supported sources:": "Unterstützte Quellen:", + "char_import_1": "Chub-Charakter (Direktlink oder ID)", + "char_import_example": "Beispiel:", + "char_import_2": "Chub Lorebook (Direktlink oder ID)", + "char_import_3": "JanitorAI-Charakter (Direktlink oder UUID)", + "char_import_4": "Pygmalion.chat-Charakter (Direktlink oder UUID)", + "char_import_5": "AICharacterCards.com-Charakter (Direktlink oder ID)", + "char_import_6": "Direkter PNG-Link (siehe", + "char_import_7": "für erlaubte Hosts)", + "char_import_8": "RisuRealm-Charakter (Direktlink)", + "Supports importing multiple characters.": "Unterstützt den Import mehrerer Zeichen.", + "Write each URL or ID into a new line.": "Schreiben Sie jede URL oder ID in eine neue Zeile.", + "Export for character": "Export für Zeichen", + "Export prompts for this character, including their order.": "Exportieren Sie Eingabeaufforderungen für dieses Zeichen, einschließlich ihrer Reihenfolge.", + "Export all": "Alles exportieren", + "Export all your prompts to a file": "Exportieren Sie alle Eingabeaufforderungen in eine Datei", + "Insert prompt": "Aufforderung einfügen", + "Delete prompt": "Aufforderung löschen", + "Import a prompt list": "Eine Aufforderungsliste importieren", + "Export this prompt list": "Diese Aufforderungsliste exportieren", + "Reset current character": "Aktuellen Charakter zurücksetzen", + "New prompt": "Neue Aufforderung", + "Prompts": "Aufforderungen", + "Total Tokens:": "Gesamt-Token:", + "prompt_manager_tokens": "Token", + "Are you sure you want to reset your settings to factory defaults?": "Möchten Sie Ihre Einstellungen wirklich auf die Werkseinstellungen zurücksetzen?", + "Don't forget to save a snapshot of your settings before proceeding.": "Vergessen Sie nicht, einen Schnappschuss Ihrer Einstellungen zu speichern, bevor Sie fortfahren.", + "Settings Snapshots": "Einstellungs-Schnappschüsse", + "Record a snapshot of your current settings.": "Zeichnen Sie einen Schnappschuss Ihrer aktuellen Einstellungen auf.", + "Make a Snapshot": "Machen Sie einen Schnappschuss", + "Restore this snapshot": "Stellen Sie diesen Snapshot wieder her", + "Hi,": "Hallo,", + "To enable multi-account features, restart the SillyTavern server with": "Um die Multi-Account-Funktion zu aktivieren, starten Sie den SillyTavern-Server neu mit", + "set to true in the config.yaml file.": "in der Datei config.yaml auf „true“ gesetzt.", + "Account Info": "Kontoinformation", + "To change your user avatar, use the buttons below or select a default persona in the Persona Management menu.": "Um Ihren Benutzeravatar zu ändern, verwenden Sie die Schaltflächen unten oder wählen Sie eine Standardpersona im Menü „Persona-Verwaltung“ aus.", + "Set your custom avatar.": "Legen Sie Ihren benutzerdefinierten Avatar fest.", + "Remove your custom avatar.": "Entfernen Sie Ihren benutzerdefinierten Avatar.", + "Handle:": "Handhaben:", + "This account is password protected.": "Dieses Konto ist passwortgeschützt.", + "This account is not password protected.": "Dieses Konto ist nicht passwortgeschützt.", + "Account Actions": "Kontoaktionen", + "Change Password": "Kennwort ändern", + "Manage your settings snapshots.": "Verwalten Sie Ihre Einstellungs-Snapshots.", + "Download a complete backup of your user data.": "Laden Sie ein vollständiges Backup Ihrer Benutzerdaten herunter.", + "Download Backup": "Backup herunterladen", + "Danger Zone": "Gefahrenzone", + "Reset your settings to factory defaults.": "Setzen Sie Ihre Einstellungen auf die Werkseinstellungen zurück.", + "Reset Settings": "Einstellungen zurücksetzen", + "Wipe all user data and reset your account to factory settings.": "Löschen Sie alle Benutzerdaten und setzen Sie Ihr Konto auf die Werkseinstellungen zurück.", + "Reset Everything": "Alles zurücksetzen", + "Reset Code:": "Code zurücksetzen:", + "Want to update?": "Möchten Sie aktualisieren?", + "How to start chatting?": "Wie fange ich an zu chatten?", + "Click _space": "Klicken", + "and select a": "und wähle eine", + "Chat API": "Chat-API", + "and pick a character.": "und wähle einen Charakter aus.", + "You can browse a list of bundled characters in the": "Sie können eine Liste der gebündelten Charaktere im", + "Download Extensions & Assets": "Erweiterungen und Assets herunterladen", + "menu within": "Menü innerhalb", + "Confused or lost?": "Verwirrt oder verloren?", + "click these icons!": "klicke auf diese Symbole!", + "in the chat bar": "in der Chatleiste", + "SillyTavern Documentation Site": "SillyTavern-Dokumentationsseite", + "Extras Installation Guide": "Zusätzlicher Installationsleitfaden", + "Still have questions?": "Hast du immer noch Fragen?", + "Join the SillyTavern Discord": "Trete dem SillyTavern Discord bei", + "Post a GitHub issue": "Veröffentliche ein GitHub-Problem", + "Contact the developers": "Kontaktiere die Entwickler" +} diff --git a/jiuguan2025cc/public/locales/en.json b/jiuguan2025cc/public/locales/en.json new file mode 100644 index 0000000000000000000000000000000000000000..2c63c0851048d8f7bff41ecf0f8cee05f52fd120 --- /dev/null +++ b/jiuguan2025cc/public/locales/en.json @@ -0,0 +1,2 @@ +{ +} diff --git a/jiuguan2025cc/public/locales/es-es.json b/jiuguan2025cc/public/locales/es-es.json new file mode 100644 index 0000000000000000000000000000000000000000..3c13c80a544062ba88a6f2b08ff8ce2e71c7ee99 --- /dev/null +++ b/jiuguan2025cc/public/locales/es-es.json @@ -0,0 +1,1550 @@ +{ + "Favorite": "Favorito", + "Tag": "Etiqueta", + "Duplicate": "Duplicar", + "Persona": "Persona", + "Delete": "Eliminar", + "AI Response Configuration": "Configuración de Respuesta de IA", + "AI Configuration panel will stay open": "El panel de Configuración de IA permanecerá abierto", + "clickslidertips": "Haz clic para introducir valores manualmente.", + "MAD LAB MODE ON": "MODO LABORATORIO MAD ENCENDIDO", + "Documentation on sampling parameters": "Documentación sobre parámetros de muestreo", + "kobldpresets": "Preajustes de Kobold", + "guikoboldaisettings": "Ajustes de interfaz de KoboldAI", + "Update current preset": "Actualizar el preajuste actual", + "Save preset as": "Guardar preajuste como", + "Import preset": "Importar preajuste", + "Export preset": "Exportar preajuste", + "Restore current preset": "Restaurar el preajuste actual", + "Delete the preset": "Eliminar el preajuste", + "novelaipresets": "Preajustes de NovelAI", + "Default": "Predeterminado", + "openaipresets": "Preajustes de OpenAI", + "Text Completion presets": "Preajustes de Completado de Texto", + "AI Module": "Módulo de IA", + "Changes the style of the generated text.": "Cambia el estilo del texto generado.", + "No Module": "Sin módulo", + "Instruct": "Instruir", + "Prose Augmenter": "Aumentador de prosa", + "Text Adventure": "Aventura de texto", + "response legth(tokens)": "Longitud de respuesta (tokens)", + "Streaming": "Transmisión (Streaming)", + "Streaming_desc": "Mostrar la respuesta poco a poco según se genera", + "context size(tokens)": "Tamaño de contexto (tokens)", + "unlocked": "Desbloqueado", + "Only enable this if your model supports context sizes greater than 8192 tokens": "Habilita esto solo si tu modelo admite tamaños de contexto mayores de 8192 tokens", + "Max prompt cost:": "Costo inmediato máximo:", + "Display the response bit by bit as it is generated.": "Mostrar la respuesta poco a poco a medida que se genera.", + "When this is off, responses will be displayed all at once when they are complete.": "Cuando esto está apagado, las respuestas se mostrarán de una vez cuando estén completas.", + "Temperature": "Temperatura", + "rep.pen": "Penalización de repetición", + "Rep. Pen. Range.": "Rango de Pen. Rep.", + "Rep. Pen. Slope": "Pendiente de penalización de repetición", + "Rep. Pen. Freq.": "Frec. de Pen. Rep.", + "Rep. Pen. Presence": "Presencia de Pen. Rep.", + "TFS": "TFS", + "Phrase Repetition Penalty": "Penalización por repetición de frases", + "Off": "Apagado", + "Very light": "Muy ligero", + "Light": "Ligero", + "Medium": "Medio", + "Aggressive": "Agresivo", + "Very aggressive": "Muy agresivo", + "Unlocked Context Size": "Tamaño de contexto desbloqueado", + "Unrestricted maximum value for the context slider": "Valor máximo sin restricciones para el control deslizante de contexto", + "Context Size (tokens)": "Tamaño de contexto (tokens)", + "Max Response Length (tokens)": "Longitud máxima de respuesta (tokens)", + "Multiple swipes per generation": "Múltiples golpes por generación", + "Enable OpenAI completion streaming": "Activar streaming de completado de OpenAI", + "Frequency Penalty": "Penalización de frecuencia", + "Presence Penalty": "Penalización de presencia", + "Count Penalty": "Penalización de conteo", + "Top K": "Top K", + "Top P": "Top P", + "Repetition Penalty": "Penalización por Repetición", + "Min P": "P mín.", + "Top A": "Top A", + "Quick Prompts Edit": "Edición rápida de indicaciones", + "Main": "Principal", + "NSFW": "NSFW", + "Jailbreak": "Jailbreak", + "Utility Prompts": "Indicaciones de utilidad", + "Impersonation prompt": "Indicaciónes de Suplantación", + "Restore default prompt": "Restaurar las indicaciones predeterminada", + "Prompt that is used for Impersonation function": "Indicación que se utiliza para la función de Suplantación", + "World Info Format Template": "Plantilla de formato de información mundial", + "Restore default format": "Restaurar formato predeterminado", + "Wraps activated World Info entries before inserting into the prompt.": "Envuelve las entradas de información mundial activadas antes de insertarlas en el mensaje.", + "scenario_format_template_part_1": "Usar", + "scenario_format_template_part_2": "para marcar un lugar donde se inserta el contenido.", + "Scenario Format Template": "Plantilla de formato de escenario", + "Personality Format Template": "Plantilla de formato de personalidad", + "Group Nudge Prompt Template": "Plantilla de mensaje de desplazamiento grupal", + "Sent at the end of the group chat history to force reply from a specific character.": "Enviado al final del historial de chat grupal para forzar la respuesta de un personaje específico.", + "New Chat": "Nueva conversación", + "Restore new chat prompt": "Restaurar nuevo mensaje de chat", + "Set at the beginning of the chat history to indicate that a new chat is about to start.": "Establecer al principio del historial de chat para indicar que está por comenzar un nuevo chat.", + "New Group Chat": "Nuevo chat grupal", + "Restore new group chat prompt": "Restaurar mensaje predeterminado", + "Set at the beginning of the chat history to indicate that a new group chat is about to start.": "Establecer al principio del historial de chat para indicar que está a punto de comenzar un nuevo chat grupal.", + "New Example Chat": "Nuevo chat de ejemplo", + "Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.": "Establezca al comienzo de los ejemplos de diálogo para indicar que está a punto de comenzar un nuevo chat de ejemplo.", + "Continue nudge": "Continuar empujando", + "Set at the end of the chat history when the continue button is pressed.": "Se establece al final del historial de chat cuando se presiona el botón Continuar.", + "Replace empty message": "Reemplazar mensaje vacío", + "Send this text instead of nothing when the text box is empty.": "Enviar este texto en lugar de nada cuando el cuadro de texto está vacío.", + "Seed": "Semilla", + "Set to get deterministic results. Use -1 for random seed.": "Configurado para obtener resultados deterministas. Utilice -1 para semillas aleatorias.", + "Temperature controls the randomness in token selection": "La temperatura controla la aleatoriedad en la selección de tokens", + "Top_K_desc": "Top K establece una cantidad máxima de tokens principales que se pueden elegir", + "Top_P_desc": "Top P (también conocido como muestreo de núcleo)", + "Typical P": "P típico", + "Typical_P_desc": "El Muestreo P Típico prioriza tokens según su desviación de la entropía promedio del conjunto", + "Min_P_desc": "Min P establece una probabilidad mínima base", + "Top_A_desc": "Top A establece un umbral para la selección de tokens basado en el cuadrado de la probabilidad de token más alta", + "Tail_Free_Sampling_desc": "Muestreo sin cola (TFS)", + "rep.pen range": "rango de penalización de repetición", + "Mirostat": "mirostato", + "Mode": "Modo", + "Mirostat_Mode_desc": "Un valor de 0 desactiva Mirostat por completo. 1 es para Mirostat 1.0 y 2 es para Mirostat 2.0", + "Tau": "tau", + "Mirostat_Tau_desc": "Controla la variabilidad de las salidas de Mirostat.", + "Eta": "eta", + "Mirostat_Eta_desc": "Controla la tasa de aprendizaje de Mirostat", + "Ban EOS Token": "Prohibir token EOS", + "Ban_EOS_Token_desc": "Prohibir el token de fin de secuencia (EOS) con KoboldCpp (y posiblemente también otros tokens con KoboldAI).\rBueno para escribir historias, pero no debe usarse para chatear ni para el modo de instrucción.", + "GBNF Grammar": "Gramática GBNF", + "Type in the desired custom grammar": "Escribe la gramática personalizada deseada", + "Samplers Order": "Orden de Muestreadores", + "Samplers will be applied in a top-down order. Use with caution.": "Los Muestreadores se aplicarán en un orden de arriba hacia abajo. Úsalo con precaución.", + "Tail Free Sampling": "Muestreo sin cola", + "Load koboldcpp order": "Cargar orden de koboldcpp", + "Preamble": "Preambulo", + "Use style tags to modify the writing style of the output.": "Usa etiquetas de estilo para modificar el estilo de escritura de la salida.", + "Banned Tokens": "Tokens prohibidos", + "Sequences you don't want to appear in the output. One per line.": "Secuencias que no quieres que aparezcan en la salida. Una por línea.", + "Logit Bias": "Sesgo de logit", + "Add": "Agregar", + "Helps to ban or reenforce the usage of certain words": "Ayuda a prohibir o reforzar el uso de ciertas palabras", + "CFG Scale": "Escala CFG", + "Negative Prompt": "Indicaciónes negativas", + "Add text here that would make the AI generate things you don't want in your outputs.": "Agrega aquí texto que haría que la IA genere cosas que no quieres en tus salidas.", + "Used if CFG Scale is unset globally, per chat or character": "Usado si la Escala CFG no está configurada globalmente, por chat o por personaje", + "Mirostat Tau": "Tau de Mirostat", + "Mirostat LR": "Mirostato LR", + "Min Length": "Longitud mínima", + "Top K Sampling": "Muestreo de Top K", + "Nucleus Sampling": "Muestreo de núcleo", + "Top A Sampling": "Muestreo de Top A", + "CFG": "CFG", + "Neutralize Samplers": "Neutralizar muestreadores", + "Set all samplers to their neutral/disabled state.": "Establecer todos los muestreadores en su estado neutral/desactivado.", + "Sampler Select": "Selección de muestrario", + "Customize displayed samplers or add custom samplers.": "Personalice los samplers mostrados o agregue samplers personalizados.", + "Epsilon Cutoff": "Corte Epsilon", + "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "El corte Epsilon establece un límite de probabilidad por debajo del cual se excluyen los tokens de ser muestreados", + "Eta Cutoff": "Corte Eta", + "Eta_Cutoff_desc": "El Corte de Eta es el parámetro principal de la técnica especial de Muestreo Eta. En unidades de 1e-4; un valor razonable es 3. Establecer en 0 para desactivar. Consulte el documento Truncation Sampling as Language Model Desmoothing de Hewitt et al. (2022) para más detalles.", + "rep.pen decay": "Decaimiento de la pluma de representación", + "Encoder Rep. Pen.": "Pen. de repetición de codificador", + "No Repeat Ngram Size": "Tamaño de ngrama sin repetición", + "Skew": "Sesgar", + "Max Tokens Second": "Máximo de tokens por segundo", + "Smooth Sampling": "Muestreo suave", + "Smooth_Sampling_desc": "Le permite utilizar transformaciones cuadráticas/cúbicas para ajustar la distribución. Los valores más bajos del factor de suavizado serán más creativos, normalmente entre 0,2 y 0,3 es el punto óptimo (suponiendo que la curva = 1). Los valores más altos de la curva de suavizado harán que la curva sea más pronunciada, lo que castigará de manera más agresiva las elecciones de baja probabilidad. La curva 1,0 equivale a utilizar únicamente el factor de suavizado.", + "Smoothing Factor": "Factor de suavizado", + "Smoothing Curve": "Curva de suavizado", + "DRY_Repetition_Penalty_desc": "DRY penaliza los tokens que extenderían el final de la entrada a una secuencia que ocurrió previamente en la entrada. Establezca el multiplicador en 0 para desactivarlo.", + "DRY Repetition Penalty": "Penalización por repetición de DRY", + "DRY_Multiplier_desc": "Establezca el valor > 0 para habilitar SECO. Controla la magnitud de la penalización para las secuencias penalizadas más cortas.", + "Multiplier": "Multiplicador", + "DRY_Base_desc": "Controla qué tan rápido crece la penalización al aumentar la longitud de la secuencia.", + "Base": "Base", + "DRY_Allowed_Length_desc": "Secuencia más larga que se puede repetir sin ser penalizada.", + "Allowed Length": "Longitud permitida", + "Penalty Range": "Rango de penalización", + "DRY_Sequence_Breakers_desc": "Tokens en los que no se continúa la coincidencia de secuencias. Especificado como una lista de cadenas entre comillas separadas por comas.", + "Sequence Breakers": "Rompedores de secuencia", + "JSON-serialized array of strings.": "Matriz de cadenas serializadas en JSON.", + "Dynamic Temperature": "Temperatura dinámica", + "Scale Temperature dynamically per token, based on the variation of probabilities": "Escala la Temperatura dinámicamente por token, basado en la variación de probabilidades", + "Minimum Temp": "Temperatura mínima", + "Maximum Temp": "Temperatura máxima", + "Exponent": "Exponente", + "Mirostat (mode=1 is only for llama.cpp)": "Mirostat (modo=1 es solo para llama.cpp)", + "Mirostat_desc": "Mirostat es un termostato para la perplejidad de salida", + "Mirostat Mode": "Modo de Mirostat", + "Variability parameter for Mirostat outputs": "Parámetro de variabilidad para las salidas de Mirostat", + "Mirostat Eta": "Eta de Mirostat", + "Learning rate of Mirostat": "Tasa de aprendizaje de Mirostat", + "Beam search": "Búsqueda de haz", + "Helpful tip coming soon.": "Próximamente habrá un consejo útil.", + "Number of Beams": "Número de haces", + "Length Penalty": "Penalización de longitud", + "Early Stopping": "Detención temprana", + "Contrastive search": "Búsqueda contrastiva", + "Penalty Alpha": "Alfa de penalización", + "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "Fuerza del término de regularización de la Búsqueda Contrastiva. Establece en 0 para deshabilitar CS.", + "Do Sample": "Muestrear", + "Add BOS Token": "Agregar token BOS", + "Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative": "Agrega el token BOS al principio de las indicaciones. Desactivar esto puede hacer que las respuestas sean más creativas", + "Ban the eos_token. This forces the model to never end the generation prematurely": "Prohibir el token EOS. Esto obliga al modelo a nunca terminar la generación prematuramente", + "Ignore EOS Token": "Ignorar token EOS", + "Ignore the EOS Token even if it generates.": "Ignore el token EOS incluso si se genera.", + "Skip Special Tokens": "Omitir tokens especiales", + "Temperature Last": "Temperatura de Último", + "Temperature_Last_desc": "Usar el muestreador de temperatura al final", + "Speculative Ngram": "Ngram especulativo", + "Use a different speculative decoding method without a draft model": "Utilice un método de decodificación especulativa diferente sin un modelo preliminar. Se prefiere utilizar un modelo preliminar. El ngrama especulativo no es tan eficaz.", + "Spaces Between Special Tokens": "Espacios entre fichas especiales", + "LLaMA / Mistral / Yi models only": "Solo modelos LLaMA / Mistral / Yi", + "Example: some text [42, 69, 1337]": "Ejemplo: algún texto [42, 69, 1337]", + "Classifier Free Guidance. More helpful tip coming soon": "Guía Libre de Clasificadores. Pronto llegará un consejo más útil", + "Scale": "Escala", + "JSON Schema": "Esquema JSON", + "Type in the desired JSON schema": "Escriba el esquema JSON deseado", + "Grammar String": "Cadena de gramática", + "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF o EBNF, depende del backend en uso. Si estás usando esto, debes saber cuál.", + "Top P & Min P": "P superior y P mínima", + "Load default order": "Cargar orden predeterminado", + "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "llama.cpp únicamente. Determina el orden de los muestreadores. Si el modo Mirostat no es 0, se ignora el orden de las muestras.", + "Sampler Priority": "Prioridad del muestreador", + "Ooba only. Determines the order of samplers.": "Solo Ooba. Determina el orden de los muestreadores.", + "Character Names Behavior": "Comportamiento de los nombres de personajes", + "Helps the model to associate messages with characters.": "Ayuda al modelo a asociar mensajes con personajes.", + "None": "Ninguno", + "character_names_default": "Excepto grupos y personas pasadas. De lo contrario, asegúrese de proporcionar nombres en el mensaje.", + "Don't add character names.": "No agregues nombres de personajes.", + "Completion": "Objeto de finalización", + "character_names_completion": "Aplican restricciones: solo caracteres alfanuméricos latinos y guiones bajos. No funciona para todas las fuentes, en particular: Claude, MistralAI, Google.", + "Add character names to completion objects.": "Agregue nombres de personajes a los objetos de finalización.", + "Message Content": "Contenido del mensaje", + "Prepend character names to message contents.": "Anteponga los nombres de los caracteres al contenido del mensaje.", + "Continue Postfix": "Continuar sufijo", + "The next chunk of the continued message will be appended using this as a separator.": "El siguiente fragmento del mensaje continuado se agregará utilizando esto como separador.", + "Space": "Espacio", + "Newline": "Nueva línea", + "Double Newline": "Nueva línea doble", + "Wrap user messages in quotes before sending": "Envolver los mensajes de usuario entre comillas antes de enviarlos", + "Wrap in Quotes": "Envolver entre comillas", + "Wrap entire user message in quotes before sending.": "Envolver todo el mensaje del usuario entre comillas antes de enviarlo.", + "Leave off if you use quotes manually for speech.": "Omite esto si usas comillas manualmente para diálogo.", + "Continue prefill": "Continuar con prellenado", + "Continue sends the last message as assistant role instead of system message with instruction.": "Continuar envía el último mensaje como rol de asistente en lugar de mensaje del sistema con instrucciones.", + "Squash system messages": "Aplastar mensajes del sistema", + "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Combina mensajes del sistema consecutivos en uno solo (excluyendo diálogos de ejemplo). Puede mejorar la coherencia para algunos modelos.", + "Enable function calling": "Habilitar llamada a función", + "Send inline images": "Enviar imágenes en línea", + "image_inlining_hint_1": "Envía imágenes en mensajes si el modelo lo admite (por ejemplo, GPT-4V, Claude 3 o Llava 13B).\n Utilizar el", + "image_inlining_hint_2": "acción sobre cualquier mensaje o el", + "image_inlining_hint_3": "menú para adjuntar un archivo de imagen al chat.", + "Inline Image Quality": "Calidad de imagen en línea", + "openai_inline_image_quality_auto": "Auto", + "openai_inline_image_quality_low": "Bajo", + "openai_inline_image_quality_high": "Alto", + "Use AI21 Tokenizer": "Utilice el tokenizador AI21", + "Use the appropriate tokenizer for Jurassic models, which is more efficient than GPT's.": "Utilice el tokenizador apropiado para los modelos Jurassic, que es más eficiente que el de GPT.", + "Use Google Tokenizer": "Usar Tokenizador de Google", + "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "Usa el tokenizador apropiado para los modelos de Google a través de su API. Procesamiento de indicaciones más lento, pero ofrece un recuento de tokens mucho más preciso.", + "Use system prompt": "Usar el mensaje del sistema", + "(Gemini 1.5 Pro/Flash only)": "(Sólo Géminis 1.5 Pro/Flash)", + "Merges_all_system_messages_desc_1": "Combina todos los mensajes del sistema hasta el primer mensaje con una función que no pertenece al sistema y los envía en un", + "Merges_all_system_messages_desc_2": "campo.", + "Assistant Prefill": "Prellenado de Asistente", + "Start Claude's answer with...": "Iniciar la respuesta de Claude con...", + "Assistant Impersonation Prefill": "Precarga de suplantación de asistente", + "Use system prompt (Claude 2.1+ only)": "Usar indicación del sistema (solo para Claude 2.1+)", + "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "Enviar la indicación del sistema para los modelos admitidos. Si está desactivado, el mensaje del usuario se agrega al principio de las indicaciónes.", + "User first message": "Primer mensaje del usuario", + "Restore User first message": "Restaurar el primer mensaje del usuario", + "Human message": "Mensaje humano, instrucción, etc.\nNo agrega nada cuando está vacío, es decir, requiere un nuevo mensaje con el rol 'usuario'.", + "New preset": "Nuevo preajuste", + "Delete preset": "Eliminar preajuste", + "View / Edit bias preset": "Ver / Editar preajuste de sesgo", + "Add bias entry": "Agregar entrada de sesgo", + "Most tokens have a leading space.": "La mayoría de los tokens tienen un espacio inicial.", + "API Connections": "Conexiones de API", + "Text Completion": "Completar texto", + "Chat Completion": "Finalización del chat", + "NovelAI": "NovelAI", + "AI Horde": "AI Horde", + "KoboldAI": "KoboldAI", + "Avoid sending sensitive information to the Horde.": "Evite enviar información sensible a Horde.", + "Review the Privacy statement": "Revise la declaración de privacidad", + "Register a Horde account for faster queue times": "Registra una cuenta de Horde para tiempos de espera más rápidos", + "Learn how to contribute your idle GPU cycles to the Horde": "Aprende cómo contribuir con tus ciclos de GPU inactivos a Horde", + "Adjust context size to worker capabilities": "Ajusta el tamaño del contexto a las capacidades del trabajador", + "Adjust response length to worker capabilities": "Ajusta la longitud de la respuesta a las capacidades del trabajador", + "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "Puede ayudar con malas respuestas al encolar solo a los trabajadores aprobados. Puede ralentizar el tiempo de respuesta.", + "Trusted workers only": "Solo trabajadores de confianza", + "API key": "Clave API", + "Get it here:": "Obtenla aquí:", + "Register": "Registrar", + "View my Kudos": "Ver mis Kudos", + "Enter": "Ingresar", + "to use anonymous mode.": "para usar el modo anónimo.", + "Clear your API key": "Borrar tu clave de API", + "For privacy reasons, your API key will be hidden after you reload the page.": "Por razones de privacidad, su clave de API se ocultará después de que vuelva a cargar la página.", + "Models": "Modelos", + "Refresh models": "Actualizar modelos", + "-- Horde models not loaded --": "-- Modelos de Horde no cargados --", + "Not connected...": "No conectado...", + "API url": "URL de la API", + "Example: http://127.0.0.1:5000/api ": "Ejemplo: http://127.0.0.1:5000/api", + "Connect": "Conectar", + "Cancel": "Cancelar", + "Novel API key": "Clave API de Novel", + "Get your NovelAI API Key": "Obtenga su Clave de API de NovelAI", + "Enter it in the box below": "Introdúcelo en el cuadro de abajo", + "Novel AI Model": "Modelo Novel AI", + "No connection...": "Sin conexión...", + "API Type": "Tipo de API", + "Default (completions compatible)": "Predeterminado [compatible con OpenAI/compleciones: oobabooga, LM Studio, etc.]", + "TogetherAI API Key": "Clave API de TogetherAI", + "TogetherAI Model": "Modelo TogetherAI", + "-- Connect to the API --": "-- Conectar a la API --", + "OpenRouter API Key": "Clave API de OpenRouter", + "Click Authorize below or get the key from": "Haz clic en Autorizar a continuación o obtén la clave desde", + "View Remaining Credits": "Ver Créditos Restantes", + "OpenRouter Model": "Modelo de OpenRouter", + "Model Providers": "Proveedores de modelos", + "InfermaticAI API Key": "Clave API de InfermaticAI", + "InfermaticAI Model": "Modelo InfermaticAI", + "DreamGen API key": "Clave API de DreamGen", + "DreamGen Model": "Modelo DreamGen", + "Mancer API key": "Clave API de Mancer", + "Mancer Model": "Modelo de Mancer", + "Make sure you run it with": "Asegúrate de ejecutarlo con", + "flag": "bandera", + "API key (optional)": "Clave API (opcional)", + "Server url": "URL del servidor", + "Example: 127.0.0.1:5000": "Ejemplo: 127.0.0.1:5000", + "Custom model (optional)": "Modelo personalizado (opcional)", + "vllm-project/vllm": "vllm-project/vllm (modo contenedor de API OpenAI)", + "vLLM API key": "Clave API vLLM", + "Example: 127.0.0.1:8000": "Ejemplo: http://127.0.0.1:8000", + "vLLM Model": "Modelo vLLM", + "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (Modo envolvente para API de OpenAI)", + "Aphrodite API key": "Clave de API de Aphrodite", + "Aphrodite Model": "Modelo Afrodita", + "ggerganov/llama.cpp": "ggerganov/llama.cpp (Servidor de salida)", + "Example: 127.0.0.1:8080": "Ejemplo: 127.0.0.1:8080", + "Example: 127.0.0.1:11434": "Ejemplo: 127.0.0.1:11434", + "Ollama Model": "Modelo Ollama", + "Download": "Descargar", + "Tabby API key": "Clave API de Tabby", + "koboldcpp API key (optional)": "Clave API de koboldcpp (opcional)", + "Example: 127.0.0.1:5001": "Ejemplo: 127.0.0.1:5001", + "Authorize": "Autorizar", + "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Obtenga su token de API de OpenRouter utilizando el flujo OAuth. Será redirigido a openrouter.ai", + "Bypass status check": "Saltar la verificación del estado", + "Chat Completion Source": "Fuente de Completado de Chat", + "Reverse Proxy": "Proxy inverso", + "Proxy Presets": "Ajustes preestablecidos de proxy", + "Saved addresses and passwords.": "Direcciones y contraseñas guardadas.", + "Save Proxy": "Guardar proxy", + "Delete Proxy": "Eliminar proxy", + "Proxy Name": "Nombre del apoderado", + "This will show up as your saved preset.": "Esto aparecerá como su ajuste preestablecido guardado.", + "Proxy Server URL": "URL del servidor proxy", + "Alternative server URL (leave empty to use the default value).": "URL de servidor alternativo (deja vacío para usar el valor predeterminado).", + "Remove your real OAI API Key from the API panel BEFORE typing anything into this box": "Elimina tu verdadera clave de API de OAI del panel de API ANTES de escribir algo en este cuadro", + "We cannot provide support for problems encountered while using an unofficial OpenAI proxy": "No podemos brindar soporte para problemas encontrados al usar un proxy no oficial de OpenAI", + "Doesn't work? Try adding": "¿No funciona? Prueba a agregar", + "at the end!": "¡al final!", + "Proxy Password": "Contraseña de proxy", + "Will be used as a password for the proxy instead of API key.": "Se utilizará como contraseña para el proxy en lugar de clave API.", + "Peek a password": "Mira una contraseña", + "OpenAI API key": "Clave de API de OpenAI", + "View API Usage Metrics": "Ver métricas de uso de la API", + "Follow": "Seguir", + "these directions": "estas instrucciones", + "to get your OpenAI API key.": "para obtener tu clave API de OpenAI.", + "Use Proxy password field instead. This input will be ignored.": "Utilice el campo \"Contraseña de proxy\" en su lugar. Esta entrada será ignorada.", + "OpenAI Model": "Modelo de OpenAI", + "Bypass API status check": "Saltar la verificación del estado de la API", + "Show External models (provided by API)": "Mostrar modelos externos (provistos por la API)", + "Get your key from": "Obtén tu clave desde", + "Anthropic's developer console": "la consola de desarrolladores de Anthropic", + "Claude Model": "Modelo de Claude", + "Window AI Model": "Modelo de Window AI", + "Model Order": "Clasificación de modelos de OpenRouter", + "Alphabetically": "Alfabéticamente", + "Price": "Precio (más barato)", + "Context Size": "Tamaño del contexto", + "Group by vendors": "Agrupar por proveedores", + "Group by vendors Description": "Coloque los modelos OpenAI en un grupo, los modelos antrópicos en otro grupo, etc. Se puede combinar con la clasificación.", + "Allow fallback routes": "Permitir rutas de respaldo", + "Allow fallback routes Description": "El modelo alternativo se elige automáticamente si el modelo seleccionado no puede cumplir con tu solicitud.", + "Scale API Key": "Clave API de Scale", + "Clear your cookie": "Limpia tu cookie", + "Alt Method": "Método alternativo", + "AI21 API Key": "Clave API de AI21", + "AI21 Model": "Modelo de AI21", + "Google AI Studio API Key": "Clave API de Google AI Studio", + "Google Model": "Modelo de Google", + "MistralAI API Key": "Clave API de MistralAI", + "MistralAI Model": "Modelo MistralAI", + "Groq API Key": "Clave API de Groq", + "Groq Model": "Modelo Groq", + "Perplexity API Key": "Clave API de Perplexity", + "Perplexity Model": "Modelo de perplejidad", + "Cohere API Key": "Clave API de Cohere", + "Cohere Model": "Modelo coherente", + "Custom Endpoint (Base URL)": "Punto final personalizado (URL base)", + "Custom API Key": "Clave API personalizada", + "Available Models": "Modelos disponibles", + "Prompt Post-Processing": "Postprocesamiento rápido", + "Applies additional processing to the prompt before sending it to the API.": "Aplica procesamiento adicional al mensaje antes de enviarlo a la API.", + "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "Verifica su conexión de API enviando un breve mensaje de prueba. ¡Tenga en cuenta que se le cobrará por ello!", + "Test Message": "Mensaje de prueba", + "Auto-connect to Last Server": "Conexión automática al último servidor", + "Missing key": "❌ Llave faltante", + "Key saved": "✔️ Clave guardada", + "View hidden API keys": "Ver claves API ocultas", + "AI Response Formatting": "Formato de Respuesta de IA", + "Advanced Formatting": "Formato avanzado", + "Context Template": "Plantilla de Contexto", + "Auto-select this preset for Instruct Mode": "Auto-seleccionar este preajuste para el Modo Instrucción", + "Story String": "Cadena de historia", + "Example Separator": "Separador de ejemplo", + "Chat Start": "Inicio de chat", + "Add Chat Start and Example Separator to a list of stopping strings.": "Agregue Inicio de chat y Separador de ejemplo a una lista de cadenas de parada.", + "Use as Stop Strings": "Usar como Cadenas de Parada", + "context_allow_jailbreak": "Incluye Jailbreak al final del mensaje, si está definido en la tarjeta de personaje Y está habilitado \"Prefer Char. Jailbreak\".\nESTO NO SE RECOMIENDA PARA MODELOS DE COMPLETO DE TEXTO, PUEDE PRODUCIR UN RESULTADO INCORRECTO.", + "Allow Jailbreak": "Permitir Jailbreak", + "Context Order": "Orden de contexto", + "Summary": "Resumen", + "Author's Note": "Nota del autor", + "Example Dialogues": "Diálogos de ejemplo", + "Hint": "Pista:", + "In-Chat Position not affected": "Los pedidos de resumen y notas del autor solo se ven afectados cuando no tienen establecida una posición en el chat.", + "Instruct Mode": "Modo Instrucción", + "Enabled": "Activado", + "instruct_bind_to_context": "Si está habilitado, las plantillas de contexto se seleccionarán automáticamente según el nombre de la plantilla de instrucción seleccionada o por preferencia.", + "Bind to Context": "Vincular al Contexto", + "Presets": "Preajustes", + "Auto-select this preset on API connection": "Auto-seleccionar este preajuste en la conexión de la API", + "Activation Regex": "Regex de activación", + "Wrap Sequences with Newline": "Envolver Secuencias con Nueva línea", + "Replace Macro in Sequences": "Reemplazar Macro en Secuencias", + "Skip Example Dialogues Formatting": "Omitir Formato de Diálogos de Ejemplo", + "Include Names": "Incluir Nombres", + "Force for Groups and Personas": "Forzar para Grupos y Personas", + "System Prompt": "Indicaciones del Sistema", + "Instruct Mode Sequences": "Secuencias en Modo Instrucción", + "System Prompt Wrapping": "Ajuste de mensajes del sistema", + "Inserted before a System prompt.": "Insertado antes de un mensaje del sistema.", + "System Prompt Prefix": "Prefijo de aviso del sistema", + "Inserted after a System prompt.": "Insertado después de un mensaje del sistema.", + "System Prompt Suffix": "Sufijo de mensaje del sistema", + "Chat Messages Wrapping": "Envoltura de mensajes de chat", + "Inserted before a User message and as a last prompt line when impersonating.": "Insertado antes de un mensaje de usuario y como última línea de aviso al suplantar.", + "User Message Prefix": "Prefijo de mensaje de usuario", + "Inserted after a User message.": "Insertado después de un mensaje de usuario.", + "User Message Suffix": "Sufijo del mensaje del usuario", + "Inserted before an Assistant message and as a last prompt line when generating an AI reply.": "Se inserta antes de un mensaje del Asistente y como última línea de aviso al generar una respuesta de IA.", + "Assistant Message Prefix": "Prefijo de mensaje del asistente", + "Inserted after an Assistant message.": "Insertado después de un mensaje del Asistente.", + "Assistant Message Suffix": "Sufijo de mensaje del asistente", + "Inserted before a System (added by slash commands or extensions) message.": "Insertado antes de un mensaje del Sistema (agregado mediante comandos de barra diagonal o extensiones).", + "System Message Prefix": "Prefijo de mensaje del sistema", + "Inserted after a System message.": "Insertado después de un mensaje del sistema.", + "System Message Suffix": "Sufijo de mensaje del sistema", + "If enabled, System Sequences will be the same as User Sequences.": "Si está habilitado, las secuencias del sistema serán las mismas que las secuencias del usuario.", + "System same as User": "Sistema igual que el usuario", + "Misc. Sequences": "Secuencias varias", + "Inserted before the first Assistant's message.": "Insertado antes del mensaje del primer Asistente.", + "First Assistant Prefix": "Prefijo del primer asistente", + "instruct_last_output_sequence": "Se inserta antes del último mensaje del Asistente o como última línea de aviso al generar una respuesta de IA (excepto una función neutral/de sistema).", + "Last Assistant Prefix": "Prefijo del último asistente", + "Will be inserted as a last prompt line when using system/neutral generation.": "Se insertará como última línea de aviso cuando se utilice sistema/generación neutral.", + "System Instruction Prefix": "Prefijo de instrucción del sistema", + "If a stop sequence is generated, everything past it will be removed from the output (inclusive).": "Si se genera una secuencia de parada, todo lo que pase después se eliminará de la salida (inclusive).", + "Stop Sequence": "Secuencia de Parada", + "Will be inserted at the start of the chat history if it doesn't start with a User message.": "Se insertará al inicio del historial de chat si no comienza con un mensaje de Usuario.", + "User Filler Message": "Mensaje de relleno del usuario", + "Context Formatting": "Formato de Contexto", + "(Saved to Context Template)": "(Guardado en Plantilla de Contexto)", + "Always add character's name to prompt": "Siempre agregar el nombre del personaje a las indicaciones", + "Generate only one line per request": "Generar solo una línea por solicitud", + "Trim Incomplete Sentences": "Recortar Oraciones Incompletas", + "Include Newline": "Incluir Nueva línea", + "Misc. Settings": "Configuraciones Misceláneas", + "Collapse Consecutive Newlines": "Colapsar Nuevas líneas Consecutivas", + "Trim spaces": "Recortar espacios", + "Tokenizer": "Tokenizador", + "Token Padding": "Relleno de token", + "Start Reply With": "Iniciar Respuesta con", + "AI reply prefix": "Prefijo de Respuesta de IA", + "Show reply prefix in chat": "Mostrar prefijo de respuesta en el chat", + "Non-markdown strings": "Cadenas no Markdown", + "separate with commas w/o space between": "separe con comas sin espacio entre ellas", + "Custom Stopping Strings": "Cadenas de Detención Personalizadas", + "JSON serialized array of strings": "Arreglo de cadenas serializado en JSON", + "Replace Macro in Stop Strings": "Reemplazar macro en Cadenas de Detención Personalizadas", + "Auto-Continue": "Autocontinuar", + "Allow for Chat Completion APIs": "Permitir para APIs de Completado de Chat", + "Target length (tokens)": "Longitud objetivo (tokens)", + "World Info": "Información de Mundo (WI)", + "Locked = World Editor will stay open": "Bloqueado = El Editor de Mundo permanecerá abierto", + "Worlds/Lorebooks": "Mundos/Libros de Historia", + "Active World(s) for all chats": "Mundo(s) Activo(s) para todos los chats", + "-- World Info not found --": "-- Información de Mundo (WI) no encontrada --", + "Global World Info/Lorebook activation settings": "Configuración de activación de Global World Info/Lorebook", + "Click to expand": "Haga clic para ampliar", + "Scan Depth": "Profundidad de escaneo", + "Context %": "% de Contexto", + "Budget Cap": "Límite de presupuesto", + "(0 = disabled)": "(0 = desactivado)", + "Scan chronologically until reached min entries or token budget.": "Escanear cronológicamente hasta alcanzar el mínimo de entradas o el presupuesto de tokens.", + "Min Activations": "Activaciones mínimas", + "Max Depth": "Máxima profundidad", + "(0 = unlimited, use budget)": "(0 = ilimitado, use presupuesto)", + "Insertion Strategy": "Estrategia de Inserción", + "Sorted Evenly": "Ordenado uniformemente", + "Character Lore First": "Historia de Personaje Primero", + "Global Lore First": "Historia Global Primero", + "Entries can activate other entries by mentioning their keywords": "Las entradas pueden activar otras entradas mencionando sus palabras clave", + "Recursive Scan": "Escaneo Recursiva", + "Lookup for the entry keys in the context will respect the case": "La búsqueda de las claves de entrada en el contexto respetará mayúsculas y minúsculas", + "Case Sensitive": "Sensible a mayúsculas y minúsculas", + "If the entry key consists of only one word, it would not be matched as part of other words": "Si la clave de entrada consiste en solo una palabra, no se emparejará como parte de otras palabras", + "Match Whole Words": "Coincidir con palabras completas", + "Only the entries with the most number of key matches will be selected for Inclusion Group filtering": "Solo se seleccionarán las entradas con la mayor cantidad de coincidencias clave para el filtrado del grupo de inclusión.", + "Use Group Scoring": "Usar puntuación grupal", + "Alert if your world info is greater than the allocated budget.": "Alerta si la información de tu mundo es mayor que el presupuesto asignado.", + "Alert On Overflow": "Alerta en Desbordamiento", + "New": "Nuevo", + "or": "o", + "--- Pick to Edit ---": "--- Seleccionar para editar ---", + "Rename World Info": "Renombrar Información de Mundo (WI)", + "Open all Entries": "Abrir Todas las Entradas", + "Close all Entries": "Cerrar Todas las Entradas", + "New Entry": "Nueva Entrada", + "Fill empty Memo/Titles with Keywords": "Llenar Memos/Títulos vacíos con Palabras Clave", + "Import World Info": "Importar Información de Mundo (WI)", + "Export World Info": "Exportar Información de Mundo (WI)", + "Duplicate World Info": "Duplicar Información de Mundo (WI)", + "Delete World Info": "Eliminar Información de Mundo (WI)", + "Search...": "Buscar...", + "Search": "Buscar", + "Priority": "Prioridad", + "Custom": "Personalizado", + "Title A-Z": "Título de A a Z", + "Title Z-A": "Título de Z a A", + "Tokens ↗": "Tokens ↗", + "Tokens ↘": "Tokens ↘", + "Depth ↗": "Profundidad ↗", + "Depth ↘": "Profundidad ↘", + "Order ↗": "Orden ↗", + "Order ↘": "Orden ↘", + "UID ↗": "UID ↗", + "UID ↘": "UID ↘", + "Trigger% ↗": "Activador% ↗", + "Trigger% ↘": "Activador% ↘", + "Refresh": "Actualizar", + "User Settings": "Configuraciones de usuario", + "Simple": "Simple", + "Advanced": "Avanzado", + "UI Language": "Idioma de la UI", + "Account": "Cuenta", + "Admin Panel": "Panel de administrador", + "Logout": "Cerrar sesión", + "Search Settings": "Configuración de Búsqueda", + "UI Theme": "Tema de interfaz de usuario", + "Import a theme file": "Importar un archivo de tema", + "Export a theme file": "Exportar un archivo de tema", + "Delete a theme": "Eliminar un tema", + "Update a theme file": "Actualizar un archivo de tema", + "Save as a new theme": "Guardar como nuevo tema", + "Avatar Style:": "Estilo de Avatar", + "Circle": "Círculo", + "Square": "Cuadrado", + "Rectangle": "Rectángulo", + "Chat Style:": "Estilo de Chat:", + "Flat": "Departamento\nBurbujas\nDocumento", + "Bubbles": "Burbujas", + "Document": "Documento", + "Specify colors for your theme.": "Especifique colores para su tema.", + "Theme Colors": "Colores del tema", + "Main Text": "Texto principal", + "Italics Text": "Texto en cursiva", + "Underlined Text": "Texto subrayado", + "Quote Text": "Texto de cita", + "Shadow Color": "Color de sombra", + "Chat Background": "Fondo de Chat", + "UI Background": "Fondo de IU", + "UI Border": "Borde de IU", + "User Message Blur Tint": "Tinte de Desenfoque del Mensaje del Usuario", + "AI Message Blur Tint": "Tinte de Desenfoque del Mensaje de IA", + "Chat Width": "Ancho del chat", + "Width of the main chat window in % of screen width": "Ancho de la ventana principal de chat en % del ancho de la pantalla", + "Font Scale": "Tamaño de fuente", + "Font size": "Tamaño de fuente", + "Blur Strength": "Fuerza de desenfoque", + "Blur strength on UI panels.": "Fuerza de desenfoque en los paneles de la interfaz de usuario.", + "Text Shadow Width": "Ancho de sombra de texto", + "Strength of the text shadows": "Fuerza de las sombras del texto.", + "Disables animations and transitions": "Deshabilita animaciones y transiciones", + "Reduced Motion": "Movimiento reducido", + "removes blur from window backgrounds": "elimina el desenfoque de los fondos de ventana", + "No Blur Effect": "Sin efecto de desenfoque", + "Remove text shadow effect": "Eliminar efecto de sombra de texto", + "No Text Shadows": "Sin sombras de texto", + "Reduce chat height, and put a static sprite behind the chat window": "Reducir la altura del chat y poner un sprite estático detrás de la ventana del chat", + "Waifu Mode": "Modo Waifu", + "Always show the full list of the Message Actions context items for chat messages, instead of hiding them behind '...'": "Mostrar siempre la lista completa de elementos de contexto de Acciones de Mensaje para mensajes de chat, en lugar de ocultarlos detrás de '...'", + "Auto-Expand Message Actions": "Expandir Automáticamente de Acciones de Mensaje", + "Alternative UI for numeric sampling parameters with fewer steps": "UI alternativa para parámetros de muestreo numérico con menos pasos", + "Zen Sliders": "Deslizadores Zen", + "Entirely unrestrict all numeric sampling parameters": "Deslimitar completamente todos los parámetros de muestreo numérico", + "Mad Lab Mode": "Modo Laboratorio Loco", + "Time the AI's message generation, and show the duration in the chat log": "Medir el tiempo de generación del mensaje de IA y mostrar la duración en el registro de chat", + "Message Timer": "Temporizador de mensajes", + "Show a timestamp for each message in the chat log": "Mostrar una marca de tiempo para cada mensaje en el registro de chat", + "Chat Timestamps": "Marcas de Tiempo del Chat", + "Show an icon for the API that generated the message": "Mostrar un icono para la API que generó el mensaje", + "Model Icon": "Ícono del Modelo", + "Show sequential message numbers in the chat log": "Mostrar números de mensaje secuenciales en el registro de chat", + "Message IDs": "IDs de Mensaje", + "Hide avatars in chat messages.": "Ocultar avatares en los mensajes de chat.", + "Hide Chat Avatars": "Ocultar avatares de chat", + "Show the number of tokens in each message in the chat log": "Mostrar el número de tokens en cada mensaje en el registro de chat", + "Show Message Token Count": "Mostrar Conteo de Tokens en Mensaje", + "Single-row message input area. Mobile only, no effect on PC": "Área de entrada de mensaje de una sola fila. Solo móvil, sin efecto en PC", + "Compact Input Area (Mobile)": "Área de Entrada Compacta (Móvil)", + "In the Character Management panel, show quick selection buttons for favorited characters": "En el panel de Gestión de Personajes, mostrar botones de selección rápida para personajes favoritos", + "Characters Hotswap": "Cambio rápido de personajes", + "Enable magnification for zoomed avatar display.": "Habilitar ampliación para visualización de avatar ampliada.", + "Avatar Hover Magnification": "Ampliación de desplazamiento del avatar", + "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "Habilita un efecto de ampliación al pasar el mouse cuando muestra el avatar ampliado después de hacer clic en la imagen de un avatar en el chat.", + "Show tagged character folders in the character list": "Mostrar carpetas de personajes etiquetados en la lista de personajes", + "Tags as Folders": "Etiquetas como Carpetas", + "Tags_as_Folders_desc": "Cambio reciente: las etiquetas deben estar marcadas como carpetas en el menú Administración de etiquetas para que aparezcan como tales. Haga clic aquí para abrirlo.", + "Character Handling": "Manipulación de personajes", + "If set in the advanced character definitions, this field will be displayed in the characters list.": "Si se establece en las definiciones avanzadas de personajes, este campo se mostrará en la lista de personajes.", + "Char List Subheader": "Subtítulo de lista de caracteres", + "Character Version": "Versión del Personaje", + "Created by": "Creado por", + "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "Usar coincidencia difusa y buscar personajes en la lista por todos los campos de datos, no solo por una subcadena de nombre", + "Advanced Character Search": "Búsqueda Avanzada de Personajes", + "If checked and the character card contains a prompt override (System Prompt), use that instead": "Si está marcado y la tarjeta de personaje contiene una anulación de indicación (Indicación del sistema), usar eso en su lugar", + "Prefer Character Card Prompt": "Preferir Indicaciones en Tarjeta de Personaje", + "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Si está marcado y la tarjeta de personaje contiene una anulación de jailbreak (Instrucciones Post Historial), usar eso en su lugar", + "Prefer Character Card Jailbreak": "Preferir Jailbreak en Tarjeta de Personaje", + "never_resize_avatars_tooltip": "Evite recortar y cambiar el tamaño de las imágenes de personajes importados. Cuando esté desactivado, recorte/cambie el tamaño a 512x768.", + "Never resize avatars": "Nunca redimensionar avatares", + "Show actual file names on the disk, in the characters list display only": "Mostrar nombres de archivo reales en el disco, solo en la visualización de la lista de personajes", + "Show avatar filenames": "Mostrar nombres de archivo de avatares", + "Prompt to import embedded card tags on character import. Otherwise embedded tags are ignored": "Solicitar importar etiquetas de tarjeta incrustadas al importar un personaje. De lo contrario, las etiquetas incrustadas se ignoran", + "Import Card Tags": "Importar Etiquetas de Tarjetas", + "Hide character definitions from the editor panel behind a spoiler button": "Ocultar definiciones de personajes del panel de editor detrás de un botón de spoiler", + "Spoiler Free Mode": "Modo Libre de Spoilers", + "Miscellaneous": "Varios", + "Reload and redraw the currently open chat": "Recargar y volver a dibujar el chat abierto actualmente", + "Reload Chat": "Recargar Chat", + "Debug Menu": "Menú de depuración", + "Smooth Streaming": "Transmisión fluida", + "Experimental feature. May not work for all backends.": "Característica experimental. Puede que no funcione para todos los backends.", + "Slow": "Lento", + "Fast": "Rápido", + "Play a sound when a message generation finishes": "Reproducir un sonido cuando finaliza la generación de un mensaje", + "Message Sound": "Sonido de mensaje", + "Only play a sound when ST's browser tab is unfocused": "Solo reproducir un sonido cuando la pestaña del navegador de ST no está enfocada", + "Background Sound Only": "Solo Sonido de Fondo", + "Reduce the formatting requirements on API URLs": "Reducir los requisitos de formato en las URL de API", + "Relaxed API URLS": "URLS de API relajadas", + "Ask to import the World Info/Lorebook for every new character with embedded lorebook. If unchecked, a brief message will be shown instead": "Pedir importar Información de Mundo (WI)/Libro de Historia para cada nuevo personaje con un Libro de Historia incrustado. Si no está marcado, se mostrará un mensaje breve en su lugar", + "Lorebook Import Dialog": "Diálogo de Importación de Libro de Historia", + "Restore unsaved user input on page refresh": "Restaurar la entrada de usuario no guardada al actualizar la página", + "Restore User Input": "Restaurar Entrada de Usuario", + "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "Permitir reposicionar ciertos elementos de IU arrastrándolos. Solo PC, sin efecto en móviles", + "Movable UI Panels": "Paneles de UI Móviles", + "MovingUI preset. Predefined/saved draggable positions": "Preconfiguración MovingUI. Posiciones arrastrables predefinidas/guardadas", + "MUI Preset": "Preajuste MUI", + "Save movingUI changes to a new file": "Guardar cambios de MovingUI en un nuevo archivo", + "Reset MovingUI panel sizes/locations.": "Restablezca los tamaños/ubicaciones del panel MovingUI.", + "Apply a custom CSS style to all of the ST GUI": "Aplicar un estilo CSS personalizado a toda la GUI de ST", + "Custom CSS": "CSS personalizado", + "Expand the editor": "Expandir el editor", + "Chat/Message Handling": "Manipulación de Chat/Mensaje", + "# Messages to Load": "# Mensaje cargar", + "The number of chat history messages to load before pagination.": "La cantidad de mensajes del historial de chat que se cargarán antes de la paginación.", + "(0 = All)": "(0 = Todos)", + "Streaming FPS": "FPS de Transmisión", + "Update speed of streamed text.": "Actualizar la velocidad del texto transmitido.", + "Example Messages Behavior": "Comportamiento de mensajes de ejemplo", + "Gradual push-out": "Expulsión gradual", + "Always include examples": "Siempre incluir ejemplos", + "Never include examples": "Nunca incluir ejemplos", + "Send on Enter": "Enviar al presionar Enter", + "Disabled": "Desactivado", + "Automatic (PC)": "Automático (PC)", + "Press Send to continue": "Presionar Enviar para continuar", + "Show a button in the input area to ask the AI to continue (extend) its last message": "Mostrar un botón en el área de entrada para pedirle a la IA que continúe (extienda) su último mensaje", + "Quick 'Continue' button": "Botón 'Continuar' Rápido", + "Show arrow buttons on the last in-chat message to generate alternative AI responses. Both PC and mobile": "Mostrar botones de flecha en el último mensaje del chat para generar respuestas alternativas de la IA. Tanto PC como móvil", + "Swipes": "Deslizamientos", + "Allow using swiping gestures on the last in-chat message to trigger swipe generation. Mobile only, no effect on PC": "Permitir el uso de gestos de deslizamiento en el último mensaje del chat para activar la generación de deslizamiento. Solo móvil, sin efecto en PC", + "Gestures": "Gestos", + "Auto-load Last Chat": "Cargar automáticamente el último chat", + "Auto-scroll Chat": "Desplazamiento de Chat Automático", + "Save edits to messages without confirmation as you type": "Guardar ediciones en mensajes sin confirmación mientras escribe", + "Auto-save Message Edits": "Guardar automáticamente las Ediciones de Mensajes", + "Confirm message deletion": "Confirmar eliminación de mensaje", + "Auto-fix Markdown": "Auto-corregir Markdown", + "Disallow embedded media from other domains in chat messages": "No permitir medios incrustados de otros dominios en los mensajes de chat.", + "Forbid External Media": "Prohibir Medios Externos", + "Allow {{char}}: in bot messages": "Permitir {{char}}: en mensajes de bot", + "Allow {{user}}: in bot messages": "Permitir {{user}}: en mensajes de bot", + "Skip encoding and characters in message text, allowing a subset of HTML markup as well as Markdown": "Omitir la codificación de los caracteres en el texto del mensaje, permitiendo un subconjunto de marcado HTML, así como Markdown", + "Show tags in responses": "Mostrar etiquetas en respuestas", + "Allow AI messages in groups to contain lines spoken by other group members": "Permitir que los mensajes de IA en grupos contengan líneas habladas por otros miembros del grupo", + "Relax message trim in Groups": "Relajar recorte de mensajes en Grupos", + "Log prompts to console": "Registrar indicaciones en la consola", + "Requests logprobs from the API for the Token Probabilities feature": "Solicita logprobs de la API para la función de Probabilidades de Token", + "Request token probabilities": "Solicitar probabilidades de tokens", + "Automatically reject and re-generate AI message based on configurable criteria": "Rechazar y volver a generar automáticamente el mensaje de IA en función de criterios configurables", + "Auto-swipe": "Deslizamiento automático", + "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Habilitar la función de deslizamiento automático. La configuración en esta sección solo tiene efecto cuando el deslizamiento automático está habilitado", + "Minimum generated message length": "Longitud mínima del mensaje generado", + "If the generated message is shorter than these many characters, trigger an auto-swipe": "Si el mensaje generado es más corto que esto, activar un deslizamiento automático", + "Blacklisted words": "Palabras prohibidas", + "words you dont want generated separated by comma ','": "palabras que no desea generar separadas por coma ','", + "Blacklisted word count to swipe": "Número de palabras prohibidas para deslizar", + "Minimum number of blacklisted words detected to trigger an auto-swipe": "Número mínimo de palabras prohibidas detectadas para activar un deslizamiento automático", + "AutoComplete Settings": "Configuración de Autocompletar", + "Automatically hide details": "Ocultar detalles automáticamente", + "Determines how entries are found for autocomplete.": "Determina cómo se encuentran las entradas para autocompletar.", + "Autocomplete Matching": "Pareo", + "Starts with": "Comienza con", + "Includes": "Incluye", + "Fuzzy": "Difuso", + "Sets the style of the autocomplete.": "Establece el estilo del autocompletado.", + "Autocomplete Style": "Estilo", + "Follow Theme": "Seguir tema", + "Dark": "Oscuro", + "Sets the font size of the autocomplete.": "Establece el tamaño de fuente del autocompletado.", + "Sets the width of the autocomplete.": "Establece el ancho del autocompletar.", + "Autocomplete Width": "Ancho", + "chat input box": "cuadro de entrada de chat", + "entire chat width": "todo el ancho del chat", + "full window width": "ancho completo de la ventana", + "STscript Settings": "Configuración de STscript", + "Sets default flags for the STscript parser.": "Establece indicadores predeterminados para el analizador STscript.", + "Parser Flags": "Banderas del analizador", + "Switch to stricter escaping, allowing all delimiting characters to be escaped with a backslash, and backslashes to be escaped as well.": "Cambie a un escape más estricto, lo que permitirá que todos los caracteres delimitadores se escapen con una barra invertida y que las barras invertidas también se escapen.", + "STRICT_ESCAPING": "ESTRICT_ESCAPING", + "Replace all {{getvar::}} and {{getglobalvar::}} macros with scoped variables to avoid double macro substitution.": "Reemplace todas las macros {{getvar::}} y {{getglobalvar::}} con variables de ámbito para evitar la doble sustitución de macros.", + "REPLACE_GETVAR": "REEMPLAZAR_GETVAR", + "Change Background Image": "Cambiar Imagen de Fondo", + "Filter": "Filtro", + "Automatically select a background based on the chat context": "Seleccionar automáticamente un fondo basado en el contexto del chat", + "Auto-select": "Auto-seleccionar", + "System Backgrounds": "Fondos del Sistema", + "Chat Backgrounds": "Fondos de Chat", + "bg_chat_hint_1": "Fondos de chat generados con el", + "bg_chat_hint_2": "La extensión aparecerá aquí.", + "Extensions": "Extensiones", + "Notify on extension updates": "Notificar sobre actualizaciones de extensión", + "Manage extensions": "Gestionar extensiones", + "Import Extension From Git Repo": "Importar extensión desde repositorio Git", + "Install extension": "Instalar extensión", + "Extras API:": "API adicionales:", + "Auto-connect": "Conexión automática", + "Extras API URL": "URL de API adicional", + "Extras API key (optional)": "Clave API de Extras (opcional)", + "Persona Management": "Gestión de Personas", + "How do I use this?": "¿Cómo uso esto?", + "Click for stats!": "¡Haz clic para estadísticas!", + "Usage Stats": "Estadísticas de uso", + "Backup your personas to a file": "Realiza una copia de seguridad de tus personajes en un archivo", + "Backup": "Respaldo", + "Restore your personas from a file": "Restaura tus personajes desde un archivo", + "Restore": "Restaurar", + "Create a dummy persona": "Crear una persona ficticia", + "Create": "Crear", + "Toggle grid view": "Alternar vista de cuadrícula", + "No persona description": "[Sin descripción]", + "Name": "Nombre", + "Enter your name": "Ingrese su nombre", + "Click to set a new User Name": "Haga clic para establecer un nuevo Nombre de Usuario", + "Click to lock your selected persona to the current chat. Click again to remove the lock.": "Haga clic para bloquear su persona seleccionada en el chat actual. Haga clic nuevamente para quitar el bloqueo.", + "Click to set user name for all messages": "Haga clic para establecer el nombre de usuario para todos los mensajes", + "Persona Description": "Descripción de Persona", + "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "Ejemplo: [{{user}} es una chica gata rumana de 28 años.]", + "Tokens persona description": "Descripción de tokens", + "Position:": "Posición:", + "In Story String / Prompt Manager": "En la Cadena de Historia / Administrador de Indicaciones", + "Top of Author's Note": "Parte Superior de la Nota de Autor", + "Bottom of Author's Note": "Parte Inferior de la Nota de Autor", + "In-chat @ Depth": "En el chat @ Depth", + "Depth:": "Profundidad:", + "Role:": "Role:", + "System": "Sistema", + "User": "Usuario", + "Assistant": "Asistente", + "Show notifications on switching personas": "Mostrar notificaciones al cambiar de personas", + "Character Management": "Gestión de Personajes", + "Locked = Character Management panel will stay open": "Bloqueado = El panel de Gestión de Personajes permanecerá abierto", + "Select/Create Characters": "Seleccionar/Crear Personajes", + "Favorite characters to add them to HotSwaps": "Marcar personajes como favoritos para añadirlos a HotSwaps", + "Token counts may be inaccurate and provided just for reference.": "El conteo de tokens pueden ser inexacto y se proporcionan solo como referencia.", + "Total tokens": "fichas totales", + "Calculating...": "Calculador...", + "Tokens": "Tokens", + "Permanent tokens": "Fichas permanentes", + "Permanent": "Permanente", + "About Token 'Limits'": "Acerca de los 'límites' de tokens", + "Toggle character info panel": "Alternar panel de información de personaje", + "Name this character": "Nombre de este personaje", + "extension_token_counter": "Fichas:", + "Click to select a new avatar for this character": "Haga clic para seleccionar un nuevo avatar para este personaje", + "Add to Favorites": "Agregar a Favoritos", + "Advanced Definition": "Definición Avanzada", + "Character Lore": "Historia (Trasfondo) del personaje", + "Chat Lore": "Historia del chat", + "Export and Download": "Exportar y descargar", + "Duplicate Character": "Duplicar personaje", + "Create Character": "Crear personaje", + "Delete Character": "Eliminar personaje", + "More...": "Más...", + "Link to World Info": "Enlazar a Información de Mundo (WI)", + "Import Card Lore": "Importar Historia de Tarjeta", + "Scenario Override": "Anulación de Escenario", + "Convert to Persona": "Convertir en Persona", + "Rename": "Renombrar", + "Link to Source": "Enlace a la fuente", + "Replace / Update": "Reemplazar / Actualizar", + "Import Tags": "Etiquetas de importación", + "Search / Create Tags": "Buscar / Crear Etiquetas", + "View all tags": "Ver todas las etiquetas", + "Creator's Notes": "Nota del Creador", + "Show / Hide Description and First Message": "Mostrar / Ocultar Descripción y Primer Mensaje", + "Character Description": "Descripción del Personaje", + "Click to allow/forbid the use of external media for this character.": "Haz clic para permitir/prohibir el uso de medios externos para este personaje.", + "Ext. Media": "ext. Medios de comunicación", + "Describe your character's physical and mental traits here.": "Describa aquí las características físicas y mentales de su personaje.", + "First message": "Primer Mensaje", + "Click to set additional greeting messages": "Haz clic para establecer mensajes de saludo adicionales", + "Alt. Greetings": "Alt. Saludos", + "This will be the first message from the character that starts every chat.": "Este será el primer mensaje del personaje que inicia cada chat.", + "Group Controls": "Controles de grupo", + "Chat Name (Optional)": "Nombre del Chat (Opcional)", + "Click to select a new avatar for this group": "Haz clic para seleccionar un nuevo avatar para este grupo", + "Group reply strategy": "Estrategia de respuesta de grupo", + "Natural order": "Orden natural", + "List order": "Orden de lista", + "Group generation handling mode": "Modo de manejo de generación de grupos", + "Swap character cards": "Intercambiar tarjetas de personajes", + "Join character cards (exclude muted)": "Unirse a tarjetas de personajes (excluir silenciadas)", + "Join character cards (include muted)": "Unirse a tarjetas de personajes (incluidas silenciadas)", + "Inserted before each part of the joined fields.": "Insertado antes de cada parte de los campos unidos.", + "Join Prefix": "Unirse al prefijo", + "When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and with the name of the part (e.g.: description, personality, scenario, etc.)": "Cuando se selecciona 'Unir tarjetas de personajes', todos los campos respectivos de los personajes se unen.\rEsto significa que en la cadena de la historia, por ejemplo, todas las descripciones de los personajes se unirán en un texto grande.\rSi desea que esos campos estén separados, puede definir un prefijo o sufijo aquí.\r\rEste valor admite macros normales y también reemplazará {{char}} con el nombre del personaje relevante y con el nombre de la parte (por ejemplo: descripción, personalidad, escenario, etc.)", + "Inserted after each part of the joined fields.": "Insertado después de cada parte de los campos unidos.", + "Join Suffix": "Unirse al sufijo", + "Set a group chat scenario": "Establecer un escenario de chat grupal", + "Click to allow/forbid the use of external media for this group.": "Haga clic para permitir/prohibir el uso de medios externos para este grupo.", + "Restore collage avatar": "Restaurar avatar de collage", + "Allow self responses": "Permitir auto respuestas", + "Auto Mode": "Modo automático", + "Auto Mode delay": "Retardo del modo automático", + "Hide Muted Member Sprites": "Ocultar sprites de miembros silenciados", + "Current Members": "Miembros actuales", + "Add Members": "Agregar miembros", + "Create New Character": "Crear Nuevo Personaje", + "Import Character from File": "Importar Personaje desde Archivo", + "Import content from external URL": "Importar contenido desde URL externa", + "Create New Chat Group": "Crear Nuevo Grupo de Chat", + "Characters sorting order": "Orden de clasificación de personajes", + "A-Z": "A-Z", + "Z-A": "Z-A", + "Newest": "Más Reciente", + "Oldest": "Más Antiguo", + "Favorites": "Favoritos", + "Recent": "Reciente", + "Most chats": "Más Chats", + "Least chats": "Menos Chats", + "Most tokens": "Más tokens", + "Least tokens": "Menos tokens", + "Random": "Aleatorio", + "Toggle character grid view": "Alternar vista de cuadrícula de personajes", + "Bulk_edit_characters": "Editar personajes masivamente", + "Bulk select all characters": "Seleccionar de forma masiva todos los personajes", + "Bulk delete characters": "Eliminar personajes masivamente", + "popup-button-save": "Guardar", + "popup-button-yes": "Sí", + "popup-button-no": "No", + "popup-button-cancel": "Cancelar", + "popup-button-import": "Importar", + "Advanced Definitions": "Definiciones avanzadas", + "Prompt Overrides": "Anulaciones rápidas", + "(For Chat Completion and Instruct Mode)": "(Para completar el chat y el modo de instrucción)", + "Insert {{original}} into either box to include the respective default prompt from system settings.": "Inserte {{original}} en cualquiera de las casillas para incluir las indicaciones predeterminadas respectivas de la configuración del sistema.", + "Main Prompt": "Indicaciones Principales", + "Any contents here will replace the default Main Prompt used for this character. (v2 spec: system_prompt)": "Cualquier contenido aquí reemplazará las Indicaciones Principales predeterminada utilizada para este personaje. (especificación v2: system_prompt)", + "Any contents here will replace the default Jailbreak Prompt used for this character. (v2 spec: post_history_instructions)": "Cualquier contenido aquí reemplazará las Indicaciones de Jailbreak predeterminada utilizada para este personaje. (especificación v2: post_history_instructions)", + "Creator's Metadata (Not sent with the AI prompt)": "Metadatos del Creador (No enviados con las indicaciones de la IA)", + "Creator's Metadata": "Metadatos del creador", + "(Not sent with the AI Prompt)": "(No se envía con el mensaje AI)", + "Everything here is optional": "Todo aquí es opcional", + "(Botmaker's name / Contact Info)": "(Nombre del creador del bot / Información de contacto)", + "(If you want to track character versions)": "(Si desea rastrear versiones de personajes)", + "(Describe the bot, give use tips, or list the chat models it has been tested on. This will be displayed in the character list.)": "(Describa el bot, dé consejos de uso o enumere los modelos de chat en los que se ha probado. Esto se mostrará en la lista de personajes.)", + "Tags to Embed": "Etiquetas para Incrustar", + "(Write a comma-separated list of tags)": "(Escriba una lista de etiquetas separadas por comas)", + "Personality summary": "Resumen de personalidad", + "(A brief description of the personality)": "(Una breve descripción de la personalidad)", + "Scenario": "Escenario", + "(Circumstances and context of the interaction)": "(Circunstancias y contexto de la interacción)", + "Character's Note": "Nota del personaje", + "(Text to be inserted in-chat @ designated depth and role)": "(El texto se insertará en el chat en la profundidad y función designadas)", + "@ Depth": "@ Profundidad", + "Role": "Role", + "Talkativeness": "Habladuría", + "How often the character speaks in group chats!": "¡Con qué frecuencia habla el personaje en los chats grupales!", + "How often the character speaks in": "¿Con qué frecuencia habla el personaje?", + "group chats!": "chats grupales!", + "Shy": "Tímido", + "Normal": "Normal", + "Chatty": "Parlanchín", + "Examples of dialogue": "Ejemplos de diálogo", + "Important to set the character's writing style.": "Importante para establecer el estilo de escritura del personaje.", + "(Examples of chat dialog. Begin each example with START on a new line.)": "(Ejemplos de diálogo de chat. Comience cada ejemplo con START en una nueva línea.)", + "Save": "Guardar", + "Chat History": "Historial de chat", + "Import Chat": "Importar chat", + "Copy to system backgrounds": "Copiar a fondos del sistema", + "Rename background": "Cambiar nombre de fondo", + "Lock": "Cerrar", + "Unlock": "desbloquear", + "Delete background": "Eliminar fondo", + "Chat Scenario Override": "Anulación del escenario de chat", + "Remove": "Eliminar", + "Type here...": "Escriba aquí...", + "Chat Lorebook": "Libro de conocimientos de chat para", + "Chat Lorebook for": "Libro de conocimientos de chat para", + "chat_world_template_txt": "Una información mundial seleccionada estará vinculada a este chat. Al generar una respuesta de IA,\n se combinará con las entradas de los libros de historia globales y de personajes.", + "Select a World Info file for": "Seleccionar un archivo de Información de Mundo (WI) para", + "Primary Lorebook": "Libro de Historia primario", + "A selected World Info will be bound to this character as its own Lorebook.": "Una Información de Mundo (WI) seleccionada se vinculará a este personaje como su propio Libro de Historia.", + "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "Al generar una respuesta de IA, se combinará con las entradas de un selector global de Información Mundial.", + "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "Exportar un personaje también exportaría el archivo de Libro de Historia seleccionado incrustado en los datos JSON.", + "Additional Lorebooks": "Libros de Historia Adicionales", + "Associate one or more auxillary Lorebooks with this character.": "Asociar uno o más Libros de Historia auxiliares con este personaje.", + "NOTE: These choices are optional and won't be preserved on character export!": "NOTA: ¡Estas opciones son opcionales y no se conservarán al exportar el personaje!", + "Rename chat file": "Renombrar archivo de chat", + "Export JSONL chat file": "Exportar archivo de chat JSONL", + "Download chat as plain text document": "Descargar chat como documento de texto sin formato", + "Delete chat file": "Eliminar archivo de chat", + "Use tag as folder": "Etiquetar como carpeta", + "Delete tag": "Eliminar etiqueta", + "Entry Title/Memo": "Título/Memo", + "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized❌ Disabled": "Estado de entrada a WI:\r🔵 Constante\r🟢Normal\r🔗 Vectorizado\r❌ Deshabilitado", + "WI_Entry_Status_Constant": "Constante", + "WI_Entry_Status_Normal": "Normal", + "WI_Entry_Status_Vectorized": "Vectorizado", + "WI_Entry_Status_Disabled": "Desactivado", + "T_Position": "↑Char: antes de definiciones de personajes\n↓Char: después de definiciones de personajes\n↑AN: antes de notas del autor\n↓AN: después de notas del autor\n@D: en profundidad", + "Before Char Defs": "Antes de Def. de Personaje", + "After Char Defs": "Después de Def. de Personaje", + "Before EM": "↑EM", + "After EM": "↓EM", + "Before AN": "Antes de AN", + "After AN": "Después de AN", + "at Depth System": "@D ⚙️", + "at Depth User": "@D 👤", + "at Depth AI": "@D 🤖", + "Depth": "Profundidad", + "Order:": "Orden:", + "Order": "Orden:", + "Trigger %:": "Desencadenar %:", + "Probability": "Probabilidad", + "Duplicate world info entry": "Entrada de información mundial duplicada", + "Delete world info entry": "Eliminar entrada de información mundial", + "Comma separated (required)": "Separado por comas (requerido)", + "Primary Keywords": "Palabras Clave Primarias", + "Keywords or Regexes": "Palabras clave o expresiones regulares", + "Comma separated list": "Lista separada por comas", + "Switch to plaintext mode": "Cambiar al modo de texto sin formato", + "Logic": "Lógica", + "AND ANY": "Y CUALQUIERA", + "AND ALL": "Y TODOS", + "NOT ALL": "NO TODOS", + "NOT ANY": "NO CUALQUIERA", + "(ignored if empty)": "(ignorado si está vacío)", + "Optional Filter": "Filtro Opcional", + "Keywords or Regexes (ignored if empty)": "Palabras clave o expresiones regulares (se ignoran si están vacías)", + "Comma separated list (ignored if empty)": "Lista separada por comas (ignorada si está vacía)", + "Use global setting": "Usar configuración global", + "Case-Sensitive": "Sensible a mayúsculas y minúsculas", + "Yes": "Sí", + "No": "No", + "Can be used to automatically activate Quick Replies": "Se puede utilizar para activar automáticamente las Respuestas rápidas.", + "Automation ID": "ID de automatización", + "( None )": "( Ninguno )", + "Content": "Contenido", + "Exclude from recursion": "Excluir de la recursión", + "Prevent further recursion (this entry will not activate others)": "Evitar una mayor recurrencia (esta entrada no activará otras)", + "Delay until recursion (this entry can only be activated on recursive checking)": "Retraso hasta la recursión (esta entrada solo se puede activar en la comprobación recursiva)", + "What this keyword should mean to the AI, sent verbatim": "Lo que este palabra clave debería significar para la IA, enviado textualmente", + "Filter to Character(s)": "Filtrar a Personaje(s)", + "Character Exclusion": "Exclusión de Personaje", + "-- Characters not found --": "-- Personajes no encontrados --", + "Inclusion Group": "Grupo de Inclusión", + "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "Los grupos de inclusión garantizan que solo se active una entrada de un grupo a la vez, si se activan varias.\rAdmite múltiples grupos separados por comas.\r\rDocumentación: World Info - Grupo de Inclusión", + "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "Priorizar esta entrada: cuando está marcada, esta entrada tiene prioridad entre todas las selecciones.\rSi se priorizan varios, se elige el que tenga el 'Orden' más alto.", + "Only one entry with the same label will be activated": "Solo se activará una entrada con la misma etiqueta", + "A relative likelihood of entry activation within the group": "Una probabilidad relativa de activación de entrada dentro del grupo.", + "Group Weight": "Peso del grupo", + "Selective": "Selectivo", + "Use Probability": "Usar Probabilidad", + "Add Memo": "Agregar nota", + "Text or token ids": "Texto o [identificadores de token]", + "close": "cerca", + "prompt_manager_edit": "Editar", + "prompt_manager_name": "Nombre", + "A name for this prompt.": "Un nombre para este mensaje.", + "To whom this message will be attributed.": "A quién se le atribuirá este mensaje.", + "AI Assistant": "Asistente de IA", + "prompt_manager_position": "Posición", + "Injection position. Next to other prompts (relative) or in-chat (absolute).": "Posición de inyección. Junto a otras indicaciones (relativa) o en el chat (absoluta).", + "prompt_manager_relative": "Relativo", + "prompt_manager_depth": "Profundidad", + "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "Profundidad de inyección. 0 = después del último mensaje, 1 = antes del último mensaje, etc.", + "Prompt": "Indicar", + "The prompt to be sent.": "El mensaje que se enviará.", + "This prompt cannot be overridden by character cards, even if overrides are preferred.": "Este mensaje no puede ser anulado por tarjetas de personaje, incluso si se prefieren las anulaciones.", + "prompt_manager_forbid_overrides": "Prohibir anulaciones", + "reset": "reiniciar", + "save": "guardar", + "This message is invisible for the AI": "Este mensaje es invisible para la IA", + "Message Actions": "Acciones de mensajes", + "Translate message": "Traducir mensaje", + "Generate Image": "Generar imagen", + "Narrate": "Narrar", + "Exclude message from prompts": "Excluir mensaje de las indicaciones", + "Include message in prompts": "Incluir mensaje en las indicaciones", + "Embed file or image": "Insertar archivo o imagen", + "Create checkpoint": "Crear punto de control", + "Create Branch": "Crear Rama", + "Copy": "Copiar", + "Open checkpoint chat": "Abrir chat de punto de control", + "Edit": "Editar", + "Confirm": "Confirmar", + "Copy this message": "Copiar este mensaje", + "Delete this message": "Eliminar este mensaje", + "Move message up": "Mover mensaje hacia arriba", + "Move message down": "Mover mensaje hacia abajo", + "Enlarge": "Ampliar", + "Welcome to SillyTavern!": "¡Bienvenido a SillyTavern!", + "welcome_message_part_1": "Leer el", + "welcome_message_part_2": "Documentación oficial", + "welcome_message_part_3": null, + "welcome_message_part_4": "Tipo", + "welcome_message_part_5": "en el chat para comandos y macros.", + "welcome_message_part_6": "Disfruta el", + "Discord server": "Servidor de Discord", + "welcome_message_part_7": "para información y anuncios.", + "SillyTavern is aimed at advanced users.": "SillyTavern está dirigido a usuarios avanzados.", + "If you're new to this, enable the simplified UI mode below.": "Si eres nuevo en esto, habilita el modo de interfaz de usuario simplificado a continuación.", + "Change it later in the 'User Settings' panel.": "Cámbielo más tarde en el panel 'Configuración de usuario'.", + "Enable simple UI mode": "Habilitar el modo UI simple", + "Looking for AI characters?": "¿Buscas personajes de IA?", + "onboarding_import": "Importar", + "from supported sources or view": "desde fuentes compatibles o ver", + "Sample characters": "Personajes de muestra", + "Your Persona": "Tu Persona", + "Before you get started, you must select a persona name.": "Antes de comenzar, debe seleccionar un nombre de persona.", + "welcome_message_part_8": "Esto se puede cambiar en cualquier momento a través del", + "welcome_message_part_9": "icono.", + "Persona Name:": "Nombre de persona:", + "Temporarily disable automatic replies from this character": "Desactivar temporalmente las respuestas automáticas de este personaje", + "Enable automatic replies from this character": "Activar respuestas automáticas de este personaje", + "Trigger a message from this character": "Desencadenar un mensaje de este personaje", + "Move up": "Mover hacia arriba", + "Move down": "Mover hacia abajo", + "View character card": "Ver tarjeta de personaje", + "Remove from group": "Eliminar del grupo", + "Add to group": "Agregar al grupo", + "Alternate Greetings": "Saludos alternativos", + "Alternate_Greetings_desc": "Estos se mostrarán al deslizar el dedo en el primer mensaje al iniciar un nuevo chat.\n Los miembros del grupo pueden seleccionar uno de ellos para iniciar la conversación.", + "Alternate Greetings Hint": "¡Haga clic en el botón para comenzar!", + "(This will be the first message from the character that starts every chat)": "(Este será el primer mensaje del personaje que inicia cada chat)", + "Forbid Media Override explanation": "Capacidad del personaje/grupo actual de utilizar medios externos en los chats.", + "Forbid Media Override subtitle": "Medios: imágenes, vídeos, audio. Externo: no alojado en el servidor local.", + "Always forbidden": "siempre prohibido", + "Always allowed": "Siempre permitido", + "View contents": "Ver contenidos", + "Remove the file": "Eliminar el archivo", + "Unique to this chat": "Único para este chat", + "Checkpoints inherit the Note from their parent, and can be changed individually after that.": "Los puntos de control heredan la Nota de su padre y se pueden cambiar individualmente después de eso.", + "Include in World Info Scanning": "Incluir en el escaneo de información mundial", + "Before Main Prompt / Story String": "Antes del mensaje principal/cadena de historia", + "After Main Prompt / Story String": "Después del mensaje principal/cadena de historia", + "as": "como", + "Insertion Frequency": "Frecuencia de inserción", + "(0 = Disable, 1 = Always)": "(0 = Desactivar, 1 = Siempre)", + "User inputs until next insertion:": "Entradas del usuario hasta la próxima inserción:", + "Character Author's Note (Private)": "Nota del autor del personaje (privado)", + "Won't be shared with the character card on export.": "No se compartirá con la tarjeta de personaje al exportar.", + "Will be automatically added as the author's note for this character. Will be used in groups, but can't be modified when a group chat is open.": "Se agregará automáticamente como nota del autor para este personaje. Se utilizará en grupos, pero\n No se puede modificar cuando un chat grupal está abierto.", + "Use character author's note": "Utilice la nota del autor del personaje.", + "Replace Author's Note": "Reemplazar la nota del autor", + "Default Author's Note": "Nota del autor predeterminada", + "Will be automatically added as the Author's Note for all new chats.": "Se agregará automáticamente como nota del autor para todos los chats nuevos.", + "Chat CFG": "Chat CFG", + "1 = disabled": "1 = deshabilitado", + "write short replies, write replies using past tense": "escribir respuestas breves, escribir respuestas usando tiempo pasado", + "Positive Prompt": "Aviso positivo", + "Use character CFG scales": "Utilice escalas CFG de caracteres", + "Character CFG": "Carácter CFG", + "Will be automatically added as the CFG for this character.": "Se agregará automáticamente como CFG para este personaje.", + "Global CFG": "GFC global", + "Will be used as the default CFG options for every chat unless overridden.": "Se utilizarán como opciones CFG predeterminadas para cada chat a menos que se anulen.", + "CFG Prompt Cascading": "Cascada de avisos CFG", + "Combine positive/negative prompts from other boxes.": "Combine indicaciones positivas/negativas de otros cuadros.", + "For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string.": "Por ejemplo, al marcar las casillas de chat, global y de caracteres se combinan todas las indicaciones negativas en una cadena separada por comas.", + "Always Include": "Incluir siempre", + "Chat Negatives": "Negativos del chat", + "Character Negatives": "Carácter negativo", + "Global Negatives": "Negativos globales", + "Custom Separator:": "Separador personalizado:", + "Insertion Depth:": "Profundidad de inserción:", + "Token Probabilities": "Probabilidades de token", + "Select a token to see alternatives considered by the AI.": "Seleccione un token para ver las alternativas consideradas por la IA.", + "Not connected to API!": "¡No conectado a la API!", + "Type a message, or /? for help": "Escribe un mensaje o /? para obtener ayuda", + "Continue script execution": "Continuar la ejecución del script", + "Pause script execution": "Pausar la ejecución del script", + "Abort script execution": "Cancelar la ejecución del script", + "Abort request": "Cancelar solicitud", + "Continue the last message": "Continuar el último mensaje", + "Send a message": "Enviar un mensaje", + "Close chat": "Cerrar chat", + "Toggle Panels": "Paneles de alternancia", + "Back to parent chat": "Volver al chat principal", + "Save checkpoint": "Guardar punto de control", + "Convert to group": "Convertir a grupo", + "Start new chat": "Iniciar nuevo chat", + "Manage chat files": "Gestionar archivos de chat", + "Delete messages": "Eliminar mensajes", + "Regenerate": "Regenerar", + "Ask AI to write your message for you": "Pídele a la IA que escriba tu mensaje por ti", + "Impersonate": "Suplantar", + "Continue": "Continuar", + "Bind user name to that avatar": "Vincular nombre de usuario a ese avatar", + "Change persona image": "Cambiar imagen de persona", + "Select this as default persona for the new chats.": "Seleccionar esta persona como predeterminada para los nuevos chats.", + "Delete persona": "Eliminar persona", + "These characters are the winners of character design contests and have outstandable quality.": "Estos personajes son los ganadores de concursos de diseño de personajes y tienen una calidad sobresaliente.", + "Contest Winners": "Ganadores del concurso", + "These characters are the finalists of character design contests and have remarkable quality.": "Estos personajes son finalistas de concursos de diseño de personajes y tienen una calidad destacable.", + "Featured Characters": "Personajes destacados", + "Attach a File": "Adjuntar un archivo", + "Open Data Bank": "Banco de datos abiertos", + "Enter a URL or the ID of a Fandom wiki page to scrape:": "Ingresa una URL o el ID de una página wiki de Fandom para extraer:", + "Examples:": "Ejemplos:", + "Example:": "Ejemplo:", + "Single file": "Fila india", + "All articles will be concatenated into a single file.": "Todos los artículos se concatenarán en un único archivo.", + "File per article": "Archivo por artículo", + "Each article will be saved as a separate file.": "No recomendado. Cada artículo se guardará como un archivo independiente.", + "Data Bank": "Banco de datos", + "These files will be available for extensions that support attachments (e.g. Vector Storage).": "Estos archivos estarán disponibles para extensiones que admitan archivos adjuntos (por ejemplo, Vector Storage).", + "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.": "Tipos de archivos admitidos: texto sin formato, PDF, Markdown, HTML, EPUB.", + "Drag and drop files here to upload.": "Arrastre y suelte archivos aquí para cargarlos.", + "Date (Newest First)": "Fecha (la más reciente primero)", + "Date (Oldest First)": "Fecha (la más antigua primero)", + "Name (A-Z)": "Nombre (A-Z)", + "Name (Z-A)": "Nombre (Z-A)", + "Size (Smallest First)": "Tamaño (el más pequeño primero)", + "Size (Largest First)": "Tamaño (el más grande primero)", + "Bulk Edit": "Edición masiva", + "Select All": "Seleccionar todo", + "Select None": "Seleccionar Ninguno", + "Global Attachments": "Adjuntos globales", + "These files are available for all characters in all chats.": "Estos archivos están disponibles para todos los personajes en todos los chats.", + "Character Attachments": "Adjuntos de personajes", + "These files are available the current character in all chats they are in.": "Estos archivos están disponibles para el personaje actual en todos los chats en los que se encuentra.", + "Saved locally. Not exported.": "Guardado localmente. No exportado.", + "Chat Attachments": "Adjuntos de chat", + "These files are available to all characters in the current chat.": "Estos archivos están disponibles para todos los personajes en el chat actual.", + "Enter a base URL of the MediaWiki to scrape.": "Ingrese una URL base de MediaWiki para extraer.", + "Don't include the page name!": "¡No incluyas el nombre de la página!", + "Enter web URLs to scrape (one per line):": "Ingrese las URL web para extraer (una por línea):", + "Enter a video URL to download its transcript.": "Ingrese la URL o ID de un video para descargar su transcripción.", + "Expression API": "Extras\nlocales\nLLM", + "ext_sum_with": "Resumir con:", + "ext_sum_main_api": "API principal", + "ext_sum_current_summary": "Resumen actual:", + "ext_sum_restore_previous": "Restaurar anterior", + "ext_sum_memory_placeholder": "El resumen se generará aquí...", + "Trigger a summary update right now.": "Resumir ahora", + "ext_sum_force_text": "Resumir ahora", + "Disable automatic summary updates. While paused, the summary remains as-is. You can still force an update by pressing the Summarize now button (which is only available with the Main API).": "Deshabilite las actualizaciones resumidas automáticas. Mientras está en pausa, el resumen permanece tal como está. Aún puedes forzar una actualización presionando el botón Resumir ahora (que solo está disponible con la API principal).", + "ext_sum_pause": "Pausa", + "Omit World Info and Author's Note from text to be summarized. Only has an effect when using the Main API. The Extras API always omits WI/AN.": "Omita la información mundial y la nota del autor del texto que se va a resumir. Solo tiene efecto cuando se utiliza la API principal. La API de Extras siempre omite WI/AN.", + "ext_sum_no_wi_an": "Sin conexión Wi/AN", + "ext_sum_settings_tip": "Editar mensaje de resumen, posición de inserción, etc.", + "ext_sum_settings": "Configuración de resumen", + "ext_sum_prompt_builder": "constructor rápido", + "ext_sum_prompt_builder_1_desc": "La extensión creará su propio mensaje utilizando mensajes que aún no se han resumido. Bloquea el chat hasta que se genere el resumen.", + "ext_sum_prompt_builder_1": "Crudo, bloqueando", + "ext_sum_prompt_builder_2_desc": "La extensión creará su propio mensaje utilizando mensajes que aún no se han resumido. No bloquea el chat mientras se genera el resumen. No todos los servidores admiten este modo.", + "ext_sum_prompt_builder_2": "Crudo, sin bloqueo", + "ext_sum_prompt_builder_3_desc": "La extensión utilizará el generador de mensajes principal habitual y le agregará la solicitud de resumen como último mensaje del sistema.", + "ext_sum_prompt_builder_3": "Clásico, bloqueo", + "Summary Prompt": "Mensaje de resumen", + "ext_sum_restore_default_prompt_tip": "Restaurar mensaje predeterminado", + "ext_sum_prompt_placeholder": "Este mensaje se enviará a AI para solicitar la generación del resumen. {{words}} se resolverá en el parámetro 'Número de palabras'.", + "ext_sum_target_length_1": "Longitud del resumen objetivo", + "ext_sum_target_length_2": null, + "ext_sum_target_length_3": "palabras)", + "ext_sum_api_response_length_1": "Longitud de la respuesta API", + "ext_sum_api_response_length_2": null, + "ext_sum_api_response_length_3": "fichas)", + "ext_sum_0_default": "0 = predeterminado", + "ext_sum_raw_max_msg": "[Sin procesar] Máximo de mensajes por solicitud", + "ext_sum_0_unlimited": "0 = ilimitado", + "Update frequency": "Frecuencia de actualización", + "ext_sum_update_every_messages_1": "Actualizar cada", + "ext_sum_update_every_messages_2": "mensajes", + "ext_sum_0_disable": "0 = desactivar", + "ext_sum_auto_adjust_desc": "Intente ajustar automáticamente el intervalo en función de las métricas del chat.", + "ext_sum_update_every_words_1": "Actualizar cada", + "ext_sum_update_every_words_2": "palabras", + "ext_sum_both_sliders": "Si ambos controles deslizantes son distintos de cero, ambos activarán actualizaciones resumidas en sus respectivos intervalos.", + "ext_sum_injection_template": "Plantilla de inyección", + "ext_sum_memory_template_placeholder": "{{summary}} se resolverá en el contenido del resumen actual.", + "ext_sum_injection_position": "Posición de inyección", + "How many messages before the current end of the chat.": "Cuántos mensajes antes del final actual del chat.", + "ext_regex_title": "expresión regular", + "ext_regex_new_global_script": "+ Mundial", + "ext_regex_new_scoped_script": "+ Alcance", + "ext_regex_import_script": "Importar", + "ext_regex_global_scripts": "Guiones globales", + "ext_regex_global_scripts_desc": "Disponible para todos los personajes. Guardado en la configuración local.", + "ext_regex_scoped_scripts": "Guiones con alcance", + "ext_regex_scoped_scripts_desc": "Sólo disponible para este personaje. Guardado en los datos de la tarjeta.", + "Regex Editor": "Editor de expresiones regulares", + "Test Mode": "Modo de prueba", + "ext_regex_desc": "Regex es una herramienta para buscar/reemplazar cadenas usando expresiones regulares. Si desea obtener más información, haga clic en ? al lado del título.", + "Input": "Aporte", + "ext_regex_test_input_placeholder": "Escriba aquí...", + "Output": "Producción", + "ext_regex_output_placeholder": "Vacío", + "Script Name": "Nombre del guión", + "Find Regex": "encontrar expresiones regulares", + "Replace With": "Reemplazar con", + "ext_regex_replace_string_placeholder": "Utilice {{match}} para incluir el texto coincidente de Find Regex o $1, $2, etc. para grupos de captura.", + "Trim Out": "Recortar", + "ext_regex_trim_placeholder": "Recorta globalmente cualquier pieza no deseada de una coincidencia de expresiones regulares antes de reemplazarla. Separe cada elemento con una entrada.", + "ext_regex_affects": "Afecta", + "ext_regex_user_input": "Entrada del usuario", + "ext_regex_ai_output": "Salida de IA", + "Slash Commands": "Comandos de barra", + "ext_regex_min_depth_desc": "Cuando se aplica a indicaciones o visualización, solo afecta a los mensajes que tienen al menos N niveles de profundidad. 0 = último mensaje, 1 = penúltimo mensaje, etc. Solo cuenta las entradas WI @Depth y los mensajes utilizables, es decir, no ocultos ni del sistema.", + "Min Depth": "Profundidad mínima", + "ext_regex_min_depth_placeholder": "Ilimitado", + "ext_regex_max_depth_desc": "Cuando se aplica a indicaciones o visualización, solo afecta a los mensajes que no tengan más de N niveles de profundidad. 0 = último mensaje, 1 = penúltimo mensaje, etc. Solo cuenta las entradas WI @Depth y los mensajes utilizables, es decir, no ocultos ni del sistema.", + "ext_regex_other_options": "Otras opciones", + "Only Format Display": "Sólo formato de visualización", + "ext_regex_only_format_prompt_desc": "El historial de chat no cambiará, solo el aviso cuando se envía la solicitud (al generarse).", + "Only Format Prompt (?)": "Sólo formato de mensaje", + "Run On Edit": "Ejecutar al editar", + "ext_regex_substitute_regex_desc": "Sustituya {{macros}} en Find Regex antes de ejecutarlo", + "Substitute Regex": "Sustituir expresión regular", + "ext_regex_import_target": "Importar a:", + "ext_regex_disable_script": "Deshabilitar secuencia de comandos", + "ext_regex_enable_script": "Habilitar secuencia de comandos", + "ext_regex_edit_script": "Editar guión", + "ext_regex_move_to_global": "Pasar a scripts globales", + "ext_regex_move_to_scoped": "Pasar a secuencias de comandos con ámbito", + "ext_regex_export_script": "Exportar script", + "ext_regex_delete_script": "Eliminar guión", + "Trigger Stable Diffusion": "Activar difusión estable", + "sd_Yourself": "Tú mismo", + "sd_Your_Face": "Tu cara", + "sd_Me": "A mí", + "sd_The_Whole_Story": "La historia completa", + "sd_The_Last_Message": "El último mensaje", + "sd_Raw_Last_Message": "Último mensaje sin procesar", + "sd_Background": "Fondo", + "Image Generation": "Generación de imágenes", + "sd_refine_mode": "Permitir editar mensajes manualmente antes de enviarlos a la API de generación", + "sd_refine_mode_txt": "Editar mensajes antes de la generación", + "sd_interactive_mode": "Genera imágenes automáticamente al enviar mensajes como 'envíame una foto de gato'.", + "sd_interactive_mode_txt": "Modo interactivo", + "sd_multimodal_captioning": "Utilice subtítulos multimodales para generar indicaciones para retratos de usuarios y personajes basados ​​en sus avatares.", + "sd_multimodal_captioning_txt": "Utilice subtítulos multimodales para retratos", + "sd_expand": "Ampliar mensajes automáticamente utilizando el modelo de generación de texto", + "sd_expand_txt": "Mensajes de mejora automática", + "sd_snap": "Solicitudes de generación de instantáneas con una relación de aspecto forzada (retratos, fondos) a la resolución conocida más cercana, mientras se intenta preservar el recuento absoluto de píxeles (recomendado para SDXL).", + "sd_snap_txt": "Ajustar resoluciones ajustadas automáticamente", + "Source": "Fuente", + "sd_auto_url": "Ejemplo: {{auto_url}}", + "Authentication (optional)": "Autenticación (opcional)", + "Example: username:password": "Ejemplo: nombre de usuario:contraseña", + "Important:": "Importante:", + "sd_auto_auth_warning_1": "ejecute SD Web UI con el", + "sd_auto_auth_warning_2": "¡bandera! Se debe poder acceder al servidor desde la máquina host de SillyTavern.", + "sd_drawthings_url": "Ejemplo: {{drawthings_url}}", + "sd_drawthings_auth_txt": "¡Ejecute la aplicación DrawThings con el interruptor API HTTP habilitado en la interfaz de usuario! Se debe poder acceder al servidor desde la máquina host de SillyTavern.", + "sd_vlad_url": "Ejemplo: {{vlad_url}}", + "The server must be accessible from the SillyTavern host machine.": "Se debe poder acceder al servidor desde la máquina host de SillyTavern.", + "Hint: Save an API key in AI Horde API settings to use it here.": "Sugerencia: guarde una clave API en la configuración de API de AI Horde para usarla aquí.", + "Allow NSFW images from Horde": "Permitir imágenes NSFW de Horda", + "Sanitize prompts (recommended)": "Indicaciones para desinfectar (recomendado)", + "Automatically adjust generation parameters to ensure free image generations.": "Ajuste automáticamente los parámetros de generación para garantizar generaciones de imágenes gratuitas.", + "Avoid spending Anlas": "Evita gastar Anlas", + "Opus tier": "(Nivel de obra)", + "View my Anlas": "Ver mi Anlas", + "These settings only apply to DALL-E 3": "Estas configuraciones solo se aplican a DALL-E 3", + "Image Style": "Estilo de imagen", + "Image Quality": "Calidad de la imagen", + "Standard": "Estándar", + "HD": "alta definición", + "sd_comfy_url": "Ejemplo: {{comfy_url}}", + "Open workflow editor": "Abrir el editor de flujo de trabajo", + "Create new workflow": "Crear nuevo flujo de trabajo", + "Delete workflow": "Eliminar flujo de trabajo", + "Enhance": "Mejorar", + "Refine": "Refinar", + "Decrisper": "Descriptor", + "Sampling steps": "Pasos de muestreo ()", + "Width": "Ancho ()", + "Height": "Altura ()", + "Resolution": "Resolución", + "Model": "Modelo", + "Sampling method": "Método de muestreo", + "Karras (not all samplers supported)": "Karras (no todos los samplers son compatibles)", + "SMEA versions of samplers are modified to perform better at high resolution.": "Las versiones SMEA de los muestreadores se modifican para funcionar mejor en alta resolución.", + "SMEA": "SMEA (Asociación de Empresas de Medio Ambiente)", + "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "Las variantes DYN de los muestreadores SMEA a menudo generan resultados más variados, pero pueden fallar en resoluciones muy altas.", + "DYN": "DIN", + "Scheduler": "Programador", + "Restore Faces": "Restaurar caras", + "Hires. Fix": "Contrataciones. Arreglo", + "Upscaler": "escalador", + "Upscale by": "De lujo por", + "Denoising strength": "Fuerza de eliminación de ruido", + "Hires steps (2nd pass)": "Pasos de contrataciones (2da pasada)", + "Preset for prompt prefix and negative prompt": "Preajuste para prefijo de mensaje y mensaje negativo", + "Style": "Estilo", + "Save style": "Guardar estilo", + "Delete style": "Eliminar estilo", + "Common prompt prefix": "Prefijo de aviso común", + "sd_prompt_prefix_placeholder": "Utilice {prompt} para especificar dónde se insertará el mensaje generado", + "Negative common prompt prefix": "Prefijo de mensaje común negativo", + "Character-specific prompt prefix": "Prefijo de mensaje específico de carácter", + "Won't be used in groups.": "No se utilizará en grupos.", + "sd_character_prompt_placeholder": "Cualquier característica que describa al personaje seleccionado actualmente. Se agregará después de un prefijo de aviso común.\nEjemplo: mujer, ojos verdes, cabello castaño, camisa rosa.", + "Character-specific negative prompt prefix": "Prefijo de aviso negativo específico del personaje", + "sd_character_negative_prompt_placeholder": "Cualquier característica que no debería aparecer para el personaje seleccionado. Se agregará después de un prefijo de mensaje común negativo.\nEjemplo: joyas, zapatos, gafas.", + "Shareable": "Compartible", + "Image Prompt Templates": "Plantillas de mensajes de imagen", + "Vectors Model Warning": "Se recomienda purgar los vectores al cambiar el modelo en medio del chat. De lo contrario, se obtendrán resultados deficientes.", + "Translate files into English before processing": "Traducir archivos al inglés antes de procesarlos", + "Manager Users": "Administrar usuarios", + "New User": "Nuevo Usuario", + "Status:": "Estado:", + "Created:": "Creado:", + "Display Name:": "Nombre para mostrar:", + "User Handle:": "Identificador de usuario:", + "Password:": "Contraseña:", + "Confirm Password:": "Confirmar Contraseña:", + "This will create a new subfolder...": "Esto creará una nueva subcarpeta en el directorio /data/ con el identificador del usuario como nombre de la carpeta.", + "Current Password:": "Contraseña actual:", + "New Password:": "Nueva contraseña:", + "Confirm New Password:": "Confirmar nueva contraseña:", + "Debug Warning": "Las funciones de esta categoría son sólo para usuarios avanzados. No hagas clic en nada si no estás seguro de las consecuencias.", + "Execute": "Ejecutar", + "Are you sure you want to delete this user?": "¿Estás seguro de que deseas eliminar este usuario?", + "Deleting:": "Eliminando:", + "Also wipe user data.": "También borre los datos del usuario.", + "Warning:": "Advertencia:", + "This action is irreversible.": "Esta acción es irreversible.", + "Type the user's handle below to confirm:": "Escriba el nombre del usuario a continuación para confirmar:", + "Import Characters": "Importar personajes", + "Enter the URL of the content to import": "Ingrese la URL del contenido a importar", + "Supported sources:": "Fuentes admitidas:", + "char_import_1": "Carácter Chub (enlace directo o ID)", + "char_import_example": "Ejemplo:", + "char_import_2": "Chub Lorebook (enlace directo o ID)", + "char_import_3": "Carácter de JanitorAI (enlace directo o UUID)", + "char_import_4": "Carácter Pygmalion.chat (enlace directo o UUID)", + "char_import_5": "Carácter AICharacterCards.com (enlace directo o ID)", + "char_import_6": "Enlace PNG directo (consulte", + "char_import_7": "para hosts permitidos)", + "char_import_8": "Personaje RisuRealm (Enlace directo)", + "Supports importing multiple characters.": "Admite la importación de múltiples caracteres.", + "Write each URL or ID into a new line.": "Escriba cada URL o ID en una nueva línea.", + "Export for character": "Exportar para personaje", + "Export prompts for this character, including their order.": "Exporta indicaciones para este personaje, incluido su orden.", + "Export all": "Exportar todo", + "Export all your prompts to a file": "Exporta todas tus indicaciones a un archivo", + "Insert prompt": "Insertar indicaciones", + "Delete prompt": "Eliminar indicaciones", + "Import a prompt list": "Importar una lista de indicaciones", + "Export this prompt list": "Exportar esta lista de indicaciones", + "Reset current character": "Restablecer personaje actual", + "New prompt": "Nuevas indicaciones", + "Prompts": "Indicaciones", + "Total Tokens:": "Tokens totales:", + "prompt_manager_tokens": "Fichas", + "Are you sure you want to reset your settings to factory defaults?": "¿Está seguro de que desea restablecer la configuración a los valores predeterminados de fábrica?", + "Don't forget to save a snapshot of your settings before proceeding.": "No olvide guardar una instantánea de su configuración antes de continuar.", + "Settings Snapshots": "Instantáneas de configuración", + "Record a snapshot of your current settings.": "Grabe una instantánea de su configuración actual.", + "Make a Snapshot": "Hacer una instantánea", + "Restore this snapshot": "Restaurar esta instantánea", + "Hi,": "Hola,", + "To enable multi-account features, restart the SillyTavern server with": "Para habilitar las funciones de múltiples cuentas, reinicie el servidor SillyTavern con", + "set to true in the config.yaml file.": "establecido en verdadero en el archivo config.yaml.", + "Account Info": "Informacion de cuenta", + "To change your user avatar, use the buttons below or select a default persona in the Persona Management menu.": "Para cambiar su avatar de usuario, use los botones a continuación o seleccione una persona predeterminada en el menú Administración de personas.", + "Set your custom avatar.": "Configura tu avatar personalizado.", + "Remove your custom avatar.": "Elimina tu avatar personalizado.", + "Handle:": "Manejar:", + "This account is password protected.": "Esta cuenta está protegida con contraseña.", + "This account is not password protected.": "Esta cuenta no está protegida con contraseña.", + "Account Actions": "Acciones de cuenta", + "Change Password": "Cambiar la contraseña", + "Manage your settings snapshots.": "Administre sus instantáneas de configuración.", + "Download a complete backup of your user data.": "Descarga una copia de seguridad completa de tus datos de usuario.", + "Download Backup": "Descargar copia de seguridad", + "Danger Zone": "Zona peligrosa", + "Reset your settings to factory defaults.": "Restablezca su configuración a los valores predeterminados de fábrica.", + "Reset Settings": "Reiniciar ajustes", + "Wipe all user data and reset your account to factory settings.": "Borre todos los datos del usuario y restablezca su cuenta a la configuración de fábrica.", + "Reset Everything": "Restablecer todo", + "Reset Code:": "Restablecer Código:", + "Want to update?": "¿Quieres actualizar?", + "How to start chatting?": "¿Cómo empezar a chatear?", + "Click _space": "Hacer clic", + "and select a": "y selecciona una", + "Chat API": " API de chat", + "and pick a character.": "y elige un personaje.", + "You can browse a list of bundled characters in the": "Puedes explorar una lista de personajes incluidos en el menú de", + "Download Extensions & Assets": "Download Extensions & Assets", + "menu within": "dentro de", + "Confused or lost?": "¿Confundido o perdido?", + "click these icons!": "¡Haz clic en estos iconos!", + "in the chat bar": "en la barra de chat", + "SillyTavern Documentation Site": "Sitio de documentación de SillyTavern", + "Extras Installation Guide": "Guía de instalación de extras", + "Still have questions?": "¿Todavía tienes preguntas?", + "Join the SillyTavern Discord": "Únete al Discord de SillyTavern", + "Post a GitHub issue": "Publicar un problema en GitHub", + "Contact the developers": "Contactar a los desarrolladores", + "Prome (Visual Novel Extension)": "Prome (Extensión de Modo Waifu/Novela Visual)", + "Brought to you by": "Presentado por", + "and Prometheus.": "y Prometheus.", + "Enable Prome": "Iniciar Prome", + "Toggles Prome, VN Mode and other Prome features.": "Activa Prome, el modo VN y otras funciones de Prome.", + "Features marked with a": "Las funciones marcadas con un", + "require Prome to be enabled.": "requieren que Prome esté iniciado.", + "Sheld Configuration": "Configuración de interfaz (Sheld)", + "Hide Sheld (Message Box)": "Ocultar Sheld (cuadro de mensajes)", + "Hide the message box (sheld) in the ST UI.": "Ocultar el cuadro de mensajes (sheld) en la interfaz de usuario de SillyTavern.", + "Enable Traditional VN Mode": "Modo VN tradicional*", + "Only Show Last Message in Chat (Requires Prome to be enabled).": "Mostrar solo el último mensaje en el chat (Requiere que Prome esté iniciado).", + "Letterbox Configuration*": "Configuración de la franja negra*", + "Letterbox Mode": "Modo de franja negra", + "Select the letterbox mode for the Prome VN UI.": "Seleccione el modo de franja negra para la interfaz de usuario VN de Prome.", + "Horizontal Letterbox": "Franja negra horizontal", + "Vertical Letterbox": "Franja negra vertical", + "Letterbox Color": "Color de la franja negra", + "Select the color of the letterbox.": "Seleccione el color de la franja negra.", + "Letterbox Size": "Tamaño de la franja negra", + "Set the size of the letterbox.": "Establezca el tamaño de la franja negra.", + "Sprite Configuration": "Configuración de sprites", + "Emulate Character Card as Sprite": "[BETA] Emular tarjeta de personaje como sprite", + "Emulates the character card of a character to be a sprite. (Requires Prome to be enabled).": "Emula la tarjeta de personaje de un personaje para que sea un sprite. (Requiere que Prome esté iniciado).", + "Enable Sprite Shake": "[BETA] Sprite Shake", + "Shakes the character sprite when the character is speaking (Only works if Streaming is enabled in Preset Settings).": "Agita el sprite del personaje cuando el personaje está hablando (solo funciona si la transmisión está habilitada en la configuración preestablecida).", + "Enable Focus Mode": "Modo de enfoque", + "Focuses the current speaking character in chat. (Requires Prome to be enabled).": "Enfoca al personaje que está hablando en el chat. (Requiere que Prome esté iniciado).", + "Darken Unfocused Character Sprites": "Oscurecer sprites de personajes", + "Darkens non-speaking (unfocused) characters. (Requires Prome to be enabled).": "Oscurece a los personajes que no hablan (no enfocados). (Requiere que Prome esté iniciado).", + "Auto-Hide Sprites": "Ocultar sprites automáticamente", + "Auto-hides characters from the screen that haven't been in the conversation for a while up to X characters. (Requires Prome to be enabled).": "Oculta automáticamente a los personajes de la pantalla que no han estado en la conversación durante un tiempo hasta X personajes. (Requiere que Prome esté iniciado).", + "Max Visible Sprites": "Máximo de personajes visibles", + "Set the maximum number of visible sprites that appears in the VN screen.": "Establezca el número máximo de sprites visibles que aparecen en la pantalla VN.", + "Sprite Shadow Configuration": "Configuración de sombra de sprites", + "Enable Sprite Shadow": "Sombra de sprite", + "Adds a shadow to the character sprite.": "Agrega una sombra al sprite del personaje.", + "Shadow X Offset": "Desplazamiento X de la sombra", + "Set the X offset of the character shadow.": "Establezca el desplazamiento X de la sombra del personaje.", + "Shadow Y Offset": "Desplazamiento Y de la sombra", + "Set the Y offset of the character shadow.": "Establezca el desplazamiento Y de la sombra del personaje.", + "Shadow Blur": "Desenfoque de sombra", + "Set the blur of the character shadow.": "Establezca el desenfoque de la sombra del personaje.", + "Focus Mode Settings": "Configuración del modo de enfoque", + "Focus Mode Animation": "Animación de modo de enfoque", + "Select the animation for focus mode.": "Seleccione la animación para el modo de enfoque.", + "Focus Mode Animation Speed": "Velocidad de animación del modo de enfoque", + "Set the speed of the focus animation.": "Establezca la velocidad de la animación de enfoque.", + "User Sprite Configuration": "[BETA] Configuración de sprites de usuario", + "Enable User Sprite": "Sprites de usuario", + "Enables the ability to use a user sprite for your persona.": "Habilita la capacidad de usar un sprite de usuario para tu persona.", + "Sprite set": "Conjunto de sprites", + "Type the name of the sprite set to use for your persona. (Place your sprites in the 'characters' folder in SillyTavern).": "Escriba el nombre del conjunto de sprites que desea utilizar para su persona. (Coloque sus sprites en la carpeta 'characters' en SillyTavern).", + "Note: Create a sprite folder in the ": "Nota: Cree una carpeta de sprites en el ", + " folder of your user directory (typically 'data/default-user'). Place your expressions there.": " carpeta de su directorio de usuario (normalmente 'data/default-user'). Coloque sus expresiones allí.", + "Tint Configuration": "Configuración de tono", + "Enable Chat Tint": "Tinte de chat", + "Tints the chat background and/or character sprites.": "Tinta el fondo del chat y/o los sprites de personajes.", + "Share World Tint With Characters": "Compartir tinte mundial con personajes*", + "Applies the world tint to character sprites (Requires Prome to be enabled. This will override your character tint settings).": "Aplica el tinte mundial a los sprites de personajes (Requiere que Prome esté iniciado. Esto anulará la configuración de tinte de su personaje).", + "Tint Presets": "Preajustes de tinte", + "Select the tint preset to use for the Prome VN UI.": "Seleccione el preajuste de tinte que desea utilizar para la interfaz de usuario VN de Prome.", + "World Tint Settings": "Configuración de tinte mundial", + "Tints the world background.": "Tinta el fondo mundial.", + "Enable World Tint": "Tinte mundial", + "Set the strength of the world blur.": "Establezca la fuerza del desenfoque mundial.", + "Brightness": "Brillo", + "Set the brightness of the world.": "Establezca el brillo del mundo.", + "Contrast": "Contraste", + "Set the contrast of the world.": "Establezca el contraste del mundial.", + "Grayscale": "Escala de grises", + "Makes the world black and white.": "Hace que el mundo sea en blanco y negro.", + "Hue": "Matiz", + "Set the hue of the world tint.": "Establezca el matiz del tinte mundial.", + "Invert": "Invertir", + "Inverts the world colors.": "Invierte los colores del mundo.", + "Saturate": "Saturar", + "Saturates the world colors.": "Satura los colores del mundo.", + "Makes the world warmer in color.": "Hace que el mundo sea más cálido en color.", + "Character Tint Settings": "Configuración de tinte de sprites*", + "Enable Character Tint (Requires Prome to be enabled)": "Tinte de sprites (Requiere que Prome esté iniciado)", + "Set the strength of the character blur.": "Establezca la fuerza del desenfoque de personajes.", + "Set the brightness of the character.": "Establezca el brillo de personaje.", + "Set the contrast of the character.": "Establezca el contraste de personajes.", + "Makes the character black and white.": "Hace que el personaje sea en blanco y negro.", + "Set the hue of the character.": "Establezca el matiz del tinte de personajes.", + "Inverts the character colors.": "Invierte los colores del personaje.", + "Saturates the character colors.": "Satura los colores del personaje.", + "Makes the character warmer in color.": "Hace que el personaje sea más cálido en color.", + "Keybinds": "Atajos de teclado", + "Commands": "Comandos", + "Prome Keybinds": "Combinaciones de teclas de Prome", + "Hide/Show SillyTavern's Sheld (Message Box)": "Ocultar/Mostrar el estante de SillyTavern (cuadro de mensaje)", + "Prome Commands": "Comandos de Prome", + "Show/Hide the letterbox (black bars) in the VN UI": "Mostrar/Ocultar la franja negra (barras negras) en la interfaz VN", + "Toggles focus mode on character sprites": "Alterna el modo de enfoque en los sprites de personajes", + "Sets the focus mode animation": "Establece la animación del modo de enfoque", + "Toggles the defocus tint on non-speaking character sprites": "Alterna el tinte de desenfoque en los sprites de personajes que no hablan", + "Toggles the shake animation when a character speaks on character sprites": "Alterna la animación de sacudida cuando un personaje habla en los sprites de personajes", + "Toggles sprite shadows on character sprites": "Alterna las sombras de los sprites de personajes", + "Toggles world/character tint on the VN UI": "Alterna el tinte mundial/de personajes en la interfaz VN", + "Toggles world tint on the VN UI": "Alterna el tinte mundial en la interfaz VN", + "Toggles character tint on the VN UI": "Alterna el tinte de personajes en la interfaz VN", + "Toggles sharing world tint with character sprites (This will override Character Tint)": "Alterna el tinte mundial compartido con los sprites de personajes (esto anulará el tinte de personajes)", + "Sets the expression of the user sprite": "Establece la expresión del sprite de usuario", + "Sets the user sprite set to use for the user sprite": "Establece el conjunto de sprites de usuario para usar en el sprite de usuario", + "Toggles the user sprite on the VN UI": "Alterna el sprite de usuario en la interfaz VN" +} diff --git a/jiuguan2025cc/public/locales/fr-fr.json b/jiuguan2025cc/public/locales/fr-fr.json new file mode 100644 index 0000000000000000000000000000000000000000..16ef16c5c3c1ff45783e2abc36fc21520491312d --- /dev/null +++ b/jiuguan2025cc/public/locales/fr-fr.json @@ -0,0 +1,2052 @@ +{ + "Favorite": "Favoris", + "Tag": "Tag", + "Duplicate": "Dupliquer", + "Persona": "Persona", + "Delete": "Supprimer", + "AI Response Configuration": "Configuration de la réponse de l'IA", + "AI Configuration panel will stay open": "Le panneau de configuration de l'IA restera ouvert", + "clickslidertips": "Cliquez sur le curseur pour saisir les valeurs manuellement.", + "MAD LAB MODE ON": "MODE MAD LAB ACTIVÉ", + "Documentation on sampling parameters": "Documentation sur les paramètres d'échantillonnage", + "kobldpresets": "Presets de Kobold", + "guikoboldaisettings": "Paramètres de l'interface utilisateur de KoboldAI", + "Update current preset": "Mettre à jour le preset actuel", + "Save preset as": "Enregistrer le preset sous", + "Import preset": "Importer le preset", + "Export preset": "Exporter le preset", + "Restore current preset": "Restaurer le preset actuel", + "Delete the preset": "Supprimer le preset", + "novelaipresets": "Presets de NovelAI", + "Default": "Par défaut", + "openaipresets": "Presets d'OpenAI", + "Text Completion presets": "Presets de complétion de texte", + "AI Module": "Module IA", + "Changes the style of the generated text.": "Modifie le style du texte généré.", + "No Module": "Aucun module", + "Instruct": "Instruire", + "Prose Augmenter": "Amélioration de prose", + "Text Adventure": "Aventure textuelle", + "response legth(tokens)": "Longueur de la réponse (en tokens)", + "Streaming": "Diffusion en continu", + "Streaming_desc": "Afficher la réponse bit par bit au fur et à mesure de sa génération", + "context size(tokens)": "Taille du contexte (en tokens)", + "unlocked": "Déverrouillé", + "Only enable this if your model supports context sizes greater than 8192 tokens": "Activez cela uniquement si votre modèle prend en charge des tailles de contexte supérieures à 8192 tokens", + "Max prompt cost:": "Coût maximum du prompt:", + "Display the response bit by bit as it is generated.": "Afficher la réponse bit par bit au fur et à mesure de sa génération.", + "When this is off, responses will be displayed all at once when they are complete.": "Lorsque cette fonction est désactivée, les réponses s'affichent toutes en une fois lorsqu'elles sont complètes.", + "Temperature": "Température", + "rep.pen": "Pénalité de répétition", + "Rep. Pen. Range.": "Plage de pénalité de répétition", + "Rep. Pen. Slope": "Pente de la pénalité de répétition", + "Rep. Pen. Freq.": "Fréquence de pénalité de répétition", + "Rep. Pen. Presence": "Présence de pénalité de répétition", + "TFS": "TFS", + "Phrase Repetition Penalty": "Pénalité de répétition de phrase", + "Off": "Désactivé", + "Very light": "Très léger", + "Light": "Léger", + "Medium": "Moyen", + "Aggressive": "Agressif", + "Very aggressive": "Très agressif", + "Unlocked Context Size": "Taille du contexte déverrouillé", + "Unrestricted maximum value for the context slider": "Valeur maximale non limitée pour le curseur de contexte", + "Context Size (tokens)": "Taille du contexte (tokens)", + "Max Response Length (tokens)": "Longueur maximale de la réponse (tokens)", + "Multiple swipes per generation": "Plusieurs balayages par génération", + "Enable OpenAI completion streaming": "Activer le streaming de complétion OpenAI", + "Frequency Penalty": "Pénalité de fréquence", + "Presence Penalty": "Pénalité de présence", + "Top K": "Top K", + "Top P": "Top P", + "Repetition Penalty": "Pénalité de répétition", + "Min P": "Min P", + "Top A": "Top A", + "Quick Prompts Edit": "Édition rapide des prompts", + "Main": "Principal", + "Utility Prompts": "Prompts utilitaires", + "Impersonation prompt": "Prompt d'usurpation", + "Restore default prompt": "Restaurer le prompt par défaut", + "Prompt that is used for Impersonation function": "Prompt utilisée pour la fonction d'usurpation", + "World Info Format Template": "Modèle de format des World Info", + "Restore default format": "Restaurer le format par défaut", + "Wraps activated World Info entries before inserting into the prompt.": "Encapsule les entrées World Info activées avant de les insérer dans le prompt.", + "scenario_format_template_part_1": "Utiliser", + "scenario_format_template_part_2": "pour marquer un endroit où le contenu est inséré.", + "Scenario Format Template": "Modèle de format de scénario", + "Personality Format Template": "Modèle de format de personnalité", + "Group Nudge Prompt Template": "Modèle de prompt de groupe Nudge", + "Sent at the end of the group chat history to force reply from a specific character.": "Envoyé à la fin de l'historique des discussions de groupe pour forcer la réponse d'un personnage spécifique.", + "New Chat": "Nouvelle discussion", + "Restore new chat prompt": "Restaurer le prompt de nouvelle discussion", + "Set at the beginning of the chat history to indicate that a new chat is about to start.": "Placez-le au début de l'historique de discussion pour indiquer qu'une nouvelle discussion est sur le point de démarrer.", + "New Group Chat": "Nouvelle discussion de groupe", + "Restore new group chat prompt": "Restaurer le prompt pour les nouvelle discussion de groupe", + "Set at the beginning of the chat history to indicate that a new group chat is about to start.": "Défini au début de l'historique des discussions pour indiquer qu'une nouvelle discussion de groupe est sur le point de démarrer.", + "New Example Chat": "Nouvel exemple de discussion", + "Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.": "Défini au début des exemples de dialogue pour indiquer qu'un nouvel exemple est sur le point de démarrer.", + "Continue nudge": "Continuer le coup de pouce", + "Set at the end of the chat history when the continue button is pressed.": "Défini à la fin de l’historique des discussions lorsque vous appuyez sur le bouton Continuer.", + "Replace empty message": "Remplacer le message vide", + "Send this text instead of nothing when the text box is empty.": "Envoyer ce texte à la place de rien lorsque la zone de texte est vide.", + "Seed": "Graine", + "Set to get deterministic results. Use -1 for random seed.": "Réglé pour obtenir des résultats déterministes. Utilisez -1 pour les graines aléatoires.", + "Temperature controls the randomness in token selection": "La température contrôle l'aléatoire dans la sélection des tokens:\n- Une température basse (<1.0) entraîne un texte plus prévisible, en donnant la priorité aux tokens à forte probabilité.\n- Une température élevée (>1.0) favorise la créativité et la diversité, en donnant plus de chances aux tokens à faible probabilité.\nRéglez la valeur à 1.0 pour les probabilités d'origine.", + "Top_K_desc": "Top K définit une quantité maximale de tokens les plus fréquents qui peuvent être sélectionnés.", + "Top_P_desc": "Top P (alias échantillonnage du noyau) regroupe tous les tokens supérieurs nécessaires pour atteindre un pourcentage spécifique.\nAutrement dit, si les deux premiers tokens représentent 25 % et que Top-P est de 0,50, seuls ces deux tokens sont considérés.\nRéglez la valeur à 1.0 pour la désactiver.", + "Typical P": "P Typique", + "Typical_P_desc": "L'échantillonnage P Typique privilégie les tokens en fonction de leur écart par rapport à l'entropie moyenne de l'ensemble.\nLes tokens dont la probabilité cumulée est proche du seuil spécifié (par exemple, 0.5) sont conservés, ce qui distingue ceux contenant une information moyenne.\nRéglez la valeur à 1.0 pour la désactiver.", + "Min_P_desc": "Min P définit une probabilité minimale de base. Elle est optimisée en fonction de la probabilité du token supérieur.\nSi la probabilité du token supérieur est de 80 % et que Min P est de 0.1, seuls les tokens avec une probabilité supérieure à 8 % sont considérés.\nRéglez la valeur à 0 pour la désactiver.", + "Top_A_desc": "Top A définit un seuil pour la sélection des tokens en fonction du carré de la probabilité du token le plus élevé.\nSi Top A est de 0.2 et que la probabilité du token le plus élevé est de 50 %, les tokens avec une probabilité inférieure à 5 % sont exclus (0.2 * 0.5^2).\nRéglez la valeur à 0 pour la désactiver.", + "Tail_Free_Sampling_desc": "Échantillonnage sans queue (TFS) recherche les tokens de queue ayant une faible probabilité dans la distribution,\n en analysant le taux de changement des probabilités des tokens à l'aide de dérivées. Les tokens sont conservés jusqu'au seuil (par exemple, 0.3), en fonction de la dérivée seconde uniforme.\nPlus la valeur se rapproche de 0, plus le nombre de tokens rejetés augmente. Réglez la valeur à 1.0 pour la désactiver.", + "rep.pen range": "Plage de pénalité de répétition", + "Mirostat": "Mirostat", + "Mode": "Mode", + "Mirostat_Mode_desc": "Une valeur de 0 désactive complètement Mirostat. 1 est pour Mirostat 1.0 et 2 est pour Mirostat 2.0", + "Tau": "Tau", + "Mirostat_Tau_desc": "Contrôle la variabilité des sorties Mirostat", + "Eta": "Eta", + "Mirostat_Eta_desc": "Contrôle le taux d’apprentissage du Mirostat", + "Ban EOS Token": "Interdire le token EOS", + "Ban_EOS_Token_desc": "Interdisez le jeton de fin de séquence (EOS) avec KoboldCpp (et éventuellement aussi d'autres jetons avec KoboldAI).\rIdéal pour l'écriture d'histoires, mais ne doit pas être utilisé pour le mode chat et instruction.", + "GBNF Grammar": "Grammaire GBNF", + "Type in the desired custom grammar": "Saisissez la grammaire personnalisée souhaitée", + "Samplers Order": "Ordre des échantillonneurs", + "Samplers will be applied in a top-down order. Use with caution.": "Les échantillonneurs seront appliqués dans un ordre de haut en bas. Utilisez avec prudence.", + "Tail Free Sampling": "Échantillonnage sans queue", + "Load koboldcpp order": "Charger l'ordre koboldcpp", + "Preamble": "Préambule", + "Use style tags to modify the writing style of the output.": "Utilisez des balises de style pour modifier le style d'écriture de la sortie.", + "Banned Tokens": "Tokens interdits", + "Sequences you don't want to appear in the output. One per line.": "Séquences que vous ne voulez pas voir apparaître dans la sortie. Une par ligne.", + "Logit Bias": "Biais de logit", + "Add": "Ajouter", + "Helps to ban or reenforce the usage of certain words": "Aide à interdire ou à renforcer l'utilisation de certains mots", + "CFG Scale": "Échelle CFG", + "Negative Prompt": "Prompt négatif", + "Add text here that would make the AI generate things you don't want in your outputs.": "Ajoutez ici du texte qui ferait générer à l'IA des choses que vous ne voulez pas dans vos sorties.", + "Used if CFG Scale is unset globally, per chat or character": "Utilisé si l'échelle CFG n'est pas définie globalement, par chat ou par personnage.", + "Mirostat Tau": "Tau Mirostat", + "Mirostat LR": "Mirostat LR", + "Min Length": "Longueur minimale", + "Top K Sampling": "Échantillonnage Top K", + "Nucleus Sampling": "Échantillonnage du noyau", + "Top A Sampling": "Échantillonnage Top A", + "CFG": "CFG", + "Neutralize Samplers": "Neutraliser les échantillonneurs", + "Set all samplers to their neutral/disabled state.": "Définir tous les échantillonneurs sur leur état neutre/désactivé.", + "Sampler Select": "Sélection de l'échantillonneur", + "Customize displayed samplers or add custom samplers.": "Personnalisez les échantillonneurs affichés ou ajoutez des échantillonneurs personnalisés.", + "Epsilon Cutoff": "Coupure epsilon", + "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "La coupure epsilon définit un seuil de probabilité en dessous duquel les tokens sont exclus de l'échantillonnage.\nEn unités 1e-4; la valeur appropriée est 3. Réglez-la à 0 pour la désactiver.", + "Eta Cutoff": "Coupure Eta", + "Eta_Cutoff_desc": "Le seuil Eta est le principal paramètre de la technique d'échantillonnage Eta spéciale. En unités de 1e-4 ; une valeur raisonnable est 3. Réglez sur 0 pour désactiver. Voir l'article Truncation Sampling as Language Model Desmoothing par Hewitt et al. (2022) pour plus de détails.", + "rep.pen decay": "Déclin de la pénalité de répétition", + "Encoder Rep. Pen.": "Pénalité de répétition de l'encodeur", + "No Repeat Ngram Size": "Taille de n-gramme sans répétition", + "Skew": "Fausser", + "Max Tokens Second": "Nombre maximum de token par seconde", + "Smooth Sampling": "Échantillonnage fluide", + "Smooth_Sampling_desc": "Vous permet d'utiliser des transformations quadratiques/cubiques pour ajuster la distribution. Les valeurs inférieures du facteur de lissage seront plus créatives, généralement entre 0,2 et 0,3 comme point idéal (en supposant que la courbe = 1). Des valeurs de courbe de lissage plus élevées rendront la courbe plus raide, ce qui punira plus agressivement les choix à faible probabilité. La courbe 1,0 équivaut à utiliser uniquement le facteur de lissage.", + "Smoothing Factor": "Facteur de lissage", + "Smoothing Curve": "Courbe de lissage", + "DRY_Repetition_Penalty_desc": "DRY pénalise les jetons qui prolongeraient la fin de l'entrée dans une séquence qui s'est déjà produite dans l'entrée. Réglez le multiplicateur sur 0 pour le désactiver.", + "DRY Repetition Penalty": "Pénalité de répétition SÈCHE", + "DRY_Multiplier_desc": "Réglez sur une valeur > 0 pour activer DRY. Contrôle l'ampleur de la pénalité pour les séquences pénalisées les plus courtes.", + "Multiplier": "Multiplicateur", + "DRY_Base_desc": "Contrôle la vitesse à laquelle la pénalité augmente avec la longueur de la séquence.", + "Base": "Base", + "DRY_Allowed_Length_desc": "Séquence la plus longue pouvant être répétée sans être pénalisée.", + "Allowed Length": "Longueur autorisée", + "Penalty Range": "Fourchette de pénalité", + "DRY_Sequence_Breakers_desc": "Jetons sur lesquels la correspondance de séquence n'est pas poursuivie. Spécifié sous la forme d'une liste de chaînes entre guillemets séparées par des virgules.", + "Sequence Breakers": "Interrupteurs de séquence", + "JSON-serialized array of strings.": "Tableau de chaînes sérialisées JSON.", + "Dynamic Temperature": "Température dynamique", + "Scale Temperature dynamically per token, based on the variation of probabilities": "Échelonnez dynamiquement la température par token, en fonction de la variation des probabilités.", + "Minimum Temp": "Température minimale", + "Maximum Temp": "Température maximale", + "Exponent": "Exposant", + "Mirostat (mode=1 is only for llama.cpp)": "Mirostat (le mode=1 est uniquement pour llama.cpp)", + "Mirostat_desc": "Mirostat est un thermostat pour la perplexité de sortie", + "Mirostat Mode": "Mode Mirostat", + "Variability parameter for Mirostat outputs": "Paramètre de variabilité pour les sorties Mirostat.", + "Mirostat Eta": "Eta Mirostat", + "Learning rate of Mirostat": "Taux d'apprentissage de Mirostat.", + "Beam search": "Recherche par faisceau", + "Length Penalty": "Pénalité de longueur", + "Early Stopping": "Arrêt précoce", + "Contrastive search": "Recherche contrastive", + "Penalty Alpha": "Alpha de pénalité", + "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "Force du terme de régularisation de la recherche contrastive. Réglez la valeur à 0 pour la désactiver.", + "Do Sample": "Faire une échantillon", + "Add BOS Token": "Ajouter le token BOS", + "Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative": "Ajoutez le token BOS au début des prompts. Désactiver cela peut rendre les réponses plus créatives", + "Ban the eos_token. This forces the model to never end the generation prematurely": "Interdire le token EOS. Cela force le modèle à ne jamais terminer la génération prématurément", + "Ignore EOS Token": "Ignorer le token EOS", + "Ignore the EOS Token even if it generates.": "Ignorez le token EOS même s'il est généré.", + "Skip Special Tokens": "Ignorer les tokens spéciaux", + "Temperature Last": "Température en dernier", + "Temperature_Last_desc": "Utilisez le réglage de température en dernier. Cela est généralement logique.\nLorsqu'il est activé : une sélection de tokens potentiels est d'abord effectuée, puis la température est appliquée pour corriger leurs probabilités relatives (techniquement, les log-likelihoods).\nLorsqu'il est désactivé : la température est d'abord appliquée pour corriger les probabilités relatives de tous les tokens, puis une sélection de tokens potentiels est effectuée parmi eux.\nDésactivez la température en dernier.", + "Speculative Ngram": "Ngramme spéculatif", + "Use a different speculative decoding method without a draft model": "Utilisez une méthode de décodage spéculative différente sans projet de modèle.\rIl est préférable d’utiliser une ébauche de modèle. Le ngram spéculatif n’est pas aussi efficace.", + "Spaces Between Special Tokens": "Espaces entre les tokens spéciaux", + "LLaMA / Mistral / Yi models only": "Modèles LLaMA / Mistral / Yi uniquement. Assurez-vous de sélectionner d'abord l'analyste approprié.\nLes chaînes de caractères ne doivent pas apparaître dans les résultats.\nUne chaîne par ligne. Texte ou [identifiants de tokens].\nDe nombreux tokens commencent par un espace. Utilisez un compteur de tokens si vous n'êtes pas sûr.", + "Example: some text [42, 69, 1337]": "Exemple:\nun texte\n[42, 69, 1337]", + "Classifier Free Guidance. More helpful tip coming soon": "Guidance gratuite du classificateur. Des conseils plus utiles arrivent bientôt.", + "Scale": "Échelle", + "JSON Schema": "Schéma JSON", + "Type in the desired JSON schema": "Tapez le schéma JSON souhaité", + "Grammar String": "Chaîne de grammaire", + "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF ou EBNF dépend du backend utilisé. Si vous l'utilisez, vous devez savoir lequel.", + "Top P & Min P": "Top P et Min P", + "Load default order": "Charger l'ordre par défaut", + "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "lama.cpp uniquement. Détermine l’ordre des échantillonneurs. Si le mode Mirostat n'est pas à 0, l'ordre de l'échantillonneur est ignoré.", + "Sampler Priority": "Priorité de l'échantillonneur", + "Ooba only. Determines the order of samplers.": "Ooba uniquement. Détermine l'ordre des échantillonneurs.", + "Character Names Behavior": "Comportement des noms de personnages", + "Helps the model to associate messages with characters.": "Aide le modèle à associer les messages avec les personnages.", + "None": "Aucun", + "character_names_default": "Sauf pour les groupes et les personnages passés. Sinon, assurez-vous de fournir des noms dans le prompt.", + "character_names_completion": "Des restrictions s'appliquent : uniquement les caractères alphanumériques latins et les traits de soulignement. Ne fonctionne pas pour toutes les sources, notamment : Claude, MistralAI, Google.", + "Message Content": "Contenu du message", + "Prepend character names to message contents.": "Ajoutez les noms de caractères au contenu du message.", + "Continue Postfix": "Continuer Postfix", + "The next chunk of the continued message will be appended using this as a separator.": "Le prochain morceau du message continu sera ajouté en utilisant celui-ci comme séparateur.", + "Space": "Espace", + "Newline": "Nouvelle ligne", + "Double Newline": "Double nouvelle ligne", + "Wrap user messages in quotes before sending": "Envelopper les messages de l'utilisateur entre guillemets avant de les envoyer", + "Wrap in Quotes": "Envelopper entre guillemets", + "Wrap entire user message in quotes before sending.": "Envelopper l'ensemble du message utilisateur entre guillemets avant de l'envoyer.", + "Leave off if you use quotes manually for speech.": "Laissez-le en dehors si vous utilisez manuellement des guillemets pour la parole.", + "Continue prefill": "Continuer le pré-remplissage", + "Continue sends the last message as assistant role instead of system message with instruction.": "Continuer envoie le dernier message en tant que rôle d'assistant au lieu d'un message système avec instruction.", + "Squash system messages": "Combiner les messages système", + "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Combine les messages système consécutifs en un seul (à l'exclusion des dialogues d'exemple). Peut améliorer la cohérence pour certains modèles.", + "Enable function calling": "Activer l'appel de fonction", + "Send inline images": "Envoyer des images en ligne", + "image_inlining_hint_1": "Envoie des images dans les prompts si le modèle le prend en charge (par exemple GPT-4V, Claude 3 ou Llava 13B).\nUtilisez le", + "image_inlining_hint_2": "action sur n'importe quel message ou le", + "image_inlining_hint_3": "menu pour joindre un fichier image au chat.", + "Inline Image Quality": "Qualité d'image en ligne", + "openai_inline_image_quality_auto": "Auto", + "openai_inline_image_quality_low": "Faible", + "openai_inline_image_quality_high": "Haut", + "Use system prompt": "Utiliser le prompt système", + "Merges_all_system_messages_desc_1": "Fusionne tous les messages système jusqu'au premier message avec un rôle non-système et les envoie dans un", + "Merges_all_system_messages_desc_2": "champ.", + "Assistant Prefill": "Pré-remplissage de l'assistant", + "Start Claude's answer with...": "Commencer la réponse de Claude par...", + "Assistant Impersonation Prefill": "Pré-remplir l'usurpation d'identité de l'assistant", + "Use system prompt (Claude 2.1+ only)": "Utiliser le prompt système (uniquement Claude 2.1+)", + "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "Envoyer le prompt système pour les modèles pris en charge. Si désactivé, le message de l'utilisateur est ajouté au début du prompt.", + "New preset": "Nouveau preset", + "Delete preset": "Supprimer le preset", + "View / Edit bias preset": "Afficher/Modifier le preset de biais", + "Add bias entry": "Ajouter une entrée de biais", + "Most tokens have a leading space.": "La plupart des tokens sont précédés d'un espace.", + "API Connections": "Connexions API", + "Text Completion": "Complétion de texte", + "Chat Completion": "Complétion de chat", + "NovelAI": "NovelAI", + "AI Horde": "AI Horde", + "KoboldAI": "KoboldAI", + "Avoid sending sensitive information to the Horde.": "Évitez d'envoyer des informations sensibles à la Horde.", + "Review the Privacy statement": "Examiner la déclaration de confidentialité", + "Register a Horde account for faster queue times": "Enregistrez un compte Horde pour accélérer les files d'attente", + "Learn how to contribute your idle GPU cycles to the Horde": "Découvrez comment contribuer à la Horde avec vos cycles GPU inactifs.", + "Adjust context size to worker capabilities": "Ajuster la taille du contexte aux capacités des travailleurs", + "Adjust response length to worker capabilities": "Ajuster la longueur de la réponse aux capacités des travailleurs", + "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "Peut aider avec les mauvaises réponses en mettant en file d'attente uniquement les travailleurs approuvés. Peut ralentir le temps de réponse.", + "Trusted workers only": "Travailleurs de confiance uniquement", + "API key": "Clé API", + "Get it here:": "Obtenez-la ici :", + "Register": "S'inscrire", + "View my Kudos": "Voir mes Kudos", + "Enter": "Entrez", + "to use anonymous mode.": "pour utiliser le mode anonyme.", + "Clear your API key": "Effacer votre clé API", + "For privacy reasons, your API key will be hidden after you reload the page.": "Pour des raisons de confidentialité, votre clé API sera masquée après le rechargement de la page.", + "Models": "Modèles", + "Refresh models": "Actualiser les modèles", + "-- Horde models not loaded --": "-- Modèles Horde non chargés --", + "Not connected...": "Non connecté...", + "API url": "URL de l'API", + "Example: http://127.0.0.1:5000/api ": "Exemple : http://127.0.0.1:5000/api", + "Connect": "Connection", + "Cancel": "Annuler", + "Novel API key": "Clé API de NovelAI", + "Get your NovelAI API Key": "Obtenez votre clé API NovelAI", + "Enter it in the box below": "Entrez-le dans la boîte ci-dessous", + "Novel AI Model": "Modèle NovelAI", + "No connection...": "Pas de connexion...", + "API Type": "Type d'API", + "TogetherAI API Key": "Clé API de TogetherAI", + "TogetherAI Model": "Modèle TogetherAI", + "-- Connect to the API --": "-- Se connecter à l'API --", + "OpenRouter API Key": "Clé API OpenRouter", + "Click Authorize below or get the key from": "Cliquez sur Autoriser ci-dessous ou obtenez la clé à partir de", + "View Remaining Credits": "Afficher les crédits restants", + "OpenRouter Model": "Modèle OpenRouter", + "Model Providers": "Fournisseurs de modèles", + "InfermaticAI API Key": "Clé API InfermaticAI", + "InfermaticAI Model": "Modèle InfermaticAI", + "DreamGen API key": "Clé API DreamGen", + "DreamGen Model": "Modèle DreamGen", + "Mancer API key": "Clé API de Mancer", + "Mancer Model": "Modèle Mancer", + "Make sure you run it with": "Assurez-vous de l'exécuter avec", + "flag": "fanion", + "API key (optional)": "Clé API (optionnelle)", + "Server url": "URL du serveur", + "Example: 127.0.0.1:5000": "Exemple : 127.0.0.1:5000", + "Custom model (optional)": "Modèle personnalisé (optionnel)", + "vllm-project/vllm": "vllm-project/vllm (mode wrapper de l'API OpenAI)", + "vLLM API key": "Clé API vLLM", + "Example: 127.0.0.1:8000": "Exemple : http://127.0.0.1:8000", + "vLLM Model": "Modèle vLLM", + "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (mode wrapper pour l'API OpenAI)", + "Aphrodite API key": "Clé API Aphrodite", + "Aphrodite Model": "Modèle Aphrodite", + "ggerganov/llama.cpp": "ggerganov/llama.cpp", + "Example: 127.0.0.1:8080": "Exemple : 127.0.0.1:8080", + "Example: 127.0.0.1:11434": "Exemple : 127.0.0.1:11434", + "Ollama Model": "Modèle Ollama", + "Download": "Télécharger", + "Tabby API key": "Clé API de Tabby", + "koboldcpp API key (optional)": "Clé API koboldcpp (facultatif)", + "Example: 127.0.0.1:5001": "Exemple : 127.0.0.1:5001", + "Authorize": "Autoriser", + "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Obtenez votre jeton API OpenRouter en utilisant le flux OAuth. Vous serez redirigé vers openrouter.ai", + "Bypass status check": "Contourner la vérification de l'état", + "Chat Completion Source": "Source de complétion de chat", + "Reverse Proxy": "Reverse Proxy", + "Proxy Presets": "Presets proxy", + "Saved addresses and passwords.": "Adresses et mots de passe enregistrés.", + "Save Proxy": "Enregistrer le proxy", + "Delete Proxy": "Supprimer le proxy", + "Proxy Name": "Nom du proxy", + "This will show up as your saved preset.": "Cela apparaîtra comme votre preset enregistré.", + "Proxy Server URL": "URL du serveur proxy", + "Alternative server URL (leave empty to use the default value).": "URL du serveur alternatif (laissez vide pour utiliser la valeur par défaut).", + "Doesn't work? Try adding": "Ça ne marche pas ? Essayez d'ajouter", + "at the end!": "à la fin!", + "Proxy Password": "Mot de passe proxy", + "Will be used as a password for the proxy instead of API key.": "Sera utilisé comme mot de passe pour le proxy au lieu de la clé API.", + "Peek a password": "Jetez un œil à un mot de passe", + "OpenAI API key": "Clé API OpenAI", + "View API Usage Metrics": "Afficher les statistiques d'utilisation de l'API", + "Follow": "Suivre", + "these directions": "ces instructions", + "to get your OpenAI API key.": "pour obtenir votre clé API OpenAI.", + "Use Proxy password field instead. This input will be ignored.": "Utilisez plutôt le champ « Mot de passe proxy ». Cette entrée sera ignorée.", + "OpenAI Model": "Modèle OpenAI", + "Bypass API status check": "Contourner la vérification de l'état de l'API", + "Show External models (provided by API)": "Afficher les modèles externes (fournis par l'API)", + "Get your key from": "Obtenez votre clé à partir de", + "Anthropic's developer console": "Console de développement d'Anthropic", + "Claude Model": "Modèle Claude", + "Window AI Model": "Modèle Window AI", + "Model Order": "Tri des modèles OpenRouter", + "Alphabetically": "Alphabétiquement", + "Price": "Prix ​​(le moins cher)", + "Context Size": "Taille du contexte", + "Group by vendors": "Regrouper par fournisseurs", + "Group by vendors Description": "Placez les modèles OpenAI dans un groupe, les modèles Anthropic dans un autre groupe, etc. Peut être combiné avec le tri.", + "Allow fallback routes Description": "Le modèle alternatif est automatiquement sélectionné si le modèle choisi ne peut pas répondre à votre demande.", + "Scale API Key": "Clé API Scale", + "Clear your cookie": "Effacer vos cookies", + "Alt Method": "Méthode alternative", + "AI21 API Key": "Clé API AI21", + "AI21 Model": "Modèle AI21", + "Google AI Studio API Key": "Clé API Google AI Studio", + "Google Model": "Modèle Google", + "MistralAI API Key": "Clé API MistralAI", + "MistralAI Model": "Modèle MistralAI", + "Groq API Key": "Clé API Groq", + "Groq Model": "Modèle Groq", + "Perplexity API Key": "Clé API Perplexity", + "Perplexity Model": "Modèle Perplexity", + "Cohere API Key": "Clé API Cohere", + "Cohere Model": "Modèle Cohere", + "Custom Endpoint (Base URL)": "Point de terminaison personnalisé (URL de base)", + "Custom API Key": "Clé API personnalisée", + "Available Models": "Modèles disponibles", + "Prompt Post-Processing": "Post-traitement de prompt", + "Applies additional processing to the prompt before sending it to the API.": "Applique un traitement supplémentaire au prompt avant de l'envoyer à l'API.", + "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "Vérifie votre connexion API en envoyant un court message de test. Soyez conscient que vous serez crédité pour cela !", + "Test Message": "Message de test", + "Auto-connect to Last Server": "Connexion automatique au dernier serveur", + "Missing key": "❌ Clé manquante", + "Key saved": "✔️ Clé enregistrée", + "View hidden API keys": "Afficher les clés API cachées", + "AI Response Formatting": "Formatage de la réponse de l'IA", + "Advanced Formatting": "Formatage avancé", + "Context Template": "Modèle de contexte", + "Story String": "Chaîne d'histoire", + "Example Separator": "Séparateur d'exemple", + "Chat Start": "Début de la discussion", + "Add Chat Start and Example Separator to a list of stopping strings.": "Ajoutez Chat Start et Sample Separator à une liste de chaînes d’arrêt.", + "Author's Note": "Note d'auteur", + "Enabled": "Activé", + "instruct_bind_to_context": "Si cette option est activée, les modèles de contexte seront automatiquement sélectionnés en fonction du nom du modèle d'instruction sélectionné ou par préférence.", + "Activation Regex": "Regex d'activation", + "Wrap Sequences with Newline": "Envelopper les séquences avec un saut de ligne", + "Replace Macro in Sequences": "Remplacer la macro dans les séquences", + "Skip Example Dialogues Formatting": "Ignorer le formatage des dialogues d'exemple", + "Include Names": "Inclure les noms", + "System Prompt": "Prompt système", + "Inserted before a System prompt.": "Inséré avant un prompt système.", + "System Prompt Prefix": "Préfixe de prompt système", + "Inserted after a System prompt.": "Inséré après un prompt système.", + "System Prompt Suffix": "Suffixe de prompt système", + "Inserted before a User message and as a last prompt line when impersonating.": "Inséré avant un message utilisateur et comme dernière ligne du prompt lors de l'usurpation d'identité.", + "Inserted after a User message.": "Inséré après un message utilisateur.", + "Inserted before an Assistant message and as a last prompt line when generating an AI reply.": "Inséré avant un message de l'Assistant et comme dernière ligne du prompt lors de la génération d'une réponse de l'IA.", + "Inserted after an Assistant message.": "Inséré après un message de l'assistant.", + "Inserted before a System (added by slash commands or extensions) message.": "Inséré avant un message système (ajouté par des commandes slash ou des extensions).", + "Inserted after a System message.": "Inséré après un message système.", + "If enabled, System Sequences will be the same as User Sequences.": "Si cette option est activée, les séquences système seront les mêmes que les séquences utilisateur.", + "System same as User": "Système identique à l'utilisateur", + "Misc. Sequences": "Séquences diverses", + "Inserted before the first Assistant's message.": "Inséré avant le premier message de l'assistant.", + "First Assistant Prefix": "Préfixe du premier assistant", + "instruct_last_output_sequence": "Inséré avant le dernier message de l'assistant ou comme dernière ligne du prompt lors de la génération d'une réponse de l'IA (sauf un rôle neutre/système).", + "Last Assistant Prefix": "Préfixe du dernier assistant", + "Will be inserted as a last prompt line when using system/neutral generation.": "Sera inséré comme dernière ligne du prompt lors de l’utilisation de la génération système/neutre.", + "System Instruction Prefix": "Préfixe d'instruction système", + "If a stop sequence is generated, everything past it will be removed from the output (inclusive).": "Si une séquence d'arrêt est générée, tout ce qui se trouve au-delà sera supprimé de la sortie (inclus).", + "Stop Sequence": "Séquence d'arrêt", + "Will be inserted at the start of the chat history if it doesn't start with a User message.": "Sera inséré au début de l'historique des discussions s'il ne commence pas par un message utilisateur.", + "User Filler Message": "Message de remplissage de l'utilisateur", + "Context Formatting": "Formatage du contexte", + "Always add character's name to prompt": "Toujours ajouter le nom du personnage au prompt", + "Generate only one line per request": "Générer seulement une ligne par requête", + "Trim Incomplete Sentences": "Supprimer les phrases incomplètes", + "Collapse Consecutive Newlines": "Réduire les sauts de ligne consécutifs", + "Trim spaces": "Supprimer les espaces", + "Tokenizer": "Tokeniseur", + "Token Padding": "Remplissage de token", + "Start Reply With": "Commencer la réponse avec", + "Show reply prefix in chat": "Afficher le préfixe de réponse dans la conversation", + "Non-markdown strings": "Chaînes non Markdown", + "Custom Stopping Strings": "Chaînes d'arrêt personnalisées", + "JSON serialized array of strings": "Tableau de chaînes sérialisé JSON", + "Replace Macro in Stop Strings": "Remplacer les macro dans les chaînes d'arrêt personnalisées", + "Auto-Continue": "Auto-Continue", + "Allow for Chat Completion APIs": "Autoriser les APIs de complétion de chat", + "Target length (tokens)": "Longueur cible (tokens)", + "World Info": "World Info", + "Locked = World Editor will stay open": "Verrouillé = l'éditeur des World Info restera ouvert", + "Worlds/Lorebooks": "Worlds/Lorebooks", + "Active World(s) for all chats": "Monde(s) actif(s) pour toutes les conversations", + "-- World Info not found --": "-- World Info non trouvées --", + "Global World Info/Lorebook activation settings": "Paramètres d'activation globales des World Info/Lorebook", + "Click to expand": "Cliquez pour agrandir", + "Scan Depth": "Profondeur de scan", + "Context %": "Pourcentage de contexte", + "Budget Cap": "Limite de budget", + "(0 = disabled)": "(0 = désactivé)", + "Scan chronologically until reached min entries or token budget.": "Analysez chronologiquement jusqu'à atteindre le nombre minimum d'entrées ou le budget symbolique.", + "Min Activations": "Activations minimales", + "Max Depth": "Profondeur max", + "(0 = unlimited, use budget)": "(0 = illimité, utiliser le budget)", + "Insertion Strategy": "Stratégie d'insertion", + "Sorted Evenly": "Trié de manière égale", + "Character Lore First": "Lore du personnage d'abord", + "Global Lore First": "Lore global d'abord", + "Entries can activate other entries by mentioning their keywords": "Les entrées peuvent activer d'autres entrées en mentionnant leurs mots-clés", + "Recursive Scan": "Analyse récursive", + "Lookup for the entry keys in the context will respect the case": "La recherche des clés d'entrée dans le contexte respectera la casse", + "Case Sensitive": "Sensible à la casse", + "If the entry key consists of only one word, it would not be matched as part of other words": "Si la clé de l'entrée se compose d'un seul mot, elle ne sera pas considérée comme faisant partie d'autres mots", + "Match Whole Words": "Correspondre aux mots entiers", + "Only the entries with the most number of key matches will be selected for Inclusion Group filtering": "Seules les entrées avec le plus grand nombre de correspondances clés seront sélectionnées pour le filtrage des groupes d'inclusion.", + "Use Group Scoring": "Utiliser la notation de groupe", + "Alert if your world info is greater than the allocated budget.": "Alertez si vos informations mondiales sont supérieures au budget alloué.", + "Alert On Overflow": "Alerte en cas de dépassement", + "New": "Nouveau", + "or": "ou", + "--- Pick to Edit ---": "--- Sélectionnez pour éditer ---", + "Rename World Info": "Renommer le World Info", + "Open all Entries": "Ouvrir toutes les entrées", + "Close all Entries": "Fermer toutes les entrées", + "New Entry": "Nouvelle entrée", + "Fill empty Memo/Titles with Keywords": "Remplir les mémos/titres vides avec des mots-clés", + "Import World Info": "Importer un Wolrd Info", + "Export World Info": "Exporter le Wolrd Info", + "Duplicate World Info": "Dupliquer le World Info", + "Delete World Info": "Supprimer le World Info", + "Search...": "Rechercher...", + "Search": "Recherche", + "Priority": "Priorité", + "Custom": "Personnalisé", + "Title A-Z": "Titre A-Z", + "Title Z-A": "Titre Z-A", + "Tokens ↗": "Tokens ↗", + "Tokens ↘": "Tokens ↘", + "Depth ↗": "Profondeur ↗", + "Depth ↘": "Profondeur ↘", + "Order ↗": "Ordre ↗", + "Order ↘": "Ordre ↘", + "UID ↗": "UID ↗", + "UID ↘": "UID ↘", + "Trigger% ↗": "Déclencheur% ↗", + "Trigger% ↘": "Déclencheur% ↘", + "Refresh": "Actualiser", + "User Settings": "Paramètres utilisateur", + "UI Language": "Langue", + "Account": "Compte", + "Admin Panel": "Panneau d'administration", + "Logout": "Déconnection", + "Search Settings": "Recherche de paramètres", + "UI Theme": "Thème de l'UI", + "Import a theme file": "Importer un fichier de thème", + "Export a theme file": "Exporter un fichier de thème", + "Delete a theme": "Supprimer un thème", + "Update a theme file": "Mettre à jour un fichier de thème", + "Save as a new theme": "Enregistrer en tant que nouveau thème", + "Avatar Style:": "Style d'avatar", + "Circle": "Cercle", + "Square": "Carré", + "Rectangle": "Rectangle", + "Chat Style:": "Style de la discussion :", + "Flat": "Plat\nBulles\nDocument", + "Bubbles": "Bulles", + "Document": "Document", + "Specify colors for your theme.": "Spécifiez les couleurs de votre thème.", + "Theme Colors": "Couleurs du thème", + "Main Text": "Texte principal", + "Italics Text": "Texte en italique", + "Underlined Text": "Texte souligné", + "Quote Text": "Texte de citation", + "Shadow Color": "Couleur de l'ombre", + "Chat Background": "Arrière-plan de la discussion", + "UI Background": "Arrière-plan de l'interface utilisateur", + "UI Border": "Bordure de l'interface utilisateur", + "User Message Blur Tint": "Teinte de flou du message utilisateur", + "AI Message Blur Tint": "Teinte de flou du message AI", + "Chat Width": "Largeur de discussion", + "Width of the main chat window in % of screen width": "Largeur de la fenêtre de discussion principale en % de la largeur de l'écran", + "Font Scale": "Échelle de police", + "Font size": "Taille de police", + "Blur Strength": "Force du flou", + "Blur strength on UI panels.": "Force du flou sur les panneaux de l'interface utilisateur.", + "Text Shadow Width": "Largeur de l'ombre du texte", + "Strength of the text shadows": "Force des ombres du texte", + "Disables animations and transitions": "Désactive les animations et transitions", + "Reduced Motion": "Mouvement réduit", + "removes blur from window backgrounds": "Supprime le flou des arrière-plans de fenêtre", + "No Blur Effect": "Pas d'effet de flou", + "Remove text shadow effect": "Supprimer l'effet d'ombre du texte", + "No Text Shadows": "Pas d'ombres de texte", + "Reduce chat height, and put a static sprite behind the chat window": "Réduire la hauteur de la discussion et placer un sprite statique derrière la fenêtre de discussion", + "Waifu Mode": "Mode Waifu", + "Always show the full list of the Message Actions context items for chat messages, instead of hiding them behind '...'": "Afficher toujours la liste complète des éléments de contexte Actions de message pour les messages de discussion, au lieu de les cacher derrière '...' ", + "Auto-Expand Message Actions": "Extension automatique des actions du message", + "Alternative UI for numeric sampling parameters with fewer steps": "Interface utilisateur alternative pour les paramètres d'échantillonnage numérique avec moins d'étapes", + "Zen Sliders": "Curseurs Zen", + "Entirely unrestrict all numeric sampling parameters": "Déverrouiller entièrement tous les paramètres d'échantillonnage numérique", + "Mad Lab Mode": "Mode Mad Lab", + "Time the AI's message generation, and show the duration in the chat log": "Chronométrer la génération de messages de l'IA et afficher la durée dans le journal de discussion", + "Message Timer": "Minuteur de message", + "Show a timestamp for each message in the chat log": "Afficher un horodatage pour chaque message dans le journal de discussion", + "Chat Timestamps": "Horodatages de la discussion", + "Show an icon for the API that generated the message": "Afficher une icône pour l'API qui a généré le message", + "Model Icon": "Icône du modèle", + "Show sequential message numbers in the chat log": "Afficher les numéros de message séquentiels dans le journal de discussion", + "Message IDs": "Identifiants du message", + "Hide avatars in chat messages.": "Masquez les avatars dans les messages de discussion.", + "Hide Chat Avatars": "Masquer les avatars du chat", + "Show the number of tokens in each message in the chat log": "Afficher le nombre de tokens dans chaque message dans le journal de discussion", + "Show Message Token Count": "Afficher le nombre de tokens du message", + "Single-row message input area. Mobile only, no effect on PC": "Zone de saisie de message sur une seule ligne. Mobile uniquement, aucun effet sur PC", + "Compact Input Area (Mobile)": "Zone de saisie compacte (Mobile)", + "In the Character Management panel, show quick selection buttons for favorited characters": "Dans le panneau de gestion des personnages, afficher des boutons de sélection rapide pour les personnages favoris", + "Characters Hotswap": "Échange rapide de personnages", + "Enable magnification for zoomed avatar display.": "Activer le grossissement pour l'affichage de l'avatar zoomé.", + "Avatar Hover Magnification": "Agrandissement au survol de l'avatar", + "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "Active un effet de grossissement au survol lorsque vous affichez l'avatar zoomé après avoir cliqué sur l'image d'un avatar dans le chat.", + "Show tagged character folders in the character list": "Afficher les dossiers de personnages tagués dans la liste de personnages", + "Tags as Folders": "Tags comme dossiers", + "Tags_as_Folders_desc": "Modification récente : les tags doivent être marqués comme dossiers dans le menu Gestion des tags pour apparaître comme telles. Cliquez ici pour l'afficher.", + "Character Handling": "Gestion des personnages", + "If set in the advanced character definitions, this field will be displayed in the characters list.": "Si défini dans les définitions de personnage avancées, ce champ sera affiché dans la liste des personnages.", + "Char List Subheader": "Sous-en-tête de la liste des personnages", + "Character Version": "Version du personnage", + "Created by": "Créé par", + "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "Utiliser la correspondance floue et rechercher des personnages dans la liste par tous les champs de données, pas seulement par une sous-chaîne de nom", + "Advanced Character Search": "Recherche de personnage avancée", + "If checked and the character card contains a prompt override (System Prompt), use that instead": "Si cochée et si la carte de personnage contient un prompt de remplacement (prompt système), l'utiliser à la place", + "Prefer Character Card Prompt": "Préférer le prompt du personnage", + "never_resize_avatars_tooltip": "Évitez de recadrer et de redimensionner les images de personnages importés. Lorsqu'il est désactivé, recadrez/redimensionnez à 512 x 768.", + "Never resize avatars": "Ne jamais redimensionner les avatars", + "Show actual file names on the disk, in the characters list display only": "Afficher les noms de fichier réels sur le disque, dans l'affichage de la liste de personnages uniquement", + "Show avatar filenames": "Afficher les noms de fichier des avatars", + "Import Card Tags": "Importer les tags de carte", + "Hide character definitions from the editor panel behind a spoiler button": "Masquer les définitions de personnages du panneau d'édition derrière un bouton spoiler", + "Spoiler Free Mode": "Mode sans spoiler", + "Miscellaneous": "Divers", + "Reload and redraw the currently open chat": "Recharger et redessiner la discussion actuellement ouverte", + "Reload Chat": "Recharger la discussion", + "Debug Menu": "Menu de débogage", + "Smooth Streaming": "Diffusion fluide", + "Experimental feature. May not work for all backends.": "Fonctionnalité expérimentale. Peut ne pas fonctionner pour tous les backends.", + "Slow": "Lent", + "Fast": "Rapide", + "Play a sound when a message generation finishes": "Jouer un son lorsque la génération de message est terminée", + "Message Sound": "Son de message", + "Only play a sound when ST's browser tab is unfocused": "Jouer un son uniquement lorsque l'onglet ST du navigateur n'est pas active", + "Background Sound Only": "Son de fond uniquement", + "Reduce the formatting requirements on API URLs": "Réduire les exigences de formatage sur les URL d'API", + "Relaxed API URLS": "URLs d'API détendues", + "Ask to import the World Info/Lorebook for every new character with embedded lorebook. If unchecked, a brief message will be shown instead": "Demander d'importer le Word Info/Lorebook pour chaque nouveau personnage avec Lorebook intégré. Si non cochée, un message bref sera affiché à la place", + "Lorebook Import Dialog": "Boîte de dialogue d'importation de Lorebook", + "Restore unsaved user input on page refresh": "Restaurer les saisies utilisateur non enregistrées lors du rafraîchissement de la page", + "Restore User Input": "Restaurer l'entrée utilisateur", + "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "Permettre le repositionnement de certains éléments de l'interface utilisateur en les faisant glisser. PC uniquement, aucun effet sur mobile", + "Movable UI Panels": "Panels d'UI déplaçables", + "MovingUI preset. Predefined/saved draggable positions": "Preset MovingUI. Positions prédéfinies/enregistrées pouvant être déplacées", + "MUI Preset": "Preset MUI", + "Save movingUI changes to a new file": "Enregistrer les modifications de MovingUI dans un nouveau fichier", + "Reset MovingUI panel sizes/locations.": "Réinitialisez les tailles/emplacements des panneaux MovingUI.", + "Apply a custom CSS style to all of the ST GUI": "Appliquer un style CSS personnalisé à toute l'interface utilisateur de ST", + "Custom CSS": "CSS personnalisé", + "Expand the editor": "Agrandir l'éditeur", + "Chat/Message Handling": "Gestion de la discussion/des messages", + "# Messages to Load": "# Messages à charger", + "The number of chat history messages to load before pagination.": "Le nombre de messages de l'historique des discussions à charger avant la pagination.", + "(0 = All)": "(0 = Tout)", + "Streaming FPS": "FPS en streaming", + "Update speed of streamed text.": "Vitesse de mise à jour du texte diffusé.", + "Example Messages Behavior": "Comportement des messages d'exemple", + "Gradual push-out": "Poussée progressive", + "Always include examples": "Toujours inclure les exemples", + "Never include examples": "Ne jamais inclure les exemples", + "Send on Enter": "Envoyer sur Entrée", + "Disabled": "Désactivé", + "Automatic (PC)": "Automatique (PC)", + "Press Send to continue": "Appuyez sur Envoyer pour continuer", + "Show a button in the input area to ask the AI to continue (extend) its last message": "Afficher un bouton dans la zone de saisie pour demander à l'IA de continuer (étendre) son dernier message", + "Quick 'Continue' button": "Raccourcis 'Continuer'", + "Show arrow buttons on the last in-chat message to generate alternative AI responses. Both PC and mobile": "Afficher des boutons fléchés sur le dernier message de discussion pour générer des réponses alternatives de l'IA. Sur PC et mobile", + "Swipes": "Balayages", + "Allow using swiping gestures on the last in-chat message to trigger swipe generation. Mobile only, no effect on PC": "Autoriser l'utilisation de gestes de balayage sur le dernier message de discussion pour déclencher la génération de messages alternatifs. Mobile uniquement, aucun effet sur PC", + "Gestures": "Gestes", + "Auto-load Last Chat": "Chargement automatique de la dernière discussion", + "Auto-scroll Chat": "Défilement automatique de la discussion", + "Save edits to messages without confirmation as you type": "Enregistrer les modifications apportées aux messages sans confirmation pendant la saisie", + "Auto-save Message Edits": "Sauvegarde automatique des modifications de message", + "Confirm message deletion": "Confirmer la suppression du message", + "Auto-fix Markdown": "Correction automatique du Markdown", + "Disallow embedded media from other domains in chat messages": "Interdire les médias intégrés provenant d'autres domaines dans les messages de discussion.", + "Forbid External Media": "Interdire les médias externes", + "Allow {{char}}: in bot messages": "Autoriser {{char}} : dans les messages du bot", + "Allow {{user}}: in bot messages": "Autoriser {{user}} : dans les messages du bot", + "Skip encoding and characters in message text, allowing a subset of HTML markup as well as Markdown": "Ignorer l'encodage et les caractères < et > dans le texte du message, permettant un sous-ensemble du balisage HTML ainsi que Markdown", + "Show tags in responses": "Afficher les tags dans les réponses", + "Allow AI messages in groups to contain lines spoken by other group members": "Autoriser les messages de l'IA dans les groupes à contenir des lignes prononcées par d'autres membres du groupe", + "Relax message trim in Groups": "Relaxer la taille des messages dans les groupes", + "Log prompts to console": "Journaliser les prompts dans la console", + "Requests logprobs from the API for the Token Probabilities feature": "Demande des logprobs de l'API pour la fonctionnalité des probabilités des tokens", + "Request token probabilities": "Demande des probabilités de tokens", + "Automatically reject and re-generate AI message based on configurable criteria": "Rejeter automatiquement et régénérer un message AI en fonction de critères configurables", + "Auto-swipe": "Balayage automatique", + "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Activer la fonction de balayage automatique. Les paramètres de cette section n'ont d'effet que lorsque le balayage automatique est activé", + "Minimum generated message length": "Longueur minimale du message généré", + "If the generated message is shorter than these many characters, trigger an auto-swipe": "Si le message généré est plus court que cela, déclenchez un balayage automatique", + "Blacklisted words": "Mots en liste noire", + "words you dont want generated separated by comma ','": "mots que vous ne voulez pas générer séparés par des virgules ','", + "Blacklisted word count to swipe": "Nombre de mots en liste noire pour balayer", + "Minimum number of blacklisted words detected to trigger an auto-swipe": "Nombre minimum de mots en liste noire détectés pour déclencher un balayage automatique", + "AutoComplete Settings": "Paramètres de saisie semi-automatique", + "Automatically hide details": "Masquer automatiquement les détails", + "Determines how entries are found for autocomplete.": "Détermine comment les entrées sont trouvées pour la saisie semi-automatique.", + "Autocomplete Matching": "Correspondant à", + "Starts with": "Commence avec", + "Includes": "Comprend", + "Fuzzy": "Flou", + "Sets the style of the autocomplete.": "Définit le style de la saisie semi-automatique.", + "Autocomplete Style": "Style", + "Follow Theme": "Suivre le thème", + "Dark": "Sombre", + "Sets the font size of the autocomplete.": "Définit la taille de la police de la saisie semi-automatique.", + "Sets the width of the autocomplete.": "Définit la largeur de la saisie semi-automatique.", + "Autocomplete Width": "Largeur", + "chat input box": "zone de saisie du chat", + "entire chat width": "toute la largeur du chat", + "full window width": "pleine largeur de fenêtre", + "STscript Settings": "Paramètres STscript", + "Sets default flags for the STscript parser.": "Définit les indicateurs par défaut pour l'analyseur STscript.", + "Parser Flags": "Indicateurs de l'analyseur", + "Switch to stricter escaping, allowing all delimiting characters to be escaped with a backslash, and backslashes to be escaped as well.": "Passez à un échappement plus strict, permettant à tous les caractères de délimitation d'être échappés avec une barre oblique inverse, ainsi qu'aux barres obliques inverses.", + "STRICT_ESCAPING": "STRICT_ESCAPING", + "REPLACE_GETVAR": "REPLACE_GETVAR", + "Change Background Image": "Changer l'arrière-plans", + "Filter": "Filtre", + "Automatically select a background based on the chat context": "Sélectionner automatiquement un arrière-plan en fonction du contexte de la discussion", + "Auto-select": "Sélection automatique", + "System Backgrounds": "Arrière-plans du système", + "Chat Backgrounds": "Arrière-plans de la discussion", + "bg_chat_hint_1": "Les arrière-plans générés avec l'extension ", + "bg_chat_hint_2": " apparaîtrons ici.", + "Extensions": "Extensions", + "Notify on extension updates": "Notifier les mises à jour des extensions", + "Manage extensions": "Gérer les extensions", + "Import Extension From Git Repo": "Importer une extension depuis un dépôt Git", + "Install extension": "Installer une extension", + "Extras API:": "API supplémentaires :", + "Auto-connect": "Connexion automatique", + "Extras API URL": "URL de l'API des extras", + "Extras API key (optional)": "Clé API supplémentaire (facultatif)", + "Persona Management": "Gestion des personas", + "Click for stats!": "Cliquez pour les statistiques!", + "Usage Stats": "Statistiques d'utilisation", + "Backup your personas to a file": "Sauvegardez vos personas dans un fichier", + "Backup": "Sauvegarde", + "Restore your personas from a file": "Restaurez vos personas à partir d'un fichier", + "Restore": "Restaurer", + "Create a dummy persona": "Créer une persona factice", + "Create": "Créer", + "Toggle grid view": "Basculer en mode grille", + "No persona description": "[Pas de description]", + "Name": "Nom", + "Enter your name": "Entrez votre nom", + "Click to set a new User Name": "Cliquez pour définir un nouveau nom d'utilisateur", + "Click to lock your selected persona to the current chat. Click again to remove the lock.": "Cliquez pour verrouiller votre persona sélectionnée sur la discussion actuelle. Cliquez à nouveau pour supprimer le verrou.", + "Click to set user name for all messages": "Cliquez pour définir le nom d'utilisateur pour tous les messages", + "Persona Description": "Description de la persona", + "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "Exemple : [{{user}} est une fille chat roumaine de 28 ans.]", + "Tokens persona description": "Description des tokens", + "Position:": "Position :", + "In Story String / Prompt Manager": "Dans la chaîne d'histoire / Gestionnaire de prompt", + "Top of Author's Note": "En haut de la note d'auteur", + "Bottom of Author's Note": "En bas de la note d'auteur", + "In-chat @ Depth": "Dans le chat @ Profondeur", + "Depth:": "Profondeur :", + "Role:": "Rôle:", + "System": "Système", + "User": "Utilisateur", + "Assistant": "Assistant", + "Show notifications on switching personas": "Afficher les notifications lors du changement de persona", + "Character Management": "Gestion des personnages", + "Locked = Character Management panel will stay open": "Verrouillé = le panneau de gestion des personnages restera ouvert", + "Select/Create Characters": "Sélectionner/Créer des personnages", + "Favorite characters to add them to HotSwaps": "Mettre les personnages en favoris pour les ajouter aux HotSwaps", + "Token counts may be inaccurate and provided just for reference.": "Le comptage des tokens peut être inexacts et est fournis uniquement à titre de référence.", + "Total tokens": "Total des tokens", + "Calculating...": "Calcul en cours...", + "Tokens": "Tokens", + "Permanent tokens": "Tokens permanents", + "Permanent": "Permanent", + "About Token 'Limits'": "À propos des « limites » des tokens", + "Toggle character info panel": "Basculer le panneau d'informations sur le personnage", + "Name this character": "Nommer ce personnage", + "extension_token_counter": "Tokens :", + "Click to select a new avatar for this character": "Cliquez pour sélectionner un nouvel avatar pour ce personnage", + "Add to Favorites": "Ajouter aux favoris", + "Advanced Definition": "Définition avancée", + "Chat Lore": "Lore du chat", + "Export and Download": "Exporter et Télécharger", + "Duplicate Character": "Dupliquer le personnage", + "Create Character": "Créer un personnage", + "Delete Character": "Supprimer le personnage", + "More...": "Plus...", + "Link to World Info": "Lien vers le World Info", + "Import Card Lore": "Importer le lore de la carte", + "Scenario Override": "Remplacement du scénario", + "Convert to Persona": "Convertir en Persona", + "Rename": "Renommer", + "Link to Source": "Lien vers la source", + "Replace / Update": "Remplacer/Mettre à jour", + "Import Tags": "Importer les tags", + "Search / Create Tags": "Rechercher / Créer des tags", + "View all tags": "Voir tout les tags", + "Creator's Notes": "Notes du créateur", + "Show / Hide Description and First Message": "Afficher / Masquer la description et le premier message", + "Character Description": "Description du personnage", + "Click to allow/forbid the use of external media for this character.": "Cliquez pour autoriser/interdire l’utilisation de médias externes pour ce personnage.", + "Ext. Media": "Médias Ext.", + "Describe your character's physical and mental traits here.": "Décrivez les traits physiques et mentaux de votre personnage ici.", + "First message": "Premier message", + "Click to set additional greeting messages": "Cliquez pour définir des messages de salutation supplémentaires", + "Alt. Greetings": "Salutations Alt.", + "This will be the first message from the character that starts every chat.": "Ce sera le premier message du personnage qui démarre chaque discussion.", + "Group Controls": "Contrôles de groupe", + "Chat Name (Optional)": "Nom de la discussion (Facultatif)", + "Click to select a new avatar for this group": "Cliquez pour sélectionner un nouvel avatar pour ce groupe", + "Group reply strategy": "Stratégie de réponse de groupe", + "Natural order": "Ordre naturel", + "List order": "Ordre de la liste", + "Group generation handling mode": "Mode de gestion de la génération de groupe", + "Swap character cards": "Échanger les cartes de personnages", + "Join character cards (exclude muted)": "Joignez les cartes de personnage (excluez les cartes en sourdine)", + "Join character cards (include muted)": "Joignez les cartes de personnage (y compris en sourdine)", + "Inserted before each part of the joined fields.": "Inséré avant chaque partie des champs joints.", + "Join Prefix": "Joindre les préfixes", + "When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and with the name of the part (e.g.: description, personality, scenario, etc.)": "Lorsque « Joindre les cartes de personnage » est sélectionné, tous les champs respectifs des personnages sont réunis.\rCela signifie que dans la chaîne d'histoire, par exemple, toutes les descriptions des personnages seront réunies en un seul grand texte.\rSi vous souhaitez que ces champs soient séparés, vous pouvez définir ici un préfixe ou un suffixe.\r\rCette valeur prend en charge les macros normales et remplacera également {{char}} par le nom du caractère concerné et par le nom de la pièce (par exemple : description, personnalité, scénario, etc.)", + "Inserted after each part of the joined fields.": "Inséré après chaque partie des champs joints.", + "Join Suffix": "Suffixe de jointure", + "Set a group chat scenario": "Définir un scénario de discussion de groupe", + "Click to allow/forbid the use of external media for this group.": "Cliquez pour autoriser/interdire l’utilisation de médias externes pour ce groupe.", + "Restore collage avatar": "Restaurer l'avatar du collage", + "Allow self responses": "Autoriser les réponses à soi-même", + "Auto Mode": "Mode automatique", + "Auto Mode delay": "Délai du mode automatique", + "Hide Muted Member Sprites": "Masquer les sprites des membres muets", + "Current Members": "Membres actuels", + "Add Members": "Ajouter des membres", + "Create New Character": "Créer un nouveau personnage", + "Import Character from File": "Importer un personnage à partir d'un fichier", + "Import content from external URL": "Importer du contenu depuis une URL externe", + "Create New Chat Group": "Créer une nouvelle discussion de groupe", + "Characters sorting order": "Ordre des personnages", + "A-Z": "A-Z", + "Z-A": "Z-A", + "Newest": "Plus récent", + "Oldest": "Plus ancien", + "Favorites": "Favoris", + "Recent": "Récent", + "Most chats": "Plus de discussions", + "Least chats": "Moins de discussions", + "Most tokens": "Tokens maximum", + "Least tokens": "Tokens minimum", + "Random": "Aléatoire", + "Toggle character grid view": "Basculer vers la vue en grille des personnages", + "Bulk_edit_characters": "Édition en masse des personnages", + "Bulk select all characters": "Sélection groupée de tous les caractères", + "Bulk delete characters": "Suppression en masse des personnages", + "popup-button-save": "Sauvegarder", + "popup-button-yes": "Oui", + "popup-button-no": "Non", + "popup-button-cancel": "Annuler", + "popup-button-import": "Importer", + "Advanced Definitions": "Définitions avancées", + "Prompt Overrides": "Remplacements d'invite", + "(For Chat Completion and Instruct Mode)": "(Pour l'achèvement du chat et le mode instruction)", + "Insert {{original}} into either box to include the respective default prompt from system settings.": "Insérez {{original}} dans l'un ou l'autre des champs pour inclure l'instruction par défaut respective des paramètres système.", + "Main Prompt": "Instruction principale", + "Any contents here will replace the default Main Prompt used for this character. (v2 spec: system_prompt)": "Tout contenu ici remplacera l'instruction principale par défaut utilisée pour ce personnage. (spécification v2 : système_prompt)", + "Any contents here will replace the default Jailbreak Prompt used for this character. (v2 spec: post_history_instructions)": "Tout contenu ici remplacera l'instruction de jailbreak par défaut utilisée pour ce personnage. (spécification v2 : post_history_instructions)", + "Creator's Metadata (Not sent with the AI prompt)": "Métadonnées du créateur (Non envoyées avec l'instruction de l'IA)", + "Creator's Metadata": "Métadonnées du créateur", + "(Not sent with the AI Prompt)": "(Non envoyé avec le prompt IA)", + "Everything here is optional": "Tout ce qui se trouve ici est facultatif", + "(Botmaker's name / Contact Info)": "(Nom du créateur du bot / Informations de contact)", + "(If you want to track character versions)": "(Si vous voulez suivre les versions du personnage)", + "(Describe the bot, give use tips, or list the chat models it has been tested on. This will be displayed in the character list.)": "(Décrivez le bot, donnez des conseils d'utilisation ou répertoriez les modèles de discussion sur lesquels il a été testé. Cela s'affichera dans la liste des personnages.)", + "Tags to Embed": "Tags à intégrer", + "(Write a comma-separated list of tags)": "(Écrivez une liste de tags séparés par des virgules)", + "Personality summary": "Résumé de la personnalité", + "(A brief description of the personality)": "(Une brève description de la personnalité)", + "Scenario": "Scénario", + "(Circumstances and context of the interaction)": "(Circonstances et contexte de l'interaction)", + "Character's Note": "Note du personnage", + "(Text to be inserted in-chat @ designated depth and role)": "(Texte à insérer dans le chat @ profondeur et rôle désignés)", + "@ Depth": "@ Profondeur", + "Role": "Rôle", + "Talkativeness": "Bavardage", + "How often the character speaks in group chats!": "À quelle fréquence le personnage parle dans les discussions de groupe !", + "How often the character speaks in": "À quelle fréquence le personnage parle", + "group chats!": "les discussions de groupe !", + "Shy": "Timide", + "Normal": "Normal", + "Chatty": "Bavard", + "Examples of dialogue": "Exemples de dialogue", + "Important to set the character's writing style.": "Important de définir le style d'écriture du personnage.", + "(Examples of chat dialog. Begin each example with START on a new line.)": "(Exemples de dialogue. Commencez chaque exemple par START sur une nouvelle ligne.)", + "Save": "Enregistrer", + "Chat History": "Historique de la conversation", + "Import Chat": "Importer une discussion", + "Copy to system backgrounds": "Copier vers les arrière-plans du système", + "Rename background": "Renommer l'arrière-plan", + "Lock": "Verrouiller", + "Unlock": "Déverrouiller", + "Delete background": "Supprimer l'arrière-plan", + "Chat Scenario Override": "Remplacement du scénario de discussion", + "Remove": "Supprimer", + "Type here...": "Tapez ici...", + "Chat Lorebook": "Lorebook pour", + "Chat Lorebook for": "Chat Lorebook pour", + "chat_world_template_txt": "Un World Info sélectionné sera lié à ce chat. Lors de la génération d'une réponse IA,\n il sera combiné avec les entrées des livres de connaissances globaux et de personnages.", + "Select a World Info file for": "Sélectionnez un fichier Word Info pour", + "Primary Lorebook": "Lorebook principal", + "A selected World Info will be bound to this character as its own Lorebook.": "Un World Info sélectionnée sera liée à ce personnage comme son propre lorebook.", + "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "Lors de la génération d'une réponse de l'IA, elle sera combinée avec les entrées d'un sélecteur de World Info global.", + "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "L'exportation d'un personnage exporterait également le fichier de lorebook sélectionné incorporé dans les données JSON.", + "Additional Lorebooks": "Lorebooks supplémentaires", + "Associate one or more auxillary Lorebooks with this character.": "Associer un ou plusieurs lorebooks auxiliaires à ce personnage.", + "NOTE: These choices are optional and won't be preserved on character export!": "REMARQUE : Ces choix sont facultatifs et ne seront pas conservés lors de l'exportation du personnage !", + "Rename chat file": "Renommer le fichier de discussion", + "Export JSONL chat file": "Exporter le fichier de discussion au format JSONL", + "Download chat as plain text document": "Télécharger la discussion sous forme de document texte brut", + "Delete chat file": "Supprimer le fichier de discussion", + "Use tag as folder": "Utiliser les tags comme dossier", + "Delete tag": "Supprimer le tag'", + "Entry Title/Memo": "Titre de l'entrée/Mémo", + "WI_Entry_Status_Constant": "Constante", + "WI_Entry_Status_Normal": "Normale", + "WI_Entry_Status_Vectorized": "Vectorisé", + "T_Position": "↑Personnage : avant les définitions de personnage\n↓Personnage : après les définitions de personnage\n↑AN : avant les notes d'auteur\n↓AN : après les notes d'auteur\n@D : à la profondeur", + "Before Char Defs": "Avant les définitions de personnage", + "After Char Defs": "Après les définitions de personnage", + "Before EM": "↑EM", + "After EM": "↓EM", + "Before AN": "Avant NA", + "After AN": "Après NA", + "at Depth System": "@D ⚙️", + "at Depth User": "@D 👤", + "at Depth AI": "@D 🤖", + "Depth": "Profondeur", + "Order:": "Ordre :", + "Order": "Ordre :", + "Trigger %:": "% Déclenchement :", + "Probability": "Probabilité", + "Duplicate world info entry": "Dupliquer l'entrée du World Info", + "Delete world info entry": "Supprimer l'entrée du World Info", + "Comma separated (required)": "Séparé par des virgules (requis)", + "Primary Keywords": "Mots-clés principaux", + "Keywords or Regexes": "Mots-clés ou expressions régulières", + "Comma separated list": "Liste séparée par des virgules", + "Switch to plaintext mode": "Passer en mode texte brut", + "Logic": "Logique", + "AND ANY": "ET TOUT", + "AND ALL": "ET TOUS", + "NOT ALL": "PAS TOUS", + "NOT ANY": "PAS DE TOUS", + "(ignored if empty)": "(ignoré si vide)", + "Optional Filter": "Filtre optionnel", + "Keywords or Regexes (ignored if empty)": "Mots-clés ou expressions régulières (ignorés s'ils sont vides)", + "Comma separated list (ignored if empty)": "Liste séparée par des virgules (ignorée si vide)", + "Use global setting": "Utiliser le paramètre global", + "Case-Sensitive": "Sensible à la casse", + "Yes": "Oui", + "No": "Non", + "Can be used to automatically activate Quick Replies": "Peut être utilisé pour activer automatiquement les Quick Replies", + "Automation ID": "ID d'automatisation", + "( None )": "( Aucun )", + "Content": "Contenu", + "Prevent further recursion (this entry will not activate others)": "Empêcher toute récursion ultérieure (cette entrée n’en activera pas d’autres)", + "What this keyword should mean to the AI, sent verbatim": "Ce que ce mot-clé devrait signifier pour l'IA, envoyé textuellement", + "-- Characters not found --": "-- Personnages non trouvés --", + "Inclusion Group": "Groupe d'inclusion", + "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "Les groupes d'inclusion garantissent qu'une seule entrée d'un groupe est activée à la fois, si plusieurs sont déclenchées.\rPrend en charge plusieurs groupes séparés par des virgules.\r\rDocumentation : World Info - Groupe Inclusion", + "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "Prioriser cette entrée : Lorsque cette case est cochée, cette entrée est prioritaire parmi toutes les sélections.\rSi plusieurs sont prioritaires, celui avec l'ordre le plus élevé est choisi.", + "Only one entry with the same label will be activated": "Seule une entrée avec la même étiquette sera activée", + "A relative likelihood of entry activation within the group": "Une probabilité relative d’activation d’entrée au sein du groupe", + "Group Weight": "Poids du groupe", + "Selective": "Sélectif", + "Use Probability": "Utiliser la probabilité", + "Add Memo": "Ajouter un mémo", + "Text or token ids": "Texte ou [token ids]", + "close": "fermer", + "prompt_manager_edit": "Modifier", + "prompt_manager_name": "Nom", + "A name for this prompt.": "Un nom pour ce prompt.", + "To whom this message will be attributed.": "À qui ce message sera attribué.", + "AI Assistant": "Assistant IA", + "prompt_manager_position": "Position", + "prompt_manager_relative": "Relatif", + "prompt_manager_depth": "Profondeur", + "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "Profondeur d'injection. 0 = après le dernier message, 1 = avant le dernier message, etc.", + "Prompt": "Prompt", + "The prompt to be sent.": "Le prompt à envoyer.", + "This prompt cannot be overridden by character cards, even if overrides are preferred.": "Ce prompt ne peut pas être remplacé par les cartes de personnage, même si les remplacements sont préférés.", + "prompt_manager_forbid_overrides": "Interdire les remplacements", + "reset": "réinitialiser", + "save": "sauvegarder", + "This message is invisible for the AI": "Ce message est invisible pour l'IA", + "Message Actions": "Actions des messages", + "Translate message": "Traduire le message", + "Generate Image": "Générer une image", + "Narrate": "Narrer", + "Exclude message from prompts": "Exclure le message des prompts", + "Include message in prompts": "Inclure le message dans les prompts", + "Embed file or image": "Intégrer un fichier ou une image", + "Create checkpoint": "Créer un point de contrôle", + "Create Branch": "Créer une branche", + "Copy": "Copier", + "Edit": "Modifier", + "Confirm": "Confirmer", + "Copy this message": "Copier ce message", + "Delete this message": "Supprimer ce message", + "Move message up": "Déplacer le message vers le haut", + "Move message down": "Déplacer le message vers le bas", + "Enlarge": "Agrandir", + "Welcome to SillyTavern!": "Bienvenue sur SillyTavern !", + "welcome_message_part_1": "Lisez la", + "welcome_message_part_2": "Documentation officielle", + "welcome_message_part_3": null, + "welcome_message_part_4": "Tapez", + "welcome_message_part_5": "dans le chat pour les commandes et les macros.", + "welcome_message_part_6": "Rejoignez le", + "Discord server": "Serveur Discord", + "welcome_message_part_7": "pour les infos et annonces.", + "SillyTavern is aimed at advanced users.": "SillyTavern s'adresse aux utilisateurs avancés.", + "Looking for AI characters?": "Vous recherchez des personnages ?", + "onboarding_import": "Importer", + "from supported sources or view": "à partir de sources prises en charge ou afficher des", + "Sample characters": "Exemples de personnages", + "Your Persona": "Votre persona", + "Before you get started, you must select a persona name.": "Avant de commencer, vous devez sélectionner un nom pour votre persona.", + "welcome_message_part_8": "Ceci peut être modifié à tout moment via l'icône", + "welcome_message_part_9": ".", + "Persona Name:": "Nom de la persona :", + "Temporarily disable automatic replies from this character": "Désactiver temporairement les réponses automatiques de ce personnage", + "Enable automatic replies from this character": "Activer les réponses automatiques de ce personnage", + "Trigger a message from this character": "Déclencher un message de ce personnage", + "Move up": "Monter", + "Move down": "Descendre", + "View character card": "Voir la carte du personnage", + "Remove from group": "Retirer du groupe", + "Add to group": "Ajouter au groupe", + "Alternate Greetings": "Salutations alternatives", + "Alternate_Greetings_desc": "Ceux-ci seront affichés sous forme de balayages sur le premier message lors du démarrage d’une nouvelle discussion.\n Les membres du groupe peuvent en sélectionner un pour lancer la conversation.", + "(This will be the first message from the character that starts every chat)": "(Ce sera le premier message du personnage qui démarre chaque discussion)", + "Forbid Media Override explanation": "Capacité du personnage/groupe actuel à utiliser des médias externes dans les discussions.", + "Forbid Media Override subtitle": "Médias : images, vidéos, audio. Externe : non hébergé sur le serveur local.", + "Always forbidden": "Toujours interdit", + "Always allowed": "Toujours permis", + "View contents": "Voir le contenu", + "Remove the file": "Supprimer le fichier", + "Unique to this chat": "Unique à ce chat", + "Checkpoints inherit the Note from their parent, and can be changed individually after that.": "Les points de contrôle héritent de la note de leur parent et peuvent ensuite être modifiés individuellement.", + "Include in World Info Scanning": "Inclure dans l'analyse des Wold Info", + "Before Main Prompt / Story String": "Avant le prompt principal/la chaîne d'histoire", + "After Main Prompt / Story String": "Après le prompt principal/la chaîne d'histoire", + "as": "comme", + "Insertion Frequency": "Fréquence d'insertion", + "(0 = Disable, 1 = Always)": "(0 = Désactiver, 1 = Toujours)", + "User inputs until next insertion:": "Saisies de l'utilisateur jusqu'à la prochaine insertion :", + "Character Author's Note (Private)": "Note d'auteur du personnage (privé)", + "Won't be shared with the character card on export.": "Ne sera pas partagé avec la carte de personnage lors de l'exportation.", + "Will be automatically added as the author's note for this character. Will be used in groups, but can't be modified when a group chat is open.": "Sera automatiquement ajouté comme note d'auteur pour ce personnage. Sera utilisé en groupe, mais\n ne peut pas être modifié lorsqu'une discussion de groupe est ouverte.", + "Use character author's note": "Utiliser la note d'auteur du personnage", + "Replace Author's Note": "Remplacer la note d'auteur", + "Default Author's Note": "Note d'auteur par défaut", + "Will be automatically added as the Author's Note for all new chats.": "Sera automatiquement ajouté en tant que note d'auteur pour toutes les nouvelles discussions.", + "Chat CFG": "Chat CFG", + "1 = disabled": "1 = désactivé", + "write short replies, write replies using past tense": "rédiger des réponses courtes, rédiger des réponses en utilisant le passé", + "Positive Prompt": "Prompt positif", + "Use character CFG scales": "Utiliser les échelles CFG du personnage", + "Character CFG": "CFG du personnage", + "Will be automatically added as the CFG for this character.": "Sera automatiquement ajouté en tant que CFG pour ce personnage.", + "Global CFG": "CFG global", + "Will be used as the default CFG options for every chat unless overridden.": "Sera utilisé comme options CFG par défaut pour chaque discussion, sauf remplacement.", + "CFG Prompt Cascading": "Prompt CFG en cascade", + "Combine positive/negative prompts from other boxes.": "Combinez les prompts positifs/négatifs d’autres cases.", + "For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string.": "Par exemple, en cochant les cases Chat, Global et Personnage, vous combinez tout les prompt négatifs dans une chaîne séparée par des virgules.", + "Always Include": "Toujours inclure", + "Chat Negatives": "Points négatifs du chat", + "Character Negatives": "Points négatifs du personnage", + "Global Negatives": "Points négatifs globaux", + "Custom Separator:": "Séparateur personnalisé :", + "Insertion Depth:": "Profondeur d'insertion :", + "Token Probabilities": "Probabilités des tokens", + "Select a token to see alternatives considered by the AI.": "Sélectionnez un token pour voir les alternatives envisagées par l'IA.", + "Not connected to API!": "Non connecté à l'API !", + "Type a message, or /? for help": "Tapez un message, ou /? pour l'aide", + "Continue script execution": "Continuer l'exécution du script", + "Pause script execution": "Suspendre l'exécution du script", + "Abort script execution": "Abandonner l'exécution du script", + "Abort request": "Annuler la requête", + "Continue the last message": "Continuer le dernier message", + "Send a message": "Envoyer un message", + "Close chat": "Fermer la discussion", + "Toggle Panels": "Basculer les panneaux", + "Back to parent chat": "Retour à la conversation parente", + "Save checkpoint": "Enregistrer le point de contrôle", + "Convert to group": "Convertir en groupe", + "Start new chat": "Démarrer une nouvelle conversation", + "Manage chat files": "Gérer les fichiers de discussion", + "Delete messages": "Supprimer les messages", + "Regenerate": "Regénérer", + "Ask AI to write your message for you": "Demander à l'IA d'écrire votre message pour vous", + "Impersonate": "Usurper l'identité", + "Continue": "Continuer", + "Bind user name to that avatar": "Lier le nom d'utilisateur à cette persona", + "Change persona image": "Changer l'image de la persona", + "Select this as default persona for the new chats.": "Sélectionner ceci comme persona par défaut pour les nouvelles discussions.", + "Delete persona": "Supprimer la persona", + "These characters are the winners of character design contests and have outstandable quality.": "Ces personnages sont les gagnants de concours de conception de personnages et ont une qualité exceptionnelle.", + "Contest Winners": "Gagnants du concours", + "These characters are the finalists of character design contests and have remarkable quality.": "Ces personnages sont les finalistes des concours de conception de personnages et ont une qualité remarquable.", + "Featured Characters": "Personnages en vedette", + "Attach a File": "Joindre un fichier", + "Open Data Bank": "Ouvrir la banque de données", + "Enter a URL or the ID of a Fandom wiki page to scrape:": "Entrez une URL ou l'ID d'une page wiki Fandom à  :", + "Examples:": "Exemples:", + "Example:": "Exemple:", + "Single file": "Un seul fichier", + "All articles will be concatenated into a single file.": "Tous les articles seront concaténés dans un seul fichier.", + "File per article": "Fichier par article", + "Each article will be saved as a separate file.": "Non recommandé. Chaque article sera enregistré dans un fichier distinct.", + "Data Bank": "Banque de données", + "These files will be available for extensions that support attachments (e.g. Vector Storage).": "Ces fichiers seront disponibles pour les extensions prenant en charge les pièces jointes (par exemple Vector Storage).", + "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.": "Types de fichiers pris en charge : texte brut, PDF, Markdown, HTML, EPUB.", + "Drag and drop files here to upload.": "Faites glisser et déposez les fichiers ici pour les télécharger.", + "Date (Newest First)": "Date (le plus récent en premier)", + "Date (Oldest First)": "Date (le plus ancien en premier)", + "Name (A-Z)": "Nom (A-Z)", + "Name (Z-A)": "Nom (Z-A)", + "Size (Smallest First)": "Taille (la plus petite en premier)", + "Size (Largest First)": "Taille (la plus grande en premier)", + "Bulk Edit": "Modification groupée", + "Select All": "Tout sélectionner", + "Select None": "Ne rien sélectionner", + "Global Attachments": "Pièces jointes globales", + "These files are available for all characters in all chats.": "Ces fichiers sont disponibles pour tous les personnages de toutes les discussions.", + "Character Attachments": "Pièces jointes aux personnages", + "Saved locally. Not exported.": "Enregistré localement. Non exporté.", + "Chat Attachments": "Pièces jointes au chat", + "Enter a base URL of the MediaWiki to scrape.": "Entrez une URL de base du MediaWiki à récupérer.", + "Don't include the page name!": "N'incluez pas le nom de la page !", + "Enter web URLs to scrape (one per line):": "Entrez les URL Web à récupérer (une par ligne) :", + "Enter a video URL to download its transcript.": "Saisissez l'URL de la vidéo pour télécharger sa transcription.", + "ext_sum_with": "Résumez avec :", + "ext_sum_main_api": "API principale", + "ext_sum_current_summary": "Résumé actuel :", + "ext_sum_restore_previous": "Rétablir le précédente", + "ext_sum_memory_placeholder": "Le résumé sera généré ici...", + "ext_sum_force_text": "Résumez maintenant", + "Disable automatic summary updates. While paused, the summary remains as-is. You can still force an update by pressing the Summarize now button (which is only available with the Main API).": "Désactivez les mises à jour automatiques du résumé. Pendant la pause, le résumé reste tel quel. Vous pouvez toujours forcer une mise à jour en appuyant sur le bouton Résumer maintenant (qui n'est disponible qu'avec l'API principale).", + "ext_sum_pause": "Pause", + "Omit World Info and Author's Note from text to be summarized. Only has an effect when using the Main API. The Extras API always omits WI/AN.": "Omettre World Info et la note d'auteur du texte à résumer. N'a d'effet que lors de l'utilisation de l'API principale. L'API Extras omet toujours WI/AN.", + "ext_sum_no_wi_an": "Pas de WI/NA", + "ext_sum_settings_tip": "Modifier le prompt de résumé, la position d'insertion, etc.", + "ext_sum_settings": "Paramètres du résumé", + "ext_sum_prompt_builder": "Générateur de prompt", + "ext_sum_prompt_builder_1_desc": "L'extension créera son propre prompt en utilisant des messages qui n'ont pas encore été résumés. Bloque le chat jusqu'à ce que le résumé soit généré.", + "ext_sum_prompt_builder_1": "Brut, bloquant", + "ext_sum_prompt_builder_2_desc": "L'extension créera son propre prompt en utilisant des messages qui n'ont pas encore été résumés. Ne bloque pas le chat pendant la génération du résumé. Tous les backends ne prennent pas en charge ce mode.", + "ext_sum_prompt_builder_2": "Brut, non bloquant", + "ext_sum_prompt_builder_3_desc": "L'extension utilisera le générateur de prompt principal standard et y ajoutera la demande de résumé comme dernier message système.", + "ext_sum_prompt_builder_3": "Classique, bloquant", + "Summary Prompt": "Prompt de résumé", + "ext_sum_restore_default_prompt_tip": "Restaurer le prompt par défaut", + "ext_sum_prompt_placeholder": "Ce prompt sera envoyée à l'IA pour demander la génération du résumé. {{words}} sera résolu par le paramètre \"Nombre de mots\".", + "ext_sum_target_length_1": "Longueur cible du résumé", + "ext_sum_target_length_2": null, + "ext_sum_target_length_3": "mots)", + "ext_sum_api_response_length_1": "Longueur de réponse de l'API", + "ext_sum_api_response_length_2": null, + "ext_sum_api_response_length_3": "tokens)", + "ext_sum_0_default": "0 = par défaut", + "ext_sum_raw_max_msg": "[Brut] Nombre maximum de messages par requête", + "ext_sum_0_unlimited": "0 = illimité", + "Update frequency": "Fréquence de mise à jour", + "ext_sum_update_every_messages_1": "Mettre à jour tous les", + "ext_sum_update_every_messages_2": "messages", + "ext_sum_0_disable": "0 = désactiver", + "ext_sum_auto_adjust_desc": "Essayez d'ajuster automatiquement l'intervalle en fonction des mesures du chat.", + "ext_sum_update_every_words_1": "Mettre à jour tous les", + "ext_sum_update_every_words_2": "mots", + "ext_sum_both_sliders": "Si les deux curseurs sont différents de zéro, ils déclencheront tous deux des mises à jour récapitulatives à leurs intervalles respectifs.", + "ext_sum_injection_template": "Modèle d'injection", + "ext_sum_memory_template_placeholder": "{{summary}} sera résolu selon le contenu du résumé actuel.", + "ext_sum_injection_position": "Position d'injection", + "How many messages before the current end of the chat.": "Combien de messages avant la fin actuelle du chat.", + "ext_regex_title": "Expression régulière", + "ext_regex_new_global_script": "+ Mondial", + "ext_regex_new_scoped_script": "+ Portée", + "ext_regex_import_script": "Importer", + "ext_regex_global_scripts": "Scripts globaux", + "ext_regex_global_scripts_desc": "Disponible pour tous les personnages. Enregistré dans les paramètres locaux.", + "ext_regex_scoped_scripts": "Scripts étendus", + "ext_regex_scoped_scripts_desc": "Uniquement disponible pour ce personnage. Enregistré dans les données de la carte.", + "Regex Editor": "Éditeur d'expressions régulières", + "Test Mode": "Mode de test", + "ext_regex_desc": "Regex est un outil pour rechercher/remplacer des chaînes à l'aide d'expressions régulières. Si vous souhaitez en savoir plus, cliquez sur ? à côté du titre.", + "Input": "Saisir", + "ext_regex_test_input_placeholder": "Écrivez ici...", + "Output": "Sortir", + "ext_regex_output_placeholder": "Vide", + "Script Name": "Nom du script", + "Find Regex": "Trouver une expression régulière", + "Replace With": "Remplacer par", + "ext_regex_replace_string_placeholder": "Utilisez {{match}} pour inclure le texte correspondant de Find Regex ou $1, $2, etc. pour les groupes de capture.", + "Trim Out": "Couper", + "ext_regex_trim_placeholder": "Supprime globalement toutes les pièces indésirables d’une correspondance d’expression régulière avant le remplacement. Séparez chaque élément par une entrée.", + "ext_regex_affects": "Affecte", + "ext_regex_user_input": "Entrée de l'utilisateur", + "ext_regex_ai_output": "Sortie IA", + "Slash Commands": "Commandes barre oblique", + "ext_regex_min_depth_desc": "Lorsqu'il est appliqué aux prompts ou à l'affichage, n'affecte que les messages d'au moins N niveaux de profondeur. 0 = dernier message, 1 = avant-dernier message, etc. Ne compte que les entrées WI @Depth et les messages utilisables, c'est-à-dire non cachés ou système.", + "Min Depth": "Profondeur minimale", + "ext_regex_min_depth_placeholder": "Illimité", + "ext_regex_max_depth_desc": "Lorsqu'il est appliqué aux prompts ou à l'affichage, n'affecte que les messages en profondeur ne dépassant pas N niveaux. 0 = dernier message, 1 = avant-dernier message, etc. Ne compte que les entrées WI @Depth et les messages utilisables, c'est-à-dire non cachés ou système.", + "ext_regex_other_options": "Autres options", + "Only Format Display": "Format d'affichage uniquement", + "ext_regex_only_format_prompt_desc": "L'historique des discussions ne changera pas, seule l'invite lors de l'envoi de la demande (lors de la génération).", + "Only Format Prompt (?)": "Uniquement l'invite de formatage", + "Run On Edit": "Exécuter sur Modifier", + "ext_regex_substitute_regex_desc": "Remplacez {{macros}} dans Find Regex avant de l'exécuter", + "ext_regex_import_target": "Importer vers :", + "ext_regex_disable_script": "Désactiver le script", + "ext_regex_enable_script": "Activer le script", + "ext_regex_edit_script": "Modifier le script", + "ext_regex_move_to_global": "Passer aux scripts globaux", + "ext_regex_move_to_scoped": "Passer aux scripts étendus", + "ext_regex_export_script": "Exporter le script", + "ext_regex_delete_script": "Supprimer le script", + "Trigger Stable Diffusion": "Déclencher Stable Diffusion", + "sd_Yourself": "Vous-même", + "sd_Your_Face": "Votre visage", + "sd_Me": "Moi", + "sd_The_Whole_Story": "Toute l'histoire", + "sd_The_Last_Message": "Le dernier message", + "sd_Raw_Last_Message": "Dernier message brut", + "sd_Background": "Arrière-plan", + "Image Generation": "Génération d'images", + "sd_refine_mode": "Autoriser la modification manuelle des prompts avant de les envoyer à l'API de génération", + "sd_refine_mode_txt": "Modifier les prompts avant la génération", + "sd_interactive_mode": "Générez automatiquement des images lors de l'envoi de messages tels que « envoyez-moi une photo de chat ».", + "sd_interactive_mode_txt": "Mode interactif", + "sd_multimodal_captioning": "Utilisez le sous-titrage multimodal pour générer des prompts pour les portraits des utilisateurs et des personnages en fonction de leurs avatars.", + "sd_multimodal_captioning_txt": "Utiliser le sous-titrage multimodal pour les portraits", + "sd_snap": "Requêtes de génération d'instantanés avec un rapport hauteur/largeur forcé (portraits, arrière-plans) à la résolution connue la plus proche, tout en essayant de préserver le nombre absolu de pixels (recommandé pour SDXL).", + "sd_snap_txt": "Résolutions ajustées automatiquement", + "Source": "Source", + "sd_auto_url": "Exemple : {{auto_url}}", + "Authentication (optional)": "Authentification (facultatif)", + "Example: username:password": "Exemple : nom d'utilisateur : mot de passe", + "Important:": "Important:", + "sd_auto_auth_warning_1": "exécuter l'interface utilisateur Web SD avec le", + "sd_auto_auth_warning_2": "drapeau! Le serveur doit être accessible depuis la machine hôte de SillyTavern.", + "sd_drawthings_url": "Exemple : {{drawthings_url}}", + "sd_drawthings_auth_txt": "exécutez l'application DrawThings avec le commutateur API HTTP activé dans l'interface utilisateur ! Le serveur doit être accessible depuis la machine hôte de SillyTavern.", + "sd_vlad_url": "Exemple : {{vlad_url}}", + "The server must be accessible from the SillyTavern host machine.": "Le serveur doit être accessible depuis la machine hôte de SillyTavern.", + "Hint: Save an API key in AI Horde API settings to use it here.": "Astuce : enregistrez une clé API dans les paramètres de l'API AI Horde pour l'utiliser ici.", + "Allow NSFW images from Horde": "Autoriser les images NSFW de la Horde", + "Sanitize prompts (recommended)": "Désinfecter les prompts (recommandé)", + "Automatically adjust generation parameters to ensure free image generations.": "Ajustez automatiquement les paramètres de génération pour garantir des générations d’images gratuites.", + "Avoid spending Anlas": "Évitez de dépenser des Anlas", + "Opus tier": "(Tier Opus)", + "View my Anlas": "Voir mes Anlas", + "These settings only apply to DALL-E 3": "Ces paramètres s'appliquent uniquement à DALL-E 3", + "Image Style": "Style de l'image", + "Image Quality": "Qualité de l'image", + "Standard": "Standard", + "HD": "HD", + "sd_comfy_url": "Exemple : {{comfy_url}}", + "Open workflow editor": "Ouvrir l'éditeur de workflow", + "Create new workflow": "Créer un nouveau workflow", + "Delete workflow": "Supprimer le workflow", + "Enhance": "Améliorer", + "Decrisper": "Décrypteur", + "Sampling steps": "Étapes d'échantillonnage ()", + "Width": "Largeur", + "Height": "Hauteur", + "Resolution": "Résolution", + "Model": "Modèle", + "Sampling method": "Méthode d'échantillonnage", + "SMEA versions of samplers are modified to perform better at high resolution.": "Les versions SMEA des échantillonneurs sont modifiées pour mieux fonctionner à haute résolution.", + "SMEA": "SDMEA", + "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "Les variantes DYN des échantillonneurs SMEA conduisent souvent à des sorties plus variées, mais peuvent échouer à des résolutions très élevées.", + "DYN": "DYN", + "Scheduler": "Planificateur", + "Restore Faces": "Restaurer les visages", + "Hires. Fix": "Hires. Fix", + "Upscaler": "Upscaleur", + "Upscale by": "Upscale par", + "Denoising strength": "Force de débruitage", + "Hires steps (2nd pass)": "Nombre d'étapes Hires (2ème passage)", + "Preset for prompt prefix and negative prompt": "Preset pour le préfixe de prompt et le prompt négatif", + "Style": "Style", + "Save style": "Enregistrer le style", + "Delete style": "Supprimer le style", + "Common prompt prefix": "Préfixe de prompt commun", + "sd_prompt_prefix_placeholder": "Utilisez {prompt} pour spécifier où le prompt générée sera insérée", + "Negative common prompt prefix": "Préfixe de prompt commun négatif", + "Character-specific prompt prefix": "Préfixe de prompt spécifique au personnage", + "Won't be used in groups.": "Ne sera pas utilisé en groupe.", + "sd_character_prompt_placeholder": "Toutes les caractéristiques qui décrivent le personnage actuellement sélectionné. Sera ajouté après un préfixe de prompt commun.\nExemple : femme, yeux verts, cheveux bruns, chemise rose", + "Character-specific negative prompt prefix": "Préfixe de prompt négatif spécifique au personnage", + "sd_character_negative_prompt_placeholder": "Toutes les caractéristiques qui ne devraient pas apparaître pour le personnage sélectionné. Sera ajouté après un préfixe dde prompt commun négatif.\nExemple : bijoux, chaussures, lunettes", + "Shareable": "Partageable", + "Image Prompt Templates": "Modèles de prompt d'image", + "Translate files into English before processing": "Traduire les fichiers en anglais avant le traitement", + "Manager Users": "gérer les utilisateurs", + "New User": "Nouvel utilisateur", + "Status:": "Statut:", + "Created:": "Créé:", + "Display Name:": "Afficher un nom:", + "User Handle:": "Identifiant utilisateur :", + "Password:": "Mot de passe:", + "Confirm Password:": "Confirmez le mot de passe:", + "This will create a new subfolder...": "Cela créera un nouveau sous-dossier dans le répertoire /data/ avec le handle de l'utilisateur comme nom de dossier.", + "Current Password:": "Mot de passe actuel:", + "New Password:": "Nouveau mot de passe:", + "Confirm New Password:": "Confirmer le nouveau mot de passe:", + "Execute": "Exécuter", + "Are you sure you want to delete this user?": "Êtes-vous sûr de vouloir supprimer cet utilisateur ?", + "Deleting:": "Suppression :", + "Also wipe user data.": "Effacez également les données utilisateur.", + "Warning:": "Avertissement:", + "This action is irreversible.": "Cette action est irréversible.", + "Type the user's handle below to confirm:": "Tapez le pseudo de l'utilisateur ci-dessous pour confirmer :", + "Import Characters": "Importer des personnages", + "Enter the URL of the content to import": "Saisissez l'URL du contenu à importer", + "Supported sources:": "Sources prises en charge :", + "char_import_1": "Personnage de Chub (lien direct ou identifiant)", + "char_import_example": "Exemple:", + "char_import_2": "Lorebook de Chub (lien direct ou ID)", + "char_import_3": "Personnage de JanitorAI (lien direct ou UUID)", + "char_import_4": "Personnage de Pygmalion.chat (lien direct ou UUID)", + "char_import_5": "Personnage de AICharacterCards.com (lien direct ou identifiant)", + "char_import_6": "Lien PNG direct (voir", + "char_import_7": "pour les hôtes autorisés)", + "char_import_8": "Personnage de RisuRealm (lien direct)", + "Supports importing multiple characters.": "Prend en charge l'importation de plusieurs caractères.", + "Write each URL or ID into a new line.": "Écrivez chaque URL ou identifiant dans une nouvelle ligne.", + "Export for character": "Exportation pour le personnage", + "Export prompts for this character, including their order.": "Exportez les invites pour ce personnage, y compris leur ordre.", + "Export all": "Exporter tout", + "Export all your prompts to a file": "Exportez toutes vos invites dans un fichier", + "Insert prompt": "Insérer une invitation", + "Delete prompt": "Supprimer l'invitation", + "Import a prompt list": "Importer une liste d'invitations", + "Export this prompt list": "Exporter cette liste d'invitations", + "Reset current character": "Réinitialiser le personnage actuel", + "New prompt": "Nouvelle invitation", + "Prompts": "Invitations", + "Total Tokens:": "Tokens totaux :", + "prompt_manager_tokens": "Tokens", + "Are you sure you want to reset your settings to factory defaults?": "Êtes-vous sûr de vouloir réinitialiser vos paramètres aux valeurs d'usine par défaut ?", + "Don't forget to save a snapshot of your settings before proceeding.": "N'oubliez pas d'enregistrer un instantané de vos paramètres avant de continuer.", + "Settings Snapshots": "Paramètres des instantanés", + "Record a snapshot of your current settings.": "Enregistrez un instantané de vos paramètres actuels.", + "Make a Snapshot": "Faire un instantané", + "Restore this snapshot": "Restaurer cet instantané", + "Hi,": "Salut,", + "To enable multi-account features, restart the SillyTavern server with": "Pour activer les fonctionnalités multi-comptes, redémarrez le serveur SillyTavern avec", + "set to true in the config.yaml file.": "défini sur true dans le fichier config.yaml.", + "Account Info": "Informations de compte", + "To change your user avatar, use the buttons below or select a default persona in the Persona Management menu.": "Pour modifier votre avatar utilisateur, utilisez les boutons ci-dessous ou sélectionnez un personnage par défaut dans le menu Gestion des personnages.", + "Set your custom avatar.": "Définissez votre avatar personnalisé.", + "Remove your custom avatar.": "Supprimez votre avatar personnalisé.", + "Handle:": "Poignée:", + "This account is password protected.": "Ce compte est protégé par mot de passe.", + "This account is not password protected.": "Ce compte n'est pas protégé par mot de passe.", + "Account Actions": "Actions du compte", + "Change Password": "Changer le mot de passe", + "Manage your settings snapshots.": "Gérez vos instantanés de paramètres.", + "Download a complete backup of your user data.": "Téléchargez une sauvegarde complète de vos données utilisateur.", + "Download Backup": "Télécharger la sauvegarde", + "Danger Zone": "Zone dangereuse", + "Reset your settings to factory defaults.": "Réinitialisez vos paramètres aux valeurs par défaut d'usine.", + "Reset Settings": "Réinitialiser les options", + "Wipe all user data and reset your account to factory settings.": "Effacez toutes les données utilisateur et réinitialisez votre compte aux paramètres d'usine.", + "Reset Everything": "Tout réinitialiser", + "Reset Code:": "Code de réinitialisation :", + "Want to update?": "Envie de mettre à jour ?", + "How to start chatting?": "Comment commencer à discuter ?", + "Click _space": "Cliquez sur", + "and pick a character.": "et choisissez un personnage.", + "Download Extensions & Assets": "Télécharger des extensions et des ressources", + "menu within": "à l'intérieur de", + "Confused or lost?": "Confus ou perdu ?", + "click these icons!": "cliquez sur ces icônes !", + "in the chat bar": "dans la barre de chat", + "SillyTavern Documentation Site": "Documentation de SillyTavern", + "Still have questions?": "Vous avez encore des questions ?", + "Join the SillyTavern Discord": "Rejoignez le Discord de SillyTavern", + "Post a GitHub issue": "Poster un problème sur GitHub", + "Contact the developers": "Contacter les développeurs", + "Rename current preset": "Renommer le preset actuel", + "Linear": "Linéaire", + "Quad": "Quad", + "Conf": "Conf", + "Middle-out Transform": "Transformation Middle-out", + "Auto": "Auto", + "Allow": "Autoriser", + "Forbid": "Interdire", + "Auxiliary": "Auxiliaire", + "Post-History Instructions": "Instructions post-histoire", + "Unified Sampling": "Échantillonnage unifié", + "Top nsigma": "Top nsigma", + "Exclude Top Choices (XTC)": "Exclure les Top Choices (XTC)", + "Threshold": "Seuil", + "A greedy, brute-force algorithm used in LLM sampling to find the most likely sequence of words or tokens. It expands multiple candidate sequences at once, maintaining a fixed number (beam width) of top sequences at each step.": "Un algorithme gourmand et brutal utilisé dans l'échantillonnage LLM pour trouver la séquence de mots ou de tokens la plus probable. Il développe plusieurs séquences candidates à la fois, en conservant un nombre fixe (largeur du faisceau) de séquences supérieures à chaque étape.", + "# of Beams": "# de faisceaux", + "The number of sequences generated at each step with Beam Search.": "Le nombre de séquences générées à chaque étape avec Beam Search.", + "Penalize sequences based on their length.": "Pénaliser les séquences en fonction de leur longueur.", + "Controls the stopping condition for beam search. If checked, the generation stops as soon as there are '# of Beams' sequences. If not checked, a heuristic is applied and the generation is stopped when it's very unlikely to find better candidates.": "Contrôle la condition d'arrêt de la recherche de faisceaux. Si cette case est cochée, la génération s'arrête dès qu'il y a « # of Beams » séquences. Si cette case n'est pas cochée, une heuristique est appliquée et la génération est arrêtée lorsqu'il est très peu probable de trouver de meilleurs candidats.", + "Seed_desc": "Une graine aléatoire à utiliser pour obtenir des résultats déterministes et reproductibles. Définir à -1 pour utiliser une graine aléatoire.", + "Sampler Order": "Ordre des échantillonneurs", + "Aphrodite only. Determines the order of samplers. Skew is always applied post-softmax, so it's not included here.": "Aphrodite seulement. Determines l'ordres des échantillonneurs. L'obliquité est toujours appliquée après le softmax, elle n'est donc pas incluse ici.", + "Aphrodite only. Determines the order of samplers.": "Aphrodite seulement. Determines l'ordres des échantillonneurs.", + "character_names_none": "Ne jamais ajouter de préfixes de noms de personnages. Peut mal se comporter en groupe, à choisir avec précaution.", + "Completion Object": "Completion Object", + "enable_functions_desc_1": "Autorise l'utilisation", + "enable_functions_desc_2": "outils de fonction", + "enable_functions_desc_3": "Peut être utilisé par diverses extensions pour fournir des fonctionnalités supplémentaires.", + "Request model reasoning": "Demander les pensées du modèle", + "Allows the model to return its thinking process.": "Permet au modèle de retourner son processus de réflexion.", + "Confirm token parsing with": "Confirmer l'analyse des tokens avec", + "openai_logit_bias_no_items": "Aucun élément", + "api_no_connection": "Pas de connection...", + "AI Horde Website": "Site Web de AI Horde", + "Generic (OpenAI-compatible) [LM Studio, LiteLLM, etc.]": "Générique (OpenAI-compatible) [LM Studio, LiteLLM, etc.]", + "Allow fallback providers": "Autoriser les fournisseurs de secours", + "Model ID (optional)": "Model ID (optionnel)", + "Featherless Model Selection": "Séléction de modèle Featherless", + "category": "categorie", + "Top": "Top", + "All": "Tous", + "class": "Toutes les classes", + "No model description": "[Pas de déscription]", + "HuggingFace Token": "Token HuggingFace", + "Endpoint URL": "URL Endpoint", + "Example: https://****.endpoints.huggingface.cloud": "Exemple: https://****.endpoints.huggingface.cloud", + "Tabby Model": "Modèle Tabby", + "must be set in Tabby's config.yml to switch models.": "doit être défini dans le fichier config.yml de Tabby pour changer de modèle.", + "Use an admin API key.": "Utiliser une clé API d'administrateur.", + "Derive context size from backend": "Déterminer la taille du contexte à partir du backend", + "Custom (OpenAI-compatible)": "Personnalisé (OpenAI-compatible)", + "Using a proxy that you're not running yourself is a risk to your data privacy.": "L'utilisation d'un proxy que vous ne gérez pas vous-même présente un risque pour la confidentialité de vos données.", + "ANY support requests will be REFUSED if you are using a proxy.": "TOUTE demande d'assistance sera REFUSÉE si vous utilisez un proxy.", + "Do not proceed if you do not agree to this!": "Ne continuez pas si vous n'êtes pas d'accord avec cela !", + "Claude API Key": "Clé API Claude", + "Allow fallback models": "Autoriser les modèles de secours", + "NanoGPT API Key": "Clé API NanoGPT", + "NanoGPT Model": "Modèle NanoGPT", + "DeepSeek API Key": "Clé API DeepSeek", + "DeepSeek Model": "Modèle DeepSeek", + "Block Entropy API Key": "Clé API Block Entropy", + "Select a Model": "Sélectionner un modèle", + "Example: http://localhost:1234/v1": "Exemple: http://localhost:1234/v1", + "(Optional)": "(Optionnel)", + "Enter a Model ID": "Saisir un ID de modèle", + "Example: gpt-3.5-turbo": "Exemple: gpt-3.5-turbo", + "prompt_post_processing_none": "Aucun", + "prompt_post_processing_merge": "Fusionner les rôles consécutifs", + "prompt_post_processing_semi": "Semi-strict (rôles alternés)", + "prompt_post_processing_strict": "Strict (l'utilisateur d'abord, rôles alternés)", + "01.AI API Key": "01.Clé IA API", + "01.AI Model": "01.Modèle IA", + "Additional Parameters": "Paramètres supplémentaires", + "Import Advanced Formatting settings": "Importer les paramètres de formatage avancé\n\nVous pouvez également fournir des fichiers hérités pour les modèles Instruct et Context..", + "Master Import": "Master Import", + "Export Advanced Formatting settings": "Exporter les paramètres de formatage avancé", + "Master Export": "Master Export", + "context_derived": "Dériver des métadonnées du modèle, si possible.", + "Select your current Context Template": "Sélectionnez votre modèle de contexte actuel", + "Update current template": "Mise à jour du modèle actuel", + "Rename current template": "Renommer le modèle actuel", + "Save template as": "Enregistrer le modèle sous", + "Import template": "Importer un modèle", + "Export template": "Exporter un modèle", + "Restore current template": "Restaurer le modèle actuel", + "Delete the template": "Supprimer le modèle", + "Disabling is not recommended.": "La désactivation n'est pas recommandée.", + "Separators as Stop Strings": "Séparateurs comme chaînes d'arrêt", + "Add Character and User names to a list of stopping strings.": "Ajouter les noms de personnages et d'utilisateurs à une liste de chaînes d'arrêt.", + "Names as Stop Strings": "Noms comme chaînes d'arrêt", + "context_allow_post_history_instructions": "Inclut les instructions post-historiques à la fin du prompt, si elles sont définies dans la fiche de personnage ET si l'option 'Préférer les instructions de personnage' est activée.\nN'EST PAS RECOMMANDÉ POUR LES MODÈLES DE COMPLÉTION DE TEXTE, CAR IL PEUT ENTRAÎNER DE MAUVAIS RÉSULTATS.", + "Allow Post-History Instructions": "Autoriser les instructions post-histoire", + "Instruct Template": "Modèle d'instruction", + "instruct_derived": "Dériver des métadonnées du modèle, si possible.", + "instruct_enabled": "Activer le mode d'instruction", + "Select your current Instruct Template": "Sélectionnez votre modèle d'instruction actuel", + "Delete template": "Supprimer le modèle", + "instruct_template_activation_regex_desc": "Lors de la connexion à une API ou du choix d'un modèle, ce modèle d'instruction est automatiquement activé si le nom du modèle correspond à l'expression régulière fournie.", + "Never": "Jamais", + "Groups and Past Personas": "Groupes et personas antérieures", + "Always": "Toujours", + "Instruct Sequences": "Séquences d'instruction", + "User Message Sequences": "Séquences de messages d'utilisateurs", + "User Prefix": "Préfixe du message de l'utilisateur", + "User Suffix": "Suffixe du message de l'utilisateur", + "Assistant Message Sequences": "Séquences de messages de l'assistant", + "Assistant Prefix": "Préfixe du message de l'assistant", + "Assistant Suffix": "Suffixe du message de l'assistant", + "System Message Sequences": "Séquences de messages système", + "System Prefix": "Préfixe des messages système", + "System Suffix": "Suffixe des messages du système", + "System Prompt Sequences": "Séquences du prompt système", + "Inserted before the first User's message.": "Inséré avant le premier message de l'utilisateur.", + "First User Prefix": "Préfixe du premier utilisateur", + "instruct_last_input_sequence": "Inséré avant le dernier message de l'utilisateur.", + "Last User Prefix": "Préfixe du dernier utilisateur", + "sysprompt_enabled": "Activer le prompt système", + "Select your current System Prompt": "Sélectionnez votre prompt système actuel", + "Update current prompt": "Mise à jour du prompt actuel", + "Rename current prompt": "Renommer le prompt actuel", + "Save prompt as": "Enregistrer le prompt sous", + "Restore current prompt": "Restaurer le prompt actuel", + "Prompt Content": "Contenu du prompt", + "comma delimited,no spaces between": "délimité par des virgules, sans espace entre", + "(disabled when max recursion steps are used)": "(désactivé lorsque le nombre maximum de pas de récursivité est utilisé)", + "Cap the number of entry activation recursions": "Plafonner le nombre de récursions d'activation d'entrée", + "Max Recursion Steps": "Nombre maximal d'étapes de récursivité", + "0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc": "0 = illimité, 1 = scanne une fois et ne récure pas, 2 = scanne une fois et récure une fois, etc.\n(désactivé lorsque des activations minimales sont utilisées)", + "Include names with each message into the context for scanning": "Inclure les noms dans chaque message dans le contexte pour l'analyse.", + "Apply current sorting as Order": "Appliquer le tri actuel comme ordre", + "Display swipe numbers for all messages, not just the last.": "Afficher le nombre de balayage sur tous les messages, et pas seulement le dernier.", + "Swipe # for All Messages": "Balayage # pour tous les messages", + "Defines on importing cards which action should be chosen for importing its listed tags. 'Ask' will always display the dialog.": "Définit, lors de l'importation de cartes, l'action à choisir pour importer les tags répertoriés. L'action 'Demander' affichera toujours la boîte de dialogue.", + "Ask": "Demander", + "tag_import_none": "Aucun", + "tag_import_all": "Tous", + "tag_import_existing": "Existant", + "If checked and the character card contains a Post-History Instructions override, use that instead": "Si cette case est cochée et que la carte de personnage contient une instruction de remplacement pour le post-histoire, utilisez-la à la place.", + "Prefer Character Card Instructions": "Préférer les instructions du personnage", + "Enable auto-select of input text in some text fields when clicking/selecting them. Applies to popup input textboxes, and possible other custom input fields.": "Active la sélection automatique du texte saisi dans certains champs de texte lorsque l'on clique dessus ou qu'on les sélectionne. S'applique aux zones de texte de type popup et, éventuellement, à d'autres champs de saisie personnalisés.", + "Auto-select Input Text": "Sélection automatique du texte d'entrée", + "markdown_hotkeys_desc": "Activer les raccourcis clavier pour l'insertion de caractères au format markdown dans certaines zones de saisie de texte. Voir '/help hotkeys'.", + "Markdown Hotkeys": "Markdown Hotkeys", + "mui_reset": "Réinitialisation", + "Show a button in the input area to ask the AI to impersonate your character for a single message": "Affichez un bouton dans la zone de saisie pour demander à l'IA de se faire passer pour votre personnage le temps d'un message.", + "Quick 'Impersonate' button": "Bouton \"Usurpation\" rapide", + "In group chat, highlight the character(s) that are currently queued to generate responses and the order in which they will respond.": "Dans le chat de groupe, mettez en évidence le(s) personnage(s) qui sont actuellement en file d'attente pour générer des réponses et l'ordre dans lequel ils répondront.", + "Show group chat queue": "Afficher la file d'attente du chat de groupe", + "Keyboard": "Clavier:", + "Select with Tab or Enter": "Sélectionner avec Tab ou Entrée", + "Select with Tab": "Sélectionner avec Tab", + "Select with Enter": "Sélectionner avec Entrée", + "stscript_parser_flag_replace_getvar_label": "Empêche les macros {{getvar::}} {{getglobalvar::}} d'avoir des valeurs littérales de type macro auto-évaluées.\nPar exemple, \"{{newline}}\" reste la chaîne littérale \"{{newline}}\"\n\n((Cela se fait en remplaçant en interne les macros {{getvar::}} {{getglobalvar::}} par des variables scopées)", + "Background Image": "Arrière-plans", + "Background Fitting": "Ajustement de l'arrière-plan", + "Classic": "Classique", + "Cover": "Couvrir", + "Contain": "Contenir", + "Stretch": "Étirer", + "Center": "Centrer", + "Persona Lore Alt+Click to open the lorebook": "Lore de persona\nAlt+Click pour ouvrir le lorebook", + "None (disabled)": "Aucun (désactivé)", + "world_button_title": "Lore de personnage\n\nCliquer pour charger\nMajuscule-clic pour ouvrir la fenêtre contextuelle « Lien vers le Wold Info ».", + "Chat Lore Alt+Click to open the lorebook": "Lore du chat\nAlt+Click pour ouvrir le lorebook", + "Manual": "Manuel", + "Duplicate persona": "Dupliquer la persona", + "popup-button-crop": "Recadrer", + "Close popup": "Fermer le popup", + "Close": "Fermer", + "Any contents here will replace the default Post-History Instructions used for this character. (v2 spec: post_history_instructions)": "Tout contenu ici remplacera les instructions post-histore par défaut utilisées pour ce personnage.\n(v2 spec: post_history_instructions)", + "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized": "WI Statut de l'entrée :\r🔵 Constant\r🟢 Normal\r🔗 Vectorisé", + "Use global": "Utiliser les données globales", + "Whole Words": "Mots entiers", + "Group Scoring": "Notation des groupes", + "delay_until_recursion_level": "Définit les niveaux de délai pour les balayages récursifs.\r\rDans un premier temps, seul le premier niveau (le plus petit nombre) sera pris en compte.\rSi aucune correspondance n'est trouvée, le niveau suivant devient éligible pour la correspondance.\rCette opération est répétée jusqu'à ce que tous les niveaux soient vérifiés.\r\rLié au réglage \"Délai avant récursion\".", + "Recursion Level": "Niveau de récursivité", + "Non-recursable (will not be activated by another)": "Non récursable (ne peut être activé par un autre)", + "Delay until recursion (can only be activated on recursive checking)": "Délai jusqu'à la récursion (ne peut être activé que lors d'un contrôle récursif)", + "Prioritize": "Priorités", + "Sticky entries will stay active for N messages after being triggered.": "Les entrées collantes restent actives pendant N messages après avoir été déclenchées.", + "Sticky": "Collant", + "Entries with a cooldown can't be activated N messages after being triggered.": "Les entrées avec un temps de recharge ne peuvent pas être activées N messages après avoir été déclenchées.", + "Cooldown": "Récupération", + "Entries with a delay can't be activated until there are N messages present in the chat.": "Les entrées avec un délai ne peuvent pas être activées tant qu'il n'y a pas N messages dans le chat.", + "Delay": "Délai", + "Filter to Characters or Tags": "Filtre sur les personnages ou les tags", + "Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry": "Changez le filtre Personnages/Tags pour exclure les personnages et tags listés de la correspondance pour cette entrée.", + "Exclude": "Exclure", + "Injection position. Relative (to other prompts in prompt manager) or In-chat @ Depth.": "Position d'injection. Relative (par rapport à d'autres prompts dans le gestionnaire de prompts) ou In-chat @ Depth.", + "prompt_manager_in_chat": "In-chat", + "The content of this prompt is pulled from elsewhere and cannot be edited here.": "Le contenu de ce message est tiré d'autres sources et ne peut être modifié ici..", + "Open checkpoint chat\nShift+Click to replace the existing checkpoint with a new one": "Cliquer pour ouvrir le chat du point de contrôle\nShift+Click pour remplacer le point de contrôle existant par un nouveau.", + "Caption": "Légende", + "Swipe left": "Balayer à gauche", + "Swipe right": "Balayer à droite", + "alternate_greetings_hint_1": "Cliquez sur le", + "alternate_greetings_hint_2": "bouton pour commencer !", + "Alternate Greeting #": "Salutation alternative #", + "Reroll with the entire prefix": "Renouvellement avec l'ensemble du préfixe", + "Load a custom asset list or select": "Charger une liste de ressources personnalisée ou sélectionner", + "to install 3rd party extensions.": "pour installer des extensions tierces.", + "Assets URL": "URL des ressources", + "load_asset_list_desc": "Chargement d'une liste d'extensions et de ressources sur la base d'un fichier de liste de ressources.\n\nL'URL des ressources par défaut dans ce champ pointe vers la liste des extensions et des ressources officielles.\nSi vous disposez d'une liste de ressources personnalisée, vous pouvez l'insérer ici.\n\nPour installer une seule extension tierce, utilisez le bouton \"Installer des extensions\" en haut à droite.", + "Load an asset list": "Charger une liste de ressources", + "Load Asset List": "Charger la liste des ressources", + "Characters": "Personnages", + "Disable": "Désactiver", + "Enable": "Activer", + "These files are available for the current character in all chats they are in.": "Ces fichiers sont disponibles pour le personnage actuel dans tous les chats auxquels il participe.", + "These files are available for all characters in the current chat.": "Ces fichiers sont disponibles pour tous les personnages du chat actuel.", + "Image Captioning": "Légende des images", + "Local": "Local", + "Multimodal (OpenAI / Anthropic / llama / Google)": "Multimodal (OpenAI / Anthropic / llama / Google)", + "Extras": "Extras", + "Horde": "Horde", + "API": "API", + "Text Generation WebUI (oobabooga)": "Text Generation WebUI (oobabooga)", + "currently_selected": "[Actuellement sélectionné]", + "currently_loaded": "[Actuellement chargée]", + "Allow reverse proxy": "Autoriser le reverse proxy", + "Hint:": "Indice:", + "Set your API keys and endpoints in the 'API Connections' tab first.": "Définissez d'abord vos clés API et vos points de terminaison dans l'onglet « Connexions API ».", + "Caption Prompt": "Légende Prompt", + "Ask every time": "Demander à chaque fois", + "Message Template": "Modèle de message", + "(use _space": "(use", + "macro)": "macro)", + "Automatically caption images": "Légende automatique des images", + "Edit captions before saving": "Modifier les légendes avant l'enregistrement", + "Profile name:": "Nom du profil :", + "Creating a Connection Profile": "Création d'un profil de connexion", + "{{@key}}": "{{@key}}:", + "Enter a name:": "Saisir un nom :", + "Connection Profile": "Profil de connexion", + "View connection profile details": "Voir les détails du profil de connexion", + "Create a new connection profile": "Créer un nouveau profil de connexion", + "Update a connection profile": "Mise à jour d'un profil de connexion", + "Edit a connection profile": "Modifier un profil de connexion", + "Reload a connection profile": "Recharger un profil de connexion", + "Delete a connection profile": "Supprimer un profil de connexion", + "Omitted Settings:": "Réglages omis :", + "Character Expressions": "Expressions de personnages", + "Translate text to English before classification": "Traduire le texte en anglais avant de le classer", + "Show default images (emojis) if sprite missing": "Afficher les images par défaut (emojis) si le sprite est manquant", + "Classifier API": "API de classification", + "Select the API for classifying expressions.": "Sélectionnez l'API pour classer les expressions.", + "Main API": "API principale", + "WebLLM Extension": "Extension WebLLM", + "LLM Prompt": "Prompt LLM", + "Will be used if the API doesn't support JSON schemas or function calling.": "Sera utilisé si l'API ne prend pas en charge les schémas JSON ou les appels de fonction.", + "Default / Fallback Expression": "Expression par défaut / de secours", + "Set the default and fallback expression being used when no matching expression is found.": "Définir l'expression par défaut et l'expression de secours utilisées lorsqu'aucune expression correspondante n'est trouvée.", + "Custom Expressions": "Expressions personnalisées", + "Can be set manually or with an _space": "Peut être réglé manuellement ou à l'aide d'une", + "space_ slash command.": "commande slash.", + "Open a chat to see the character expressions.": "Ouvrez un chat pour voir les expressions du personnage.", + "You are in offline mode. Click on the image below to set the expression.": "Vous êtes en mode hors ligne. Cliquez sur l'image ci-dessous pour définir l'expression.", + "Sprite Folder Override": "Remplacement du dossier des sprites", + "Use a forward slash to specify a subfolder. Example: _space": "Utilisez une barre oblique pour spécifier un sous-dossier. Exemple :", + "Upload sprite pack (ZIP)": "Charger le pack de sprites (ZIP)", + "Remove all image overrides": "Suppression de toutes les surcharges d'image", + "Create new folder in the _space": "Créer un nouveau dossier dans le", + "folder of your user data directory and name it as the name of the character.": "de votre répertoire de données utilisateur et nommez-le comme le nom du personnage.", + "Put images with expressions there. File names should follow the pattern:": "Placez-y des images avec des expressions. Les noms de fichiers doivent suivre le modèle :", + "expression_label_pattern": "[expression_label].[image_format]", + "Sprite set:": "Ensemble de sprites :", + "Show Gallery": "Show Gallery", + "ext_sum_title": "Résumer", + "ext_sum_webllm": "Extension WebLLM", + "ext_sum_restore_tip": "Rétablir un résumé précédent ; à utiliser plusieurs fois pour effacer l'état du résumé pour ce chat.", + "ext_sum_force_tip": "Déclencher une mise à jour du résumé dès maintenant.", + "ext_sum_include_wi_scan_desc": "Inclure le dernier résumé dans l'analyse WI.", + "ext_sum_include_wi_scan": "Inclure dans l'analyse des World Info", + "None (not injected)": "Aucune (pas d'injection)", + "ext_sum_injection_position_none": "Le résumé ne sera pas injecté dans le prompt. Vous pouvez toujours y accéder via la macro {{summary}}.", + "Labels and Message": "Étiquettes et message", + "Label": "Étiquette", + "(label of the button, if no icon is chosen) ": "(étiquette du bouton, si aucune icône n'est choisie)", + "Title": "Titre", + "(tooltip, leave empty to show message or /command)": "(info-bulle, laisser vide pour afficher un message ou une commande)", + "Message / Command:": "Message / Commande :", + "Word wrap": "Enveloppe de mot", + "Tab size:": "Tab size:", + "Ctrl+Enter to execute": "Ctrl+Entrée pour exécuter", + "Context Menu": "Menu Contexte", + "Auto-Execute": "Auto-Exécution", + "Don't trigger auto-execute": "Ne pas déclencher l'exécution automatique", + "Invisible (auto-execute only)": "Invisible (exécution automatique uniquement)", + "Execute on startup": "Exécuter au démarrage", + "Execute on user message": "Exécuter sur message de l'utilisateur", + "Execute on AI message": "Exécuter sur message de l'IA", + "Execute on chat change": "Exécuter sur changement de chat", + "Execute on new chat": "Exécution sur un nouveau chat", + "Execute on group member draft": "Execute on group member draft", + "Automation ID:": "Automation ID", + "Testing": "Essai", + "Quick Reply": "Quick Reply", + "Enable Quick Replies": "Activer les Quick Replies", + "Combine Quick Replies": "Combiner les Quick Replies", + "Show Popout Button": "Afficher le bouton contextuel (sur le bureau)", + "Global Quick Reply Sets": "Global Quick Reply Sets", + "Chat Quick Reply Sets": "Chat Quick Reply Sets", + "Edit Quick Replies": "Editer les Quick Replies", + "Disable Send (Insert Into Input Field)": "Désactiver l'envoi (insérer dans le champ de saisie)", + "Place Quick Reply Before Input": "Placez le quick reply avant la saisie", + "Inject user input automatically": "Injecter automatiquement les données de l'utilisateur", + "(if disabled, use ": "(si désactivé, utiliser", + "macro for manual injection)": "macro pour injection manuelle)", + "Color": "Couleur", + "Only apply color as accent": "N'appliquez la couleur qu'en tant qu'accent", + "ext_regex_new_global_script_desc": "Nouveau script global de regex", + "ext_regex_new_scoped_script_desc": "Nouveau script délimitée de regex", + "ext_regex_disallow_scoped": "Interdire l'utilisation de regex délimitée", + "ext_regex_allow_scoped": "Autoriser l'utilisation de regex délimitées", + "ext_regex_user_input_desc": "Messages envoyés par l'utilisateur.", + "ext_regex_ai_input_desc": "Messages reçus de l'API Génération.", + "ext_regex_slash_desc": "Messages envoyés à l'aide de commandes STscript.", + "ext_regex_wi_desc": "Contenu de l'entrée Lorebook/World Info. Nécessite de cocher la case 'Only Format Prompt' !", + "ext_regex_run_on_edit_desc": "Exécute le script regex lorsque le message appartenant à un ou plusieurs rôles spécifiés est modifié.", + "Macro in Find Regex": "Macros dans Find Regex", + "Don't substitute": "Ne pas substituer", + "Substitute (raw)": "Substituer (raw)", + "Substitute (escaped)": "Substituer (escaped)", + "Ephemerality": "Éphémérité", + "ext_regex_only_format_visual_desc": "Le contenu du fichier d'historique du chat ne changera pas, mais les regex seront appliquées aux messages affichés dans l'UI du chat.", + "Abort current image generation task": "Abandonner la tâche de génération d'images en cours", + "Stop Image Generation": "Arrêt de la génération d'images", + "sd_function_tool": "Utilisez les outils pour détecter automatiquement les intentions de générer des images.", + "sd_function_tool_txt": "Utilisez les outils", + "sd_free_extend": "Étendre automatiquement les prompts de sujet en mode libre (pas les portraits ou les arrière-plans) à l'aide d'un LLM actuellement sélectionné.", + "sd_free_extend_txt": "Étendre les prompts de sujet en mode libre", + "sd_free_extend_small": "(interactif/commandes)", + "Model ID": "Model ID", + "e.g. black-forest-labs/FLUX.1-dev": "ex. black-forest-labs/FLUX.1-dev", + "API Key": "Clé API", + "Click to set": "Cliquez pour définir", + "You can find your API key in the Stability AI dashboard.": "Vous trouverez votre clé API dans le tableau de bord de Stability AI.", + "Style Preset": "Preset de style", + "Prompt Upsampling": "Prompt Upsampling", + "Swap width and height": "Intervertir la largeur et la hauteur", + "CLIP Skip": "CLIP Skip", + "Karras": "Karras", + "Not all samplers supported.": "Tous les échantillonneurs ne sont pas pris en charge.", + "sd_adetailer_face": "Utiliser ADetailer avec le modèle de visage pendant la génération. L'extension ADetailer doit être installée sur le backend.", + "Use ADetailer (Face)": "Utiliser ADetailer (Face)", + "(-1 for random)": "(-1 pour aléatoire)", + "Chat Message Visibility (by source)": "Visibilité des messages de chat (par source)", + "Uncheck to hide the extension's messages in chat prompts.": "Décochez cette case pour masquer les messages de l'extension dans les prompts de chat.", + "Extensions Menu": "Menu des extensions", + "Slash Command": "Commande Slash", + "Interactive Mode": "Mode interactif", + "Function Tool": "Outils", + "ext_translate_btn_chat": "Traduire le chat", + "ext_translate_btn_input": "Traduire la saisie", + "ext_translate_delete_confirm_1": "Êtes-vous sûr ?", + "ext_translate_delete_confirm_2": "Cette action supprime le texte traduit de tous les messages de la discussion en cours. Cette action ne peut pas être annulée.", + "ext_translate_title": "Traduction du chat", + "ext_translate_auto_mode": "Mode auto", + "ext_translate_mode_none": "Aucun", + "ext_translate_mode_responses": "Traduire les réponses", + "ext_translate_mode_inputs": "Traduire la saisie", + "ext_translate_mode_both": "Traduire les deux", + "ext_translate_mode_provider": "Fournisseur", + "ext_translate_target_lang": "Langue cible", + "ext_translate_clear": "Clear Translations", + "Select TTS Provider": "Sélectionner le fournisseur TTS", + "tts_enabled": "Activé", + "Narrate user messages": "Narrer les messages de l'utilisateur", + "Auto Generation": "Generation Auto", + "Requires auto generation to be enabled.": "La génération automatique doit être activée.", + "Narrate by paragraphs (when streaming)": "Narration par paragraphes (en cas de diffusion en continu)", + "Only narrate quotes": "Ne narrer que les \"citations\"", + "Ignore text, even quotes, inside asterisk": "Ignorer le *texte, même les \"citations\", à l'intérieur d'astérisques*", + "Narrate only the translated text": "Ne narrer que le texte traduit", + "Skip codeblocks": "Sauter les blocs de code", + "Skip tagged blocks": "Skip blocks", + "Pass Asterisks to TTS Engine": "Transmettre les astérisques au moteur TTS", + "Audio Playback Speed": "Vitesse de lecture audio", + "Vector Storage": "Vector Storage", + "Vectorization Source": "Source de vectorisation", + "Local (Transformers)": "Local (Transformers)", + "Vectorization Model": "Modèle de vectorisation", + "Keep model in memory": "Garder le modèle en mémoire", + "Hint: Set the URL in the API connection settings.": "Conseil : définissez l'URL dans les paramètres de connexion à l'API.", + "The server MUST be started with the --embedding flag to use this feature!": "Le serveur DOIT être démarré avec l'option --embedding pour utiliser cette fonctionnalité !", + "NomicAI API Key": "Clé API NomicAI", + "Query messages": "Messages de requête", + "Score threshold": "Seuil de score", + "Chunk boundary": "Limite des morceaux", + "World Info settings": "Réglages desWorld Info", + "Enable for World Info": "Activer pour les World Info", + "Enabled for all entries": "Activé pour toutes les entrées", + "Checked: all entries except ❌ status can be activated.": "Vérifié : toutes les entrées sauf l'état ❌ peuvent être activées..", + "Unchecked: only entries with ❌ status can be activated.": "Non coché : seules les entrées ayant un statut 🔗 peuvent être activées.", + "Max Entries": "Nombre maximal d'entrées", + "File vectorization settings": "Paramètres de vectorisation des fichiers", + "Enable for files": "Activer pour les fichiers", + "Message attachments": "Pièces jointes aux messages", + "Size threshold (KB)": "Seuil de taille (KB)", + "Chunk size (chars)": "Taille des morceaux (chars)", + "Chunk overlap (%)": "Chevauchement des morceaux (%)", + "Retrieve chunks": "Récupérer des morceaux", + "Data Bank files": "Fichiers de la banque de données", + "Injection Template": "Modèle d'injection", + "Injection Position": "Position d'injection", + "Vectorize All": "Vectoriser tout", + "Purge Vectors": "Vecteurs de purge", + "Chat vectorization settings": "Paramètres de vectorisation du chat", + "Enabled for chat messages": "Activé pour les messages de chat", + "Retain#": "Conserver#", + "Insert#": "Insérer#", + "Vector Summarization": "Résumés vectoriels", + "Summarize chat messages for vector generation": "Résumer les messages de chat pour la génération de vecteurs", + "Warning: This will slow down vector generation drastically, as all messages have to be summarized first.": "Attention : Cela ralentira considérablement la génération de vecteurs, car tous les messages doivent d'abord être résumés.", + "Summarize chat messages when sending": "Résumer les messages de chat lors de l'envoi", + "Warning: This might cause your sent messages to take a bit to process and slow down response time.": "Attention : Le traitement des messages envoyés risque d'être un peu plus long et de ralentir le temps de réponse.", + "Extras API": "Extras API", + "Only used when Main API or WebLLM Extension is selected.": "Utilisé uniquement lorsque l'API principale ou l'extension WebLLM est sélectionnée.", + "Old messages are vectorized gradually as you chat. To process all previous messages, click the button below.": "Les anciens messages sont vectorisés progressivement au fur et à mesure que vous discutez.\n To process all previous messages, click the button below.", + "View Stats": "Voir les statistiques", + "Note:": "Note:", + "this chat is temporary and will be deleted as soon as you leave it.": "ce chat est temporaire et sera supprimé dès que vous le quitterez.", + "Enter a new display name:": "Saisissez un nouveau nom d'affichage :", + "Import Tags For _begin": "Importer des tags pour ", + "Click remove on any tag to remove it from this import.
      Select one of the import options to finish importing the tags.": "Cliquez sur le bouton « Supprimer » d'un tag pour le retirer de l'importation..\n Sélectionnez l'une des options d'importation pour terminer l'importation des tags.", + "Existing Tags": "Tags existantes", + "New Tags": "Nouveaux tags", + "Folder Tags": "Tags de dossier", + "The following tags will be auto-imported based on the currently selected folders": "Les tags suivants seront importés automatiquement en fonction des dossiers sélectionnés.", + "Import None": "Aucun Import", + "Import All": "Importer Tout", + "Import Existing": "Importer l'existants", + "Import": "Importer", + "chat_rename_1": "Saisissez le nouveau nom du chat :", + "chat_rename_2": "!!L'utilisation d'un nom de fichier existant produira une erreur !!!", + "chat_rename_3": "Cela rompra le lien entre les points de contrôle des chats .", + "chat_rename_4": "Il n'est pas nécessaire d'ajouter '.jsonl' à la fin.", + "Enter Checkpoint Name:": "Saisir le nom du point de contrôle :", + "(Leave empty to auto-generate)": "(Laisser vide pour une génération automatique)", + "The currently existing checkpoint will be unlinked and replaced with the new checkpoint, but can still be found in the Chat Management.": "Le point de contrôle existant sera dissocié et remplacé par le nouveau point de contrôle, mais pourra toujours être trouvé dans la gestion du chat.", + "Include Body Parameters": "Inclure les paramètres du corps", + "custom_include_body_desc": "Paramètres à inclure dans le corps de la requête Chat Completion (objet YAML)\n\nExemple:\n- top_k: 20\n- repetition_penalty: 1.1", + "Exclude Body Parameters": "Exclure les paramètres du corps", + "custom_exclude_body_desc": "Paramètres à exclure du corps de la requête Chat Completion (tableau YAML)\n\nExemple:\n- frequency_penalty\n- presence_penalty", + "Include Request Headers": "Inclure les en-têtes des requêtes", + "custom_include_headers_desc": "En-têtes supplémentaires pour les demandes de Chat Completion (objet YAML)\n\nExemple:\n- CustomHeader: custom-value\n- AnotherHeader: custom-value", + "Functions in this category are for advanced users only. Don't click anything if you're not sure about the consequences.": "Les fonctions de cette catégorie sont réservées aux utilisateurs avancés. Ne cliquez sur rien si vous n'êtes pas sûr des conséquences.", + "THIS IS PERMANENT!": "CECI EST PERMANENT !", + "Also delete the chat files": "Supprimez également les fichiers de chat", + "Are you sure you want to duplicate this character?": "Êtes-vous sûr de vouloir dupliquer ce personnage ?", + "If you just want to start a new chat with the same character...": "Si vous voulez simplement commencer un nouveau chat avec le même personnage, utilisez l'option \"Commencer un nouveau chat\" dans le menu d'options en bas à gauche.", + "forbid_media_global_state_forbidden": "(interdit)", + "forbid_media_global_state_allowed": "(autorisé)", + "help_format_1": "Commandes de mise en forme du texte :", + "help_format_2": "*texte*", + "help_format_3": "s'affiche comme", + "help_format_4": "italique", + "help_format_5": "**texte**", + "help_format_6": "s'affiche comme", + "help_format_7": "gras", + "help_format_8": "***text***", + "help_format_9": "s'affiche comme", + "help_format_10": "gras italique", + "help_format_11": "__texte__", + "help_format_12": "s'affiche comme", + "help_format_13": "souligné", + "help_format_14": "~~texte~~", + "help_format_15": "displays as a", + "help_format_16": "strikethough", + "help_format_17": "[texte](url)", + "help_format_18": "s'affiche comme un", + "help_format_19": "hyperlink", + "help_format_20": "![texte](url)", + "help_format_21": "s'affiche sous forme d'image", + "help_format_22": "```texte```", + "help_format_23": "s'affiche comme un bloc de code (de nouvelles lignes sont autorisées entre les backticks)", + "help_format_like_this": "comme cela", + "help_format_24": "`texte`", + "help_format_25": "s'affiche comme du", + "help_format_26": "code inline", + "help_format_27": "> texte", + "help_format_28": "s'affiche comme une citation en bloc (notez l'espace après >)", + "help_format_29": "# texte", + "help_format_30": "s'affiche comme un grand en-tête (notez l'espace)", + "help_format_32": "## texte", + "help_format_33": "s'affiche comme un en-tête moyen (notez l'espace)", + "help_format_35": "### texte", + "help_format_36": "s'affiche comme un petit en-tête (notez l'espace)", + "help_1": "Bonjour à tous ! Veuillez sélectionner la rubrique d'aide sur laquelle vous souhaitez en savoir plus :", + "help_2": "Commands Slash", + "help_or": "ou", + "help_3": "Formatage", + "help_4": "Raccourcis", + "help_5": "{{Macros}}", + "help_6": "Vous avez encore des questions ? Le", + "help_7": "la documentation officielle de SillyTavern", + "help_8": "contient beaucoup plus d'informations !", + "help_hotkeys_0": "Raccourcis du chat", + "help_hotkeys_1": "Haut", + "help_hotkeys_2": "Modifier le dernier message dans le chat", + "help_hotkeys_3": "Ctrl+Haut", + "help_hotkeys_4": "Modifier le dernier message de l'utilisateur dans le chat", + "help_hotkeys_5": "Gauche", + "help_hotkeys_6": "balayage gauche", + "help_hotkeys_7": "Droite", + "help_hotkeys_8": "balayage droite (REMARQUE : les touches de raccourci sont désactivées lorsque quelque chose est tapé dans la barre de discussion.)", + "help_hotkeys_9": "Entrée", + "help_hotkeys_10": "(avec la barre de chat sélectionnée)", + "help_hotkeys_10_1": "envoyez votre message à l'IA", + "help_hotkeys_11": "Ctrl+Entrée", + "help_hotkeys_12": "Régénérer la dernière réponse de l'IA", + "help_hotkeys_13": "Alt+Entrée", + "help_hotkeys_14": "Poursuivre la dernière réponse de l'IA", + "help_hotkeys_15": "Echap", + "help_hotkeys_16": "arrêter la génération de réponses de l'IA, fermer les panneaux de l'interface utilisateur, annuler l'édition du message", + "help_hotkeys_17": "Ctrl+Maj+Haut", + "help_hotkeys_18": "Défiler jusqu'à la ligne de contexte", + "help_hotkeys_19": "Ctrl+Maj+Bas", + "help_hotkeys_20": "Raccourcis Markdown", + "help_hotkeys_21": "Fonctionne dans la barre de chat et les zones de texte marquées par cette icône :", + "help_hotkeys_22": "**gras**", + "help_hotkeys_23": "*italique*", + "help_hotkeys_24": "__underline__", + "help_hotkeys_25": "`code inline`", + "help_hotkeys_26": "~~strikethrough~~", + "Enter the Git URL of the extension to install": "Saisir l'URL Git de l'extension à installer", + "Disclaimer:": "Disclaimer:", + "Please be aware that using external extensions can have unintended side effects and may pose security risks. Always make sure you trust the source before importing an extension. We are not responsible for any damage caused by third-party extensions.": "Veuillez noter que l'utilisation d'extensions externes peut avoir des effets secondaires inattendus et présenter des risques pour la sécurité. Assurez-vous toujours de la fiabilité de la source avant d'importer une extension. Nous ne sommes pas responsables des dommages causés par des extensions tierces.", + "Prompt Itemization": "Prompt Itemization", + "Show Raw Prompt": "Afficher le prompt brut", + "Copy Prompt": "Copier le prompt", + "Show Prompt Differences": "Montrer les différences entre les prompts", + "API/Model:": "API/Modèle:", + "Preset:": "Preset:", + "Tokenizer:": "Tokenizer:", + "Only the white numbers really matter. All numbers are estimates. Grey color items may not have been included in the context due to certain prompt format settings.": "Seuls les chiffres blancs comptent vraiment. Tous les chiffres sont des estimations.\n Les éléments de couleur grise peuvent ne pas avoir été inclus dans le contexte en raison de certains paramètres du format du prompt.", + "System Info:": "Info système :", + "Prompt Tokens:": "Prompt Tokens:", + "World Info:": "World Info:", + "Chat History:": "Historique du chat :", + "Extensions:": "Extensions:", + "Bias:": "Biais:", + "Total Tokens in Prompt:": "Total des Tokens dans le Prompt:", + "Max Context": "Contexte Maximums", + "(Context Size - Response Length)": "(Taille du contexte - Longueur de la réponse)", + "System-wide Replacement Macros (in order of evaluation):": "Macros de remplacement globales (par ordre d'évaluation) :", + "help_macros_1": "uniquement pour la mise en lot des commandes slash. Remplacé par le résultat de la commande précédente.", + "help_macros_2": "insère simplement une nouvelle ligne.", + "help_macros_3": "supprime les nouvelles lignes entourant cette macro.", + "help_macros_4": "pas d'opération, juste une chaîne vide.", + "help_macros_5": "prompts globaux définis dans les paramètres de l'API. Valable uniquement dans les overrides de définitions avancées.", + "help_macros_6": "l'entrée de l'utilisateur", + "help_macros_7": "l'override du prompt principal du personnage", + "help_macros_8": "les overrides des instructions post-histoire du personnage", + "help_macros_9": "la description du personnage", + "help_macros_10": "la personnalité du personnage", + "help_macros_11": "le scénario du personnage", + "help_macros_12": "la description de votre persona actuelle", + "help_macros_13": "Exemples de dialogue du personnage", + "help_macros_14": "Exemples de dialogues non formatés", + "(only for Story String)": "(uniquement pour Story String)", + "help_macros_summary": "le dernier résumé du chat généré par l'extension \"Summarize\" (si disponible).", + "help_macros_15": "votre nom de persona actuel", + "help_macros_16": "le nom du personnage", + "help_macros_17": "le numéro de version du personnage", + "help_macros_18": "une liste de noms de membres du groupe séparés par des virgules (y compris les personnes en sourdine) ou le nom du personnage dans les discussions en solo. Alias: {{charIfNotGroup}}", + "help_groupNotMuted": "la même chose que {{group}}, mais exclut les membres en sourdine", + "help_macros_19": "un nom de modèle de génération de texte pour l'API actuellement sélectionnée.", + "Can be inaccurate!": "Peut être imprécis !", + "help_macros_20": "le texte du dernier message de chat.", + "help_macros_lastUser": "le texte du dernier message de chat de l'utilisateur.", + "help_macros_lastChar": "le texte du dernier message de chat du personnage.", + "help_macros_21": "index # du dernier message de chat. Utile pour la mise en lot des commandes slash.", + "help_macros_22": "l'ID du premier message inclus dans le contexte. La génération doit être exécutée au moins une fois dans la session en cours.", + "help_macros_23": "l'ID basé sur 1 du swipe actuel dans le dernier message de chat. Chaîne vide si le dernier message est caché par l'utilisateur ou le prompt.", + "help_macros_24": "le nombre de swipes dans le dernier message de chat. Chaîne vide si le dernier message est caché par l'utilisateur ou le prompt.", + "help_macros_reverse": "inverse le contenu de la macro.", + "help_macros_25": "vous pouvez laisser une note ici, et la macro sera remplacée par un contenu vide. Non visible pour l'IA.", + "help_macros_26": "l'heure actuelle", + "help_macros_27": "la date du jour", + "help_macros_28": "le jour de la semaine", + "help_macros_29": "l'heure ISO actuelle (24 heures)", + "help_macros_30": "la date ISO actuelle (AAAA-MM-JJ)", + "help_macros_31": "la date et l'heure actuelles dans le format spécifié, par exemple pour la date/heure allemandes :", + "help_macros_32": "l'heure actuelle dans le fuseau horaire UTC spécifié, ex. UTC-4 or UTC+2", + "help_macros_33": "la différence de temps entre time1 et time2. Accepte les macros d'heure et de date. (Ex: {{timeDiff::{{isodate}} {{time}}::2024/5/11 12:30:00}})", + "help_macros_34": "le temps écoulé depuis l'envoi du dernier message de l'utilisateur", + "help_macros_35": "définit un biais comportemental pour l'IA jusqu'à la prochaine entrée de l'utilisateur. Les guillemets autour du texte sont importants.", + "help_macros_36": "lance un dé. (ex :", + "space_ will roll a 6-sided dice and return a number between 1 and 6)": "lancera un dé à 6 faces et renverra un nombre entre 1 et 6)", + "help_macros_37": "renvoie un élément aléatoire de la liste. (ex :", + "space_ will return 1 of the 4 numbers at random. Works with text lists too.": "renverra 1 des 4 nombres au hasard. Fonctionne également avec les listes de texte.", + "help_macros_38": "syntaxe alternative pour random qui permet d'utiliser des virgules dans les éléments de la liste.", + "help_macros_39": "choisit un élément aléatoire dans la liste. Fonctionne de la même manière que {{random}}, avec les mêmes options syntaxiques possibles, mais le choix restera cohérent pour ce chat une fois choisi et ne sera pas relancé sur les messages consécutifs et le traitement des prompts.", + "help_macros_40": "ajoute dynamiquement du texte entre guillemets aux séquences de mots interdits, si le backend Text Generation WebUI est utilisé. Ne fait rien pour les autres backends. Peut être utilisé n'importe où (description de personnage, WI, AN, etc.) Les guillemets autour du texte sont importants.", + "help_macros_isMobile": "\"true\" si ST fonctionne actuellement dans un environnement mobile, \"false\" sinon", + "Instruct Mode and Context Template Macros:": "Mode d'instruction et macros de modèle de contexte :", + "(enabled in the Advanced Formatting settings)": "(activée dans les paramètres de formatage avancés)", + "help_macros_41": "longueur maximale autorisée du prompt en tokens = (taille du contexte - longueur de la réponse)", + "help_macros_42": "contexte modèle exemple dialogues séparateur", + "help_macros_43": "contexte modèle chat ligne de début", + "help_macros_44": "contenu du prompt système s'il est activé (soit override du prompt du personnage si c'est autorisée, soit defaultSystemPrompt)", + "help_macros_45": "contenu du prompt système", + "help_macros_46": "séquence de préfixes du prompt système d'instruction", + "help_macros_47": "séquence de suffixes du prompt système d'instruction", + "help_macros_48": "séquence de préfixes de l'utilisateur d'instruction", + "help_macros_49": "séquence de suffixes de l'utilisateur d'instruction", + "help_macros_50": "séquence de préfixes de l'assistant d'instruction", + "help_macros_51": "séquence de suffixes de l'assistant d'instruction", + "help_macros_52": "instruct assistant first output sequence", + "help_macros_53": "instruct assistant last output sequence", + "help_macros_54": "instruct system message prefix sequence", + "help_macros_55": "instruct system message suffix sequence", + "help_macros_56": "instruct system instruction prefix", + "help_macros_57": "instruct first user message filler", + "help_macros_58": "instruct stop sequence", + "help_macros_first_user": "instruct user first input sequence", + "help_macros_last_user": "instruct user last input sequence", + "Chat variables Macros:": "Macros de variables de chat :", + "Local variables = unique to the current chat": "Variables locales = propres au chat actuel", + "Global variables = works in any chat for any character": "Variables globales = fonctionnent dans n'importe quel chat pour n'importe quel personnage", + "Scoped variables = works in STscript": "Variables scopés = fonctionne dans STscript", + "help_macros_59": "remplacée par la valeur de la variable locale \"name\"", + "help_macros_60": "remplacée par une chaîne vide, définit la variable locale \"name\" à \"value\"", + "help_macros_61": "remplacés par des chaînes vides, ajoute une valeur numérique de \"increment\" à la variable locale \"name\"", + "help_macros_62": "remplacé par le résultat de l'incrémentation de la valeur de la variable \"name\" de 1", + "help_macros_63": "remplacé par le résultat de la décrémentation de la valeur de la variable \"name\" de 1", + "help_macros_64": "remplacée par la valeur de la variable globale \"name\"", + "help_macros_65": "remplacée par une chaîne vide, définit la variable globale \"name\" à \"value\"", + "help_macros_66": "remplacé par une chaîne vide, ajoute une valeur numérique de \"increment\" à la variable globale \"name\"", + "help_macros_67": "remplacé par le résultat de l'incrémentation de la valeur de la variable globale \"name\" de 1", + "help_macros_68": "remplacé par le résultat de la décrémentation de la valeur de la variable globale \"name\" de 1", + "help_macros_69": "remplacée par la valeur de la variable scopée \"name\"", + "help_macros_70": "remplacée par la valeur de l'élément à l'index (pour les tableaux / listes ou objets / dictionnaires) de la variable scopée \"name\"", + "Choose what to export": "Choisir ce qui doit être exporté", + "{{name}}": "{{name}}", + "Choose what to import": "Choisir ce qu'il faut importer", + "If necessary, you can later restore this chat file from the /backups folder": "Si nécessaire, vous pouvez restaurer ultérieurement ce fichier de chat à partir du dossier /backups", + "Also delete the current chat file": "Supprime également le fichier de chat actuel", + "Persona Lorebook for": "Persona Lorebook pour", + "persona_world_template_txt": "Une Wolrd Info sélectionnée sera liée à ce personnage. Lors de la création d'une réponse de l'IA,\n il sera combiné avec les entrées des lorebooks globaux, de personnages et de chat.", + "Are you sure you want to connect to the following proxy URL?": "Êtes-vous sûr de vouloir vous connecter à l'URL proxy suivante ?", + "Encountered an error while processing your request.": "Une erreur s'est produite lors du traitement de votre requête.", + "Check you have credits available on your": "Vérifiez que vous avez des crédits disponibles sur votre", + "OpenAI account quora_error": "compte OpenAI", + "dot quota_error": ".", + "If you have sufficient credits, please try again later.": "Si vous avez suffisamment de crédits, veuillez réessayer plus tard.", + "Enter your password below to confirm:": "Entrez votre mot de passe ci-dessous pour confirmer :", + "Unique to this chat.": "Unique à ce chat.", + "All group members will use the following scenario text instead of what is specified in their character cards.": "Tous les membres du groupe utiliseront le texte du scénario suivant au lieu de ce qui est spécifié dans leur fiche de personnage.", + "The following scenario text will be used instead of the value set in the character card.": "Le texte du scénario suivant sera utilisé à la place de la valeur définie dans la fiche de personnage.", + "Checkpoints inherit the scenario override from their parent, and can be changed individually after that.": "Les points de contrôle héritent du scénario de leur parent et peuvent ensuite être modifiés individuellement.", + "Download Model": "Télécharger le modèle", + "Downloader Options": "Options de téléchargement", + "Extra parameters for downloading/HuggingFace API": "Paramètres supplémentaires pour le téléchargement/HuggingFace API.\rSi vous n'êtes pas sûr, laissez ces paramètres vides.", + "Revision": "Révision", + "Folder Name": "Nom du dossier de sortie", + "HF Token": "Token HF", + "Include Patterns": "Inclure les patterns", + "Glob patterns of files to include in the download.": "Patterns globaux de fichiers à inclure dans le téléchargement.\rSéparer chaque pattern par une nouvelle ligne.", + "Exclude Patterns": "Exclure les patterns", + "Glob patterns of files to exclude in the download.": "Patterns globaux de fichiers à exclure du téléchargement.\rSéparer chaque pattern par une nouvelle ligne.", + "Tag Management": "Gestion des tags", + "Save your tags to a file": "Enregistrer vos tags dans un fichier", + "Restore tags from a file": "Enregistrer vos tags dans un fichier", + "Create a new tag": "Créer un nouveau tag", + "Drag handle to reorder. Click name to rename. Click color to change display.": "Faites glisser la poignée pour réorganiser. Cliquez sur le nom pour le renommer. Cliquez sur la couleur pour modifier l'affichage.", + "Click on the folder icon to use this tag as a folder.": "Cliquez sur l'icône de dossier pour utiliser ce tag comme dossier.", + "Use alphabetical sorting": "Utiliser le tri alphabétique", + "tags_sorting_desc": "Si cette option est activée, les tags seront automatiquement triés par ordre alphabétique lors de leur création ou de leur renommage.\nSi cette option est désactivée, les nouveaux tags seront ajoutés à la fin.\n\nSi un tag est réorganisé manuellement en le faisant glisser, le tri automatique sera désactivé.", + "Are you sure you want to delete the theme?": "Êtes-vous sûr de vouloir supprimer le thème ?", + "This will delete all your settings and data. There will be no undo button. Make sure you have a backup before proceeding.": "Cette opération effacera tous vos paramètres et toutes vos données. Il n'y aura pas de bouton d'annulation.\n Assurez-vous de disposer d'une sauvegarde avant de poursuivre.", + "Account reset code has been posted to the server console.": "Le code de réinitialisation du compte a été affiché sur la console du serveur.", + "and connect to an": "et se connectez à une", + "You can add more": "Vous pouvez ajouter d'autres", + "or_welcome": "ou", + "from other websites": "d'autres sites web.", + "Go to the": "Aller au menu ", + "to install additional features.": "pour installer des fonctionnalités supplémentaires.", + "If you're connected to an API, try asking me something!": "Si vous êtes connecté à une API, essayez de me demander quelque chose !", + "Title/Memo": "Titre/Memo", + "Strategy": "Stratégie", + "Position": "Position", + "Trigger %": "Déclencheur %", + "Only chunk on custom boundary": "Only chunk on custom boundary", + "Generate Caption": "Générer une légende", + "Use System Prompt": "Utiliser le prompt système:", + "Settings Preset": "Preset de réglages:", + "System Prompt Name": "Nom du prompt système:", + "Instruct Mode": "Mode Instruction:", + "Save and Update": "Sauvegarder et mettre à jour", + "Don't ask again for this URL": "Ne plus demander pour cette URL" +} diff --git a/jiuguan2025cc/public/locales/is-is.json b/jiuguan2025cc/public/locales/is-is.json new file mode 100644 index 0000000000000000000000000000000000000000..8180c79856d41aaacf0c82e7847faa82f70ff135 --- /dev/null +++ b/jiuguan2025cc/public/locales/is-is.json @@ -0,0 +1,1443 @@ +{ + "Favorite": "Uppáhalds", + "Tag": "Merkja", + "Duplicate": "Afrit", + "Persona": "Persóna", + "Delete": "Eyða", + "AI Response Configuration": "Stillingar á AI svar", + "AI Configuration panel will stay open": "AI stillingar ramma verða opnar", + "clickslidertips": "Smelltu til að slá inn gildi handvirkt.", + "MAD LAB MODE ON": "MAD LAB MODE ON", + "Documentation on sampling parameters": "Skráning um sýnishornseiginleika", + "kobldpresets": "Fyrir stillingar Kobold", + "guikoboldaisettings": "Stillingar fyrir KoboldAI viðmót", + "Update current preset": "Uppfæra núverandi forskrift", + "Save preset as": "Vista forsnið sem", + "Import preset": "Flytja inn forskrift", + "Export preset": "Flytja út forskrift", + "Restore current preset": "Endurheimta núverandi forskrift", + "Delete the preset": "Eyða forskriftinni", + "novelaipresets": "Fyrir stillingar NovelAI", + "Default": "Sjálfgefið", + "openaipresets": "Fyrir stillingar OpenAI", + "Text Completion presets": "Forskriftir um textaútfyllingu", + "AI Module": "AI módel", + "Changes the style of the generated text.": "Breytir stíl úttaksins.", + "No Module": "Engin eining", + "Instruct": "Leiðbeina", + "Prose Augmenter": "Prosa Augmenter", + "Text Adventure": "Textaævintýri", + "response legth(tokens)": "Lengd svars (í táknum eða stöfum)", + "Streaming": "Straumur", + "Streaming_desc": "Birta svarið bita fyrir bita þegar það er myndað.", + "context size(tokens)": "Stærð samhengis (í táknum eða stöfum)", + "unlocked": "Opinn", + "Only enable this if your model supports context sizes greater than 8192 tokens": "Virkjið þetta aðeins ef stærð samhengis styður model meira en 8192 tákn.", + "Max prompt cost:": "Hámarks skyndikostnaður:", + "Display the response bit by bit as it is generated.": "Birta svarid bita fyrir bita þegar það er búið til.", + "When this is off, responses will be displayed all at once when they are complete.": "Þegar þetta er slökkt verða svör birt allt í einu þegar þau eru búin.", + "Temperature": "Hitastig", + "rep.pen": "Endurtaka refsing", + "Rep. Pen. Range.": "Staðla breytu. Endurtekningarbrot", + "Rep. Pen. Slope": "Skopplengi endurtekningarrefsingar", + "Rep. Pen. Freq.": "Staðla tíðni. Endurtekningarbrot", + "Rep. Pen. Presence": "Til staðar. Endurtekningarbrot", + "TFS": "TFS", + "Phrase Repetition Penalty": "Endurtekningartíma refning", + "Off": "Af", + "Very light": "Mjög létt", + "Light": "Létt", + "Medium": "Miðlungs", + "Aggressive": "Árásargjarn", + "Very aggressive": "Mjög árásargjarn", + "Unlocked Context Size": "Opnað samhengi stærð", + "Unrestricted maximum value for the context slider": "Ótakmarkað hámarksgildi fyrir samhengisslíðurinn", + "Context Size (tokens)": "Stærð samhengis (í táknum)", + "Max Response Length (tokens)": "Hámarks lengd svörunar (í táknum)", + "Multiple swipes per generation": "Mörg högg á hverja kynslóð", + "Enable OpenAI completion streaming": "Virkja OpenAI klárastreymi", + "Frequency Penalty": "Tíðnarefning", + "Presence Penalty": "Tilkoma refning", + "Count Penalty": "Telja víti", + "Top K": "Topp K", + "Top P": "Topp P", + "Repetition Penalty": "Endurtekningarbrot", + "Min P": "Min P", + "Top A": "Topp A", + "Quick Prompts Edit": "Fljótar umbreytingar á hvöttum", + "Main": "Aðal", + "NSFW": "NSFW", + "Jailbreak": "Fangabrot", + "Utility Prompts": "Hjálpar hvöttir", + "Impersonation prompt": "Tilvísun að gersemi", + "Restore default prompt": "Endurheimta sjálfgefna leiðbeiningar", + "Prompt that is used for Impersonation function": "Tilvísun sem notað er fyrir gersemi virkni", + "World Info Format Template": "World Info sniðmát", + "Restore default format": "Endurheimta sjálfgefið snið", + "Wraps activated World Info entries before inserting into the prompt.": "Umlykur virkar World Info færslur áður en þær eru settar inn í hvetja.", + "scenario_format_template_part_1": "Notaðu", + "scenario_format_template_part_2": "til að merkja stað þar sem efnið er sett inn.", + "Scenario Format Template": "Sniðmát fyrir atburðarás", + "Personality Format Template": "Sniðmát fyrir persónuleikasnið", + "Group Nudge Prompt Template": "Sniðmát fyrir Group Nudge hvetja", + "Sent at the end of the group chat history to force reply from a specific character.": "Sendt í lok hópspjallssögunnar til að þvinga fram svör frá tiltekinni persónu.", + "New Chat": "Nýtt spjall", + "Restore new chat prompt": "Endurheimta nýja spjallkvaðningu", + "Set at the beginning of the chat history to indicate that a new chat is about to start.": "Stilltu í upphafi spjallferilsins til að gefa til kynna að nýtt spjall sé að hefjast.", + "New Group Chat": "Nýtt hópspjall", + "Restore new group chat prompt": "Endurheimta sjálfgefna kvaðningu", + "Set at the beginning of the chat history to indicate that a new group chat is about to start.": "Stilltu í upphafi spjallferilsins til að gefa til kynna að nýtt hópspjall sé að hefjast.", + "New Example Chat": "Nýtt dæmi spjall", + "Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.": "Stilltu í upphafi Dialogue dæmi til að gefa til kynna að nýtt dæmi spjall sé að hefjast.", + "Continue nudge": "Haltu áfram að ýta", + "Set at the end of the chat history when the continue button is pressed.": "Stillt í lok spjallferilsins þegar ýtt er á hnappinn Halda áfram.", + "Replace empty message": "Skipta út tómu skilaboði", + "Send this text instead of nothing when the text box is empty.": "Senda þennan texta í stað þess að ekki sé sent neitt þegar textareitinn er tómur.", + "Seed": "Sæti", + "Set to get deterministic results. Use -1 for random seed.": "Stilltu til að fá ákvarðaðar niðurstöður. Notaðu -1 fyrir tilviljunarkennd fræ.", + "Temperature controls the randomness in token selection": "Hitastig stjórnar handahófi í vali táknanna:\n- Lágt hitastig (<1,0) leiðir til snjallara texta, með að gefa forgang (fyrir setningar og orð) táknum með hátt líkur.\n- Hátt hitastig (>1,0) aukar nýsköpun og fjölbreytni í úttakinu, með að veita táknum (setningum og orðum) með lága líkur meiri tækifæri.\nSettu gildið 1,0 fyrir upprunalegar líkur.", + "Top_K_desc": "Top K stillir hámarksfjölda efsta táknanna sem hægt er að velja úr.", + "Top_P_desc": "Top P (kallað kjarnaúrtaka) safnar saman öllum þeim efstu táknunum sem þarf til að ná ákveðnu prósentu hlutfalli.\nMeð öðrum orðum, ef efstu 2 táknin táknleggja 25%, og Top-P er 0,50, þá eru einungis þessi tvö tákn valin.\nSettu gildið 1,0 til að slökkva.", + "Typical P": "Venjulegt P", + "Typical_P_desc": "Venjuleg P-úrtaka veitir forgang táknum út frá afvíkni þeirra frá meðalfarbandi innihaldsgjafa.\nTákn sem hafa hæfnisgildi þeirra nærri fastmörkuninni (til dæmis, 0,5), eru varðveitt, sem greinir þá sem hafa meðalupplýsingar.\nSettu gildið 1,0 til að slökkva.", + "Min_P_desc": "Min P stillir grunnlægsta mögulegt líkur. Það er aðlagað út frá hæfnisgildi efstu táknanna.\nEf líkur fyrir efstu táknin eru 80%, og Min P er 0,1, aðeins tákn með líkur hærri en 8% eru tekin til greina.\nSettu gildið 0 til að slökkva.", + "Top_A_desc": "Top A stillir mörk fyrir táknaval samkvæmt ferningshæð hæstu tákns. \nEf Top A gildið er 0,2, og líkur fyrir hæstu táknið eru 50%, þá eru tákn með líkur lægri en 5% hafnað (0,2 * 0,5^2).\nSettu gildið 0 til að slökkva.", + "Tail_Free_Sampling_desc": "Tail-Free Sampling (TFS) leitar að litlum líkurum í dreifingu,\nmeð því að greina breytingar á tækifærismöguleikum táknanna með öðrum orðum. Hægt er að halda áfram með tákn allt að mörk (t.d. 0,3) miðað við önnur afleiðingar.\nSem betur fer að gildi sem liggur nálægt 0, því fleiri tákn eru hafnað. Settu gildið 1,0 til að slökkva.", + "rep.pen range": "Svið endurtakarefsingar.", + "Mirostat": "Mirostat", + "Mode": "Mode", + "Mirostat_Mode_desc": "Gildið 0 gerir Mirostat algjörlega óvirkt. 1 er fyrir Mirostat 1.0 og 2 er fyrir Mirostat 2.0", + "Tau": "Tau", + "Mirostat_Tau_desc": "Stýrir breytileika Mirostat úttakanna", + "Eta": "Eta", + "Mirostat_Eta_desc": "Stjórnar námshraða Mirostat", + "Ban EOS Token": "Banna EOS tákn", + "Ban_EOS_Token_desc": "Bannaðu end-of-sequence (EOS) táknið með KoboldCpp (og hugsanlega einnig önnur tákn með KoboldAI).\rGott til að skrifa sögur, en ætti ekki að nota fyrir spjall og leiðbeiningar.", + "GBNF Grammar": "GBNF málfræði", + "Type in the desired custom grammar": "Sláðu inn þær sérstakar málfræðireglur sem þú vilt", + "Samplers Order": "Röð Samplers", + "Samplers will be applied in a top-down order. Use with caution.": "Samplers verða beitt í röð frá toppi niður. Notaðu með varúð.", + "Tail Free Sampling": "Úrtaka án halda", + "Load koboldcpp order": "Hlaðið inn færslu af koboldcpp", + "Preamble": "Forspil", + "Use style tags to modify the writing style of the output.": "Notaðu stílmerki til að breyta stílinum á úttakinu.", + "Banned Tokens": "Bannaðar tákna", + "Sequences you don't want to appear in the output. One per line.": "Röðir sem þú vilt ekki sjá í úttakinu. Ein á línu.", + "Logit Bias": "Logit bjóður", + "Add": "Bæta við", + "Helps to ban or reenforce the usage of certain words": "Hjálpar til að banna eða styrkja notkun ákveðinna orða", + "CFG Scale": "CFG Skala", + "Negative Prompt": "Neikvæð fyrirspurn", + "Add text here that would make the AI generate things you don't want in your outputs.": "Bættu við texta sem myndi koma fram ef AI býr til hluti sem þú vilt ekki í úttökum þínum.", + "Used if CFG Scale is unset globally, per chat or character": "Notað ef CFG Scale er óbreytt heimsspekilega, í hverri spjalli eða staf.", + "Mirostat Tau": "Mirostat Tau", + "Mirostat LR": "Mirostat LR", + "Min Length": "Minnsti lengd", + "Top K Sampling": "Top K örlög", + "Nucleus Sampling": "Kjarnaörlög", + "Top A Sampling": "Top A örlög", + "CFG": "CFG", + "Neutralize Samplers": "Jafna samplara", + "Set all samplers to their neutral/disabled state.": "Setjið alla samplara í hlutlausan/óvirkan ástand.", + "Sampler Select": "Sýnishorn Velja", + "Customize displayed samplers or add custom samplers.": "Sérsníddu sýnd sýnishorn eða bættu við sérsniðnum sýnishornum.", + "Epsilon Cutoff": "Epsilon klippa", + "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "Epsilon afskurður stillir lágmarks líkur þar sem tæknar eru útilokaðir frá sýnum.\nÍ einingum 1e-4; viðeigandi gildi er 3.\nSettu 0 til að slökkva.", + "Eta Cutoff": "Eta klippa", + "Eta_Cutoff_desc": "Eta afhending er aðalbreytan í sértækri Eta örlögum. Í einingum af 1e-4; skynsamlegt gildi er 3. Stillt á 0 til að óvirkja. Sjá greinina Truncation Sampling as Language Model Desmoothing eftir Hewitt et al. (2022) fyrir nánari upplýsingar.", + "rep.pen decay": "Rep Pen Decay", + "Encoder Rep. Pen.": "Endurtaka kóðara.", + "No Repeat Ngram Size": "Stærð Ngram án endurtekninga", + "Skew": "Skekkja", + "Max Tokens Second": "Hámarks tákna / sekúnda", + "Smooth Sampling": "Slétt sýnataka", + "Smooth_Sampling_desc": "Gerir þér kleift að nota fernings-/kubískar umbreytingar til að stilla dreifinguna. Lægri sléttunarstuðull gildi verða meira skapandi, venjulega á bilinu 0,2-0,3 er sweetspot (að því gefnu að ferillinn = 1). Hærri sléttunarferill mun gera ferilinn brattari, sem mun refsa vali með litlum líkum á harðari hátt. 1.0 kúrfa jafngildir því að nota aðeins sléttunarstuðul.", + "Smoothing Factor": "Jafnvægissfaktor", + "Smoothing Curve": "Sléttunarferill", + "DRY_Repetition_Penalty_desc": "DRY refsar táknum sem myndu lengja endann á inntakinu inn í röð sem hefur áður átt sér stað í inntakinu. Stilltu margfaldara á 0 til að slökkva á.", + "DRY Repetition Penalty": "DRY Endurtekningarvíti", + "DRY_Multiplier_desc": "Stilltu á gildi > 0 til að virkja DRY. Stýrir stærð refsingar fyrir stystu refsingar.", + "Multiplier": "Margfaldari", + "DRY_Base_desc": "Stýrir hversu hratt refsingin vex með vaxandi röð lengd.", + "Base": "Grunnur", + "DRY_Allowed_Length_desc": "Lengsta röð sem hægt er að endurtaka án þess að vera refsað.", + "Allowed Length": "Leyfileg lengd", + "Penalty Range": "Vítaspyrna", + "DRY_Sequence_Breakers_desc": "Tákn þar sem samsvörun raðarinnar er ekki haldið áfram. Tilgreindur sem kommuaðskilinn listi yfir tilvitnaða strengi.", + "Sequence Breakers": "Sequence Breakers", + "JSON-serialized array of strings.": "JSON-raðraðað fylki strengja.", + "Dynamic Temperature": "Dynamísk hitastig", + "Scale Temperature dynamically per token, based on the variation of probabilities": "Hiti er stilltur afkvörðunartíma á hvern tákni, byggt á mismunandi líkur.", + "Minimum Temp": "Lágmarks hitastig", + "Maximum Temp": "Hámarks hitastig", + "Exponent": "Útþensla", + "Mirostat (mode=1 is only for llama.cpp)": "Mirostat (mode=1 er einungis fyrir llama.cpp)", + "Mirostat_desc": "Mirostat er hitamælir fyrir úttak hröðleika", + "Mirostat Mode": "Mirostat Ham", + "Variability parameter for Mirostat outputs": "Breytileikabreyt fyrir Mirostat úttaki.", + "Mirostat Eta": "Mirostat Eta", + "Learning rate of Mirostat": "Námshraði Mirostat.", + "Beam search": "Beimleit", + "Helpful tip coming soon.": "Gagnleg ábending kemur fljótlega.", + "Number of Beams": "Fjöldi beam", + "Length Penalty": "Lengdarrefning", + "Early Stopping": "Tímafrádráttur", + "Contrastive search": "Mótaákvörðun", + "Penalty Alpha": "Bóta alfa", + "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "Styrkur samhæfðrar leitarmiðilsins. Settu gildið í 0 til að slökkva á CS.", + "Do Sample": "Gera úrtak", + "Add BOS Token": "Bæta við BOS tákninu", + "Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative": "Bættu við bos_token í upphafi fyrirspurnarinnar. Að slökkva á þessu getur gert svarin meira skapandi.", + "Ban the eos_token. This forces the model to never end the generation prematurely": "Banna eos_token. Þetta skilur því að úrmyndin endi aldrei framleiðsluna of snemma", + "Ignore EOS Token": "Hunsa EOS Token", + "Ignore the EOS Token even if it generates.": "Hunsa EOS-táknið, jafnvel þótt það myndist.", + "Skip Special Tokens": "Sleppa sérstökum táknum", + "Temperature Last": "Hitastig síðast", + "Temperature_Last_desc": "Notaðu hitastigsprófanirnar síðast. Þetta er almennt skynsamlegt.\nÞegar virkjun: Fyrst er valið sýn, þá er hitastigið beitt til að laga hlutfallslega líkur þeirra (tæknilega, logits).\nEf óvirkjað: Hitastigið er fyrst beitt til að laga hlutfallslegar líkur hvers tákns, þá er sýnt val sýnanna. \nAð slökkva á hitastigi síðast eykur líkur á tákn í endi dreifingarinnar, sem aukar möguleikana á ósamræmi.", + "Speculative Ngram": "Spákaupmennska Ngram", + "Use a different speculative decoding method without a draft model": "Notaðu aðra íhugandi afkóðunaðferð án drög að líkani.\rÆskilegt er að nota drög að líkani. Spákaupmennska ngram er ekki eins áhrifaríkt.", + "Spaces Between Special Tokens": "Bil á milli sérstakra tákna", + "LLaMA / Mistral / Yi models only": "Aðeins fyrir LLaMA / Mistral / Yi mótela. Vinsamlegast ákveðið viðeigandi skoðunaraðgerð fyrst.\nRöðir sem þú vilt ekki sjá í niðurstöðunum.\nEin röð á hverjum línu. Texti eða [tákna auðkenni].\nFleiri tákn byrja á bilum. Notaðu táknafjölda ef þú ert ekki viss.", + "Example: some text [42, 69, 1337]": "Dæmi:\nEitthvað texti\n[42, 69, 1337]", + "Classifier Free Guidance. More helpful tip coming soon": "Leiðsögn óháð flokkara. Meiri hjálp kemur bráðar.", + "Scale": "Skala", + "JSON Schema": "JSON kerfi", + "Type in the desired JSON schema": "Sláðu inn æskilegt JSON skema", + "Grammar String": "Málfræðistrengur", + "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF eða EBNF, fer eftir bakendanum sem er í notkun. Ef þú ert að nota þetta ættir þú að vita hvaða.", + "Top P & Min P": "Efstu P & Min P", + "Load default order": "Hlaða sjálfgefna röð", + "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "llama.cpp eingöngu. Ákveður röð sýnataka. Ef Mirostat hamur er ekki 0, er röð sýnatöku hunsuð.", + "Sampler Priority": "Forgangsraða rannsóknarbyssu", + "Ooba only. Determines the order of samplers.": "Aðeins Ooba. Ákvarðar röð rannsóknarbyssa.", + "Character Names Behavior": "Hegðun persónunafna", + "Helps the model to associate messages with characters.": "Hjálpar líkaninu að tengja skilaboð við stafi.", + "None": "Enginn", + "character_names_default": "Nema hópar og fyrri persónur. Annars, vertu viss um að gefa upp nöfn í hvetjunni.", + "Don't add character names.": "Ekki bæta við persónunöfnum.", + "Completion": "Lokunarhlutur", + "character_names_completion": "Takmarkanir gilda: aðeins latneskar tölustafir og undirstrik. Virkar ekki fyrir allar heimildir, sérstaklega: Claude, MistralAI, Google.", + "Add character names to completion objects.": "Bættu persónunöfnum við fullnaðarhluti.", + "Message Content": "Innihald skilaboða", + "Prepend character names to message contents.": "Setjið nöfn stafa við innihald skilaboðanna.", + "Continue Postfix": "Halda áfram Postfix", + "The next chunk of the continued message will be appended using this as a separator.": "Næsta hluti af áframhaldandi skilaboðum verður bætt við með því að nota þetta sem skilju.", + "Space": "Rými", + "Newline": "Nýlína", + "Double Newline": "Tvöföld nýlína", + "Wrap user messages in quotes before sending": "Loka notendaskilaboðum í fyrir sendingu", + "Wrap in Quotes": "Pakkka í tilvitnunum", + "Wrap entire user message in quotes before sending.": "Pakkaðu allt notendaskilaboð í tilvitnunum áður en þau eru send.", + "Leave off if you use quotes manually for speech.": "Látu vera að nota þetta ef þú notar tilvitnunum handvirkt í tal.", + "Continue prefill": "Haltu áfram fyrirfram fyllingu", + "Continue sends the last message as assistant role instead of system message with instruction.": "Haltu áfram sendir síðasta skilaboðið sem hjálparhlutverk frekar en kerfisskilaboð með leiðbeiningum.", + "Squash system messages": "Flatta kerfisskilaboð", + "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Sameinar samhliða kerfisskilaboð í eitt (sem er utan umsagna dæmum). Getur bætt samfelldni fyrir sumar módel.", + "Enable function calling": "Virkja aðgerðarkall", + "Send inline images": "Senda myndir í línu", + "image_inlining_hint_1": "Sendir myndir í skilaboðum ef líkanið styður það (t.d. GPT-4V, Claude 3 eða Llava 13B).\n Nota", + "image_inlining_hint_2": "aðgerð á hvaða skilaboðum sem er eða", + "image_inlining_hint_3": "valmynd til að hengja myndskrá við spjallið.", + "Inline Image Quality": "Innbyggð myndgæði", + "openai_inline_image_quality_auto": "Sjálfvirk", + "openai_inline_image_quality_low": "Lágt", + "openai_inline_image_quality_high": "Hár", + "Use AI21 Tokenizer": "Notaðu AI21 Tokenizer", + "Use the appropriate tokenizer for Jurassic models, which is more efficient than GPT's.": "Notaðu viðeigandi auðkenni fyrir Jurassic módel, sem er skilvirkara en GPT.", + "Use Google Tokenizer": "Notaðu Google Tokenizer", + "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "Notaðu rétta tokenizer fyrir Google módel með þeirra API. Hægri umhvörf fyrir hvöttavinnslu, en býður upp á miklu nákvæmari talningu á táknunum.", + "Use system prompt": "Notaðu kerfishvöt", + "(Gemini 1.5 Pro/Flash only)": "(aðeins Gemini 1.5 Pro/Flash)", + "Merges_all_system_messages_desc_1": "Sameinar öll kerfisskilaboð fram að fyrstu skilaboðum með hlutverki utan kerfis og sendir þau í a", + "Merges_all_system_messages_desc_2": "sviði.", + "Assistant Prefill": "Fyrirfram fylla viðstoðarmanns", + "Start Claude's answer with...": "Byrjaðu svör Claude með...", + "Assistant Impersonation Prefill": "Forfylling aðstoðarmanns eftirlíkingar", + "Use system prompt (Claude 2.1+ only)": "Nota kerfisflug (einungis Claude 2.1+)", + "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "Senda kerfisflug fyrir styðjandi módel. Ef óvirk, er notendaskilaboð bætt við byrjun flugs.", + "User first message": "Fyrstu skilaboð notanda", + "Restore User first message": "Endurheimta fyrstu skilaboð notanda", + "Human message": "Mannleg skilaboð, fræðsla o.fl.\nBætir engu við þegar það er tómt, þ.e.a.s. krefst nýrrar leiðbeiningar með hlutverkinu „notandi“.", + "New preset": "Ný stilling", + "Delete preset": "Eyða stillingu", + "View / Edit bias preset": "Skoða/Breyta forhöfn", + "Add bias entry": "Bæta við forhöfn", + "Most tokens have a leading space.": "Flest tákn eru með leiðandi rými.", + "API Connections": "Tengingar við API", + "Text Completion": "Textaútfylling", + "Chat Completion": "Spjalllokun", + "NovelAI": "NovelAI", + "AI Horde": "AI Horde", + "KoboldAI": "KoboldAI", + "Avoid sending sensitive information to the Horde.": "Forðastu að senda viðkvæm gögn til Hórdans.", + "Review the Privacy statement": "Farið yfir Persónuverndarskýrsluna", + "Register a Horde account for faster queue times": "Skráðu þig á Horde reikning til að fá hraðari biðartíma", + "Learn how to contribute your idle GPU cycles to the Horde": "Lærðu hvernig þú getur stuðlað að hléum GPU hringjum þínum til Horde", + "Adjust context size to worker capabilities": "Aðlagaðu stærð samhengis til færni verkmanns", + "Adjust response length to worker capabilities": "Aðlagaðu lengd svars til færni verkmanns", + "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "Getur hjálpað við slæm svör með því að biðra bara um samþykktum verkamönnum. Getur hægjað á svari tíma.", + "Trusted workers only": "Aðeins treystir starfsmenn", + "API key": "API lykill", + "Get it here:": "Fáðu það hér:", + "Register": "Skrá", + "View my Kudos": "Skoða mín Kudos", + "Enter": "Slá inn", + "to use anonymous mode.": "til að nota dulin hátt.", + "Clear your API key": "Hreinsa API lykilinn þinn", + "For privacy reasons, your API key will be hidden after you reload the page.": "Útaf persónuverndarástæðum verður API lykillinn þinn falinn eftir að þú endurhlaðar síðunni.", + "Models": "Módel", + "Refresh models": "Endurnýja líkön", + "-- Horde models not loaded --": "-- Hórdi myndir eru ekki hlaðnar --", + "Not connected...": "Ekki tengdur...", + "API url": "URL API", + "Example: http://127.0.0.1:5000/api ": "Dæmi: http://127.0.0.1:5000/api", + "Connect": "Tengjast", + "Cancel": "Hætta við", + "Novel API key": "Nýskrifa API lykill", + "Get your NovelAI API Key": "Fáðu NovelAI API lykilinn þinn", + "Enter it in the box below": "Sláðu hann inn í kassanum hér fyrir neðan", + "Novel AI Model": "Nýskrifandi AI módel", + "No connection...": "Engin tenging...", + "API Type": "Tegund API", + "Default (completions compatible)": "Sjálfgefið [OpenAI /completions samhæft: oobabooga, LM Studio, osfrv.]", + "TogetherAI API Key": "SamanAI API lykill", + "TogetherAI Model": "SamanAI módel", + "-- Connect to the API --": "-- Tengjast forritunargrensl --", + "OpenRouter API Key": "Lykill API fyrir OpenRouter", + "Click Authorize below or get the key from": "Smellið á heimilda neðan eða fáið lykilinn frá", + "View Remaining Credits": "Skoða eftirvinnandi trúnaðarorð", + "OpenRouter Model": "OpenRouter Módel", + "Model Providers": "Fyrirmyndarveitendur", + "InfermaticAI API Key": "InfermaticAI API lykill", + "InfermaticAI Model": "InfermaticAI líkan", + "DreamGen API key": "DreamGen API lykill", + "DreamGen Model": "DreamGen líkan", + "Mancer API key": "Mancer API lykill", + "Mancer Model": "Mancer Módel", + "Make sure you run it with": "Gakktu viss um að þú keyrir það með", + "flag": "merki", + "API key (optional)": "API lykill (valkvæmt)", + "Server url": "URL þjóns", + "Example: 127.0.0.1:5000": "Dæmi: 127.0.0.1:5000", + "Custom model (optional)": "Sérsniðið módel (valkvæmt)", + "vllm-project/vllm": "vllm-project/vllm (OpenAI API umbúðastilling)", + "vLLM API key": "vLLM API lykill", + "Example: 127.0.0.1:8000": "Dæmi: http://127.0.0.1:8000", + "vLLM Model": "vLLM líkan", + "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (OpenAI forritunargrensl)", + "Aphrodite API key": "Aphrodite API lykill", + "Aphrodite Model": "Afródíta fyrirmynd", + "ggerganov/llama.cpp": "ggerganov/llama.cpp (úttak þjónn)", + "Example: 127.0.0.1:8080": "Dæmi: 127.0.0.1:8080", + "Example: 127.0.0.1:11434": "Dæmi: 127.0.0.1:11434", + "Ollama Model": "Ollama módel", + "Download": "Niðurhal", + "Tabby API key": "Tabby API lykill", + "koboldcpp API key (optional)": "koboldcpp API lykill (valfrjálst)", + "Example: 127.0.0.1:5001": "Dæmi: 127.0.0.1:5001", + "Authorize": "Heimild", + "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Fáðu API lykilinn þinn fyrir OpenRouter með því að nota OAuth strauminn. Þú verður endurvísað(ð/ur) á openrouter.ai", + "Bypass status check": "Hlaupa framhjá stöðutík", + "Chat Completion Source": "Heimild að fullvirkni spjalls", + "Reverse Proxy": "Reverse proxy", + "Proxy Presets": "Forstillingar proxy", + "Saved addresses and passwords.": "Vistað heimilisföng og lykilorð.", + "Save Proxy": "Vista umboð", + "Delete Proxy": "Eyða umboði", + "Proxy Name": "Nafn umboðsmanns", + "This will show up as your saved preset.": "Þetta mun birtast sem vistuð forstilling þín.", + "Proxy Server URL": "Vefslóð proxy-þjóns", + "Alternative server URL (leave empty to use the default value).": "Annar valkostur fyrir URL netþjónsinn (skilja autt til að nota sjálfgefna gildið).", + "Remove your real OAI API Key from the API panel BEFORE typing anything into this box": "Fjarlægðu raunverulega OAI API lykilinn þinn frá API töflunni FYRIR en þú skrifar eitthvað í þennan reit", + "We cannot provide support for problems encountered while using an unofficial OpenAI proxy": "Við getum ekki veitt stuðning fyrir vandamál sem komast upp við notkun óopinbers OpenAI fyrirvara", + "Doesn't work? Try adding": "Virkar ekki? Prófaðu að bæta við", + "at the end!": "undir lokin!", + "Proxy Password": "Lykilorð umboðsmanns", + "Will be used as a password for the proxy instead of API key.": "Verður notað sem lykilorð fyrir proxy í stað API lykils.", + "Peek a password": "Skoðaðu lykilorð", + "OpenAI API key": "OpenAI API lykill", + "View API Usage Metrics": "Skoða notkun gagnafræði API", + "Follow": "Fylgja", + "these directions": "þessum leiðbeiningum", + "to get your OpenAI API key.": "til að fá OpenAI API lykilinn þinn.", + "Use Proxy password field instead. This input will be ignored.": "Notaðu reitinn „Proxy lykilorð“ í staðinn. Þetta inntak verður hunsað.", + "OpenAI Model": "OpenAI módel", + "Bypass API status check": "Hlaupa framhjá API stöðutík", + "Show External models (provided by API)": "Sýna ytri módel (veitt af API)", + "Get your key from": "Fáðu lykla þína frá", + "Anthropic's developer console": "Uppbyggingaraðilar Forritara stjórnborð", + "Claude Model": "Claude módel", + "Window AI Model": "Vindauga AI módel", + "Model Order": "OpenRouter líkanaflokkun", + "Alphabetically": "Stafrófsröð", + "Price": "Verð (ódýrast)", + "Context Size": "Samhengisstærð", + "Group by vendors": "Flokkaðu eftir söluaðilum", + "Group by vendors Description": "Setjið OpenAI módel í einn hóp, Anthropic módel í annan hóp osfrv. Hægt að sameina við flokkun.", + "Allow fallback routes": "Leyfa bakfallssvæði", + "Allow fallback routes Description": "Veldur hlutleysa vélbúnaðarinn við val þinn ef valið módel getur ekki uppfyllt beiðni þína.", + "Scale API Key": "Lykill API fyrir Scale", + "Clear your cookie": "Hreinsaðu kökuna þína", + "Alt Method": "Aðferð Bakmenn", + "AI21 API Key": "Lykill API fyrir AI21", + "AI21 Model": "AI21 Módel", + "Google AI Studio API Key": "Google AI Studio API lykill", + "Google Model": "Google líkan", + "MistralAI API Key": "MistralAI API lykill", + "MistralAI Model": "MistralAI líkan", + "Groq API Key": "Groq API lykill", + "Groq Model": "Groq líkan", + "Perplexity API Key": "Perplexity API lykill", + "Perplexity Model": "Perplexity Model", + "Cohere API Key": "Cohere API lykill", + "Cohere Model": "Cohere líkan", + "Custom Endpoint (Base URL)": "Sérsniðinn endapunktur (grunnslóð)", + "Custom API Key": "Sérsniðinn API lykill", + "Available Models": "Módel í boði", + "Prompt Post-Processing": "Skjót eftirvinnsla", + "Applies additional processing to the prompt before sending it to the API.": "Beitir viðbótarvinnslu á boðunina áður en hún er send í API.", + "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "Sannreynir API tengingu þína með því að senda stutt skilaboð til að prófa. Vertu meðvituð(ur/ur) um að þú færð fyrir það!", + "Test Message": "Prufu skilaboð", + "Auto-connect to Last Server": "Tengjast sjálfkrafa við síðustu framendurnar", + "Missing key": "❌ Vantar lykil", + "Key saved": "✔️ Lykill vistaður", + "View hidden API keys": "Skoða faldir API lyklar", + "AI Response Formatting": "Útlit svars frá AI", + "Advanced Formatting": "Tæknifærni Snúningur", + "Context Template": "Umsjónarformaður Grunnur", + "Auto-select this preset for Instruct Mode": "Sjálfvalið þessi forskrift fyrir Leiðbeina háttur", + "Story String": "Saga Snúningur", + "Example Separator": "Dæmi Skilji", + "Chat Start": "Chat Start", + "Add Chat Start and Example Separator to a list of stopping strings.": "Bættu Chat Start og Example Separator við lista yfir stöðvunarstrengi.", + "Use as Stop Strings": "Nota sem Stoppa Strengir", + "context_allow_jailbreak": "Inniheldur Jailbreak í lok hvetjunnar, ef það er skilgreint á stafkortinu OG ''Velst Char. Jailbreak'' er virkt.\nÞETTA ER EKKI MÆLT FYRIR TEXTAÚRSLUNARGERÐ, GETUR leitt til lélegrar úttaks.", + "Allow Jailbreak": "Leyfa jailbreak", + "Context Order": "Samhengisröð", + "Summary": "Samantekt", + "Author's Note": "Athugasemd höfundar", + "Example Dialogues": "Dæmi um samræður", + "Hint": "Vísbending:", + "In-Chat Position not affected": "Samantekt og athugasemdarpöntun höfundar hafa aðeins áhrif þegar þær eru ekki með stillingar í spjalli.", + "Instruct Mode": "Leiðbeina Aðferð", + "Enabled": "Virkjað", + "instruct_bind_to_context": "Ef það er virkt verða samhengissniðmát sjálfkrafa valin á grundvelli valins heiti leiðbeiningarsniðmáts eða eftir vali.", + "Bind to Context": "Binda við Umhverfi", + "Presets": "Forstillingar", + "Auto-select this preset on API connection": "Sjálfvalið þessi forskrift við API tengingu", + "Activation Regex": "Virking Regex", + "Wrap Sequences with Newline": "Pakka Þrepi með Nýr lína", + "Replace Macro in Sequences": "Skipta út í Macro í runum", + "Skip Example Dialogues Formatting": "Sleppa sniði dæmishugmynda", + "Include Names": "Innifalið Nöfn", + "Force for Groups and Personas": "Tvöng fyrir Hópa og Personas", + "System Prompt": "Kerfis Boð", + "Instruct Mode Sequences": "Leiðbeina Aðferð Þrepi", + "System Prompt Wrapping": "Kerfisskýringar umbúðir", + "Inserted before a System prompt.": "Sett inn á undan kerfiskvaðningu.", + "System Prompt Prefix": "Kerfisboðsforskeyti", + "Inserted after a System prompt.": "Sett inn á eftir kerfiskvaðningu.", + "System Prompt Suffix": "Viðskeyti kerfisvísunar", + "Chat Messages Wrapping": "Spjallskilaboð umbúðir", + "Inserted before a User message and as a last prompt line when impersonating.": "Sett inn fyrir notandaskilaboð og sem síðasta biðlína þegar verið er að herma eftir.", + "User Message Prefix": "Forskeyti notandaskilaboða", + "Inserted after a User message.": "Sett inn á eftir notandaskilaboðum.", + "User Message Suffix": "Viðskeyti notandaskilaboða", + "Inserted before an Assistant message and as a last prompt line when generating an AI reply.": "Sett inn á undan aðstoðarskilaboðum og sem síðasta biðlína þegar búið er til gervigreindarsvar.", + "Assistant Message Prefix": "Skilaboðaforskeyti aðstoðarmanns", + "Inserted after an Assistant message.": "Sett inn á eftir aðstoðarskilaboðum.", + "Assistant Message Suffix": "Skilaboð aðstoðarmanns", + "Inserted before a System (added by slash commands or extensions) message.": "Sett á undan kerfisskilaboðum (bætt við með skáskipunum eða viðbótum).", + "System Message Prefix": "Forskeyti kerfisskilaboða", + "Inserted after a System message.": "Sett inn á eftir kerfisskilaboðum.", + "System Message Suffix": "Viðskeyti kerfisskilaboða", + "If enabled, System Sequences will be the same as User Sequences.": "Ef það er virkt verða System Sequences þau sömu og User Sequences.", + "System same as User": "Kerfi sama og notandi", + "Misc. Sequences": "Ýmislegt. Röð", + "Inserted before the first Assistant's message.": "Sett inn á undan fyrstu skilaboðum hjálparans.", + "First Assistant Prefix": "Fyrsta aðstoðarforskeyti", + "instruct_last_output_sequence": "Sett inn á undan síðustu skilaboðum aðstoðarmanns eða sem síðasta leiðbeiningarlína þegar gervigreindarsvar er búið til (nema hlutlaust/kerfishlutverk).", + "Last Assistant Prefix": "Síðasta forskeyti aðstoðarmanns", + "Will be inserted as a last prompt line when using system/neutral generation.": "Verður sett inn sem síðasta biðlína þegar kerfi/hlutlaus kynslóð er notuð.", + "System Instruction Prefix": "Kerfisleiðbeiningarforskeyti", + "If a stop sequence is generated, everything past it will be removed from the output (inclusive).": "Ef stöðvunarröð er mynduð verður allt sem er framhjá henni fjarlægt úr úttakinu (meðtalið).", + "Stop Sequence": "Stoppa Þrepi", + "Will be inserted at the start of the chat history if it doesn't start with a User message.": "Verður sett inn í byrjun spjallferils ef hann byrjar ekki með notandaskilaboðum.", + "User Filler Message": "Notandafyllingarskilaboð", + "Context Formatting": "Umsjónarformaður Snúningur", + "(Saved to Context Template)": "(Vistað á umsjónarformaðan Grunn)", + "Always add character's name to prompt": "Alltaf bæta við nafni persónu til fyrirmæla", + "Generate only one line per request": "Mynda aðeins ein lína fyrir hvern beiðni", + "Trim Incomplete Sentences": "Skera burt ófullkomnar setningar", + "Include Newline": "Setja inn ný línu", + "Misc. Settings": "Ólíkar stillingar", + "Collapse Consecutive Newlines": "Hrun Samtengd Nýjar Línur", + "Trim spaces": "Skera burt bilum", + "Tokenizer": "Texta Dreifandi", + "Token Padding": "Texta Stoppa", + "Start Reply With": "Byrja svar með", + "AI reply prefix": "AI svar forseti", + "Show reply prefix in chat": "Sýna forseta svars í spjalli", + "Non-markdown strings": "Strengi sem ekki eru merktir með Markdown", + "separate with commas w/o space between": "aðskilið með kommum án bila milli", + "Custom Stopping Strings": "Eigin stopp-strengir", + "JSON serialized array of strings": "JSON raðað fylki af strengjum", + "Replace Macro in Stop Strings": "Skiptu út í macro í sérsniðnum stoppa strengjum", + "Auto-Continue": "Sjálfvirk Forná", + "Allow for Chat Completion APIs": "Leyfa fyrir spjall Loka APIs", + "Target length (tokens)": "Markaðarlengd (texti)", + "World Info": "Heimur Upplýsingar", + "Locked = World Editor will stay open": "Læst = Heimur ritstjóra verður opinn", + "Worlds/Lorebooks": "Heimar/Lorebooks", + "Active World(s) for all chats": "Virk(ir) heim(ur) fyrir öll spjöll", + "-- World Info not found --": "-- Heimsupplýsingar finnast ekki --", + "Global World Info/Lorebook activation settings": "Global World Info/Lorebook virkjunarstillingar", + "Click to expand": "Smelltu til að stækka", + "Scan Depth": "Skan djúpt", + "Context %": "Umhverfi %", + "Budget Cap": "Búgetti Kap", + "(0 = disabled)": "(0 = óvirk)", + "Scan chronologically until reached min entries or token budget.": "Skannaðu í tímaröð þar til lágmarksfærslum eða kostnaðarhámarki er náð.", + "Min Activations": "Mín virkjanir", + "Max Depth": "Hámarksdýpt", + "(0 = unlimited, use budget)": "(0 = ótakmarkað, notaðu kostnaðarhámark)", + "Insertion Strategy": "Innsetningaráætlun", + "Sorted Evenly": "Raðað jafnt", + "Character Lore First": "Fyrst persónufræði", + "Global Lore First": "Fyrst heimsfræði", + "Entries can activate other entries by mentioning their keywords": "Færslur geta virkjað aðrar færslur með því að nefna lykilorð þeirra", + "Recursive Scan": "Endurkvæm skoðun", + "Lookup for the entry keys in the context will respect the case": "Leit að lyklum færslunnar í samhengi mun virða málið", + "Case Sensitive": "Skilgreiningarfræðilegt", + "If the entry key consists of only one word, it would not be matched as part of other words": "Ef lykill færslunnar samanstendur af aðeins einni orði, verður hann ekki samið sem hluti af öðrum orðum", + "Match Whole Words": "Samræma Öll Orð", + "Only the entries with the most number of key matches will be selected for Inclusion Group filtering": "Aðeins þær færslur sem hafa flesta lyklasamsvörun verða valdar fyrir þátttökuhópssíu", + "Use Group Scoring": "Notaðu hópstig", + "Alert if your world info is greater than the allocated budget.": "Viðvörun ef heimsupplýsingarnar þínar eru meiri en úthlutað fjárhagsáætlun.", + "Alert On Overflow": "Viðvörun um flæði", + "New": "Nýtt", + "or": "eða", + "--- Pick to Edit ---": "--- Veldu til að breyta ---", + "Rename World Info": "Endurnefna heiminn", + "Open all Entries": "Opna allar færslur", + "Close all Entries": "Loka öllum færslum", + "New Entry": "Ný færsla", + "Fill empty Memo/Titles with Keywords": "Fylla tóma minnispunkta/Heiti með lykilorðum", + "Import World Info": "Flytja inn heiminn", + "Export World Info": "Flytja út heiminn", + "Duplicate World Info": "Tvöföld heimurinn", + "Delete World Info": "Eyða heiminum", + "Search...": "Leita...", + "Search": "Leita", + "Priority": "Forgangsraða", + "Custom": "Sérsniðið", + "Title A-Z": "Titill A-Ö", + "Title Z-A": "Titill Ö-A", + "Tokens ↗": "Tákn ↗", + "Tokens ↘": "Tákn ↘", + "Depth ↗": "Dýpt ↗", + "Depth ↘": "Dýpt ↘", + "Order ↗": "Raða ↗", + "Order ↘": "Raða ↘", + "UID ↗": "UID ↗", + "UID ↘": "UID ↘", + "Trigger% ↗": "Kveikja% ↗", + "Trigger% ↘": "Kveikja% ↘", + "Refresh": "Endurnýja", + "User Settings": "Notendastillingar", + "Simple": "Einfalt", + "Advanced": "Ítarlegt", + "UI Language": "Tungumál", + "Account": "Reikningur", + "Admin Panel": "Stjórnborð", + "Logout": "Að skrá þig út", + "Search Settings": "Leitaðu í stillingum", + "UI Theme": "Þema notendaviðmóts", + "Import a theme file": "Flytja inn þema skrá", + "Export a theme file": "Flytja út þema skrá", + "Delete a theme": "Eyða þema", + "Update a theme file": "Uppfæra þemu skrá", + "Save as a new theme": "Vista sem nýja þemu", + "Avatar Style:": "Avatar Stíll", + "Circle": "Hring", + "Square": "Reitur", + "Rectangle": "Ferhyrningur", + "Chat Style:": "Stíll spjalls:", + "Flat": "Flat\nBólur\nSkjal", + "Bubbles": "Bubblur", + "Document": "Skjal", + "Specify colors for your theme.": "Tilgreindu liti fyrir þemað þitt.", + "Theme Colors": "Þema litir", + "Main Text": "Aðaltexti", + "Italics Text": "Skáletraður texti", + "Underlined Text": "Undirstrikaður texti", + "Quote Text": "Tilvitnunartexti", + "Shadow Color": "Skuggalitur", + "Chat Background": "Bakgrunnur spjalls", + "UI Background": "Bakgrunnur viðmóts", + "UI Border": "Rammi viðmóts", + "User Message Blur Tint": "Dökkun á skilaboðum notenda", + "AI Message Blur Tint": "Dökkun á skilaboðum AI", + "Chat Width": "Spjallbreidd", + "Width of the main chat window in % of screen width": "Breidd aðalspjallgluggans í % af skjábreidd", + "Font Scale": "Leturstærð", + "Font size": "Leturstærð", + "Blur Strength": "Mýkur styrkur", + "Blur strength on UI panels.": "Þokastyrkur á UI spjöldum.", + "Text Shadow Width": "Breidd textaskugga", + "Strength of the text shadows": "Styrkur textaskugganna", + "Disables animations and transitions": "Óvirkjaður aðgerðir og yfirgangur", + "Reduced Motion": "Minnkaður hreyfing", + "removes blur from window backgrounds": "Fjarlægðu fyrirbærið frá bakgrunnsmyndum glugga", + "No Blur Effect": "Engin Slør Áhrif", + "Remove text shadow effect": "Fjarlægðu textaskugga", + "No Text Shadows": "Engin Texta Skuggar", + "Reduce chat height, and put a static sprite behind the chat window": "Minnkaðu hæð spjallsins og settu fastan myndsprite á eftir spjallglugganum", + "Waifu Mode": "Waifu Hamur", + "Always show the full list of the Message Actions context items for chat messages, instead of hiding them behind '...'": "Sýna alltaf fulla listann yfir hluti efnis í boðum um skilaboð, frekar en að fela þá fyrir aftan '...'", + "Auto-Expand Message Actions": "Sjálfvirk auka boða aðgerðir", + "Alternative UI for numeric sampling parameters with fewer steps": "Valkostur UI fyrir talna sýnaeiginleika með færri skrefum", + "Zen Sliders": "Sláðar fyrir ró", + "Entirely unrestrict all numeric sampling parameters": "Helt ótakmarka allar tölulegar sýnaeiginleika", + "Mad Lab Mode": "Heimur labba", + "Time the AI's message generation, and show the duration in the chat log": "Tímaðu framleiðslu skilaboða AI og sýndu varaktina í spjall skránni", + "Message Timer": "Skilaboð Veggklukka", + "Show a timestamp for each message in the chat log": "Sýna tímasetningu fyrir hvert skilaboð í spjall skránni", + "Chat Timestamps": "Tímastimplar í spjalli", + "Show an icon for the API that generated the message": "Sýna tákn fyrir API sem búað til skilaboðin", + "Model Icon": "Módel Tákn", + "Show sequential message numbers in the chat log": "Sýna röðuð skilaboðanúmer í spjall skránni", + "Message IDs": "Skilaboðaauðkenni", + "Hide avatars in chat messages.": "Fela avatar í spjallskilaboðum.", + "Hide Chat Avatars": "Fela spjallmyndir", + "Show the number of tokens in each message in the chat log": "Sýna fjölda tákn í hverju skilaboði í spjall skránni", + "Show Message Token Count": "Sýna fjölda tákn í skilaboðum", + "Single-row message input area. Mobile only, no effect on PC": "Einn röð skilaboða innskots svæði. Aðeins fyrir farsíma, engin áhrif á PC", + "Compact Input Area (Mobile)": "Þjappað svæði fyrir inntak (farsími)", + "In the Character Management panel, show quick selection buttons for favorited characters": "Í stjórnborði persónu stjórnunar, sýna fljótsval hnappa fyrir uppáhalds persónur", + "Characters Hotswap": "Breyta persónum á hraða", + "Enable magnification for zoomed avatar display.": "Virkja stækkun fyrir aðdráttarmyndaskjá.", + "Avatar Hover Magnification": "Avatar sveima stækkun", + "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "Virkjar stækkunaráhrif á sveimi þegar þú birtir aðdráttarmynd eftir að hafa smellt á mynd notanda í spjalli.", + "Show tagged character folders in the character list": "Sýna tegundaðar persónumöppur í persónulista", + "Tags as Folders": "Tákn sem möppur", + "Tags_as_Folders_desc": "Nýleg breyting: Merki verða að vera merkt sem möppur í valmyndinni Tag Management til að birtast sem slík. Smelltu hér til að koma því upp.", + "Character Handling": "Meðhöndlun persónu", + "If set in the advanced character definitions, this field will be displayed in the characters list.": "Ef stillt í nákvæmum skilgreiningum á persónum, verður þessi reitur sýndur í lista yfir persónur.", + "Char List Subheader": "Char List Undirhaus", + "Character Version": "Útgáfa á persónu", + "Created by": "Búið til af", + "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "Notaðu óljós samræmi og leitaðu að persónum í listanum eftir öllum gagnasviðum, ekki bara með nafn hlutstreng", + "Advanced Character Search": "Framfarin persónuleg leit", + "If checked and the character card contains a prompt override (System Prompt), use that instead": "Ef merkt er og kortið inniheldur framkallanatilbirtingu (kerfisframkallanir), notaðu það í staðinn", + "Prefer Character Card Prompt": "Kosstu kvenkortu fyrirspurn", + "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Ef merkt er og kortið inniheldur fangabrotsskil, notaðu það í staðinn", + "Prefer Character Card Jailbreak": "Kosstu kvenkortu fangabrot", + "never_resize_avatars_tooltip": "Forðastu að klippa og breyta stærð innfluttra stafamynda. Þegar slökkt er á því skaltu skera/breyta stærð í 512x768.", + "Never resize avatars": "Aldrei breyta stærðinni á merkjum", + "Show actual file names on the disk, in the characters list display only": "Sýna raunveruleg nöfn skráa á diskinum, í lista yfir persónur sýna aðeins", + "Show avatar filenames": "Sýna nöfn merkja", + "Prompt to import embedded card tags on character import. Otherwise embedded tags are ignored": "Biðja um að flytja inn innbyggðar kortaáhöfn við flytjanlegar persónur. Annars verða innbyggðar áhöfnir fyrirgefnar", + "Import Card Tags": "Flytja inn kortaáhöfn", + "Hide character definitions from the editor panel behind a spoiler button": "Fela skilgreiningar persónu frá ritstjórnarljós bak við spennulitann", + "Spoiler Free Mode": "Leynir ókeypis ham", + "Miscellaneous": "Ýmislegt", + "Reload and redraw the currently open chat": "Endurhlaða og endurnýta núverandi opna spjall", + "Reload Chat": "Endurhlaða spjalli", + "Debug Menu": "Aðgerða valmynd", + "Smooth Streaming": "Sléttur streymi", + "Experimental feature. May not work for all backends.": "Tilraunaeiginleiki. Virkar kannski ekki fyrir alla bakenda.", + "Slow": "Hægur", + "Fast": "Hratt", + "Play a sound when a message generation finishes": "Spila hljóð þegar skilaboðaframleiðsla er lokið", + "Message Sound": "Hljóð skilaboða", + "Only play a sound when ST's browser tab is unfocused": "Spilaðu aðeins hljóð þegar vafrahnappurinn á ST er ekki miðaður", + "Background Sound Only": "Bakgrunnsljóð einungis", + "Reduce the formatting requirements on API URLs": "Minnkaðu kröfur um snið á API URL", + "Relaxed API URLS": "Afslappaðar API URLS", + "Ask to import the World Info/Lorebook for every new character with embedded lorebook. If unchecked, a brief message will be shown instead": "Biðja um að flytja inn heimurinn Info/Lorebook fyrir hverja nýja persónu með innbyggðan lorebook. Ef óskað er ekki verður sýnd stutta skilaboð í staðinn", + "Lorebook Import Dialog": "Saga Bók Import Dæmi", + "Restore unsaved user input on page refresh": "Endurheimta óvistaða notendainnslegu viðbótina við endurnýjun síðu", + "Restore User Input": "Endurheimta notenda inntak", + "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "Leyfa endursetningu ákveðinna UI atriða með því að draga þau. Aðeins PC, engin áhrif á farsíma", + "Movable UI Panels": "Hreyfanlegar UI-pallar", + "MovingUI preset. Predefined/saved draggable positions": "MovingUI forskrift. Forstillingar/geymdir dragbærir staðsetningar", + "MUI Preset": "Forsnið MUI:", + "Save movingUI changes to a new file": "Vistaðu breytingar á MovingUI í nýrri skrá", + "Reset MovingUI panel sizes/locations.": "Endurstilla MovingUI spjaldið stærðir/staðsetningar.", + "Apply a custom CSS style to all of the ST GUI": "Beita sérstakri CSS stillingu fyrir allt ST GUI", + "Custom CSS": "Sérsniðin CSS", + "Expand the editor": "Stækkaðu ritstjórann", + "Chat/Message Handling": "Meðhöndlun spjalls/skilaboða", + "# Messages to Load": "#Sk. að hlaða", + "The number of chat history messages to load before pagination.": "Fjöldi spjallferilsskilaboða sem á að hlaða fyrir síðuskipun.", + "(0 = All)": "(0 = Allt)", + "Streaming FPS": "FPS í flæði", + "Update speed of streamed text.": "Uppfærðu hraða á streymdum texta.", + "Example Messages Behavior": "Atriði hegðunar skilaboða", + "Gradual push-out": "Klifur aðeins út", + "Always include examples": "Alltaf innifæra dæmi", + "Never include examples": "Aldrei innifæra dæmi", + "Send on Enter": "Senda á Enter", + "Disabled": "Öruggað", + "Automatic (PC)": "Sjálfvirkt (PC)", + "Press Send to continue": "Ýttu á Senda til að halda áfram", + "Show a button in the input area to ask the AI to continue (extend) its last message": "Sýna hnapp í innskráningar svæði til að biðja AI um að halda áfram (framlengja) síðustu skilaboðin", + "Quick 'Continue' button": "Fljótar 'Halda áfram' hnappur", + "Show arrow buttons on the last in-chat message to generate alternative AI responses. Both PC and mobile": "Sýna örhnappa á síðustu skilaboðum í spjallinu til að búa til annan AI svarmöguleika. Bæði PC og farsími", + "Swipes": "Strjúkun", + "Allow using swiping gestures on the last in-chat message to trigger swipe generation. Mobile only, no effect on PC": "Leyfa notkun á sveipum á síðustu skilaboðum í spjallinu til að kalla fram sveiflugerð. Aðeins fyrir farsíma, engin áhrif á PC", + "Gestures": "Tákn", + "Auto-load Last Chat": "Sjálfvirkur hleðsla síðustu spjalls", + "Auto-scroll Chat": "Sjálfvirkur rúlla spjall", + "Save edits to messages without confirmation as you type": "Vistaðu breytingar á skilaboðum án staðfestingar meðan þú skrifar", + "Auto-save Message Edits": "Sjálfvirkur vistun skilaboðabreytinga", + "Confirm message deletion": "Staðfesta eyðingu skilaboða", + "Auto-fix Markdown": "Sjálfvirk lagfæring Markdown", + "Disallow embedded media from other domains in chat messages": "Ekki leyfa innfellda miðla frá öðrum lénum í spjallskilaboðum.", + "Forbid External Media": "Banna ytri miðla", + "Allow {{char}}: in bot messages": "Leyfa {{char}}: í boðum botts", + "Allow {{user}}: in bot messages": "Leyfa {{user}}: í boðum botts", + "Skip encoding and characters in message text, allowing a subset of HTML markup as well as Markdown": "Sleppa kodunar og tengingar í texta skilaboða, leyfa hluta af HTML merkingu og Markdown", + "Show tags in responses": "Sýna merki í svörum", + "Allow AI messages in groups to contain lines spoken by other group members": "Leyfa AI skilaboð í hópum að innihalda línur talaðar af öðrum hópmeðlimum", + "Relax message trim in Groups": "Slaka á skurðboðum í hópum", + "Log prompts to console": "Skráðu boð í tölvuna", + "Requests logprobs from the API for the Token Probabilities feature": "Óskar logprobs frá API fyrir sýnileika áhlutum", + "Request token probabilities": "Beiðni um tóka líkur", + "Automatically reject and re-generate AI message based on configurable criteria": "Hafnaðu sjálfkrafa og endurheimtu AI skilaboð miðað við stillanlega skilyrði", + "Auto-swipe": "Sjálfvirkur sveip", + "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Virkjaðu sjálfvirka sveiflugerð. Stillingar í þessum hluta hafa aðeins áhrif þegar sjálfvirkur sveiflugerð er virk", + "Minimum generated message length": "Lágmarks lengd á mynduðum skilaboðum", + "If the generated message is shorter than these many characters, trigger an auto-swipe": "Ef mynduðu skilaboðin eru styttri en þessi, kallaðu fram sjálfvirkar sveiflugerðar", + "Blacklisted words": "Svört orð", + "words you dont want generated separated by comma ','": "orð sem þú vilt ekki að framleiða aðskilin með kommu ','", + "Blacklisted word count to swipe": "Fjöldi svörtra orða til að sveipa", + "Minimum number of blacklisted words detected to trigger an auto-swipe": "Lágmarksfjöldi svörtu orða sem greindir eru til að valda sjálfvirku sveipi", + "AutoComplete Settings": "Stillingar sjálfvirkrar útfyllingar", + "Automatically hide details": "Fela sjálfkrafa upplýsingar", + "Determines how entries are found for autocomplete.": "Ákveður hvernig færslur finnast fyrir sjálfvirka útfyllingu.", + "Autocomplete Matching": "Samsvörun", + "Starts with": "Byrjar með", + "Includes": "Inniheldur", + "Fuzzy": "Óljóst", + "Sets the style of the autocomplete.": "Stillir stíl sjálfvirkrar útfyllingar.", + "Autocomplete Style": "Stíll", + "Follow Theme": "Fylgstu með þema", + "Dark": "Myrkur", + "Sets the font size of the autocomplete.": "Stillir leturstærð sjálfvirkrar útfyllingar.", + "Sets the width of the autocomplete.": "Stillir breidd sjálfvirkrar útfyllingar.", + "Autocomplete Width": "Breidd", + "chat input box": "inntaksbox fyrir spjall", + "entire chat width": "alla spjallbreiddina", + "full window width": "fullri gluggabreidd", + "STscript Settings": "STscript stillingar", + "Sets default flags for the STscript parser.": "Setur sjálfgefna fána fyrir STscript þáttarann.", + "Parser Flags": "Parser Fánar", + "Switch to stricter escaping, allowing all delimiting characters to be escaped with a backslash, and backslashes to be escaped as well.": "Skiptu yfir í strangari sleppi, sem gerir kleift að sleppa öllum afmörkunarstöfum með bakskástrikum og afturskástrikum líka.", + "STRICT_ESCAPING": "STRICT_ESCAPING", + "Replace all {{getvar::}} and {{getglobalvar::}} macros with scoped variables to avoid double macro substitution.": "Skiptu út öllum {{getvar::}} og {{getglobalvar::}} fjölvunum fyrir umfangsbreytur til að koma í veg fyrir tvöfalda fjölvaskipti.", + "REPLACE_GETVAR": "REPLACE_GETVAR", + "Change Background Image": "Breyta bakgrunnsmynd", + "Filter": "Sía", + "Automatically select a background based on the chat context": "Velja sjálfkrafa bakgrunn út frá samhengi spjallsins", + "Auto-select": "Sjálfval", + "System Backgrounds": "Kerfis bakgrunnsmyndir", + "Chat Backgrounds": "Bakgrunnsmyndir spjalls", + "bg_chat_hint_1": "Spjallbakgrunnur myndaður með", + "bg_chat_hint_2": "viðbót mun birtast hér.", + "Extensions": "Viðbætur", + "Notify on extension updates": "Tilkynna um uppfærslur á viðbótum", + "Manage extensions": "Stjórna viðbótum", + "Import Extension From Git Repo": "Flytja inn viðbót frá Git geymslu", + "Install extension": "Setja upp viðbót", + "Extras API:": "Aukaforritaskil:", + "Auto-connect": "Sjálfvirk tenging", + "Extras API URL": "Aukahlutir API vefslóð", + "Extras API key (optional)": "Aukastafi API lykill (valkvæmur)", + "Persona Management": "Stjórnun á persónu", + "How do I use this?": "Hvernig notar ég þetta?", + "Click for stats!": "Smelltu til að sjá tölfræði!", + "Usage Stats": "Nota tölfræði", + "Backup your personas to a file": "Skráðu persónurnar þínar í skrá", + "Backup": "Öryggisafrit", + "Restore your personas from a file": "Endurheimta persónurnar þínar úr skrá", + "Restore": "Endurheimta", + "Create a dummy persona": "Búa til falsa persónu", + "Create": "Búa til", + "Toggle grid view": "Skipti um líkamlega sýn", + "No persona description": "[Engin lýsing]", + "Name": "Nafn", + "Enter your name": "Sláðu inn nafn þitt", + "Click to set a new User Name": "Smelltu til að stilla nýjan notandanafn", + "Click to lock your selected persona to the current chat. Click again to remove the lock.": "Smelltu til að lássetja valda persónu þína í núverandi spjalli. Smelltu aftur til að fjarlægja læsuna.", + "Click to set user name for all messages": "Smelltu til að stilla notendanafn fyrir öll skilaboð", + "Persona Description": "Lýsing persónu", + "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "Dæmi: [{{user}} er 28 ára gömul Rúmensk köttatík.]", + "Tokens persona description": "Tákn lýsingar á persónu", + "Position:": "Staða:", + "In Story String / Prompt Manager": "Í saga streng / Leiðbeinendur", + "Top of Author's Note": "Toppur höfundarathugasemda", + "Bottom of Author's Note": "Botn höfundarathugasemda", + "In-chat @ Depth": "Í spjalli @ Dýpt", + "Depth:": "Dýpt:", + "Role:": "Hlutverk:", + "System": "Kerfi", + "User": "Notandi", + "Assistant": "Aðstoðarmaður", + "Show notifications on switching personas": "Sýna tilkynningar við skipti á persónum", + "Character Management": "Stjórnun persónu", + "Locked = Character Management panel will stay open": "Læst = Paneel stjórnunar persónu verður opinn", + "Select/Create Characters": "Velja/Búa til persónur", + "Favorite characters to add them to HotSwaps": "Setja uppáhalds persónur í HotSwaps", + "Token counts may be inaccurate and provided just for reference.": "Táknatala getur verið ónákvæm og veitt bara til viðmiðunar.", + "Total tokens": "Samtals tákn", + "Calculating...": "Er að reikna...", + "Tokens": "Tákn", + "Permanent tokens": "Varanleg tákn", + "Permanent": "Varanleg", + "About Token 'Limits'": "Um Token 'Limits'", + "Toggle character info panel": "Skiptu um persónuupplýsingar", + "Name this character": "Nefndu þessa persónu", + "extension_token_counter": "Tákn:", + "Click to select a new avatar for this character": "Smelltu til að velja nýja avatar fyrir þessa persónu", + "Add to Favorites": "Bæta í uppáhald", + "Advanced Definition": "Ítarleg skilgreining", + "Character Lore": "Persónu Saga", + "Chat Lore": "Spjallaðu Lore", + "Export and Download": "Flytja út og niðurhal", + "Duplicate Character": "Tvöfalda persónu", + "Create Character": "Búa til persónu", + "Delete Character": "Eyða persónu", + "More...": "Meira...", + "Link to World Info": "Tengill á heimur upplýsingar", + "Import Card Lore": "Flytja inn kortaleður", + "Scenario Override": "Afbrotasögu Íhald", + "Convert to Persona": "Umbreyttu í Persónu", + "Rename": "Endurnefna", + "Link to Source": "Tengill á Source", + "Replace / Update": "Skipta út / uppfæra", + "Import Tags": "Flytja inn merki", + "Search / Create Tags": "Leitaðu / Búðu til merkingar", + "View all tags": "Skoða allar merki", + "Creator's Notes": "Athugasemdir höfundar", + "Show / Hide Description and First Message": "Sýna / Fela Lýsingu og Fyrsta Skilaboð", + "Character Description": "Lýsing á persónu", + "Click to allow/forbid the use of external media for this character.": "Smelltu til að leyfa/banna notkun ytri miðla fyrir þessa persónu.", + "Ext. Media": "Ext. Fjölmiðlar", + "Describe your character's physical and mental traits here.": "Lýstu líkamlegum og andlegum einkennum persónunnar þinnar hér.", + "First message": "Fyrsta skilaboð", + "Click to set additional greeting messages": "Smelltu til að stilla viðbótarheilsuskilaboð", + "Alt. Greetings": "Alt. Kveðja", + "This will be the first message from the character that starts every chat.": "Þetta verður fyrsta skilaboðið frá persónunni sem byrjar á hverju spjalli.", + "Group Controls": "Hópastjórn", + "Chat Name (Optional)": "Spjall Nafn (valkvæmt)", + "Click to select a new avatar for this group": "Smelltu til að velja nýja avatar fyrir þessa hóp", + "Group reply strategy": "Stefna svara í hóp", + "Natural order": "Náttúruleg röð", + "List order": "Listar röð", + "Group generation handling mode": "Meðhöndlunarhamur hópkynslóða", + "Swap character cards": "Skiptu um persónukort", + "Join character cards (exclude muted)": "Tengdu persónukort (útiloka þöggð)", + "Join character cards (include muted)": "Tengdu persónuspjöld (innifalin þögguð)", + "Inserted before each part of the joined fields.": "Sett inn fyrir hvern hluta sameinaðra reita.", + "Join Prefix": "Skráðu þig í Forskeyti", + "When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and with the name of the part (e.g.: description, personality, scenario, etc.)": "Þegar 'Tengdu persónukort' er valið er verið að tengja saman alla viðkomandi reitir persónanna.\rÞetta þýðir að í sögustrengnum verða til dæmis allar persónulýsingar sameinaðar í einn stóran texta.\rEf þú vilt að þessir reitir séu aðskildir geturðu skilgreint forskeyti eða viðskeyti hér.\r\rÞetta gildi styður venjulega fjölva og mun einnig skipta út {{char}} fyrir viðkomandi bleikjunafni og fyrir nafn hlutans (t.d.: lýsing, persónuleiki, atburðarás osfrv.)", + "Inserted after each part of the joined fields.": "Sett inn á eftir hverjum hluta sameinaðra reita.", + "Join Suffix": "Skráðu þig í viðskeyti", + "Set a group chat scenario": "Setja hópspjallsskipulag", + "Click to allow/forbid the use of external media for this group.": "Smelltu til að leyfa/banna notkun ytri miðla fyrir þennan hóp.", + "Restore collage avatar": "Endurheimta samsettu avatar", + "Allow self responses": "Leyfa sjálfsvör", + "Auto Mode": "Sjálfvirkur hamur", + "Auto Mode delay": "Töf sjálfvirkrar stillingar", + "Hide Muted Member Sprites": "Fela þögguð meðlim Sprites", + "Current Members": "Núverandi meðlimir", + "Add Members": "Bæta við meðlimum", + "Create New Character": "Búa til nýja persónu", + "Import Character from File": "Flytja inn persónu úr skrá", + "Import content from external URL": "Flytja inn efni frá ytri vefslóð", + "Create New Chat Group": "Búa til nýjan spjallhóp", + "Characters sorting order": "Raða röð persóna", + "A-Z": "A-Ö", + "Z-A": "Ö-A", + "Newest": "Nýjast", + "Oldest": "Eldst", + "Favorites": "Uppáhald", + "Recent": "Nýleg", + "Most chats": "Flest spjall", + "Least chats": "Minnst spjall", + "Most tokens": "Flest tákn", + "Least tokens": "Minnst tákn", + "Random": "Handahófskennt", + "Toggle character grid view": "Skipta um útlit á karakterkortum", + "Bulk_edit_characters": "Breyta mörgum persónum í einu", + "Bulk select all characters": "Velja alla stafi í magni", + "Bulk delete characters": "Eyða mörgum persónum í einu", + "popup-button-save": "Vista", + "popup-button-yes": "Já", + "popup-button-no": "Nei", + "popup-button-cancel": "Hætta við", + "popup-button-import": "Flytja inn", + "Advanced Definitions": "Ítarleg skilgreiningar", + "Prompt Overrides": "Hnekkja hvetjandi", + "(For Chat Completion and Instruct Mode)": "(Til að ljúka spjalli og leiðbeiningarham)", + "Insert {{original}} into either box to include the respective default prompt from system settings.": "Settu inn {{original}} í hvora kassa til að innifela viðkomandi sjálfgefna framkallan frá kerfisstillingum.", + "Main Prompt": "Höfuðkerfisframkallan", + "Any contents here will replace the default Main Prompt used for this character. (v2 spec: system_prompt)": "Allt innihald hér verður að setja sjálfgefna aðalskrefið sem notast er við þessa persónu.", + "Any contents here will replace the default Jailbreak Prompt used for this character. (v2 spec: post_history_instructions)": "Allt innihald hér verður að setja sjálfgefna fangabrotsávarpið sem notast er við þessa persónu.", + "Creator's Metadata (Not sent with the AI prompt)": "Upplýsingar höfundar (Ekki send með AI framkallan)", + "Creator's Metadata": "Lýsigögn skapara", + "(Not sent with the AI Prompt)": "(Ekki sent með AI hvetjunni)", + "Everything here is optional": "Allt hér er valfrjálst", + "(Botmaker's name / Contact Info)": "(Nafn og tengiliðir geranda)", + "(If you want to track character versions)": "(Ef þú vilt fylgjast með útgáfum persónu)", + "(Describe the bot, give use tips, or list the chat models it has been tested on. This will be displayed in the character list.)": "(Lýstu bót, gefðu notkunartips eða listar spjallmynstrin sem það hefur verið prófað á. Þetta verður sýnt í persónulistanum.)", + "Tags to Embed": "Merkingar til að festa", + "(Write a comma-separated list of tags)": "(Skrifaðu kommu aðskilnaðið lista af merkjum)", + "Personality summary": "Samantekt persónuleika", + "(A brief description of the personality)": "(Stutt lýsing á persónuleika)", + "Scenario": "Atburðir", + "(Circumstances and context of the interaction)": "(Aðstæður og samhengi samskipti)", + "Character's Note": "Athugasemd persóna", + "(Text to be inserted in-chat @ designated depth and role)": "(Texti sem á að setja inn í spjall @ tilnefnd dýpt og hlutverk)", + "@ Depth": "@ Dýpt", + "Role": "Hlutverk", + "Talkativeness": "Prátgjarnleiki", + "How often the character speaks in group chats!": "Hversu oft persónan talar í hópspjallum!", + "How often the character speaks in": "Hversu oft persónan talar inn", + "group chats!": "hópa spjallar!", + "Shy": "Feiminn", + "Normal": "Venjulegur", + "Chatty": "Ógleðilegur", + "Examples of dialogue": "Dæmi um ræðu", + "Important to set the character's writing style.": "Mikilvægt að stilla skrifstíl persónunnar.", + "(Examples of chat dialog. Begin each example with START on a new line.)": "(Dæmi um spjallræðu. Byrjaðu hverja dæmi með BYRJA á nýrri línu.)", + "Save": "Vista", + "Chat History": "Spjall saga", + "Import Chat": "Flytja inn spjall", + "Copy to system backgrounds": "Afritaðu í kerfisbakgrunn", + "Rename background": "Endurnefna bakgrunn", + "Lock": "Læsa", + "Unlock": "Opnaðu", + "Delete background": "Eyða bakgrunni", + "Chat Scenario Override": "Hneka spjallatburðarás", + "Remove": "Fjarlægja", + "Type here...": "Skrifaðu hér...", + "Chat Lorebook": "Spjall Lorebook fyrir", + "Chat Lorebook for": "Spjall Lorebook fyrir", + "chat_world_template_txt": "Valdar Heimsupplýsingar verða bundnar við þetta spjall. Þegar þú býrð til AI svar,\n það verður sameinað færslum úr heimsbókum og persónufræðibókum.", + "Select a World Info file for": "Veldu heimsupplýsingaskrá fyrir", + "Primary Lorebook": "Aðal Saga Bók", + "A selected World Info will be bound to this character as its own Lorebook.": "Valin heimsupplýsingar verða tengdar þessari persónu sem eigin Saga Bók.", + "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "Þegar verið er að búa til svar frá AI, verður það sameinað við færslur frá almennum heimsupplýsingaval.", + "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "Til að flytja út persónu mun einnig verða valin Saga Bókaskrá eingöngu í JSON gögnunum.", + "Additional Lorebooks": "Viðbótar Saga Bækur", + "Associate one or more auxillary Lorebooks with this character.": "Tengja við einn eða fleiri aukahald Saga Bækur við þessa persónu.", + "NOTE: These choices are optional and won't be preserved on character export!": "ATHUGIÐ: Þessir valkostir eru valfrjálsir og verða ekki varðveittir við útflutning persónu!", + "Rename chat file": "Endurnefna spjallaskrá", + "Export JSONL chat file": "Flytja út JSONL spjallaskrá", + "Download chat as plain text document": "Niðurhala spjalli sem einfaldan textaskjal", + "Delete chat file": "Eyða spjallaskrá", + "Use tag as folder": "Merktu sem mappa", + "Delete tag": "Eyða merki", + "Entry Title/Memo": "Titill færslu/Minnisblað", + "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized❌ Disabled": "WI inngangsstaða:\r🔵 Stöðugt\r😢 Venjulegt\r🔗 Vectorized\r❌ Óvirk", + "WI_Entry_Status_Constant": "Stöðugt", + "WI_Entry_Status_Normal": "Eðlilegt", + "WI_Entry_Status_Vectorized": "Vectorized", + "WI_Entry_Status_Disabled": "Öryrkjar", + "T_Position": "↑Char: Fyrir persónutákningar\n↓Char: Eftir persónutákningar\n↑AN: Fyrir athugasemdir höfundar\n↓AN: Eftir athugasemdir höfundar\n@D: Á dýpt", + "Before Char Defs": "Fyrir persónutákningar", + "After Char Defs": "Eftir persónutákningar", + "Before EM": "↑EM", + "After EM": "↓EM", + "Before AN": "Fyrir AN", + "After AN": "Eftir AN", + "at Depth System": "@D ⚙️", + "at Depth User": "@D 👤", + "at Depth AI": "@D 🤖", + "Depth": "Dýpt", + "Order:": "Raða:", + "Order": "Raða:", + "Trigger %:": "Kveikja %:", + "Probability": "Líkur", + "Duplicate world info entry": "Afrit af heimsupplýsingafærslu", + "Delete world info entry": "Eyða heimsupplýsingafærslu", + "Comma separated (required)": "Koma aðskilið (krafist)", + "Primary Keywords": "Aðal orðlyklar", + "Keywords or Regexes": "Leitarorð eða Regexes", + "Comma separated list": "Listi aðskilinn með kommum", + "Switch to plaintext mode": "Skiptu yfir í textastillingu", + "Logic": "Rökhugsun", + "AND ANY": "OG, HVERGI", + "AND ALL": "OG, ALLT", + "NOT ALL": "EKKI ALLT", + "NOT ANY": "EKKI HVERGI", + "(ignored if empty)": "(hunsað ef það er tómt)", + "Optional Filter": "Frjálst síur", + "Keywords or Regexes (ignored if empty)": "Leitarorð eða Regexes (hunsað ef tómt)", + "Comma separated list (ignored if empty)": "Kommuaðskilinn listi (hunsaður ef hann er tómur)", + "Use global setting": "Nota heimsstillingu", + "Case-Sensitive": "Máli-í-litlum", + "Yes": "Já", + "No": "Nei", + "Can be used to automatically activate Quick Replies": "Hægt að nota til að virkja sjálfkrafa Quick Replies", + "Automation ID": "Sjálfvirkni auðkenni", + "( None )": "( Enginn )", + "Content": "Efnisatriði", + "Exclude from recursion": "Útiloka frá endurtekningu", + "Prevent further recursion (this entry will not activate others)": "Koma í veg fyrir frekari endurkomu (þessi færsla mun ekki virkja aðra)", + "Delay until recursion (this entry can only be activated on recursive checking)": "Seinkað þar til endurkomu (þessi færsla er aðeins hægt að virkja við endurkvæma athugun)", + "What this keyword should mean to the AI, sent verbatim": "Hvað þetta lykilorð ætti að þýða fyrir AI, sent bókstaflega", + "Filter to Character(s)": "Sía til Persónu(r)", + "Character Exclusion": "Persónuúteslutningur", + "-- Characters not found --": "-- Persónur finnast ekki --", + "Inclusion Group": "Innifólgur Hópur", + "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "Inntökuhópar tryggja að aðeins ein færsla úr hópi sé virkjuð í einu, ef margar eru ræstar.\rStyður marga hópa aðskilda með kommum.\r\rSkjöl: World Info - Inclusion Group", + "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "Forgangsraða þessari færslu: Þegar hakað er við þá er þessari færslu forgangsraðað úr öllu vali.\rEf mörgum er forgangsraðað er sá sem hefur hæstu 'pöntun' valin.", + "Only one entry with the same label will be activated": "Aðeins ein skrá með sömu merki verður virk", + "A relative likelihood of entry activation within the group": "Hlutfallslegar líkur á inngönguvirkjun innan hópsins", + "Group Weight": "Þyngd hópa", + "Selective": "Valinn", + "Use Probability": "Nota líkur", + "Add Memo": "Bæta við minnisblaði", + "Text or token ids": "Texti eða [tákn auðkenni]", + "close": "loka", + "prompt_manager_edit": "Breyta", + "prompt_manager_name": "Nafn", + "A name for this prompt.": "Nafn fyrir þessa tilvitnun.", + "To whom this message will be attributed.": "Hverjum þessi skilaboð verða eignuð.", + "AI Assistant": "AI aðstoðarmaður", + "prompt_manager_position": "Staða", + "Injection position. Next to other prompts (relative) or in-chat (absolute).": "Inndælingarstaða. Við hliðina á öðrum leiðbeiningum (afstætt) eða í spjalli (algert).", + "prompt_manager_relative": "Aðstandandi", + "prompt_manager_depth": "Dýpt", + "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "Inndælingardýpt. 0 = eftir síðustu skilaboð, 1 = fyrir síðustu skilaboð o.s.frv.", + "Prompt": "Ábending", + "The prompt to be sent.": "Tilvitnunin sem á að senda.", + "This prompt cannot be overridden by character cards, even if overrides are preferred.": "Ekki er hægt að hnekkja þessari vísbendingu með persónuspjöldum, jafnvel þótt hnekkingar séu æskilegar.", + "prompt_manager_forbid_overrides": "Banna hnekkingar", + "reset": "endurstilla", + "save": "vista", + "This message is invisible for the AI": "Þessi skilaboð eru ósýnileg fyrir AI", + "Message Actions": "Skilaboðaaðgerðir", + "Translate message": "Þýða skilaboð", + "Generate Image": "Búa til mynd", + "Narrate": "Segja frá", + "Exclude message from prompts": "Útiloka skilaboð frá hvatningum", + "Include message in prompts": "Innifera skilaboð í hvatningum", + "Embed file or image": "Innlima skrá eða mynd", + "Create checkpoint": "Búa til leiðarljós", + "Create Branch": "Búa til grein", + "Copy": "Afrita", + "Open checkpoint chat": "Opna checkpoint spjall", + "Edit": "Breyta", + "Confirm": "Staðfesta", + "Copy this message": "Afrita þetta skilaboð", + "Delete this message": "Eyða þessum skilaboðum", + "Move message up": "Færa skilaboðin upp", + "Move message down": "Færa skilaboðin niður", + "Enlarge": "Stækka", + "Welcome to SillyTavern!": "Velkomin í SillyTavern!", + "welcome_message_part_1": "Lestu", + "welcome_message_part_2": "Opinber skjöl", + "welcome_message_part_3": null, + "welcome_message_part_4": "Gerð", + "welcome_message_part_5": "í spjalli fyrir skipanir og fjölvi.", + "welcome_message_part_6": "Skráðu þig í", + "Discord server": "Discord þjónn", + "welcome_message_part_7": "fyrir upplýsingar og tilkynningar.", + "SillyTavern is aimed at advanced users.": "SillyTavern er ætlað háþróuðum notendum.", + "If you're new to this, enable the simplified UI mode below.": "Ef þú ert nýr í þessu skaltu virkja einfaldaða notendaviðmótið hér að neðan.", + "Change it later in the 'User Settings' panel.": "Breyttu því síðar í 'Notandastillingum' spjaldinu.", + "Enable simple UI mode": "Virkjaðu einfaldan notendaham", + "Looking for AI characters?": "Ertu að leita að gervigreindarstöfum?", + "onboarding_import": "Flytja inn", + "from supported sources or view": "frá studdum heimildum eða útsýni", + "Sample characters": "Dæmi um stafi", + "Your Persona": "Þín persóna", + "Before you get started, you must select a persona name.": "Áður en þú byrjar verður þú að velja persónuheiti.", + "welcome_message_part_8": "Þessu er hægt að breyta hvenær sem er í gegnum", + "welcome_message_part_9": "táknmynd.", + "Persona Name:": "Persónuheiti:", + "Temporarily disable automatic replies from this character": "Tímabundið aftengja sjálfvirka svör frá þessari persónu", + "Enable automatic replies from this character": "Virkja sjálfvirka svör frá þessari persónu", + "Trigger a message from this character": "Kveikja á skilaboðum frá þessari persónu", + "Move up": "Færa upp", + "Move down": "Færa niður", + "View character card": "Skoða persónukort", + "Remove from group": "Fjarlægja úr hóp", + "Add to group": "Bæta við hóp", + "Alternate Greetings": "Varakveðjur", + "Alternate_Greetings_desc": "Þetta mun birtast sem högg í fyrstu skilaboðunum þegar nýtt spjall er hafið.\n Hópmeðlimir geta valið einn þeirra til að hefja samtalið.", + "Alternate Greetings Hint": "Smelltu á hnappinn til að byrja!", + "(This will be the first message from the character that starts every chat)": "(Þetta verður fyrsta skilaboðið frá persónunni sem byrjar á hverju spjalli)", + "Forbid Media Override explanation": "Geta núverandi persónu/hóps til að nota ytri miðla í spjalli.", + "Forbid Media Override subtitle": "Miðlar: myndir, myndbönd, hljóð. Ytra: ekki hýst á staðbundnum netþjóni.", + "Always forbidden": "Alltaf bannað", + "Always allowed": "Alltaf leyfilegt", + "View contents": "Skoða innihald", + "Remove the file": "Fjarlægðu skrána", + "Unique to this chat": "Einstakt fyrir þetta spjall", + "Checkpoints inherit the Note from their parent, and can be changed individually after that.": "Eftirlitsstöðvar erfa athugasemdina frá foreldri sínu og hægt er að breyta þeim hver fyrir sig eftir það.", + "Include in World Info Scanning": "Taka með í World Info Scanning", + "Before Main Prompt / Story String": "Áður en aðalkvaðningur / sögustrengur", + "After Main Prompt / Story String": "Eftir aðalkvaðningu / sögustreng", + "as": "sem", + "Insertion Frequency": "Innsetningartíðni", + "(0 = Disable, 1 = Always)": "(0 = Slökkva, 1 = Alltaf)", + "User inputs until next insertion:": "Notandainntak fram að næstu innsetningu:", + "Character Author's Note (Private)": "Athugasemd höfundar persónu (einka)", + "Won't be shared with the character card on export.": "Verður ekki deilt með persónuspjaldinu við útflutning.", + "Will be automatically added as the author's note for this character. Will be used in groups, but can't be modified when a group chat is open.": "Verður sjálfkrafa bætt við sem athugasemd höfundar fyrir þessa persónu. Verður notað í hópum, en\n ekki hægt að breyta þegar hópspjall er opið.", + "Use character author's note": "Notaðu athugasemd höfundar persónu", + "Replace Author's Note": "Skiptu um athugasemd höfundar", + "Default Author's Note": "Sjálfgefin athugasemd höfundar", + "Will be automatically added as the Author's Note for all new chats.": "Verður sjálfkrafa bætt við sem athugasemd höfundar fyrir öll ný spjall.", + "Chat CFG": "Spjall CFG", + "1 = disabled": "1 = óvirkur", + "write short replies, write replies using past tense": "skrifaðu stutt svör, skrifaðu svör með því að nota þátíð", + "Positive Prompt": "Jákvæð hvatning", + "Use character CFG scales": "Notaðu CFG stafkvarða", + "Character CFG": "Karakter CFG", + "Will be automatically added as the CFG for this character.": "Verður sjálfkrafa bætt við sem CFG fyrir þennan karakter.", + "Global CFG": "Global CFG", + "Will be used as the default CFG options for every chat unless overridden.": "Verður notaður sem sjálfgefinn CFG valkostur fyrir hvert spjall nema hnekkt.", + "CFG Prompt Cascading": "CFG Prompt Cascading", + "Combine positive/negative prompts from other boxes.": "Sameina jákvæðar/neikvæðar leiðbeiningar frá öðrum reitum.", + "For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string.": "Til dæmis, með því að haka í reitina fyrir spjall, alþjóðlegt og tákn sameinar allar neikvæðar tilkynningar í streng aðskilinn með kommum.", + "Always Include": "Taka alltaf með", + "Chat Negatives": "Neikvætt spjall", + "Character Negatives": "Persónu neikvæðar", + "Global Negatives": "Alþjóðleg neikvæðni", + "Custom Separator:": "Sérsniðinn aðskilnaður:", + "Insertion Depth:": "Innsetningardýpt:", + "Token Probabilities": "Líkur á táknum", + "Select a token to see alternatives considered by the AI.": "Veldu tákn til að sjá valkosti sem gervigreindin hefur í huga.", + "Not connected to API!": "Ekki tengt við API!", + "Type a message, or /? for help": "Sláðu inn skilaboð, eða /? fyrir hjálp", + "Continue script execution": "Halda áfram að keyra handrit", + "Pause script execution": "Gera hlé á framkvæmd skriftu", + "Abort script execution": "Hætta framkvæmd handrits", + "Abort request": "Hætta við beiðni", + "Continue the last message": "Halda áfram síðustu skilaboðin", + "Send a message": "Senda skilaboð", + "Close chat": "Loka spjalli", + "Toggle Panels": "Skiptu um spjöld", + "Back to parent chat": "Aftur á yfirspjall", + "Save checkpoint": "Vista eftirlitsstöð", + "Convert to group": "Breyta í hóp", + "Start new chat": "Hefja nýtt spjall", + "Manage chat files": "Stjórna spjallaskrám", + "Delete messages": "Eyða skilaboðum", + "Regenerate": "Endurnýja", + "Ask AI to write your message for you": "Biðja AI um að skrifa skilaboðin fyrir þig", + "Impersonate": "Áhrifa af", + "Continue": "Halda áfram", + "Bind user name to that avatar": "Tengja notendanafn við þann avatar", + "Change persona image": "Breyta mynd persónu", + "Select this as default persona for the new chats.": "Veldu þetta sem sjálfgefna persónu fyrir nýjar spjall.", + "Delete persona": "Eyða persónu", + "These characters are the winners of character design contests and have outstandable quality.": "Þessar persónur eru sigurvegarar í persónuhönnunarkeppnum og hafa framúrskarandi gæði.", + "Contest Winners": "Sigurvegarar keppninnar", + "These characters are the finalists of character design contests and have remarkable quality.": "Þessar persónur eru keppendur í persónuhönnunarkeppnum og hafa ótrúleg gæði.", + "Featured Characters": "Valdar persónur", + "Attach a File": "Hengja skrá", + "Open Data Bank": "Opna gagnabanka", + "Enter a URL or the ID of a Fandom wiki page to scrape:": "Sláðu inn slóð eða auðkenni Fandom wiki síðu til að skafa:", + "Examples:": "Dæmi:", + "Example:": "Dæmi:", + "Single file": "Ein skrá", + "All articles will be concatenated into a single file.": "Allar greinar verða settar saman í eina skrá.", + "File per article": "Skrá fyrir hverja grein", + "Each article will be saved as a separate file.": "Ekki mælt með. Hver grein verður vistuð sem sér skrá.", + "Data Bank": "Gagnabanki", + "These files will be available for extensions that support attachments (e.g. Vector Storage).": "Þessar skrár verða tiltækar fyrir viðbætur sem styðja viðhengi (t.d. Vector Storage).", + "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.": "Stuðlar skráargerðir: Venjulegur texti, PDF, Markdown, HTML, EPUB.", + "Drag and drop files here to upload.": "Dragðu og slepptu skrám hingað til að hlaða upp.", + "Date (Newest First)": "Dagsetning (nýjast fyrst)", + "Date (Oldest First)": "Dagsetning (elst fyrst)", + "Name (A-Z)": "Nafn (A-Ö)", + "Name (Z-A)": "Nafn (Z-A)", + "Size (Smallest First)": "Stærð (minnst fyrst)", + "Size (Largest First)": "Stærð (stærst fyrst)", + "Bulk Edit": "Magnbreyting", + "Select All": "Velja allt", + "Select None": "Veldu Ekkert", + "Global Attachments": "Alþjóðleg viðhengi", + "These files are available for all characters in all chats.": "Þessar skrár eru tiltækar fyrir alla stafi í öllum spjallum.", + "Character Attachments": "Persónuviðhengi", + "These files are available the current character in all chats they are in.": "Þessar skrár eru tiltækar núverandi karakter í öllum spjalli sem þeir eru í.", + "Saved locally. Not exported.": "Vistað á staðnum. Ekki flutt út.", + "Chat Attachments": "Spjallviðhengi", + "These files are available to all characters in the current chat.": "Þessar skrár eru aðgengilegar öllum persónum í núverandi spjalli.", + "Enter a base URL of the MediaWiki to scrape.": "Sláðu inn grunnslóð MediaWiki til að skafa.", + "Don't include the page name!": "Ekki láta síðuheitið fylgja með!", + "Enter web URLs to scrape (one per line):": "Sláðu inn vefslóðir til að skafa (ein í hverja línu):", + "Enter a video URL to download its transcript.": "Sláðu inn slóð myndbands eða auðkenni til að hlaða niður afriti þess.", + "Expression API": "Staðbundið\nAukahlutir\nLLM", + "ext_sum_with": "Dragðu saman með:", + "ext_sum_main_api": "Aðal API", + "ext_sum_current_summary": "Núverandi samantekt:", + "ext_sum_restore_previous": "Endurheimta fyrri", + "ext_sum_memory_placeholder": "Samantekt verður búin til hér...", + "Trigger a summary update right now.": "Taktu saman núna", + "ext_sum_force_text": "Taktu saman núna", + "Disable automatic summary updates. While paused, the summary remains as-is. You can still force an update by pressing the Summarize now button (which is only available with the Main API).": "Slökktu á sjálfvirkum samantektaruppfærslum. Á meðan hlé er gert er yfirlitið áfram eins og það er. Þú getur samt þvingað uppfærslu með því að ýta á Summarize now hnappinn (sem er aðeins fáanlegur með Main API).", + "ext_sum_pause": "Gera hlé", + "Omit World Info and Author's Note from text to be summarized. Only has an effect when using the Main API. The Extras API always omits WI/AN.": "Slepptu heimsupplýsingum og athugasemd höfundar úr texta til að draga saman. Hefur aðeins áhrif þegar Main API er notað. Extras API sleppir alltaf WI/AN.", + "ext_sum_no_wi_an": "Ekkert WI/AN", + "ext_sum_settings_tip": "Breyta samantektarfyrirmælum, innsetningarstöðu osfrv.", + "ext_sum_settings": "Yfirlitsstillingar", + "ext_sum_prompt_builder": "Hvetjandi byggingaraðili", + "ext_sum_prompt_builder_1_desc": "Viðbót mun búa til sína eigin vísbendingu með því að nota skilaboð sem ekki voru tekin saman enn. Lokar á spjallið þar til yfirlitið er búið til.", + "ext_sum_prompt_builder_1": "Hrátt, blokkandi", + "ext_sum_prompt_builder_2_desc": "Viðbót mun búa til sína eigin vísbendingu með því að nota skilaboð sem ekki voru tekin saman enn. Lokar ekki á spjallið á meðan yfirlitið er búið til. Ekki styðja allir bakendarnir þessa stillingu.", + "ext_sum_prompt_builder_2": "Hrátt, ekki blokkandi", + "ext_sum_prompt_builder_3_desc": "Viðbót mun nota venjulegan aðalkvaðningarsmið og bæta yfirlitsbeiðninni við hana sem síðustu kerfisskilaboð.", + "ext_sum_prompt_builder_3": "Klassískt, blokkandi", + "Summary Prompt": "Samantektarboð", + "ext_sum_restore_default_prompt_tip": "Endurheimta sjálfgefna kvaðningu", + "ext_sum_prompt_placeholder": "Þessi kvaðning verður send til gervigreindar til að biðja um myndun yfirlits. {{words}} breytist í færibreytuna 'Fjöldi orða'.", + "ext_sum_target_length_1": "Lengd miðað við samantekt", + "ext_sum_target_length_2": null, + "ext_sum_target_length_3": "orð)", + "ext_sum_api_response_length_1": "Lengd API svars", + "ext_sum_api_response_length_2": null, + "ext_sum_api_response_length_3": "tákn)", + "ext_sum_0_default": "0 = sjálfgefið", + "ext_sum_raw_max_msg": "[Raw] Hámarksskilaboð fyrir hverja beiðni", + "ext_sum_0_unlimited": "0 = ótakmarkað", + "Update frequency": "Uppfærslutíðni", + "ext_sum_update_every_messages_1": "Uppfærðu á hverjum", + "ext_sum_update_every_messages_2": "skilaboð", + "ext_sum_0_disable": "0 = slökkva á", + "ext_sum_auto_adjust_desc": "Reyndu að stilla bilið sjálfkrafa út frá spjallmælingum.", + "ext_sum_update_every_words_1": "Uppfærðu á hverjum", + "ext_sum_update_every_words_2": "orð", + "ext_sum_both_sliders": "Ef báðir rennibrautirnar eru ekki núll, þá munu báðir kveikja á yfirlitsuppfærslum á sitt hvoru millibili.", + "ext_sum_injection_template": "Sniðmát fyrir inndælingu", + "ext_sum_memory_template_placeholder": "{{yfirlit}} mun breytast í núverandi samantekt.", + "ext_sum_injection_position": "Inndælingarstaða", + "How many messages before the current end of the chat.": "Hversu mörg skilaboð fyrir núverandi lok spjallsins.", + "ext_regex_title": "Regex", + "ext_regex_new_global_script": "+ Alþjóðlegt", + "ext_regex_new_scoped_script": "+ Umfang", + "ext_regex_import_script": "Flytja inn", + "ext_regex_global_scripts": "Alþjóðleg forskriftir", + "ext_regex_global_scripts_desc": "Í boði fyrir allar persónur. Vistað í staðbundnum stillingum.", + "ext_regex_scoped_scripts": "Umfangsmikil handrit", + "ext_regex_scoped_scripts_desc": "Aðeins í boði fyrir þessa persónu. Vistað í kortagögnum.", + "Regex Editor": "Regex ritstjóri", + "Test Mode": "Prófunarhamur", + "ext_regex_desc": "Regex er tól til að finna/skipta um strengi með því að nota reglulegar segðir. Ef þú vilt læra meira skaltu smella á ? við hliðina á titlinum.", + "Input": "Inntak", + "ext_regex_test_input_placeholder": "Skrifaðu hér...", + "Output": "Framleiðsla", + "ext_regex_output_placeholder": "Tómt", + "Script Name": "Nafn handrits", + "Find Regex": "Finndu Regex", + "Replace With": "Skipta út fyrir", + "ext_regex_replace_string_placeholder": "Notaðu {{samsvörun}} til að innihalda samsvarandi texta úr Find Regex eða $1, $2, osfrv. fyrir myndatökuhópa.", + "Trim Out": "Klipptu út", + "ext_regex_trim_placeholder": "Klippir á heimsvísu alla óæskilega hluti úr regex samsvörun áður en skipt er út. Aðskildu hvern þátt með enter.", + "ext_regex_affects": "Hefur áhrif", + "ext_regex_user_input": "Notandainntak", + "ext_regex_ai_output": "AI framleiðsla", + "Slash Commands": "Slash skipanir", + "ext_regex_min_depth_desc": "Þegar það er notað á boð eða skjá hefur það aðeins áhrif á skilaboð sem eru að minnsta kosti N stig djúp. 0 = síðasta skeyti, 1 = næstsíðasta skeyti o.s.frv. Telur aðeins WI færslur @Depth og nothæf skilaboð, þ.e. ekki falin eða kerfi.", + "Min Depth": "Min dýpt", + "ext_regex_min_depth_placeholder": "Ótakmarkað", + "ext_regex_max_depth_desc": "Þegar það er notað á boð eða skjá hefur það aðeins áhrif á skilaboð sem eru ekki meira en N stig djúp. 0 = síðasta skeyti, 1 = næstsíðasta skeyti o.s.frv. Telur aðeins WI færslur @Depth og nothæf skilaboð, þ.e. ekki falin eða kerfi.", + "ext_regex_other_options": "Aðrir valkostir", + "Only Format Display": "Aðeins forsníða skjá", + "ext_regex_only_format_prompt_desc": "Spjallferillinn mun ekki breytast, aðeins hvetja þegar beiðnin er send (eftir kynslóð).", + "Only Format Prompt (?)": "Aðeins sniðbeiðni", + "Run On Edit": "Keyra á Edit", + "ext_regex_substitute_regex_desc": "Skiptu út fyrir {{makrós}} í Find Regex áður en þú keyrir það", + "Substitute Regex": "Staðgengill Regex", + "ext_regex_import_target": "Flytja inn í:", + "ext_regex_disable_script": "Slökktu á skriftu", + "ext_regex_enable_script": "Virkja skriftu", + "ext_regex_edit_script": "Breyta handriti", + "ext_regex_move_to_global": "Farðu í alþjóðlegt forskrift", + "ext_regex_move_to_scoped": "Fara í sviðsskriftir", + "ext_regex_export_script": "Flytja út handrit", + "ext_regex_delete_script": "Eyða skriftu", + "Trigger Stable Diffusion": "Kveikja á stöðugri dreifingu", + "sd_Yourself": "Sjálfur", + "sd_Your_Face": "Andlitið þitt", + "sd_Me": "Ég", + "sd_The_Whole_Story": "Sagan öll", + "sd_The_Last_Message": "Síðasta skilaboðin", + "sd_Raw_Last_Message": "Hrátt síðasta skilaboð", + "sd_Background": "Bakgrunnur", + "Image Generation": "Myndagerð", + "sd_refine_mode": "Leyfðu að breyta leiðbeiningum handvirkt áður en þú sendir þær í kynslóð API", + "sd_refine_mode_txt": "Breyttu leiðbeiningum fyrir kynslóð", + "sd_interactive_mode": "Búðu til myndir sjálfkrafa þegar þú sendir skilaboð eins og 'senda mér mynd af kötti'.", + "sd_interactive_mode_txt": "Gagnvirk stilling", + "sd_multimodal_captioning": "Notaðu fjölþætta skjátexta til að búa til leiðbeiningar um andlitsmyndir notenda og persóna á grundvelli avatars þeirra.", + "sd_multimodal_captioning_txt": "Notaðu fjölþætta myndatexta fyrir andlitsmyndir", + "sd_expand": "Lengja sjálfkrafa fyrirmæli með því að nota textagerð", + "sd_expand_txt": "Sjálfvirk aukning hvetja", + "sd_snap": "Smelltu kynslóðarbeiðnir með þvinguðu stærðarhlutfalli (andlitsmyndir, bakgrunnur) í næstu þekktu upplausn, á meðan reynt er að varðveita alger pixlafjölda (mælt með fyrir SDXL).", + "sd_snap_txt": "Taktu sjálfvirka upplausn", + "Source": "Heimild", + "sd_auto_url": "Dæmi: {{auto_url}}", + "Authentication (optional)": "Auðkenning (valfrjálst)", + "Example: username:password": "Dæmi: notendanafn:lykilorð", + "Important:": "Mikilvægt:", + "sd_auto_auth_warning_1": "keyra SD Web UI með", + "sd_auto_auth_warning_2": "fána! Miðlarinn verður að vera aðgengilegur frá SillyTavern hýsingarvélinni.", + "sd_drawthings_url": "Dæmi: {{drawthings_url}}", + "sd_drawthings_auth_txt": "keyrðu DrawThings app með HTTP API rofi virkt í notendaviðmótinu! Miðlarinn verður að vera aðgengilegur frá SillyTavern hýsingarvélinni.", + "sd_vlad_url": "Dæmi: {{vlad_url}}", + "The server must be accessible from the SillyTavern host machine.": "Miðlarinn verður að vera aðgengilegur frá SillyTavern hýsingarvélinni.", + "Hint: Save an API key in AI Horde API settings to use it here.": "Ábending: Vistaðu API lykil í AI Horde API stillingum til að nota hann hér.", + "Allow NSFW images from Horde": "Leyfa NSFW myndir frá Horde", + "Sanitize prompts (recommended)": "Hreinsunarleiðbeiningar (ráðlagt)", + "Automatically adjust generation parameters to ensure free image generations.": "Stilltu kynslóðarbreytur sjálfkrafa til að tryggja ókeypis myndmyndun.", + "Avoid spending Anlas": "Forðastu að eyða Anlas", + "Opus tier": "(Opus flokkur)", + "View my Anlas": "Skoðaðu Anlas minn", + "These settings only apply to DALL-E 3": "Þessar stillingar eiga aðeins við um DALL-E 3", + "Image Style": "Myndstíll", + "Image Quality": "Myndgæði", + "Standard": "Standard", + "HD": "HD", + "sd_comfy_url": "Dæmi: {{comfy_url}}", + "Open workflow editor": "Opnaðu verkflæðisritil", + "Create new workflow": "Búðu til nýtt verkflæði", + "Delete workflow": "Eyða verkflæði", + "Enhance": "Bæta", + "Refine": "Betrumbæta", + "Decrisper": "Skýrari", + "Sampling steps": "Sýnatökuskref ()", + "Width": "Breidd ()", + "Height": "Hæð ()", + "Resolution": "Upplausn", + "Model": "Fyrirmynd", + "Sampling method": "Sýnatökuaðferð", + "Karras (not all samplers supported)": "Karras (ekki allir sýnatökutæki studdir)", + "SMEA versions of samplers are modified to perform better at high resolution.": "SMEA útgáfur af sýnishornum eru breyttar til að skila betri árangri í mikilli upplausn.", + "SMEA": "SMEA", + "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "DYN afbrigði af SMEA sýnatökutækjum leiða oft til fjölbreyttara úttaks, en geta mistekist við mjög háa upplausn.", + "DYN": "DYN", + "Scheduler": "Dagskrármaður", + "Restore Faces": "Endurheimtu andlit", + "Hires. Fix": "Ráðningar. Laga", + "Upscaler": "Fínari", + "Upscale by": "Uppskera eftir", + "Denoising strength": "Afneitandi styrkur", + "Hires steps (2nd pass)": "Leiguþrep (2. passa)", + "Preset for prompt prefix and negative prompt": "Forstillt fyrir hvetjandi forskeyti og neikvæða kvaðningu", + "Style": "Stíll", + "Save style": "Vistaðu stíl", + "Delete style": "Eyða stíl", + "Common prompt prefix": "Algengt hvetja forskeytið", + "sd_prompt_prefix_placeholder": "Notaðu {prompt} til að tilgreina hvar myndað hvetja verður sett inn", + "Negative common prompt prefix": "Neikvætt algengt forskeyti", + "Character-specific prompt prefix": "Stafnasértækt forskeyti", + "Won't be used in groups.": "Verður ekki notað í hópum.", + "sd_character_prompt_placeholder": "Allir eiginleikar sem lýsa stafnum sem er valinn. Verður bætt við á eftir sameiginlegu forskeyti.\nDæmi: kvenkyns, græn augu, brúnt hár, bleik skyrta", + "Character-specific negative prompt prefix": "Persónu-sérstakt neikvætt kvaðningarforskeyti", + "sd_character_negative_prompt_placeholder": "Allir eiginleikar sem ættu ekki að birtast fyrir valda persónu. Verður bætt við á eftir neikvæðu algengu forskeyti.\nDæmi: skartgripir, skór, gleraugu", + "Shareable": "Hægt að deila", + "Image Prompt Templates": "Sniðmát fyrir myndakvaðningu", + "Vectors Model Warning": "Mælt er með því að hreinsa vektora þegar skipt er um líkan í miðju spjalli. Annars mun það leiða til niðurstaðna undir pari.", + "Translate files into English before processing": "Þýddu skrár yfir á ensku fyrir vinnslu", + "Manager Users": "Stjórna notendum", + "New User": "Nýr notandi", + "Status:": "Staða:", + "Created:": "Búið til:", + "Display Name:": "Birtingarnafn:", + "User Handle:": "Notendahandfang:", + "Password:": "Lykilorð:", + "Confirm Password:": "Staðfesta lykilorð:", + "This will create a new subfolder...": "Þetta mun búa til nýja undirmöppu í /data/ möppunni með handfang notandans sem möppuheiti.", + "Current Password:": "Núverandi lykilorð:", + "New Password:": "Nýtt lykilorð:", + "Confirm New Password:": "Staðfestu nýtt lykilorð:", + "Debug Warning": "Aðgerðir í þessum flokki eru aðeins fyrir lengra komna notendur. Ekki smella á neitt ef þú ert ekki viss um afleiðingarnar.", + "Execute": "Framkvæma", + "Are you sure you want to delete this user?": "Ertu viss um að þú viljir eyða þessum notanda?", + "Deleting:": "Eyðir:", + "Also wipe user data.": "Þurrkaðu einnig notendagögn.", + "Warning:": "Viðvörun:", + "This action is irreversible.": "Þessi aðgerð er óafturkræf.", + "Type the user's handle below to confirm:": "Sláðu inn handfang notandans hér að neðan til að staðfesta:", + "Import Characters": "Flytja inn stafi", + "Enter the URL of the content to import": "Sláðu inn vefslóð efnisins sem á að flytja inn", + "Supported sources:": "Stuðlar heimildir:", + "char_import_1": "Chub Character (beinn hlekkur eða auðkenni)", + "char_import_example": "Dæmi:", + "char_import_2": "Chub Lorebook (beinn hlekkur eða auðkenni)", + "char_import_3": "JanitorAI karakter (beinn hlekkur eða UUID)", + "char_import_4": "Pygmalion.chat karakter (beinn hlekkur eða UUID)", + "char_import_5": "AICharacterCards.com Karakter (beinn hlekkur eða auðkenni)", + "char_import_6": "Beinn PNG hlekkur (sjá", + "char_import_7": "fyrir leyfilega gestgjafa)", + "char_import_8": "RisuRealm karakter (beinn hlekkur)", + "Supports importing multiple characters.": "Styður innflutning á mörgum stöfum.", + "Write each URL or ID into a new line.": "Skrifaðu hverja vefslóð eða auðkenni í nýja línu.", + "Export for character": "Flytja út fyrir persónu", + "Export prompts for this character, including their order.": "Flytja út kvaðningar fyrir þennan staf, þar á meðal röð þeirra.", + "Export all": "Flytja allt út", + "Export all your prompts to a file": "Flyttu út allar leiðbeiningarnar þínar í skrá", + "Insert prompt": "Setja inn hvött", + "Delete prompt": "Eyða hvött", + "Import a prompt list": "Flytja inn hvöttlista", + "Export this prompt list": "Flytja út þessa hvöttlista", + "Reset current character": "Endurstilla núverandi persónu", + "New prompt": "Nýr hvött", + "Prompts": "Hvöttir", + "Total Tokens:": "Heildartákn:", + "prompt_manager_tokens": "Tákn", + "Are you sure you want to reset your settings to factory defaults?": "Ertu viss um að þú viljir endurstilla stillingarnar þínar á sjálfgefnar verksmiðjustillingar?", + "Don't forget to save a snapshot of your settings before proceeding.": "Ekki gleyma að vista mynd af stillingunum þínum áður en þú heldur áfram.", + "Settings Snapshots": "Stillingar Skyndimyndir", + "Record a snapshot of your current settings.": "Taktu upp skyndimynd af núverandi stillingum þínum.", + "Make a Snapshot": "Gerðu skyndimynd", + "Restore this snapshot": "Endurheimtu þessa skyndimynd", + "Hi,": "Hæ,", + "To enable multi-account features, restart the SillyTavern server with": "Til að virkja eiginleika margra reikninga skaltu endurræsa SillyTavern netþjóninn með", + "set to true in the config.yaml file.": "stillt á satt í config.yaml skránni.", + "Account Info": "Reikningsupplýsingar", + "To change your user avatar, use the buttons below or select a default persona in the Persona Management menu.": "Til að breyta notandamyndinni þinni skaltu nota hnappana hér að neðan eða velja sjálfgefna persónu í persónustjórnunarvalmyndinni.", + "Set your custom avatar.": "Stilltu sérsniðna avatar þinn.", + "Remove your custom avatar.": "Fjarlægðu sérsniðna avatarinn þinn.", + "Handle:": "Handfang:", + "This account is password protected.": "Þessi reikningur er varinn með lykilorði.", + "This account is not password protected.": "Þessi reikningur er ekki varinn með lykilorði.", + "Account Actions": "Reikningsaðgerðir", + "Change Password": "Breyta lykilorði", + "Manage your settings snapshots.": "Hafðu umsjón með stillingamyndum þínum.", + "Download a complete backup of your user data.": "Sæktu fullkomið öryggisafrit af notendagögnum þínum.", + "Download Backup": "Sækja öryggisafrit", + "Danger Zone": "Hættusvæði", + "Reset your settings to factory defaults.": "Endurstilltu stillingarnar þínar í verksmiðjustillingar.", + "Reset Settings": "Endurstilla stillingar", + "Wipe all user data and reset your account to factory settings.": "Þurrkaðu öll notendagögn og endurstilltu reikninginn þinn í verksmiðjustillingar.", + "Reset Everything": "Endurstilla allt", + "Reset Code:": "Endurstilla kóða:", + "Want to update?": "Viltu uppfæra?", + "How to start chatting?": "Hvernig á að byrja að spjalla?", + "Click _space": "Smellur", + "and select a": "og veldu", + "Chat API": "Spjall API", + "and pick a character.": "og veldu karakter.", + "You can browse a list of bundled characters in the": "Þú getur flett í lista yfir stafi með búntum í", + "Download Extensions & Assets": "Sækja viðbætur og eignir", + "menu within": "valmynd innan", + "Confused or lost?": "Óttin eða villt?", + "click these icons!": "smelltu á þessi tákn!", + "in the chat bar": "í spjallstiku", + "SillyTavern Documentation Site": "SillyTavern Skjölunarsíða", + "Extras Installation Guide": "Leiðbeiningar um viðbætur", + "Still have questions?": "Ertu enn með spurningar?", + "Join the SillyTavern Discord": "Skráðu þig í SillyTavern Discord", + "Post a GitHub issue": "Senda inn GitHub málefni", + "Contact the developers": "Hafa samband við þróunaraðila" +} diff --git a/jiuguan2025cc/public/locales/it-it.json b/jiuguan2025cc/public/locales/it-it.json new file mode 100644 index 0000000000000000000000000000000000000000..85ffca8dc1a22ab5961f1edefd4b6db30561c9a5 --- /dev/null +++ b/jiuguan2025cc/public/locales/it-it.json @@ -0,0 +1,1443 @@ +{ + "Favorite": "Preferito", + "Tag": "Etichetta", + "Duplicate": "Duplicare", + "Persona": "Persona", + "Delete": "Elimina", + "AI Response Configuration": "Configurazione Risposta AI", + "AI Configuration panel will stay open": "Il pannello di configurazione dell'AI rimarrà aperto", + "clickslidertips": "Fare clic per inserire manualmente i valori.", + "MAD LAB MODE ON": "MODALITÀ MAD LAB ATTIVA", + "Documentation on sampling parameters": "Documentazione sui parametri di campionamento", + "kobldpresets": "Preimpostazioni Kobold", + "guikoboldaisettings": "Impostazioni dell'interfaccia KoboldAI", + "Update current preset": "Aggiorna l'attuale preset", + "Save preset as": "Salva preimpostazione come", + "Import preset": "Importa preset", + "Export preset": "Esporta preset", + "Restore current preset": "Ripristina l'attuale preimpostazione", + "Delete the preset": "Elimina il preset", + "novelaipresets": "Preimpostazioni NovelAI", + "Default": "Predefinito", + "openaipresets": "Preimpostazioni OpenAI", + "Text Completion presets": "Preimpostazioni completamento del testo", + "AI Module": "Modulo AI", + "Changes the style of the generated text.": "Cambia lo stile del testo generato.", + "No Module": "Nessun modulo", + "Instruct": "Istruire", + "Prose Augmenter": "Aumentatore di prosa", + "Text Adventure": "Avventura testuale", + "response legth(tokens)": "Lunghezza della risposta (token)", + "Streaming": "Streaming", + "Streaming_desc": "Mostra la risposta pezzo per pezzo man mano che viene generata", + "context size(tokens)": "Dimensione del contesto (token)", + "unlocked": "Sbloccato", + "Only enable this if your model supports context sizes greater than 8192 tokens": "Abilita solo se il tuo modello supporta dimensioni del contesto superiori a 8192 token", + "Max prompt cost:": "Costo massimo immediato:", + "Display the response bit by bit as it is generated.": "Visualizza la risposta pezzo per pezzo mentre viene generata.", + "When this is off, responses will be displayed all at once when they are complete.": "Quando questo è disattivato, le risposte verranno visualizzate tutte in una volta quando sono complete.", + "Temperature": "Temperatura", + "rep.pen": "Pena per ripetizione", + "Rep. Pen. Range.": "Intervallo di Pen. Rip.", + "Rep. Pen. Slope": "Pendenza della penalità di ripetizione", + "Rep. Pen. Freq.": "Freq. Pen. Rip.", + "Rep. Pen. Presence": "Presenza Pen. Rip.", + "TFS": "TFS", + "Phrase Repetition Penalty": "Penalità per la ripetizione di frasi", + "Off": "Spento", + "Very light": "Molto leggero", + "Light": "Leggero", + "Medium": "Medio", + "Aggressive": "Aggressivo", + "Very aggressive": "Molto aggressivo", + "Unlocked Context Size": "Dimensione contesto sbloccato", + "Unrestricted maximum value for the context slider": "Valore massimo illimitato per lo slider di contesto", + "Context Size (tokens)": "Dimensione del contesto (token)", + "Max Response Length (tokens)": "Lunghezza massima della risposta (token)", + "Multiple swipes per generation": "Più passaggi per generazione", + "Enable OpenAI completion streaming": "Abilita lo streaming di completamento OpenAI", + "Frequency Penalty": "Penalità di frequenza", + "Presence Penalty": "Penalità di presenza", + "Count Penalty": "Conte Penalità", + "Top K": "Top K", + "Top P": "Top P", + "Repetition Penalty": "Penalità per Ripetizione", + "Min P": "Min P", + "Top A": "Top A", + "Quick Prompts Edit": "Modifica rapida delle richieste", + "Main": "Principale", + "NSFW": "NSFW", + "Jailbreak": "Sblocco", + "Utility Prompts": "Richieste di utilità", + "Impersonation prompt": "Prompt di impersonazione", + "Restore default prompt": "Ripristina il prompt predefinito", + "Prompt that is used for Impersonation function": "Prompt che viene utilizzato per la funzione di impersonazione", + "World Info Format Template": "Modello di formato informazioni sul mondo", + "Restore default format": "Ripristina il formato predefinito", + "Wraps activated World Info entries before inserting into the prompt.": "Inserisce le voci attivate delle Informazioni mondiali prima di inserirle nel prompt.", + "scenario_format_template_part_1": "Utilizzo", + "scenario_format_template_part_2": "per contrassegnare un punto in cui è inserito il contenuto.", + "Scenario Format Template": "Modello di formato dello scenario", + "Personality Format Template": "Modello di formato della personalità", + "Group Nudge Prompt Template": "Modello di richiesta di spinta del gruppo", + "Sent at the end of the group chat history to force reply from a specific character.": "Inviato alla fine della cronologia della chat di gruppo per forzare la risposta di un personaggio specifico.", + "New Chat": "Nuova chiacchierata", + "Restore new chat prompt": "Ripristina il nuovo messaggio di chat", + "Set at the beginning of the chat history to indicate that a new chat is about to start.": "Impostato all'inizio della cronologia della chat per indicare che sta per iniziare una nuova chat.", + "New Group Chat": "Nuova chat di gruppo", + "Restore new group chat prompt": "Ripristina il prompt predefinito", + "Set at the beginning of the chat history to indicate that a new group chat is about to start.": "Impostato all'inizio della cronologia della chat per indicare che sta per iniziare una nuova chat di gruppo.", + "New Example Chat": "Nuova chat di esempio", + "Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.": "Impostato all'inizio degli esempi di dialogo per indicare che sta per iniziare una nuova chat di esempio.", + "Continue nudge": "Continua a spingere", + "Set at the end of the chat history when the continue button is pressed.": "Impostato alla fine della cronologia della chat quando si preme il pulsante Continua.", + "Replace empty message": "Sostituisci messaggio vuoto", + "Send this text instead of nothing when the text box is empty.": "Invia questo testo invece di niente quando la casella di testo è vuota.", + "Seed": "Seme", + "Set to get deterministic results. Use -1 for random seed.": "Impostato per ottenere risultati deterministici. Usa -1 per il seme casuale.", + "Temperature controls the randomness in token selection": "La temperatura controlla la casualità nella selezione dei token", + "Top_K_desc": "Top K imposta una quantità massima di token migliori che possono essere scelti", + "Top_P_desc": "Top P (alias campionamento del nucleo)", + "Typical P": "P tipico", + "Typical_P_desc": "Il campionamento P tipico prioritizza i token in base alla loro deviazione dall'entropia media del set", + "Min_P_desc": "Min P imposta una probabilità minima di base", + "Top_A_desc": "Top A imposta una soglia per la selezione dei token in base al quadrato della probabilità più alta del token", + "Tail_Free_Sampling_desc": "Campionamento senza coda (TFS)", + "rep.pen range": "Intervallo di pena per ripetizione", + "Mirostat": "Mirostat", + "Mode": "Modalità", + "Mirostat_Mode_desc": "Un valore pari a 0 disabilita completamente Mirostat. 1 è per Mirostat 1.0 e 2 è per Mirostat 2.0", + "Tau": "Tau", + "Mirostat_Tau_desc": "Controlla la variabilità delle uscite Mirostat", + "Eta": "Eta", + "Mirostat_Eta_desc": "Controlla il tasso di apprendimento di Mirostat", + "Ban EOS Token": "Bandisci il token EOS", + "Ban_EOS_Token_desc": "Vietare il token End-of-Sequence (EOS) con KoboldCpp (e possibilmente anche altri token con KoboldAI). Ottimo per la scrittura di storie, ma non dovrebbe essere utilizzato per la chat e la modalità istruzioni.", + "GBNF Grammar": "Grammatica GBNF", + "Type in the desired custom grammar": "Digita la grammatica personalizzata desiderata", + "Samplers Order": "Ordine dei Campionatori", + "Samplers will be applied in a top-down order. Use with caution.": "I Campionatori saranno applicati in ordine dall'alto verso il basso. Usare con cautela.", + "Tail Free Sampling": "Campionamento senza coda", + "Load koboldcpp order": "Carica l'ordine koboldcpp", + "Preamble": "Preambolo", + "Use style tags to modify the writing style of the output.": "Usa i tag di stile per modificare lo stile di scrittura dell'output.", + "Banned Tokens": "Token banditi", + "Sequences you don't want to appear in the output. One per line.": "Sequenze che non vuoi che compaiano nell'output. Una per riga.", + "Logit Bias": "Bias del logit", + "Add": "Aggiungere", + "Helps to ban or reenforce the usage of certain words": "Aiuta a vietare o rafforzare l'uso di determinate parole", + "CFG Scale": "Scala CFG", + "Negative Prompt": "Prompt negativo", + "Add text here that would make the AI generate things you don't want in your outputs.": "Aggiungi qui del testo che farebbe generare all'IA cose che non vuoi nei tuoi output.", + "Used if CFG Scale is unset globally, per chat or character": "Usato se la scala CFG non è impostata globalmente, per chat o carattere", + "Mirostat Tau": "Tau di Mirostat", + "Mirostat LR": "Mirostat LR", + "Min Length": "Lunghezza minima", + "Top K Sampling": "Campionamento top K", + "Nucleus Sampling": "Campionamento nucleare", + "Top A Sampling": "Campionamento top A", + "CFG": "CFG", + "Neutralize Samplers": "Neutralizza i campionatori", + "Set all samplers to their neutral/disabled state.": "Imposta tutti i campionatori sullo stato neutro/disabilitato.", + "Sampler Select": "Seleziona campionatore", + "Customize displayed samplers or add custom samplers.": "Personalizza i campionatori visualizzati o aggiungi campionatori personalizzati.", + "Epsilon Cutoff": "Taglio epsilon", + "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "Il taglio epsilon imposta un limite di probabilità al di sotto del quale i token vengono esclusi dal campionamento", + "Eta Cutoff": "Taglio eta", + "Eta_Cutoff_desc": "Il taglio Eta è il parametro principale della tecnica di campionamento Eta speciale. In unità di 1e-4; un valore ragionevole è 3. Impostare su 0 per disabilitare. Consultare l'articolo Truncation Sampling as Language Model Desmoothing di Hewitt et al. (2022) per i dettagli.", + "rep.pen decay": "Decadimento della penna rappresentante", + "Encoder Rep. Pen.": "Penalità di ripetizione dell'encoder", + "No Repeat Ngram Size": "Dimensione ngram senza ripetizione", + "Skew": "Storto", + "Max Tokens Second": "Max Tokens per secondo", + "Smooth Sampling": "Campionamento regolare", + "Smooth_Sampling_desc": "Consente di utilizzare trasformazioni quadratiche/cubiche per regolare la distribuzione. Valori inferiori del fattore di livellamento saranno più creativi, solitamente tra 0,2 e 0,3 è il punto debole (assumendo che la curva = 1). Valori più elevati della curva di livellamento renderanno la curva più ripida, penalizzando in modo più aggressivo le scelte a bassa probabilità. La curva 1.0 equivale a utilizzare solo il fattore di livellamento.", + "Smoothing Factor": "Fattore di smorzamento", + "Smoothing Curve": "Curva di livellamento", + "DRY_Repetition_Penalty_desc": "DRY penalizza i token che estenderebbero la fine dell'input in una sequenza precedentemente verificata nell'input. Imposta il moltiplicatore su 0 per disabilitarlo.", + "DRY Repetition Penalty": "Penalità di ripetizione ASCIUTTA", + "DRY_Multiplier_desc": "Impostare su un valore > 0 per abilitare DRY. Controlla l'entità della penalità per le sequenze penalizzate più brevi.", + "Multiplier": "Moltiplicatore", + "DRY_Base_desc": "Controlla la velocità con cui la penalità aumenta con l'aumentare della lunghezza della sequenza.", + "Base": "Base", + "DRY_Allowed_Length_desc": "Sequenza più lunga che può essere ripetuta senza essere penalizzata.", + "Allowed Length": "Lunghezza consentita", + "Penalty Range": "Gamma di penalità", + "DRY_Sequence_Breakers_desc": "Token attraverso i quali la corrispondenza della sequenza non viene continuata. Specificato come elenco separato da virgole di stringhe tra virgolette.", + "Sequence Breakers": "Interruttori di sequenza", + "JSON-serialized array of strings.": "Matrice di stringhe serializzate JSON.", + "Dynamic Temperature": "Temperatura dinamica", + "Scale Temperature dynamically per token, based on the variation of probabilities": "Scala la temperatura dinamicamente per token, in base alla variazione delle probabilità", + "Minimum Temp": "Temperatura minima", + "Maximum Temp": "Temperatura massima", + "Exponent": "Esponente", + "Mirostat (mode=1 is only for llama.cpp)": "Mirostat (la modalità=1 è solo per llama.cpp)", + "Mirostat_desc": "Mirostat è un termostato per la perplessità dell'output", + "Mirostat Mode": "Modalità Mirostat", + "Variability parameter for Mirostat outputs": "Parametro di variabilità per le uscite di Mirostat", + "Mirostat Eta": "Eta di Mirostat", + "Learning rate of Mirostat": "Tasso di apprendimento di Mirostat", + "Beam search": "Ricerca a fascio", + "Helpful tip coming soon.": "Suggerimento utile in arrivo.", + "Number of Beams": "Numero di fasci", + "Length Penalty": "Penalità di lunghezza", + "Early Stopping": "Arresto anticipato", + "Contrastive search": "Ricerca contrastiva", + "Penalty Alpha": "Alfa di penalità", + "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "Intensità del termine di regolarizzazione della ricerca contrastiva. Impostare su 0 per disabilitare CS.", + "Do Sample": "Eseguire il campionamento", + "Add BOS Token": "Aggiungi token BOS", + "Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative": "Aggiungi il bos_token all'inizio dei suggerimenti. Disabilitare questa opzione può rendere le risposte più creative", + "Ban the eos_token. This forces the model to never end the generation prematurely": "Bandisci il token eos. Questo costringe il modello a non terminare mai la generazione prematuramente", + "Ignore EOS Token": "Ignora il token EOS", + "Ignore the EOS Token even if it generates.": "Ignora il token EOS anche se viene generato.", + "Skip Special Tokens": "Salta i token speciali", + "Temperature Last": "Ultima temperatura", + "Temperature_Last_desc": "Usa l'ultimo campionatore di temperatura", + "Speculative Ngram": "Ngram speculativo", + "Use a different speculative decoding method without a draft model": "Utilizzare un diverso metodo di decodifica speculativa senza una bozza di modello.\rÈ preferibile l'utilizzo di un modello in bozza. Il ngram speculativo non è altrettanto efficace.", + "Spaces Between Special Tokens": "Spazi tra i gettoni speciali", + "LLaMA / Mistral / Yi models only": "Solo modelli LLaMA / Mistral / Yi", + "Example: some text [42, 69, 1337]": "Esempio: un po' di testo [42, 69, 1337]", + "Classifier Free Guidance. More helpful tip coming soon": "Guida gratuita del classificatore. Presto arriverà un consiglio più utile", + "Scale": "Scala", + "JSON Schema": "Schema JSON", + "Type in the desired JSON schema": "Digita lo schema JSON desiderato", + "Grammar String": "Stringa grammaticale", + "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF o EBNF, dipende dal backend in uso. Se stai usando questo dovresti sapere quale.", + "Top P & Min P": "P massimo e P minimo", + "Load default order": "Carica ordine predefinito", + "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "Solo lama.cpp. Determina l'ordine dei campionatori. Se la modalità Mirostat non è 0, l'ordine del campionatore viene ignorato.", + "Sampler Priority": "Priorità del campionatore", + "Ooba only. Determines the order of samplers.": "Solo Ooba. Determina l'ordine dei campionatori.", + "Character Names Behavior": "Comportamento dei nomi dei personaggi", + "Helps the model to associate messages with characters.": "Aiuta il modello ad associare i messaggi ai personaggi.", + "None": "Nessuno", + "character_names_default": "Fatta eccezione per i gruppi e i personaggi passati. Altrimenti, assicurati di fornire i nomi nel prompt.", + "Don't add character names.": "Non aggiungere nomi di personaggi.", + "Completion": "Oggetto di completamento", + "character_names_completion": "Si applicano restrizioni: solo caratteri alfanumerici latini e trattini bassi. Non funziona con tutte le fonti, in particolare: Claude, MistralAI, Google.", + "Add character names to completion objects.": "Aggiungere nomi di personaggi agli oggetti di completamento.", + "Message Content": "Contenuto del messaggio", + "Prepend character names to message contents.": "Anteponi i nomi dei caratteri al contenuto del messaggio.", + "Continue Postfix": "Continua Postfisso", + "The next chunk of the continued message will be appended using this as a separator.": "La parte successiva del messaggio continuato verrà aggiunta utilizzando questo come separatore.", + "Space": "Spazio", + "Newline": "Nuova linea", + "Double Newline": "Doppia nuova riga", + "Wrap user messages in quotes before sending": "Avvolgi i messaggi degli utenti tra virgolette prima di inviarli", + "Wrap in Quotes": "Avvolgi tra virgolette", + "Wrap entire user message in quotes before sending.": "Avvolgi l'intero messaggio dell'utente tra virgolette prima di inviarlo.", + "Leave off if you use quotes manually for speech.": "Lascia perdere se usi manualmente le virgolette per il discorso.", + "Continue prefill": "Continua il precompilamento", + "Continue sends the last message as assistant role instead of system message with instruction.": "Continua invia l'ultimo messaggio come ruolo assistente invece di messaggio di sistema con istruzioni.", + "Squash system messages": "Sistema messaggi schiaccianti", + "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Combina i messaggi di sistema consecutivi in uno solo (escludendo i dialoghi di esempio). Potrebbe migliorare la coerenza per alcuni modelli.", + "Enable function calling": "Abilita la chiamata alla funzione", + "Send inline images": "Invia immagini inline", + "image_inlining_hint_1": "Invia immagini nei prompt se il modello lo supporta (ad esempio GPT-4V, Claude 3 o Llava 13B).\n Usa il", + "image_inlining_hint_2": "azione su qualsiasi messaggio o il", + "image_inlining_hint_3": "menu per allegare un file immagine alla chat.", + "Inline Image Quality": "Qualità dell'immagine in linea", + "openai_inline_image_quality_auto": "Auto", + "openai_inline_image_quality_low": "Basso", + "openai_inline_image_quality_high": "Alto", + "Use AI21 Tokenizer": "Usa il token AI21", + "Use the appropriate tokenizer for Jurassic models, which is more efficient than GPT's.": "Utilizza il tokenizzatore appropriato per i modelli giurassici, che è più efficiente di quello GPT.", + "Use Google Tokenizer": "Usa il Tokenizer di Google", + "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "Utilizza il tokenizer appropriato per i modelli Google tramite la loro API. Elaborazione dei prompt più lenta, ma offre un conteggio dei token molto più accurato.", + "Use system prompt": "Utilizza il prompt del sistema", + "(Gemini 1.5 Pro/Flash only)": "(Solo Gemini 1.5 Pro/Flash)", + "Merges_all_system_messages_desc_1": "Unisce tutti i messaggi di sistema fino al primo messaggio con un ruolo non di sistema e li invia in un file", + "Merges_all_system_messages_desc_2": "campo.", + "Assistant Prefill": "Prefill assistente", + "Start Claude's answer with...": "Inizia la risposta di Claude con...", + "Assistant Impersonation Prefill": "Precompilazione imitazione assistente", + "Use system prompt (Claude 2.1+ only)": "Usa prompt di sistema (solo Claude 2.1+)", + "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "Invia il prompt di sistema per i modelli supportati. Se disabilitato, il messaggio dell'utente viene aggiunto all'inizio del prompt.", + "User first message": "Primo messaggio dell'utente", + "Restore User first message": "Ripristina il primo messaggio dell'utente", + "Human message": "Messaggio umano, istruzioni, ecc.\nNon aggiunge nulla quando è vuoto, ovvero richiede un nuovo prompt con il ruolo \"utente\".", + "New preset": "Nuovo preset", + "Delete preset": "Elimina preset", + "View / Edit bias preset": "Visualizza / Modifica la preimpostazione del bias", + "Add bias entry": "Aggiungi voce di bias", + "Most tokens have a leading space.": "La maggior parte dei gettoni ha uno spazio iniziale.", + "API Connections": "Connessioni API", + "Text Completion": "Completamento del testo", + "Chat Completion": "Completamento della chat", + "NovelAI": "NovelAI", + "AI Horde": "AI Horde", + "KoboldAI": "KoboldAI", + "Avoid sending sensitive information to the Horde.": "Evita di inviare informazioni sensibili all'Orda.", + "Review the Privacy statement": "Revisione della dichiarazione sulla privacy", + "Register a Horde account for faster queue times": "Registrati per un account Horde per tempi di attesa più brevi", + "Learn how to contribute your idle GPU cycles to the Horde": "Scopri come contribuire ai cicli GPU inattivi all'Orda", + "Adjust context size to worker capabilities": "Regola la dimensione del contesto in base alle capacità del lavoratore", + "Adjust response length to worker capabilities": "Regola la lunghezza della risposta in base alle capacità del lavoratore", + "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "Può aiutare con le risposte negative mettendo in coda solo i lavoratori approvati. Potrebbe rallentare il tempo di risposta.", + "Trusted workers only": "Solo lavoratori fidati", + "API key": "Chiave API", + "Get it here:": "Ottienilo qui:", + "Register": "Registrati", + "View my Kudos": "Visualizza i miei Kudos", + "Enter": "Inserisci", + "to use anonymous mode.": "per utilizzare la modalità anonima.", + "Clear your API key": "Cancella la tua chiave API", + "For privacy reasons, your API key will be hidden after you reload the page.": "Per motivi di privacy, la tua chiave API sarà nascosta dopo che ricarichi la pagina.", + "Models": "Modelli", + "Refresh models": "Aggiorna modelli", + "-- Horde models not loaded --": "-- Modelli Orda non caricati --", + "Not connected...": "Non connesso...", + "API url": "URL API", + "Example: http://127.0.0.1:5000/api ": "Esempio: http://127.0.0.1:5000/api", + "Connect": "Collega", + "Cancel": "Annulla", + "Novel API key": "Chiave API di Novel", + "Get your NovelAI API Key": "Ottieni la tua Chiave API NovelAI", + "Enter it in the box below": "Inseriscilo nella casella qui sotto", + "Novel AI Model": "Modello Novel AI", + "No connection...": "Nessuna connessione...", + "API Type": "Tipo di API", + "Default (completions compatible)": "Predefinito [Compatibile con OpenAI/completamenti: oobabooga, LM Studio, ecc.]", + "TogetherAI API Key": "Chiave API di TogetherAI", + "TogetherAI Model": "Modello TogetherAI", + "-- Connect to the API --": "-- Collegati all'API --", + "OpenRouter API Key": "Chiave API di OpenRouter", + "Click Authorize below or get the key from": "Fai clic su Autorizza qui sotto o ottieni la chiave da", + "View Remaining Credits": "Visualizza i crediti rimanenti", + "OpenRouter Model": "Modello OpenRouter", + "Model Providers": "Fornitori di modelli", + "InfermaticAI API Key": "Chiave API InfermaticAI", + "InfermaticAI Model": "Modello InfermaticAI", + "DreamGen API key": "Chiave API DreamGen", + "DreamGen Model": "Modello DreamGen", + "Mancer API key": "Chiave API di Mancer", + "Mancer Model": "Modello Mancer", + "Make sure you run it with": "Assicurati di eseguirlo con", + "flag": "bandiera", + "API key (optional)": "Chiave API (opzionale)", + "Server url": "URL del server", + "Example: 127.0.0.1:5000": "Esempio: 127.0.0.1:5000", + "Custom model (optional)": "Modello personalizzato (opzionale)", + "vllm-project/vllm": "vllm-project/vllm (modalità wrapper API OpenAI)", + "vLLM API key": "Chiave API vLLM", + "Example: 127.0.0.1:8000": "Esempio: http://127.0.0.1:8000", + "vLLM Model": "Modello vLLM", + "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (Modalità wrapper per l'API OpenAI)", + "Aphrodite API key": "Chiave API di Aphrodite", + "Aphrodite Model": "Modello di Afrodite", + "ggerganov/llama.cpp": "ggerganov/llama.cpp (Server di output)", + "Example: 127.0.0.1:8080": "Esempio: 127.0.0.1:8080", + "Example: 127.0.0.1:11434": "Esempio: 127.0.0.1:11434", + "Ollama Model": "Modello Ollama", + "Download": "Scarica", + "Tabby API key": "Chiave API di Tabby", + "koboldcpp API key (optional)": "Chiave API koboldcpp (opzionale)", + "Example: 127.0.0.1:5001": "Esempio: 127.0.0.1:5001", + "Authorize": "Autorizzare", + "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Ottieni il tuo token API di OpenRouter utilizzando il flusso OAuth. Sarai reindirizzato su openrouter.ai", + "Bypass status check": "Ignora controllo stato", + "Chat Completion Source": "Fonte di Completamento della Chat", + "Reverse Proxy": "Proxy inverso", + "Proxy Presets": "Preimpostazioni proxy", + "Saved addresses and passwords.": "Indirizzi e password salvati.", + "Save Proxy": "Salva proxy", + "Delete Proxy": "Elimina proxy", + "Proxy Name": "Nome proxy", + "This will show up as your saved preset.": "Questo verrà visualizzato come preimpostazione salvata.", + "Proxy Server URL": "URL del server proxy", + "Alternative server URL (leave empty to use the default value).": "URL del server alternativo (lasciare vuoto per utilizzare il valore predefinito).", + "Remove your real OAI API Key from the API panel BEFORE typing anything into this box": "Rimuovi la tua vera chiave API OAI dal pannello API PRIMA di digitare qualcosa in questo campo", + "We cannot provide support for problems encountered while using an unofficial OpenAI proxy": "Non possiamo fornire supporto per i problemi riscontrati durante l'utilizzo di un proxy non ufficiale di OpenAI", + "Doesn't work? Try adding": "Non funziona? Prova ad aggiungere", + "at the end!": "alla fine!", + "Proxy Password": "Password proxy", + "Will be used as a password for the proxy instead of API key.": "Verrà utilizzato come password per il proxy anziché come chiave API.", + "Peek a password": "Dai un'occhiata a una password", + "OpenAI API key": "Chiave API di OpenAI", + "View API Usage Metrics": "Visualizza le metriche sull'uso dell'API", + "Follow": "Segui", + "these directions": "queste istruzioni", + "to get your OpenAI API key.": "per ottenere la tua chiave API di OpenAI.", + "Use Proxy password field instead. This input will be ignored.": "Utilizza invece il campo \"Password proxy\". Questo input verrà ignorato.", + "OpenAI Model": "Modello OpenAI", + "Bypass API status check": "Ignora il controllo dello stato dell'API", + "Show External models (provided by API)": "Mostra modelli esterni (forniti dall'API)", + "Get your key from": "Ottieni la tua chiave da", + "Anthropic's developer console": "Console dello sviluppatore di Anthropic", + "Claude Model": "Modello Claude", + "Window AI Model": "Modello AI di Window", + "Model Order": "Ordinamento dei modelli OpenRouter", + "Alphabetically": "In ordine alfabetico", + "Price": "Prezzo (il più economico)", + "Context Size": "Dimensione del contesto", + "Group by vendors": "Raggruppa per fornitori", + "Group by vendors Description": "Metti i modelli OpenAI in un gruppo, i modelli antropici in un altro gruppo, ecc. Può essere combinato con l'ordinamento.", + "Allow fallback routes": "Consenti percorsi alternativi", + "Allow fallback routes Description": "Il modello alternativo viene automaticamente scelto se il modello selezionato non può soddisfare la tua richiesta.", + "Scale API Key": "Chiave API di Scale", + "Clear your cookie": "Cancella il tuo cookie", + "Alt Method": "Metodo alternativo", + "AI21 API Key": "Chiave API di AI21", + "AI21 Model": "Modello AI21", + "Google AI Studio API Key": "Chiave API Google AI Studio", + "Google Model": "Modello Google", + "MistralAI API Key": "Chiave API MistralAI", + "MistralAI Model": "Modello MistralAI", + "Groq API Key": "Chiave API Groq", + "Groq Model": "Modello Groq", + "Perplexity API Key": "Chiave API Perplessità", + "Perplexity Model": "Modello di perplessità", + "Cohere API Key": "Chiave API Cohere", + "Cohere Model": "Modello coerente", + "Custom Endpoint (Base URL)": "Endpoint personalizzato (URL di base)", + "Custom API Key": "Chiave API personalizzata", + "Available Models": "Modelli disponibili", + "Prompt Post-Processing": "Post-elaborazione rapida", + "Applies additional processing to the prompt before sending it to the API.": "Applica un'ulteriore elaborazione al prompt prima di inviarlo all'API.", + "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "Verifica la tua connessione API inviando un breve messaggio di prova. Tieni presente che verrai accreditato per questo!", + "Test Message": "Messaggio di prova", + "Auto-connect to Last Server": "Connetti automaticamente all'ultimo server", + "Missing key": "❌ Chiave mancante", + "Key saved": "✔️ Chiave salvata", + "View hidden API keys": "Visualizza le chiavi API nascoste", + "AI Response Formatting": "Formattazione Risposta AI", + "Advanced Formatting": "Formattazione avanzata", + "Context Template": "Modello di contesto", + "Auto-select this preset for Instruct Mode": "Seleziona automaticamente questo preset per la Modalità Istruzioni", + "Story String": "Stringa della storia", + "Example Separator": "Separatore di esempio", + "Chat Start": "Inizio chat", + "Add Chat Start and Example Separator to a list of stopping strings.": "Aggiungi Inizio chat e Separatore di esempio a un elenco di stringhe di arresto.", + "Use as Stop Strings": "Usa come stringhe di arresto", + "context_allow_jailbreak": "Include il jailbreak alla fine del prompt, se definito nella carta personaggio E ''Preferisci Char. Il jailbreak'' è abilitato.\nQUESTO NON È CONSIGLIATO PER I MODELLI DI COMPLETAMENTO DEL TESTO, PUÒ PORTARE A UN RISULTATO CATTIVO.", + "Allow Jailbreak": "Consenti jailbreak", + "Context Order": "Ordine del contesto", + "Summary": "Riepilogo", + "Author's Note": "Nota dell'Autore", + "Example Dialogues": "Dialoghi di esempio", + "Hint": "Suggerimento:", + "In-Chat Position not affected": "Gli ordini di riepilogo e nota dell'autore vengono influenzati solo quando non hanno una posizione in chat impostata.", + "Instruct Mode": "Modalità di istruzione", + "Enabled": "Abilitato", + "instruct_bind_to_context": "Se abilitati, i modelli di contesto verranno selezionati automaticamente in base al nome del modello di istruzione selezionato o in base alle preferenze.", + "Bind to Context": "Collega al contesto", + "Presets": "Preimpostazioni", + "Auto-select this preset on API connection": "Seleziona automaticamente questo preset alla connessione API", + "Activation Regex": "Regex di attivazione", + "Wrap Sequences with Newline": "Avvolgi le sequenze con una nuova riga", + "Replace Macro in Sequences": "Sostituisci Macro in Sequenze", + "Skip Example Dialogues Formatting": "Salta formattazione dialoghi di esempio", + "Include Names": "Includi i nomi", + "Force for Groups and Personas": "Forza per Gruppi e Personaggi", + "System Prompt": "Prompt di sistema", + "Instruct Mode Sequences": "Sequenze della modalità di istruzione", + "System Prompt Wrapping": "Avvolgimento dei prompt di sistema", + "Inserted before a System prompt.": "Inserito prima di un prompt di sistema.", + "System Prompt Prefix": "Prefisso prompt di sistema", + "Inserted after a System prompt.": "Inserito dopo un prompt di sistema.", + "System Prompt Suffix": "Suffisso prompt di sistema", + "Chat Messages Wrapping": "Avvolgimento dei messaggi di chat", + "Inserted before a User message and as a last prompt line when impersonating.": "Inserito prima di un messaggio utente e come ultima riga di prompt quando si impersona.", + "User Message Prefix": "Prefisso messaggio utente", + "Inserted after a User message.": "Inserito dopo un messaggio dell'utente.", + "User Message Suffix": "Suffisso messaggio utente", + "Inserted before an Assistant message and as a last prompt line when generating an AI reply.": "Inserito prima di un messaggio dell'Assistente e come ultima riga di prompt durante la generazione di una risposta AI.", + "Assistant Message Prefix": "Prefisso messaggio assistente", + "Inserted after an Assistant message.": "Inserito dopo un messaggio dell'assistente.", + "Assistant Message Suffix": "Suffisso messaggio assistente", + "Inserted before a System (added by slash commands or extensions) message.": "Inserito prima di un messaggio di sistema (aggiunto da comandi slash o estensioni).", + "System Message Prefix": "Prefisso messaggio di sistema", + "Inserted after a System message.": "Inserito dopo un messaggio di sistema.", + "System Message Suffix": "Suffisso messaggio di sistema", + "If enabled, System Sequences will be the same as User Sequences.": "Se abilitate, le sequenze di sistema saranno le stesse delle sequenze utente.", + "System same as User": "Sistema uguale all'utente", + "Misc. Sequences": "Varie Sequenze", + "Inserted before the first Assistant's message.": "Inserito prima del primo messaggio dell'Assistente.", + "First Assistant Prefix": "Prefisso del primo assistente", + "instruct_last_output_sequence": "Inserito prima dell'ultimo messaggio dell'Assistente o come ultima riga di prompt durante la generazione di una risposta AI (eccetto un ruolo neutrale/di sistema).", + "Last Assistant Prefix": "Ultimo prefisso assistente", + "Will be inserted as a last prompt line when using system/neutral generation.": "Verrà inserito come ultima riga di prompt quando si utilizza la generazione di sistema/neutra.", + "System Instruction Prefix": "Prefisso istruzione di sistema", + "If a stop sequence is generated, everything past it will be removed from the output (inclusive).": "Se viene generata una sequenza di stop, tutto ciò che segue verrà rimosso dall'output (incluso).", + "Stop Sequence": "Sequenza di arresto", + "Will be inserted at the start of the chat history if it doesn't start with a User message.": "Verrà inserito all'inizio della cronologia chat se non inizia con un messaggio Utente.", + "User Filler Message": "Messaggio di riempimento utente", + "Context Formatting": "Formattazione del contesto", + "(Saved to Context Template)": "(Salvato nel modello di contesto)", + "Always add character's name to prompt": "Aggiungi sempre il nome del personaggio alla prompt", + "Generate only one line per request": "Genera solo una riga per richiesta", + "Trim Incomplete Sentences": "Taglia Frasi Incomplete", + "Include Newline": "Includi Ritorno a Capo", + "Misc. Settings": "Impostazioni varie", + "Collapse Consecutive Newlines": "Riduci a capo consecutivi", + "Trim spaces": "Taglia spazi", + "Tokenizer": "Tokenizer", + "Token Padding": "Riempimento token", + "Start Reply With": "Inizia Risposta Con", + "AI reply prefix": "Prefisso risposta AI", + "Show reply prefix in chat": "Mostra prefisso risposta in chat", + "Non-markdown strings": "Stringhe non markdown", + "separate with commas w/o space between": "separati con virgole senza spazio tra loro", + "Custom Stopping Strings": "Stringhe di Stop Personalizzate", + "JSON serialized array of strings": "Matrice serializzata JSON di stringhe", + "Replace Macro in Stop Strings": "Sostituisci Macro in Stringhe di Arresto Personalizzate", + "Auto-Continue": "Auto-continua", + "Allow for Chat Completion APIs": "Consenti per API di completamento chat", + "Target length (tokens)": "Lunghezza obiettivo (token)", + "World Info": "Informazioni sul mondo", + "Locked = World Editor will stay open": "Bloccato = L'Editor del Mondo rimarrà aperto", + "Worlds/Lorebooks": "Mondi/Libri di Lore", + "Active World(s) for all chats": "Mondo/i Attivo/i per tutte le chat", + "-- World Info not found --": "-- Informazioni sul Mondo non trovate --", + "Global World Info/Lorebook activation settings": "Impostazioni di attivazione delle informazioni sul mondo globale/del libro di conoscenze", + "Click to expand": "Clicca per espandere", + "Scan Depth": "Profondità della scansione", + "Context %": "Contesto %", + "Budget Cap": "Limite di bilancio", + "(0 = disabled)": "(0 = disabilitato)", + "Scan chronologically until reached min entries or token budget.": "Esegui la scansione in ordine cronologico fino al raggiungimento delle voci minime o del budget dei token.", + "Min Activations": "Attivazioni minime", + "Max Depth": "Profondità massima", + "(0 = unlimited, use budget)": "(0 = illimitato, utilizza il budget)", + "Insertion Strategy": "Strategia di inserimento", + "Sorted Evenly": "Ordinato Equamente", + "Character Lore First": "Lore del Personaggio Prima", + "Global Lore First": "Lore Globale Prima", + "Entries can activate other entries by mentioning their keywords": "Le voci possono attivare altre voci menzionando le loro parole chiave", + "Recursive Scan": "Scansione Ricorsiva", + "Lookup for the entry keys in the context will respect the case": "La ricerca delle chiavi di ingresso nel contesto rispetterà la maiuscole e minuscole", + "Case Sensitive": "Sensibile alle Maiuscole", + "If the entry key consists of only one word, it would not be matched as part of other words": "Se la chiave di ingresso consiste in una sola parola, non verrà abbinata come parte di altre parole", + "Match Whole Words": "Corrispondi parole intere", + "Only the entries with the most number of key matches will be selected for Inclusion Group filtering": "Solo le voci con il maggior numero di corrispondenze chiave verranno selezionate per il filtraggio del gruppo di inclusione", + "Use Group Scoring": "Utilizza il punteggio di gruppo", + "Alert if your world info is greater than the allocated budget.": "Avvisa se le informazioni sul tuo mondo superano il budget assegnato.", + "Alert On Overflow": "Avviso Su Overflow", + "New": "Nuovo", + "or": "o", + "--- Pick to Edit ---": "--- Scegli da Modificare ---", + "Rename World Info": "Rinomina Informazioni sul Mondo", + "Open all Entries": "Apri Tutte le Voci", + "Close all Entries": "Chiudi Tutte le Voci", + "New Entry": "Nuova Voce", + "Fill empty Memo/Titles with Keywords": "Riempi Memo/Titoli vuoti con Parole Chiave", + "Import World Info": "Importa Informazioni sul Mondo", + "Export World Info": "Esporta Informazioni sul Mondo", + "Duplicate World Info": "Duplica Informazioni sul Mondo", + "Delete World Info": "Elimina Informazioni sul Mondo", + "Search...": "Cerca...", + "Search": "Ricerca", + "Priority": "Priorità", + "Custom": "Personalizzato", + "Title A-Z": "Titolo A-Z", + "Title Z-A": "Titolo Z-A", + "Tokens ↗": "Token ↗", + "Tokens ↘": "Token ↘", + "Depth ↗": "Profondità ↗", + "Depth ↘": "Profondità ↘", + "Order ↗": "Ordine ↗", + "Order ↘": "Ordine ↘", + "UID ↗": "UID ↗", + "UID ↘": "UID ↘", + "Trigger% ↗": "Trigger% ↗", + "Trigger% ↘": "Trigger% ↘", + "Refresh": "Aggiorna", + "User Settings": "Impostazioni utente", + "Simple": "Semplice", + "Advanced": "Avanzato", + "UI Language": "Lingua", + "Account": "Account", + "Admin Panel": "Pannello di Amministrazione", + "Logout": "Disconnettersi", + "Search Settings": "Impostazioni di Ricerca", + "UI Theme": "Tema UI", + "Import a theme file": "Importa un file di tema", + "Export a theme file": "Esporta un file di tema", + "Delete a theme": "Elimina un tema", + "Update a theme file": "Aggiorna un file di tema", + "Save as a new theme": "Salva come nuovo tema", + "Avatar Style:": "Stile avatar", + "Circle": "Cerchio", + "Square": "Quadrato", + "Rectangle": "Rettangolo", + "Chat Style:": "Stile Chat:", + "Flat": "Piatto\nBolle\nDocumento", + "Bubbles": "Bolle", + "Document": "Documento", + "Specify colors for your theme.": "Specifica i colori per il tuo tema.", + "Theme Colors": "Colori del tema", + "Main Text": "Testo principale", + "Italics Text": "Testo corsivo", + "Underlined Text": "Testo sottolineato", + "Quote Text": "Testo citazione", + "Shadow Color": "Colore dell'ombra", + "Chat Background": "Sfondo Chat", + "UI Background": "Sfondo UI", + "UI Border": "Bordo UI", + "User Message Blur Tint": "Tonalità di Sfocatura del Messaggio Utente", + "AI Message Blur Tint": "Tonalità di Sfocatura del Messaggio AI", + "Chat Width": "Larghezza della chat", + "Width of the main chat window in % of screen width": "Larghezza della finestra di chat principale in % della larghezza dello schermo", + "Font Scale": "Scala del carattere", + "Font size": "Dimensione del font", + "Blur Strength": "Intensità della sfocatura", + "Blur strength on UI panels.": "Intensità della sfocatura sui pannelli dell'interfaccia utente.", + "Text Shadow Width": "Larghezza dell'ombra del testo", + "Strength of the text shadows": "Intensità delle ombre del testo", + "Disables animations and transitions": "Disabilita animazioni e transizioni", + "Reduced Motion": "Movimento ridotto", + "removes blur from window backgrounds": "rimuove la sfocatura dagli sfondi delle finestre", + "No Blur Effect": "Nessun effetto di sfocatura", + "Remove text shadow effect": "Rimuovi effetto ombra del testo", + "No Text Shadows": "Nessuna ombra di testo", + "Reduce chat height, and put a static sprite behind the chat window": "Riduci l'altezza della chat e metti uno sprite statico dietro la finestra della chat", + "Waifu Mode": "Modalità Waifu", + "Always show the full list of the Message Actions context items for chat messages, instead of hiding them behind '...'": "Mostra sempre l'elenco completo degli elementi di contesto delle Azioni Messaggio per i messaggi della chat, invece di nasconderli dietro '...'", + "Auto-Expand Message Actions": "Espandi Automaticamente le Azioni Messaggio", + "Alternative UI for numeric sampling parameters with fewer steps": "UI alternativa per i parametri di campionamento numerico con meno passaggi", + "Zen Sliders": "Cursori Zen", + "Entirely unrestrict all numeric sampling parameters": "Rimuovi completamente tutte le restrizioni dai parametri di campionamento numerico", + "Mad Lab Mode": "Modalità Mad Lab", + "Time the AI's message generation, and show the duration in the chat log": "Misura il tempo di generazione del messaggio dell'AI e mostra la durata nel registro della chat", + "Message Timer": "Timer del messaggio", + "Show a timestamp for each message in the chat log": "Mostra un timestamp per ogni messaggio nel registro della chat", + "Chat Timestamps": "Timestamp Chat", + "Show an icon for the API that generated the message": "Mostra un'icona per l'API che ha generato il messaggio", + "Model Icon": "Icona del modello", + "Show sequential message numbers in the chat log": "Mostra numeri di messaggi sequenziali nel registro della chat", + "Message IDs": "ID Messaggio", + "Hide avatars in chat messages.": "Nascondi gli avatar nei messaggi di chat.", + "Hide Chat Avatars": "Nascondi avatar di chat", + "Show the number of tokens in each message in the chat log": "Mostra il numero di token in ogni messaggio nel registro della chat", + "Show Message Token Count": "Mostra Conteggio Token Messaggio", + "Single-row message input area. Mobile only, no effect on PC": "Area di input messaggio a una riga. Solo mobile, nessun effetto su PC", + "Compact Input Area (Mobile)": "Area di Input Compatta (Mobile)", + "In the Character Management panel, show quick selection buttons for favorited characters": "Nel pannello Gestione Personaggi, mostra pulsanti di selezione rapida per i personaggi preferiti", + "Characters Hotswap": "Scambio rapido dei personaggi", + "Enable magnification for zoomed avatar display.": "Abilita l'ingrandimento per la visualizzazione dell'avatar ingrandito.", + "Avatar Hover Magnification": "Ingrandimento tramite passaggio del mouse sull'avatar", + "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "Abilita un effetto di ingrandimento al passaggio del mouse quando visualizzi l'avatar ingrandito dopo aver fatto clic sull'immagine di un avatar nella chat.", + "Show tagged character folders in the character list": "Mostra cartelle dei personaggi contrassegnati nell'elenco dei personaggi", + "Tags as Folders": "Tag come Cartelle", + "Tags_as_Folders_desc": "Modifica recente: i tag devono essere contrassegnati come cartelle nel menu Gestione tag per apparire come tali. Clicca qui per visualizzarlo.", + "Character Handling": "Gestione dei personaggi", + "If set in the advanced character definitions, this field will be displayed in the characters list.": "Se impostato nelle definizioni avanzate dei personaggi, questo campo verrà visualizzato nell'elenco dei personaggi.", + "Char List Subheader": "Sottointestazione elenco caratteri", + "Character Version": "Versione del Personaggio", + "Created by": "Creato da", + "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "Usa corrispondenze fuzzy e cerca personaggi nell'elenco per tutti i campi dati, non solo per una sottostringa di nome", + "Advanced Character Search": "Ricerca avanzata dei personaggi", + "If checked and the character card contains a prompt override (System Prompt), use that instead": "Se selezionato e la scheda del personaggio contiene una sovrascrittura del prompt (Prompt di Sistema), usalo invece", + "Prefer Character Card Prompt": "Preferisci Prompt della Scheda Personaggio", + "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Se selezionato e la scheda del personaggio contiene una sovrascrittura jailbreak (Istruzione Storico Post), usalo invece", + "Prefer Character Card Jailbreak": "Preferisci Jailbreak della Scheda Personaggio", + "never_resize_avatars_tooltip": "Evita di ritagliare e ridimensionare le immagini dei personaggi importati. Quando è disattivato, ritaglia/ridimensiona a 512x768.", + "Never resize avatars": "Non ridimensionare mai gli avatar", + "Show actual file names on the disk, in the characters list display only": "Mostra i nomi file effettivi sul disco, solo nella visualizzazione dell'elenco dei personaggi", + "Show avatar filenames": "Mostra nomi file avatar", + "Prompt to import embedded card tags on character import. Otherwise embedded tags are ignored": "Prompt per importare tag della scheda incorporati all'importazione del personaggio. Altrimenti i tag incorporati vengono ignorati", + "Import Card Tags": "Importa Tag della Scheda", + "Hide character definitions from the editor panel behind a spoiler button": "Nascondi le definizioni del personaggio dal pannello dell'editor dietro a un pulsante spoiler", + "Spoiler Free Mode": "Modalità Senza Spoiler", + "Miscellaneous": "Varie", + "Reload and redraw the currently open chat": "Ricarica e ridisegna la chat attualmente aperta", + "Reload Chat": "Ricarica Chat", + "Debug Menu": "Menu di debug", + "Smooth Streaming": "Streaming fluido", + "Experimental feature. May not work for all backends.": "Funzionalità sperimentale. Potrebbe non funzionare per tutti i backend.", + "Slow": "Lento", + "Fast": "Veloce", + "Play a sound when a message generation finishes": "Riproduci un suono quando la generazione del messaggio è completa", + "Message Sound": "Suono Messaggio", + "Only play a sound when ST's browser tab is unfocused": "Riproduci un suono solo quando la scheda del browser di ST non è focalizzata", + "Background Sound Only": "Solo suono di sfondo", + "Reduce the formatting requirements on API URLs": "Riduci i requisiti di formattazione degli URL dell'API", + "Relaxed API URLS": "URL API rilassati", + "Ask to import the World Info/Lorebook for every new character with embedded lorebook. If unchecked, a brief message will be shown instead": "Chiedi di importare le Informazioni sul Mondo/Lorebook per ogni nuovo personaggio con lorebook incorporato. Se non selezionato, verrà mostrato invece un breve messaggio", + "Lorebook Import Dialog": "Dialogo di importazione del lorebook", + "Restore unsaved user input on page refresh": "Ripristina l'input utente non salvato al ricaricamento della pagina", + "Restore User Input": "Ripristina l'input dell'utente", + "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "Consenti il riposizionamento di determinati elementi UI trascinandoli. Solo PC, nessun effetto su mobile", + "Movable UI Panels": "Pannelli UI mobili", + "MovingUI preset. Predefined/saved draggable positions": "Preset MovingUI. Posizioni trascinabili predefinite/salvate", + "MUI Preset": "Preset MUI", + "Save movingUI changes to a new file": "Salva le modifiche di MovingUI in un nuovo file", + "Reset MovingUI panel sizes/locations.": "Ripristina le dimensioni/posizioni del pannello MovingUI.", + "Apply a custom CSS style to all of the ST GUI": "Applica uno stile CSS personalizzato a tutta l'interfaccia grafica di ST", + "Custom CSS": "CSS personalizzato", + "Expand the editor": "Espandi l'editor", + "Chat/Message Handling": "Gestione della chat/dei messaggi", + "# Messages to Load": "#Msg. caricare", + "The number of chat history messages to load before pagination.": "Il numero di messaggi della cronologia chat da caricare prima dell'impaginazione.", + "(0 = All)": "(0 = Tutti)", + "Streaming FPS": "FPS Streaming", + "Update speed of streamed text.": "Aggiorna la velocità del testo in streaming.", + "Example Messages Behavior": "Comportamento dei messaggi di esempio", + "Gradual push-out": "Push-out graduale", + "Always include examples": "Includi sempre gli esempi", + "Never include examples": "Non includere mai gli esempi", + "Send on Enter": "Invia su Invio", + "Disabled": "Disabilitato", + "Automatic (PC)": "Automatico (PC)", + "Press Send to continue": "Premi Invia per continuare", + "Show a button in the input area to ask the AI to continue (extend) its last message": "Mostra un pulsante nell'area di input per chiedere all'AI di continuare (estendere) il suo ultimo messaggio", + "Quick 'Continue' button": "Pulsante 'Continua' rapido", + "Show arrow buttons on the last in-chat message to generate alternative AI responses. Both PC and mobile": "Mostra pulsanti a freccia sull'ultimo messaggio in-chat per generare risposte alternative AI. Sia su PC che su mobile", + "Swipes": "Scorrimenti", + "Allow using swiping gestures on the last in-chat message to trigger swipe generation. Mobile only, no effect on PC": "Consenti l'uso di gesti di scorrimento sull'ultimo messaggio in-chat per attivare la generazione di scorrimento. Solo mobile, nessun effetto su PC", + "Gestures": "Gesti", + "Auto-load Last Chat": "Caricamento automatico dell'ultima chat", + "Auto-scroll Chat": "Chat di scorrimento automatico", + "Save edits to messages without confirmation as you type": "Salva le modifiche ai messaggi senza conferma mentre digiti", + "Auto-save Message Edits": "Salvataggio automatico delle modifiche ai messaggi", + "Confirm message deletion": "Conferma eliminazione messaggio", + "Auto-fix Markdown": "Correzione automatica di Markdown", + "Disallow embedded media from other domains in chat messages": "Non consentire contenuti multimediali incorporati da altri domini nei messaggi di chat.", + "Forbid External Media": "Vietare i media esterni", + "Allow {{char}}: in bot messages": "Consenti {{char}}: nei messaggi del bot", + "Allow {{user}}: in bot messages": "Consenti {{user}}: nei messaggi del bot", + "Skip encoding and characters in message text, allowing a subset of HTML markup as well as Markdown": "Salta la codifica di e e caratteri nel testo del messaggio, consentendo un subset di markup HTML così come Markdown", + "Show tags in responses": "Mostra tag nelle risposte", + "Allow AI messages in groups to contain lines spoken by other group members": "Consenti ai messaggi dell'IA nei gruppi di contenere righe pronunciate da altri membri del gruppo", + "Relax message trim in Groups": "Rilassa il taglio dei messaggi nei Gruppi", + "Log prompts to console": "Registra i prompt sulla console", + "Requests logprobs from the API for the Token Probabilities feature": "Richiede logprobs dall'API per la funzionalità di Probabilità dei Token", + "Request token probabilities": "Richiesta delle probabilità dei token", + "Automatically reject and re-generate AI message based on configurable criteria": "Rifiuta e rigenera automaticamente il messaggio AI in base a criteri configurabili", + "Auto-swipe": "Auto-swipe", + "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Abilita la funzione di auto-swipe. Le impostazioni in questa sezione hanno effetto solo quando l'auto-swipe è abilitato", + "Minimum generated message length": "Lunghezza minima del messaggio generato", + "If the generated message is shorter than these many characters, trigger an auto-swipe": "Se il messaggio generato è più breve di questo, attiva un'automatica rimozione", + "Blacklisted words": "Parole in blacklist", + "words you dont want generated separated by comma ','": "parole che non vuoi generate separate da virgola ','", + "Blacklisted word count to swipe": "Numero di parole in blacklist per attivare un'automatica rimozione", + "Minimum number of blacklisted words detected to trigger an auto-swipe": "Numero minimo di parole in blacklist rilevate per attivare un'automatica rimozione", + "AutoComplete Settings": "Impostazioni di completamento automatico", + "Automatically hide details": "Nascondi automaticamente i dettagli", + "Determines how entries are found for autocomplete.": "Determina il modo in cui vengono trovate le voci per il completamento automatico.", + "Autocomplete Matching": "Corrispondenza", + "Starts with": "Inizia con", + "Includes": "Include", + "Fuzzy": "Sfocato", + "Sets the style of the autocomplete.": "Imposta lo stile del completamento automatico.", + "Autocomplete Style": "Stile", + "Follow Theme": "Segui il tema", + "Dark": "Buio", + "Sets the font size of the autocomplete.": "Imposta la dimensione del carattere del completamento automatico.", + "Sets the width of the autocomplete.": "Imposta la larghezza del completamento automatico.", + "Autocomplete Width": "Larghezza", + "chat input box": "casella di input della chat", + "entire chat width": "tutta la larghezza della chat", + "full window width": "larghezza completa della finestra", + "STscript Settings": "Impostazioni STscript", + "Sets default flags for the STscript parser.": "Imposta i flag predefiniti per il parser STscript.", + "Parser Flags": "Flag del parser", + "Switch to stricter escaping, allowing all delimiting characters to be escaped with a backslash, and backslashes to be escaped as well.": "Passare a un'escape più rigorosa, consentendo l'escape di tutti i caratteri di delimitazione con una barra rovesciata e anche delle barre rovesciate.", + "STRICT_ESCAPING": "STRICT_ESCAPING", + "Replace all {{getvar::}} and {{getglobalvar::}} macros with scoped variables to avoid double macro substitution.": "Sostituisci tutte le macro {{getvar::}} e {{getglobalvar::}} con variabili con ambito per evitare la doppia sostituzione di macro.", + "REPLACE_GETVAR": "SOSTITUISCI_GETVAR", + "Change Background Image": "Cambia Immagine di Sfondo", + "Filter": "Filtro", + "Automatically select a background based on the chat context": "Seleziona automaticamente uno sfondo in base al contesto della chat", + "Auto-select": "Selezione automatica", + "System Backgrounds": "Sfondi di sistema", + "Chat Backgrounds": "Sfondi Chat", + "bg_chat_hint_1": "Sfondi chat generati con", + "bg_chat_hint_2": "l'estensione apparirà qui.", + "Extensions": "Estensioni", + "Notify on extension updates": "Notifica sugli aggiornamenti dell'estensione", + "Manage extensions": "Gestisci estensioni", + "Import Extension From Git Repo": "Importa estensione dal repository Git", + "Install extension": "Installa estensione", + "Extras API:": "API extra:", + "Auto-connect": "Auto-connetti", + "Extras API URL": "URL dell'API extra", + "Extras API key (optional)": "Chiave API extra (opzionale)", + "Persona Management": "Gestione Personaggio", + "How do I use this?": "Come lo uso?", + "Click for stats!": "Clicca per le statistiche!", + "Usage Stats": "Statistiche d'uso", + "Backup your personas to a file": "Esegui il backup delle tue personalità su un file", + "Backup": "Backup", + "Restore your personas from a file": "Ripristina le tue personalità da un file", + "Restore": "Ripristina", + "Create a dummy persona": "Crea una persona fittizia", + "Create": "Crea", + "Toggle grid view": "Attiva/Disattiva la vista a griglia", + "No persona description": "[Nessuna descrizione]", + "Name": "Nome", + "Enter your name": "Inserisci il tuo nome", + "Click to set a new User Name": "Fai clic per impostare un nuovo Nome Utente", + "Click to lock your selected persona to the current chat. Click again to remove the lock.": "Fai clic per bloccare il personaggio selezionato alla chat attuale. Fai di nuovo clic per rimuovere il blocco.", + "Click to set user name for all messages": "Fai clic per impostare il nome utente per tutti i messaggi", + "Persona Description": "Descrizione Personaggio", + "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "Esempio: [{{user}} è una ragazza gatta rumena di 28 anni.]", + "Tokens persona description": "Descrizione della persona dei token", + "Position:": "Posizione:", + "In Story String / Prompt Manager": "In Stringa della Storia / Gestore di Prompt", + "Top of Author's Note": "In Alto alla Nota dell'Autore", + "Bottom of Author's Note": "In Basso alla Nota dell'Autore", + "In-chat @ Depth": "In chat @ Profondità", + "Depth:": "Profondità:", + "Role:": "Ruolo:", + "System": "Sistema", + "User": "Utente", + "Assistant": "Assistente", + "Show notifications on switching personas": "Mostra notifiche durante il cambio di personaggi", + "Character Management": "Gestione Personaggio", + "Locked = Character Management panel will stay open": "Bloccato = Il pannello di Gestione Personaggio rimarrà aperto", + "Select/Create Characters": "Seleziona/Crea Personaggi", + "Favorite characters to add them to HotSwaps": "Aggiungi personaggi preferiti per aggiungerli a HotSwaps", + "Token counts may be inaccurate and provided just for reference.": "I conteggi dei token possono essere inaccurati e forniti solo per riferimento.", + "Total tokens": "Gettoni totali", + "Calculating...": "Calcolo...", + "Tokens": "Token", + "Permanent tokens": "Gettoni permanenti", + "Permanent": "Permanente", + "About Token 'Limits'": "Informazioni sui \"Limiti\" dei token", + "Toggle character info panel": "Attiva/disattiva il pannello delle informazioni sul personaggio", + "Name this character": "Dai un nome a questo personaggio", + "extension_token_counter": "Gettoni:", + "Click to select a new avatar for this character": "Fai clic per selezionare una nuova immagine del profilo per questo personaggio", + "Add to Favorites": "Aggiungi ai Preferiti", + "Advanced Definition": "Definizione Avanzata", + "Character Lore": "Storia del Personaggio", + "Chat Lore": "Chatta Lore", + "Export and Download": "Esporta e Scarica", + "Duplicate Character": "Duplica Personaggio", + "Create Character": "Crea Personaggio", + "Delete Character": "Elimina Personaggio", + "More...": "Altro...", + "Link to World Info": "Collegamento alle Informazioni del Mondo", + "Import Card Lore": "Importa Lore della Carta", + "Scenario Override": "Sostituzione Scenario", + "Convert to Persona": "Converti in Persona", + "Rename": "Rinomina", + "Link to Source": "Collegamento alla fonte", + "Replace / Update": "Sostituisci/Aggiorna", + "Import Tags": "Importa tag", + "Search / Create Tags": "Cerca / Crea Tag", + "View all tags": "Visualizza tutti i Tag", + "Creator's Notes": "Note del Creatore", + "Show / Hide Description and First Message": "Mostra / Nascondi Descrizione e Primo Messaggio", + "Character Description": "Descrizione del Personaggio", + "Click to allow/forbid the use of external media for this character.": "Fai clic per consentire/vietare l'uso di media esterni per questo personaggio.", + "Ext. Media": "Est. Media", + "Describe your character's physical and mental traits here.": "Descrivi qui le caratteristiche fisiche e mentali del tuo personaggio.", + "First message": "Primo messaggio", + "Click to set additional greeting messages": "Fai clic per impostare ulteriori messaggi di saluto", + "Alt. Greetings": "Alt. Saluti", + "This will be the first message from the character that starts every chat.": "Questo sarà il primo messaggio del personaggio che avvia ogni chat.", + "Group Controls": "Controlli di gruppo", + "Chat Name (Optional)": "Nome della Chat (Opzionale)", + "Click to select a new avatar for this group": "Fai clic per selezionare una nuova immagine del profilo per questo gruppo", + "Group reply strategy": "Strategia di risposta di gruppo", + "Natural order": "Ordine naturale", + "List order": "Ordine della lista", + "Group generation handling mode": "Modalità di gestione della generazione di gruppi", + "Swap character cards": "Scambia le carte personaggio", + "Join character cards (exclude muted)": "Unisci le carte dei personaggi (escludi l'audio disattivato)", + "Join character cards (include muted)": "Unisci le carte dei personaggi (includi disattivate)", + "Inserted before each part of the joined fields.": "Inserito prima di ogni parte dei campi uniti.", + "Join Prefix": "Unisciti al prefisso", + "When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and with the name of the part (e.g.: description, personality, scenario, etc.)": "Quando viene selezionato \"Unisci carte personaggio\", tutti i rispettivi campi dei personaggi verranno uniti.\rCiò significa che nella stringa della storia, ad esempio, tutte le descrizioni dei personaggi verranno unite in un unico grande testo.\rSe desideri che questi campi siano separati, puoi definire un prefisso o un suffisso qui.\r\rQuesto valore supporta le macro normali e sostituirà anche {{char}} con il nome del carattere rilevante e con il nome della parte (es.: descrizione, personalità, scenario, ecc.)", + "Inserted after each part of the joined fields.": "Inserito dopo ogni parte dei campi uniti.", + "Join Suffix": "Unisciti al suffisso", + "Set a group chat scenario": "Imposta uno scenario di chat di gruppo", + "Click to allow/forbid the use of external media for this group.": "Fare clic per consentire/vietare l'uso di media esterni per questo gruppo.", + "Restore collage avatar": "Ripristina l'immagine del profilo a collage", + "Allow self responses": "Consenti risposte automatiche", + "Auto Mode": "Modalità automatica", + "Auto Mode delay": "Ritardo modalità automatica", + "Hide Muted Member Sprites": "Nascondi gli sprite dei membri disattivati", + "Current Members": "Membri attuali", + "Add Members": "Aggiungi membri", + "Create New Character": "Crea un Nuovo Personaggio", + "Import Character from File": "Importa Personaggio da File", + "Import content from external URL": "Importa contenuto da URL esterno", + "Create New Chat Group": "Crea un Nuovo Gruppo di Chat", + "Characters sorting order": "Ordine di Ordinamento dei Personaggi", + "A-Z": "A-Z", + "Z-A": "Z-A", + "Newest": "Più Recente", + "Oldest": "Più Vecchio", + "Favorites": "Preferiti", + "Recent": "Recente", + "Most chats": "Più Chat", + "Least chats": "Meno Chat", + "Most tokens": "La maggior parte dei token", + "Least tokens": "Meno token", + "Random": "Casuale", + "Toggle character grid view": "Attiva/disattiva visualizzazione griglia personaggi", + "Bulk_edit_characters": "Modifica personaggi in blocco", + "Bulk select all characters": "Seleziona in blocco tutti i personaggi", + "Bulk delete characters": "Elimina personaggi in blocco", + "popup-button-save": "Salva", + "popup-button-yes": "SÌ", + "popup-button-no": "NO", + "popup-button-cancel": "Annulla", + "popup-button-import": "Importare", + "Advanced Definitions": "Definizioni avanzate", + "Prompt Overrides": "Sostituzioni richieste", + "(For Chat Completion and Instruct Mode)": "(Per il completamento della chat e la modalità istruzione)", + "Insert {{original}} into either box to include the respective default prompt from system settings.": "Inserisci {{originale}} in uno dei due riquadri per includere il prompt predefinito corrispondente dalle impostazioni di sistema.", + "Main Prompt": "Prompt Principale", + "Any contents here will replace the default Main Prompt used for this character. (v2 spec: system_prompt)": "Ogni contenuto qui sostituirà il prompt principale predefinito utilizzato per questo personaggio. (spec v2: system_prompt)", + "Any contents here will replace the default Jailbreak Prompt used for this character. (v2 spec: post_history_instructions)": "Ogni contenuto qui sostituirà il prompt di Jailbreak predefinito utilizzato per questo personaggio. (spec v2: post_history_instructions)", + "Creator's Metadata (Not sent with the AI prompt)": "Metadati del Creatore (Non inviati con il prompt AI)", + "Creator's Metadata": "Metadati del creatore", + "(Not sent with the AI Prompt)": "(Non inviato con il prompt AI)", + "Everything here is optional": "Tutto qui è facoltativo", + "(Botmaker's name / Contact Info)": "(Nome del Creatore del Bot / Informazioni di Contatto)", + "(If you want to track character versions)": "(Se vuoi tracciare le versioni del personaggio)", + "(Describe the bot, give use tips, or list the chat models it has been tested on. This will be displayed in the character list.)": "(Descrivi il bot, dai suggerimenti sull'uso o elenca i modelli di chat su cui è stato testato. Questo verrà visualizzato nell'elenco dei personaggi.)", + "Tags to Embed": "Tag da Incorporare", + "(Write a comma-separated list of tags)": "(Scrivi un elenco di tag separati da virgole)", + "Personality summary": "Sommario della personalità", + "(A brief description of the personality)": "(Una breve descrizione della personalità)", + "Scenario": "Scenario", + "(Circumstances and context of the interaction)": "(Circostanze e contesto dell'interazione)", + "Character's Note": "Nota del personaggio", + "(Text to be inserted in-chat @ designated depth and role)": "(Testo da inserire in chat @ profondità e ruolo designati)", + "@ Depth": "@ Profondità", + "Role": "Ruolo", + "Talkativeness": "Loquacità", + "How often the character speaks in group chats!": "Quanto spesso il personaggio parla nelle chat di gruppo!", + "How often the character speaks in": "Quanto spesso parla il personaggio", + "group chats!": "chat di gruppo!", + "Shy": "Timido", + "Normal": "Normale", + "Chatty": "Chiacchierone", + "Examples of dialogue": "Esempi di dialogo", + "Important to set the character's writing style.": "Importante impostare lo stile di scrittura del personaggio.", + "(Examples of chat dialog. Begin each example with START on a new line.)": "(Esempi di dialogo in chat. Inizia ogni esempio con START su una nuova riga.)", + "Save": "Salva", + "Chat History": "Cronologia Chat", + "Import Chat": "Importa chat", + "Copy to system backgrounds": "Copia negli sfondi di sistema", + "Rename background": "Rinominare lo sfondo", + "Lock": "Serratura", + "Unlock": "Sbloccare", + "Delete background": "Elimina lo sfondo", + "Chat Scenario Override": "Sostituzione dello scenario di chat", + "Remove": "Rimuovi", + "Type here...": "Scrivi qui...", + "Chat Lorebook": "Chatta Lorebook per", + "Chat Lorebook for": "Chatta Lorebook per", + "chat_world_template_txt": "Un'Info mondiale selezionata sarà associata a questa chat. Quando si genera una risposta AI, questa verrà combinata con le voci dei lorebook globali e dei personaggi.", + "Select a World Info file for": "Seleziona un file di Informazioni sul Mondo per", + "Primary Lorebook": "Libro di Storia Principale", + "A selected World Info will be bound to this character as its own Lorebook.": "Un'Informazione Mondiale selezionata sarà vincolata a questo personaggio come il suo proprio Libro di Storia.", + "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "Quando viene generata una risposta AI, sarà combinata con le voci da un selettore globale di Informazioni sul Mondo.", + "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "L'esportazione di un personaggio comporterà anche l'esportazione del file di Libro di Storia selezionato incorporato nei dati JSON.", + "Additional Lorebooks": "Libri di Storia Aggiuntivi", + "Associate one or more auxillary Lorebooks with this character.": "Associa uno o più Libri di Storia ausiliari a questo personaggio.", + "NOTE: These choices are optional and won't be preserved on character export!": "NOTA: Queste scelte sono opzionali e non verranno conservate nell'esportazione del personaggio!", + "Rename chat file": "Rinomina il file di chat", + "Export JSONL chat file": "Esporta file di chat JSONL", + "Download chat as plain text document": "Scarica la chat come documento di testo semplice", + "Delete chat file": "Elimina il file di chat", + "Use tag as folder": "Contrassegna come cartella", + "Delete tag": "Elimina il tag", + "Entry Title/Memo": "Titolo/Memo dell'Ingresso", + "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized❌ Disabled": "Stato della voce WI:\r🔵 Costante\r🟢 Normale\r🔗 Vettorializzato\r❌Disabili", + "WI_Entry_Status_Constant": "Costante", + "WI_Entry_Status_Normal": "Normale", + "WI_Entry_Status_Vectorized": "Vettorializzato", + "WI_Entry_Status_Disabled": "Disabilitato", + "T_Position": "↑Car: prima delle definizioni del personaggio\n↓Car: dopo le definizioni del personaggio\n↑AN: prima delle note dell'autore\n↓AN: dopo le note dell'autore\n@D: alla profondità", + "Before Char Defs": "Prima delle Definizioni del Personaggio", + "After Char Defs": "Dopo le Definizioni del Personaggio", + "Before EM": "↑EM", + "After EM": "↓EM", + "Before AN": "Prima delle AN", + "After AN": "Dopo le AN", + "at Depth System": "@D ⚙️", + "at Depth User": "@D 👤", + "at Depth AI": "@D 🤖", + "Depth": "Profondità", + "Order:": "Ordine:", + "Order": "Ordine:", + "Trigger %:": "Grilletto %:", + "Probability": "Probabilità", + "Duplicate world info entry": "Voce di informazioni sul mondo duplicata", + "Delete world info entry": "Elimina la voce di informazioni mondiali", + "Comma separated (required)": "Separato da virgole (richiesto)", + "Primary Keywords": "Parole Chiave Principali", + "Keywords or Regexes": "Parole chiave o espressioni regolari", + "Comma separated list": "Elenco separato da virgole", + "Switch to plaintext mode": "Passa alla modalità testo normale", + "Logic": "Logica", + "AND ANY": "E QUALSIASI", + "AND ALL": "E TUTTI", + "NOT ALL": "NON TUTTI", + "NOT ANY": "NESSUNO", + "(ignored if empty)": "(ignorato se vuoto)", + "Optional Filter": "Filtro Opzionale", + "Keywords or Regexes (ignored if empty)": "Parole chiave o espressioni regolari (ignorate se vuote)", + "Comma separated list (ignored if empty)": "Elenco separato da virgole (ignorato se vuoto)", + "Use global setting": "Usa l'impostazione globale", + "Case-Sensitive": "Sensibile alle maiuscole/minuscole", + "Yes": "Sì", + "No": "No", + "Can be used to automatically activate Quick Replies": "Può essere utilizzato per attivare automaticamente le risposte rapide", + "Automation ID": "Identificativo dell'automazione", + "( None )": "( Nessuno )", + "Content": "Contenuto", + "Exclude from recursion": "Escludi dalla ricorsione", + "Prevent further recursion (this entry will not activate others)": "Prevenire ulteriore ricorsione (questa voce non ne attiverà altre)", + "Delay until recursion (this entry can only be activated on recursive checking)": "Ritardo fino alla ricorsione (questa voce può essere attivata solo durante il controllo ricorsivo)", + "What this keyword should mean to the AI, sent verbatim": "Cosa dovrebbe significare questa parola chiave per l'AI, inviata testualmente", + "Filter to Character(s)": "Filtra per Personaggio(i)", + "Character Exclusion": "Esclusione Personaggio", + "-- Characters not found --": "-- Personaggi non trovati --", + "Inclusion Group": "Gruppo di Inclusione", + "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "I gruppi di inclusione garantiscono che venga attivata solo una voce di un gruppo alla volta, se ne vengono attivate più.\rSupporta più gruppi separati da virgole.\r\rDocumentazione: World Info – Gruppo Inclusione", + "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "Dai priorità a questa voce: se selezionata, questa voce ha la priorità tra tutte le selezioni. Se vengono date priorità a più voci, viene scelta quella con l'\"Ordine\" più alto.", + "Only one entry with the same label will be activated": "Sarà attivato solo un unico ingresso con lo stesso etichetta", + "A relative likelihood of entry activation within the group": "Una probabilità relativa di attivazione dell'ingresso all'interno del gruppo", + "Group Weight": "Peso del gruppo", + "Selective": "Selettivo", + "Use Probability": "Usa Probabilità", + "Add Memo": "Aggiungi promemoria", + "Text or token ids": "Testo o [ID token]", + "close": "vicino", + "prompt_manager_edit": "Modificare", + "prompt_manager_name": "Nome", + "A name for this prompt.": "Un nome per questo prompt.", + "To whom this message will be attributed.": "A chi verrà attribuito questo messaggio.", + "AI Assistant": "Assistente AI", + "prompt_manager_position": "Posizione", + "Injection position. Next to other prompts (relative) or in-chat (absolute).": "Posizione di iniezione. Accanto ad altri suggerimenti (relativo) o in chat (assoluto).", + "prompt_manager_relative": "Parente", + "prompt_manager_depth": "Profondità", + "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "Profondità di iniezione. 0 = dopo l'ultimo messaggio, 1 = prima dell'ultimo messaggio, ecc.", + "Prompt": "Prompt", + "The prompt to be sent.": "La richiesta da inviare.", + "This prompt cannot be overridden by character cards, even if overrides are preferred.": "Questo prompt non può essere sostituito dalle schede personaggio, anche se si preferisce sostituirlo.", + "prompt_manager_forbid_overrides": "Vieta sostituzioni", + "reset": "Ripristina", + "save": "salva", + "This message is invisible for the AI": "Questo messaggio è invisibile per l'IA", + "Message Actions": "Azioni del messaggio", + "Translate message": "Traduci messaggio", + "Generate Image": "Genera Immagine", + "Narrate": "Narrare", + "Exclude message from prompts": "Escludi messaggio dalle richieste", + "Include message in prompts": "Includi messaggio nelle richieste", + "Embed file or image": "Incorpora file o immagine", + "Create checkpoint": "Crea checkpoint", + "Create Branch": "Crea Branch", + "Copy": "Copia", + "Open checkpoint chat": "Apri la chat del checkpoint", + "Edit": "Modifica", + "Confirm": "Conferma", + "Copy this message": "Copia questo messaggio", + "Delete this message": "Elimina questo messaggio", + "Move message up": "Sposta il messaggio verso l'alto", + "Move message down": "Sposta il messaggio verso il basso", + "Enlarge": "Ingrandire", + "Welcome to SillyTavern!": "Benvenuti a Silly Tavern!", + "welcome_message_part_1": "Leggi il", + "welcome_message_part_2": "Documentazione ufficiale", + "welcome_message_part_3": null, + "welcome_message_part_4": "Tipo", + "welcome_message_part_5": "nella chat per comandi e macro.", + "welcome_message_part_6": "Aderire al", + "Discord server": "Server Discordia", + "welcome_message_part_7": "per info e annunci.", + "SillyTavern is aimed at advanced users.": "SillyTavern è rivolto agli utenti avanzati.", + "If you're new to this, enable the simplified UI mode below.": "Se sei nuovo a questo, abilita la modalità interfaccia utente semplificata di seguito.", + "Change it later in the 'User Settings' panel.": "Modificalo successivamente nel pannello \"Impostazioni utente\".", + "Enable simple UI mode": "Abilita la modalità interfaccia utente semplice", + "Looking for AI characters?": "Cerchi personaggi IA?", + "onboarding_import": "Importare", + "from supported sources or view": "da fonti o visualizzazioni supportate", + "Sample characters": "Caratteri campione", + "Your Persona": "Il Tuo Personaggio", + "Before you get started, you must select a persona name.": "Prima di iniziare, devi selezionare un nome per la persona.", + "welcome_message_part_8": "Questo può essere modificato in qualsiasi momento tramite il", + "welcome_message_part_9": "icona.", + "Persona Name:": "Nome della persona:", + "Temporarily disable automatic replies from this character": "Disabilita temporaneamente le risposte automatiche da questo personaggio", + "Enable automatic replies from this character": "Abilita risposte automatiche da questo personaggio", + "Trigger a message from this character": "Scatenare un messaggio da questo personaggio", + "Move up": "Sposta verso l'alto", + "Move down": "Sposta verso il basso", + "View character card": "Visualizza la carta del personaggio", + "Remove from group": "Rimuovi dal gruppo", + "Add to group": "Aggiungi al gruppo", + "Alternate Greetings": "Saluti alternativi", + "Alternate_Greetings_desc": "Questi verranno visualizzati come passaggi sul primo messaggio quando si avvia una nuova chat.\n I membri del gruppo possono selezionarne uno per avviare la conversazione.", + "Alternate Greetings Hint": "Fare clic sul pulsante per iniziare!", + "(This will be the first message from the character that starts every chat)": "(Questo sarà il primo messaggio del personaggio che avvia ogni chat)", + "Forbid Media Override explanation": "Capacità del personaggio/gruppo attuale di utilizzare media esterni nelle chat.", + "Forbid Media Override subtitle": "Media: immagini, video, audio. Esterno: non ospitato sul server locale.", + "Always forbidden": "Sempre proibito", + "Always allowed": "sempre permesso", + "View contents": "Visualizza i contenuti", + "Remove the file": "Rimuovere il file", + "Unique to this chat": "Unico per questa chat", + "Checkpoints inherit the Note from their parent, and can be changed individually after that.": "I checkpoint ereditano la nota dal genitore e successivamente possono essere modificati individualmente.", + "Include in World Info Scanning": "Includi nella scansione delle informazioni sul mondo", + "Before Main Prompt / Story String": "Prima della stringa del prompt principale/della storia", + "After Main Prompt / Story String": "Dopo il prompt principale/stringa della storia", + "as": "COME", + "Insertion Frequency": "Frequenza di inserimento", + "(0 = Disable, 1 = Always)": "(0 = Disabilita, 1 = Sempre)", + "User inputs until next insertion:": "Input dell'utente fino al prossimo inserimento:", + "Character Author's Note (Private)": "Nota dell'autore del personaggio (privata)", + "Won't be shared with the character card on export.": "Non verrà condiviso con la scheda personaggio durante l'esportazione.", + "Will be automatically added as the author's note for this character. Will be used in groups, but can't be modified when a group chat is open.": "Verrà aggiunto automaticamente come nota dell'autore per questo personaggio. Verrà utilizzato nei gruppi, ma non può essere modificato quando è aperta una chat di gruppo.", + "Use character author's note": "Usa la nota dell'autore del personaggio", + "Replace Author's Note": "Sostituisci la nota dell'autore", + "Default Author's Note": "Nota dell'autore predefinita", + "Will be automatically added as the Author's Note for all new chats.": "Verrà aggiunto automaticamente come Nota dell'autore per tutte le nuove chat.", + "Chat CFG": "Chatta CFG", + "1 = disabled": "1 = disabilitato", + "write short replies, write replies using past tense": "scrivere risposte brevi, scrivere risposte utilizzando il passato", + "Positive Prompt": "Suggerimento positivo", + "Use character CFG scales": "Usa le scale CFG dei personaggi", + "Character CFG": "Carattere CFG", + "Will be automatically added as the CFG for this character.": "Verrà aggiunto automaticamente come CFG per questo personaggio.", + "Global CFG": "CFG globale", + "Will be used as the default CFG options for every chat unless overridden.": "Verranno utilizzate come opzioni CFG predefinite per ogni chat a meno che non vengano sovrascritte.", + "CFG Prompt Cascading": "Richiesta CFG a cascata", + "Combine positive/negative prompts from other boxes.": "Combina suggerimenti positivi/negativi da altre caselle.", + "For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string.": "Ad esempio, selezionando le caselle chat, globale e carattere si combinano tutti i suggerimenti negativi in ​​una stringa separata da virgole.", + "Always Include": "Includi sempre", + "Chat Negatives": "Chatta negativi", + "Character Negatives": "Aspetti negativi dei personaggi", + "Global Negatives": "Negativi globali", + "Custom Separator:": "Separatore personalizzato:", + "Insertion Depth:": "Profondità di inserimento:", + "Token Probabilities": "Probabilità dei token", + "Select a token to see alternatives considered by the AI.": "Seleziona un token per visualizzare le alternative prese in considerazione dall'IA.", + "Not connected to API!": "Non connesso all'API!", + "Type a message, or /? for help": "Digita un messaggio o /? per un aiuto", + "Continue script execution": "Continua l'esecuzione dello script", + "Pause script execution": "Sospende l'esecuzione dello script", + "Abort script execution": "Interrompe l'esecuzione dello script", + "Abort request": "Annulla richiesta", + "Continue the last message": "Continua l'ultimo messaggio", + "Send a message": "Invia un messaggio", + "Close chat": "Chiudi chat", + "Toggle Panels": "Attiva/Disattiva pannelli", + "Back to parent chat": "Torna alla chat principale", + "Save checkpoint": "Salva il punto di controllo", + "Convert to group": "Converti in gruppo", + "Start new chat": "Avvia nuova chat", + "Manage chat files": "Gestisci file di chat", + "Delete messages": "Elimina messaggi", + "Regenerate": "Rigenerare", + "Ask AI to write your message for you": "Chiedi all'IA di scrivere il tuo messaggio per te", + "Impersonate": "Imitare", + "Continue": "Continua", + "Bind user name to that avatar": "Associa il nome utente a quell'avatar", + "Change persona image": "Cambia immagine della persona", + "Select this as default persona for the new chats.": "Seleziona questo come persona predefinita per le nuove chat.", + "Delete persona": "Elimina persona", + "These characters are the winners of character design contests and have outstandable quality.": "Questi personaggi sono i vincitori dei concorsi di design dei personaggi e hanno una qualità eccezionale.", + "Contest Winners": "Vincitori del concorso", + "These characters are the finalists of character design contests and have remarkable quality.": "Questi personaggi sono i finalisti dei concorsi di design dei personaggi e hanno una qualità notevole.", + "Featured Characters": "Personaggi in primo piano", + "Attach a File": "Allega un file", + "Open Data Bank": "Apri Banca Dati", + "Enter a URL or the ID of a Fandom wiki page to scrape:": "Inserisci un URL o l'ID di una pagina wiki di Fandom da analizzare:", + "Examples:": "Esempi:", + "Example:": "Esempio:", + "Single file": "File singolo", + "All articles will be concatenated into a single file.": "Tutti gli articoli verranno concatenati in un unico file.", + "File per article": "File per articolo", + "Each article will be saved as a separate file.": "Non consigliato. Ogni articolo verrà salvato come file separato.", + "Data Bank": "Banca dati", + "These files will be available for extensions that support attachments (e.g. Vector Storage).": "Questi file saranno disponibili per le estensioni che supportano gli allegati (ad esempio Vector Storage).", + "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.": "Tipi di file supportati: testo normale, PDF, Markdown, HTML, EPUB.", + "Drag and drop files here to upload.": "Trascina e rilascia i file qui per caricarli.", + "Date (Newest First)": "Data (prima il più recente)", + "Date (Oldest First)": "Data (prima il più vecchio)", + "Name (A-Z)": "Nome (A-Z)", + "Name (Z-A)": "Nome (Z-A)", + "Size (Smallest First)": "Dimensioni (prima la più piccola)", + "Size (Largest First)": "Dimensioni (prima la più grande)", + "Bulk Edit": "Modifica collettiva", + "Select All": "Seleziona tutto", + "Select None": "Non selezionare niente", + "Global Attachments": "Allegati globali", + "These files are available for all characters in all chats.": "Questi file sono disponibili per tutti i personaggi in tutte le chat.", + "Character Attachments": "Allegati ai personaggi", + "These files are available the current character in all chats they are in.": "Questi file sono disponibili per il personaggio corrente in tutte le chat in cui si trova.", + "Saved locally. Not exported.": "Salvato localmente. Non esportato.", + "Chat Attachments": "Allegati della chat", + "These files are available to all characters in the current chat.": "Questi file sono disponibili per tutti i personaggi nella chat corrente.", + "Enter a base URL of the MediaWiki to scrape.": "Inserisci un URL di base del MediaWiki da cui effettuare lo scraping.", + "Don't include the page name!": "Non includere il nome della pagina!", + "Enter web URLs to scrape (one per line):": "Inserisci gli URL web da analizzare (uno per riga):", + "Enter a video URL to download its transcript.": "Inserisci l'URL o l'ID del video per scaricarne la trascrizione.", + "Expression API": "Locale\nExtra\nLLM", + "ext_sum_with": "Riassumi con:", + "ext_sum_main_api": "API principale", + "ext_sum_current_summary": "Riepilogo attuale:", + "ext_sum_restore_previous": "Ripristina precedente", + "ext_sum_memory_placeholder": "Il riepilogo verrà generato qui...", + "Trigger a summary update right now.": "Riassumi ora", + "ext_sum_force_text": "Riassumi ora", + "Disable automatic summary updates. While paused, the summary remains as-is. You can still force an update by pressing the Summarize now button (which is only available with the Main API).": "Disattiva gli aggiornamenti di riepilogo automatici. Durante la pausa, il riepilogo rimane così com'è. Puoi comunque forzare un aggiornamento premendo il pulsante Riepiloga ora (disponibile solo con l'API principale).", + "ext_sum_pause": "Pausa", + "Omit World Info and Author's Note from text to be summarized. Only has an effect when using the Main API. The Extras API always omits WI/AN.": "Ometti World Info e Author's Note dal testo da riassumere. Ha effetto solo quando si usa l'API principale. L'API Extras omette sempre WI/AN.", + "ext_sum_no_wi_an": "Nessuna connessione WI/AN", + "ext_sum_settings_tip": "Modifica la richiesta di riepilogo, la posizione di inserimento, ecc.", + "ext_sum_settings": "Impostazioni di riepilogo", + "ext_sum_prompt_builder": "Costruttore rapido", + "ext_sum_prompt_builder_1_desc": "L'estensione creerà il proprio prompt utilizzando i messaggi che non sono stati ancora riepilogati. Blocca la chat finché non viene generato il riepilogo.", + "ext_sum_prompt_builder_1": "Crudo, bloccante", + "ext_sum_prompt_builder_2_desc": "L'estensione creerà il proprio prompt utilizzando i messaggi che non sono stati ancora riepilogati. Non blocca la chat durante la generazione del riepilogo. Non tutti i backend supportano questa modalità.", + "ext_sum_prompt_builder_2": "Grezzo, non bloccante", + "ext_sum_prompt_builder_3_desc": "L'estensione utilizzerà il normale generatore di prompt principale e vi aggiungerà la richiesta di riepilogo come ultimo messaggio di sistema.", + "ext_sum_prompt_builder_3": "Classico, bloccante", + "Summary Prompt": "Richiesta di riepilogo", + "ext_sum_restore_default_prompt_tip": "Ripristina richiesta predefinita", + "ext_sum_prompt_placeholder": "Questa richiesta verrà inviata ad AI per richiedere la generazione del riepilogo. {{words}} verrà risolto nel parametro \"Numero di parole\".", + "ext_sum_target_length_1": "Lunghezza del riepilogo target", + "ext_sum_target_length_2": null, + "ext_sum_target_length_3": "parole)", + "ext_sum_api_response_length_1": "Lunghezza della risposta API", + "ext_sum_api_response_length_2": null, + "ext_sum_api_response_length_3": "gettoni)", + "ext_sum_0_default": "0 = predefinito", + "ext_sum_raw_max_msg": "[Raw] Numero massimo di messaggi per richiesta", + "ext_sum_0_unlimited": "0 = illimitato", + "Update frequency": "Frequenza di aggiornamento", + "ext_sum_update_every_messages_1": "Aggiorna ogni", + "ext_sum_update_every_messages_2": "messaggi", + "ext_sum_0_disable": "0 = disabilita", + "ext_sum_auto_adjust_desc": "Prova a regolare automaticamente l'intervallo in base alle metriche della chat.", + "ext_sum_update_every_words_1": "Aggiorna ogni", + "ext_sum_update_every_words_2": "parole", + "ext_sum_both_sliders": "Se entrambi i dispositivi di scorrimento sono diversi da zero, entrambi attiveranno gli aggiornamenti di riepilogo ai rispettivi intervalli.", + "ext_sum_injection_template": "Modello di iniezione", + "ext_sum_memory_template_placeholder": "{{summary}} verrà risolto con il contenuto del riepilogo corrente.", + "ext_sum_injection_position": "Posizione di iniezione", + "How many messages before the current end of the chat.": "Quanti messaggi prima della fine corrente della chat.", + "ext_regex_title": "Regex", + "ext_regex_new_global_script": "+ Globale", + "ext_regex_new_scoped_script": "+ Ambito", + "ext_regex_import_script": "Importare", + "ext_regex_global_scripts": "Script globali", + "ext_regex_global_scripts_desc": "Disponibile per tutti i personaggi. Salvato nelle impostazioni locali.", + "ext_regex_scoped_scripts": "Script con ambito", + "ext_regex_scoped_scripts_desc": "Disponibile solo per questo personaggio. Salvato nei dati della carta.", + "Regex Editor": "Editor di espressioni regolari", + "Test Mode": "Modalità di prova", + "ext_regex_desc": "Regex è uno strumento per trovare/sostituire stringhe utilizzando espressioni regolari. Se vuoi saperne di più clicca sul ? accanto al titolo.", + "Input": "Ingresso", + "ext_regex_test_input_placeholder": "Digitare qui...", + "Output": "Produzione", + "ext_regex_output_placeholder": "Vuoto", + "Script Name": "Nome dello script", + "Find Regex": "Trova Regex", + "Replace With": "Sostituirlo con", + "ext_regex_replace_string_placeholder": "Utilizza {{match}} per includere il testo corrispondente da Trova Regex o $1, $2, ecc. per i gruppi di acquisizione.", + "Trim Out": "Tagliare", + "ext_regex_trim_placeholder": "Taglia globalmente tutte le parti indesiderate da una corrispondenza regex prima della sostituzione. Separa ogni elemento con un invio.", + "ext_regex_affects": "Colpisce", + "ext_regex_user_input": "Ingresso dell'utente", + "ext_regex_ai_output": "Uscita AI", + "Slash Commands": "Comandi barra", + "ext_regex_min_depth_desc": "Se applicato ai prompt o alla visualizzazione, influisce solo sui messaggi con una profondità di almeno N livelli. 0 = ultimo messaggio, 1 = penultimo messaggio, ecc. Conta solo le voci WI @Depth e i messaggi utilizzabili, ovvero non nascosti o di sistema.", + "Min Depth": "Profondità minima", + "ext_regex_min_depth_placeholder": "Illimitato", + "ext_regex_max_depth_desc": "Se applicato a prompt o display, influisce solo sui messaggi con una profondità non superiore a N livelli. 0 = ultimo messaggio, 1 = penultimo messaggio, ecc. Conta solo le voci WI @Depth e i messaggi utilizzabili, ovvero non nascosti o di sistema.", + "ext_regex_other_options": "Altre opzioni", + "Only Format Display": "Solo visualizzazione del formato", + "ext_regex_only_format_prompt_desc": "La cronologia della chat non cambierà, solo il messaggio richiesto quando viene inviata la richiesta (al momento della generazione).", + "Only Format Prompt (?)": "Solo richiesta di formattazione", + "Run On Edit": "Esegui in fase di modifica", + "ext_regex_substitute_regex_desc": "Sostituisci {{macros}} in Trova Regex prima di eseguirlo", + "Substitute Regex": "Sostituisci Regex", + "ext_regex_import_target": "Importa in:", + "ext_regex_disable_script": "Disabilita script", + "ext_regex_enable_script": "Abilita script", + "ext_regex_edit_script": "Modifica copione", + "ext_regex_move_to_global": "Passa agli script globali", + "ext_regex_move_to_scoped": "Passare agli script con ambito", + "ext_regex_export_script": "Esporta script", + "ext_regex_delete_script": "Elimina copione", + "Trigger Stable Diffusion": "Attiva la diffusione stabile", + "sd_Yourself": "Te stesso", + "sd_Your_Face": "La tua faccia", + "sd_Me": "Me", + "sd_The_Whole_Story": "L'intera storia", + "sd_The_Last_Message": "L'ultimo messaggio", + "sd_Raw_Last_Message": "Ultimo messaggio grezzo", + "sd_Background": "Sfondo", + "Image Generation": "Generazione di immagini", + "sd_refine_mode": "Consenti di modificare manualmente i prompt prima di inviarli all'API di generazione", + "sd_refine_mode_txt": "Modifica i prompt prima della generazione", + "sd_interactive_mode": "Genera automaticamente immagini quando invii messaggi come \"inviami una foto di gatto\".", + "sd_interactive_mode_txt": "Modalità interattiva", + "sd_multimodal_captioning": "Utilizza i sottotitoli multimodali per generare richieste per i ritratti di utenti e personaggi in base ai loro avatar.", + "sd_multimodal_captioning_txt": "Utilizza didascalie multimodali per i ritratti", + "sd_expand": "Estendi automaticamente i prompt utilizzando il modello di generazione del testo", + "sd_expand_txt": "Prompt di miglioramento automatico", + "sd_snap": "Richieste di generazione di snap con proporzioni forzate (ritratti, sfondi) alla risoluzione conosciuta più vicina, cercando di preservare il numero assoluto di pixel (consigliato per SDXL).", + "sd_snap_txt": "Risoluzioni autoregolate Snap", + "Source": "Fonte", + "sd_auto_url": "Esempio: {{auto_url}}", + "Authentication (optional)": "Autenticazione (facoltativa)", + "Example: username:password": "Esempio: nome utente: password", + "Important:": "Importante:", + "sd_auto_auth_warning_1": "eseguire l'interfaccia utente Web SD con", + "sd_auto_auth_warning_2": "bandiera! Il server deve essere accessibile dalla macchina host SillyTavern.", + "sd_drawthings_url": "Esempio: {{drawthings_url}}", + "sd_drawthings_auth_txt": "esegui l'app DrawThings con lo switch API HTTP abilitato nell'interfaccia utente! Il server deve essere accessibile dalla macchina host SillyTavern.", + "sd_vlad_url": "Esempio: {{vlad_url}}", + "The server must be accessible from the SillyTavern host machine.": "Il server deve essere accessibile dalla macchina host SillyTavern.", + "Hint: Save an API key in AI Horde API settings to use it here.": "Suggerimento: salva una chiave API nelle impostazioni API AI Horde per usarla qui.", + "Allow NSFW images from Horde": "Consenti immagini NSFW da Horde", + "Sanitize prompts (recommended)": "Messaggi di disinfezione (consigliato)", + "Automatically adjust generation parameters to ensure free image generations.": "Regola automaticamente i parametri di generazione per garantire generazioni di immagini gratuite.", + "Avoid spending Anlas": "Evita di spendere Anlas", + "Opus tier": "(Livello Opus)", + "View my Anlas": "Visualizza il mio Anlas", + "These settings only apply to DALL-E 3": "Queste impostazioni si applicano solo a DALL-E 3", + "Image Style": "Stile immagine", + "Image Quality": "Qualità dell'immagine", + "Standard": "Standard", + "HD": "HD", + "sd_comfy_url": "Esempio: {{comfy_url}}", + "Open workflow editor": "Apri l'editor del flusso di lavoro", + "Create new workflow": "Crea un nuovo flusso di lavoro", + "Delete workflow": "Elimina flusso di lavoro", + "Enhance": "Migliorare", + "Refine": "Perfeziona", + "Decrisper": "Decrisper", + "Sampling steps": "Passaggi di campionamento ()", + "Width": "Larghezza ()", + "Height": "Altezza ()", + "Resolution": "Risoluzione", + "Model": "Modello", + "Sampling method": "Metodo di campionamento", + "Karras (not all samplers supported)": "Karras (non tutti i campionatori sono supportati)", + "SMEA versions of samplers are modified to perform better at high resolution.": "Le versioni SMEA dei campionatori sono state modificate per garantire prestazioni migliori ad alta risoluzione.", + "SMEA": "SMEA", + "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "Le varianti DYN dei campionatori SMEA spesso portano a un output più vario, ma potrebbero fallire a risoluzioni molto elevate.", + "DYN": "DIN", + "Scheduler": "Pianificatore", + "Restore Faces": "Ripristina volti", + "Hires. Fix": "Assunzioni. Aggiustare", + "Upscaler": "Miglioratore", + "Upscale by": "Di lusso da", + "Denoising strength": "Forza di denoising", + "Hires steps (2nd pass)": "Passaggi di assunzione (2° passaggio)", + "Preset for prompt prefix and negative prompt": "Preimpostato per prefisso prompt e prompt negativo", + "Style": "Stile", + "Save style": "Salva stile", + "Delete style": "Elimina stile", + "Common prompt prefix": "Prefisso prompt comune", + "sd_prompt_prefix_placeholder": "Utilizzare {prompt} per specificare dove verrà inserito il prompt generato", + "Negative common prompt prefix": "Prefisso prompt comune negativo", + "Character-specific prompt prefix": "Prefisso del prompt specifico del carattere", + "Won't be used in groups.": "Non verrà utilizzato in gruppi.", + "sd_character_prompt_placeholder": "Qualsiasi caratteristica che descriva il personaggio attualmente selezionato. Verrà aggiunto dopo un prefisso prompt comune.\nEsempio: donna, occhi verdi, capelli castani, maglietta rosa", + "Character-specific negative prompt prefix": "Prefisso del prompt negativo specifico del carattere", + "sd_character_negative_prompt_placeholder": "Qualsiasi caratteristica che non dovrebbe apparire per il personaggio selezionato. Verrà aggiunto dopo un prefisso prompt comune negativo.\nEsempio: gioielli, scarpe, occhiali", + "Shareable": "Condivisibile", + "Image Prompt Templates": "Modelli di richiesta immagine", + "Vectors Model Warning": "Si consiglia di eliminare i vettori quando si modifica il modello durante la chat. Altrimenti porterà a risultati inferiori alla media.", + "Translate files into English before processing": "Traduci i file in inglese prima dell'elaborazione", + "Manager Users": "Gestisci utenti", + "New User": "Nuovo utente", + "Status:": "Stato:", + "Created:": "Creato:", + "Display Name:": "Nome da visualizzare:", + "User Handle:": "Maniglia utente:", + "Password:": "Parola d'ordine:", + "Confirm Password:": "Conferma password:", + "This will create a new subfolder...": "Ciò creerà una nuova sottocartella nella directory /data/ con l'handle dell'utente come nome della cartella.", + "Current Password:": "Password attuale:", + "New Password:": "Nuova password:", + "Confirm New Password:": "Conferma la nuova password:", + "Debug Warning": "Le funzioni di questa categoria sono riservate agli utenti esperti. Non fare clic su nulla se non sei sicuro delle conseguenze.", + "Execute": "Eseguire", + "Are you sure you want to delete this user?": "Sei sicuro di voler eliminare questo utente?", + "Deleting:": "Eliminazione:", + "Also wipe user data.": "Cancella anche i dati utente.", + "Warning:": "Avvertimento:", + "This action is irreversible.": "Questa azione è irreversibile.", + "Type the user's handle below to confirm:": "Digita l'handle dell'utente qui sotto per confermare:", + "Import Characters": "Importa caratteri", + "Enter the URL of the content to import": "Inserisci l'URL del contenuto da importare", + "Supported sources:": "Fonti supportate:", + "char_import_1": "Personaggio Chub (collegamento diretto o ID)", + "char_import_example": "Esempio:", + "char_import_2": "Lorebook di Chub (collegamento diretto o ID)", + "char_import_3": "Carattere JanitorAI (collegamento diretto o UUID)", + "char_import_4": "Carattere Pygmalion.chat (collegamento diretto o UUID)", + "char_import_5": "Carattere AICharacterCards.com (Link diretto o ID)", + "char_import_6": "Collegamento PNG diretto (fare riferimento a", + "char_import_7": "per gli host consentiti)", + "char_import_8": "Personaggio RisuRealm (collegamento diretto)", + "Supports importing multiple characters.": "Supporta l'importazione di più caratteri.", + "Write each URL or ID into a new line.": "Scrivi ogni URL o ID in una nuova riga.", + "Export for character": "Esporta per carattere", + "Export prompts for this character, including their order.": "L'esportazione richiede questo personaggio, incluso il suo ordine.", + "Export all": "Esporta tutto", + "Export all your prompts to a file": "Esporta tutte le tue richieste in un file", + "Insert prompt": "Inserisci prompt", + "Delete prompt": "Elimina prompt", + "Import a prompt list": "Importa un elenco di prompt", + "Export this prompt list": "Esporta questo elenco di prompt", + "Reset current character": "Ripristina personaggio attuale", + "New prompt": "Nuovo prompt", + "Prompts": "Richieste", + "Total Tokens:": "Token totali:", + "prompt_manager_tokens": "Gettoni", + "Are you sure you want to reset your settings to factory defaults?": "Sei sicuro di voler ripristinare le impostazioni predefinite di fabbrica?", + "Don't forget to save a snapshot of your settings before proceeding.": "Non dimenticare di salvare un'istantanea delle tue impostazioni prima di procedere.", + "Settings Snapshots": "Impostazioni Istantanee", + "Record a snapshot of your current settings.": "Registra un'istantanea delle tue impostazioni attuali.", + "Make a Snapshot": "Fai un'istantanea", + "Restore this snapshot": "Ripristina questa istantanea", + "Hi,": "CIAO,", + "To enable multi-account features, restart the SillyTavern server with": "Per abilitare le funzionalità multi-account, riavvia il server SillyTavern con", + "set to true in the config.yaml file.": "impostato su true nel file config.yaml.", + "Account Info": "Informazioni sull'account", + "To change your user avatar, use the buttons below or select a default persona in the Persona Management menu.": "Per cambiare il tuo avatar utente, usa i pulsanti qui sotto o seleziona un personaggio predefinito nel menu Gestione Persona.", + "Set your custom avatar.": "Imposta il tuo avatar personalizzato.", + "Remove your custom avatar.": "Rimuovi il tuo avatar personalizzato.", + "Handle:": "Maniglia:", + "This account is password protected.": "Questo account è protetto da password.", + "This account is not password protected.": "Questo account non è protetto da password.", + "Account Actions": "Azioni dell'account", + "Change Password": "Cambiare la password", + "Manage your settings snapshots.": "Gestisci le istantanee delle tue impostazioni.", + "Download a complete backup of your user data.": "Scarica un backup completo dei tuoi dati utente.", + "Download Backup": "Scarica Backup", + "Danger Zone": "Zona pericolosa", + "Reset your settings to factory defaults.": "Ripristina le impostazioni ai valori predefiniti di fabbrica.", + "Reset Settings": "Ripristina le impostazioni", + "Wipe all user data and reset your account to factory settings.": "Cancella tutti i dati utente e ripristina il tuo account alle impostazioni di fabbrica.", + "Reset Everything": "Ripristina tutto", + "Reset Code:": "Codice di ripristino:", + "Want to update?": "Vuoi aggiornare?", + "How to start chatting?": "Come iniziare a chattare?", + "Click _space": "Clic", + "and select a": " e seleziona un", + "Chat API": " API di chat", + "and pick a character.": "e scegli un personaggio.", + "You can browse a list of bundled characters in the": "Puoi sfogliare un elenco di personaggi raggruppati nel file", + "Download Extensions & Assets": "Scarica estensioni e risorse", + "menu within": "menù all'interno", + "Confused or lost?": "Confuso o perso?", + "click these icons!": "clicca su queste icone!", + "in the chat bar": " nella barra di chat", + "SillyTavern Documentation Site": "SillyTavern Sito di documentazione", + "Extras Installation Guide": "Guida all'installazione di extra", + "Still have questions?": "Hai ancora domande?", + "Join the SillyTavern Discord": "Unisciti al SillyTavern Discord", + "Post a GitHub issue": "Pubblica un problema su GitHub", + "Contact the developers": "Contatta gli sviluppatori" +} diff --git a/jiuguan2025cc/public/locales/ja-jp.json b/jiuguan2025cc/public/locales/ja-jp.json new file mode 100644 index 0000000000000000000000000000000000000000..4c5c167ae46f87404de5a19a9b1b7fd4a0e1448b --- /dev/null +++ b/jiuguan2025cc/public/locales/ja-jp.json @@ -0,0 +1,1448 @@ +{ + "Favorite": "お気に入り", + "Tag": "タグ", + "Duplicate": "重複", + "Persona": "ペルソナ", + "Delete": "削除", + "AI Response Configuration": "AI応答の構成", + "AI Configuration panel will stay open": "AI構成パネルが開いたままになります", + "clickslidertips": "手動で値を入力するにはクリックしてください。", + "MAD LAB MODE ON": "マッドラボモードオン", + "Documentation on sampling parameters": "サンプリングパラメータのドキュメント", + "kobldpresets": "Koboldのプリセット", + "guikoboldaisettings": "KoboldAIのGUI設定", + "Update current preset": "現在のプリセットを更新", + "Save preset as": "プリセットを保存", + "Import preset": "プリセットをインポート", + "Export preset": "プリセットをエクスポート", + "Restore current preset": "現在のプリセットを復元", + "Delete the preset": "プリセットを削除", + "novelaipresets": "NovelAIのプリセット", + "Default": "デフォルト", + "openaipresets": "OpenAIのプリセット", + "Text Completion presets": "テキスト補完のプリセット", + "AI Module": "AIモジュール", + "Changes the style of the generated text.": "生成されたテキストのスタイルを変更します。", + "No Module": "モジュールなし", + "Instruct": "指導する", + "Prose Augmenter": "散文増強装置", + "Text Adventure": "テキストアドベンチャー", + "response legth(tokens)": "応答の長さ(トークン数)", + "Streaming": "ストリーミング", + "Streaming_desc": "生成された応答を逐次表示します。", + "context size(tokens)": "コンテキストのサイズ(トークン数)", + "unlocked": "ロック解除", + "Only enable this if your model supports context sizes greater than 8192 tokens": "モデルが8192トークンを超えるコンテキストサイズをサポートしている場合にのみ有効にします", + "Max prompt cost:": "最大プロンプトコスト:", + "Display the response bit by bit as it is generated.": "生成されるたびに、応答を逐次表示します。", + "When this is off, responses will be displayed all at once when they are complete.": "この機能がオフの場合、応答は完全に生成されたときに一度ですべて表示されます。", + "Temperature": "温度", + "rep.pen": "繰り返しペナルティ", + "Rep. Pen. Range.": "繰り返しペナルティの範囲", + "Rep. Pen. Slope": "繰り返しペナルティスロープ", + "Rep. Pen. Freq.": "繰り返しペナルティの頻度", + "Rep. Pen. Presence": "繰り返しペナルティの存在", + "TFS": "TFS", + "Phrase Repetition Penalty": "フレーズの繰り返しペナルティ", + "Off": "オフ", + "Very light": "非常に軽い", + "Light": "軽め", + "Medium": "中程度", + "Aggressive": "強め", + "Very aggressive": "非常に強い", + "Unlocked Context Size": "ロック解除されたコンテキストサイズ", + "Unrestricted maximum value for the context slider": "コンテキストスライダーの制限なしの最大値", + "Context Size (tokens)": "コンテキストサイズ(トークン数)", + "Max Response Length (tokens)": "最大応答長(トークン数)", + "Multiple swipes per generation": "世代ごとに複数のスワイプ", + "Enable OpenAI completion streaming": "OpenAIの完了ストリーミングを有効にする", + "Frequency Penalty": "頻度ペナルティ", + "Presence Penalty": "存在ペナルティ", + "Count Penalty": "カウントペナルティ", + "Top K": "トップK", + "Top P": "トップP", + "Repetition Penalty": "繰り返しペナルティ", + "Min P": "最小P", + "Top A": "トップA", + "Quick Prompts Edit": "クイックプロンプトの編集", + "Main": "メイン", + "NSFW": "閲覧注意", + "Jailbreak": "脱獄", + "Utility Prompts": "ユーティリティプロンプト", + "Impersonation prompt": "なりすましプロンプト", + "Restore default prompt": "デフォルトのプロンプトを復元", + "Prompt that is used for Impersonation function": "なりすまし機能に使用されるプロンプト", + "World Info Format Template": "世界情報フォーマットテンプレート", + "Restore default format": "デフォルトの形式を復元する", + "Wraps activated World Info entries before inserting into the prompt.": "プロンプトに挿入する前に、アクティブ化された World Info エントリをラップします。", + "scenario_format_template_part_1": "使用", + "scenario_format_template_part_2": "コンテンツが挿入される場所をマークします。", + "Scenario Format Template": "シナリオ形式テンプレート", + "Personality Format Template": "パーソナリティフォーマットテンプレート", + "Group Nudge Prompt Template": "グループナッジプロンプトテンプレート", + "Sent at the end of the group chat history to force reply from a specific character.": "グループチャット履歴の最後に送信して、特定のキャラクターからの返信を強制します。", + "New Chat": "新しいチャット", + "Restore new chat prompt": "新しいチャットプロンプトを復元する", + "Set at the beginning of the chat history to indicate that a new chat is about to start.": "チャット履歴の先頭に設定して、新しいチャットが開始されることを示します。", + "New Group Chat": "新しいグループチャット", + "Restore new group chat prompt": "デフォルトのプロンプトを復元する", + "Set at the beginning of the chat history to indicate that a new group chat is about to start.": "チャット履歴の先頭に設定して、新しいグループチャットが開始されることを示します。", + "New Example Chat": "新しいサンプルチャット", + "Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.": "ダイアログ例の先頭に設定して、新しいサンプル チャットが開始されることを示します。", + "Continue nudge": "ナッジを続ける", + "Set at the end of the chat history when the continue button is pressed.": "続行ボタンを押したときにチャット履歴の最後に設定します。", + "Replace empty message": "空のメッセージを置換", + "Send this text instead of nothing when the text box is empty.": "テキストボックスが空の場合、何もない代わりにこのテキストを送信します。", + "Seed": "シード", + "Set to get deterministic results. Use -1 for random seed.": "決定論的な結果を得るために設定します。ランダム シードには -1 を使用します。", + "Temperature controls the randomness in token selection": "温度はトークン選択のランダム性を制御します", + "Top_K_desc": "Top Kは選択できるトップトークンの最大量を設定します", + "Top_P_desc": "Top P(別名核サンプリング)", + "Typical P": "典型的なP", + "Typical_P_desc": "典型的なPサンプリングは、セットの平均エントロピーからの偏差に基づいてトークンを優先します", + "Min_P_desc": "Min Pは基本的な最小確率を設定します", + "Top_A_desc": "Top Aは最高のトークン確率の二乗に基づいてトークン選択の閾値を設定します", + "Tail_Free_Sampling_desc": "Tail-Freeサンプリング(TFS)", + "rep.pen range": "繰り返しペナルティの範囲", + "Mirostat": "ミロスタット", + "Mode": "モード", + "Mirostat_Mode_desc": "値 0 は Mirostat を完全に無効にします。1 は Mirostat 1.0、2 は Mirostat 2.0 です。", + "Tau": "タウ", + "Mirostat_Tau_desc": "ミロスタット出力の変動を制御", + "Eta": "エタ", + "Mirostat_Eta_desc": "Mirostatの学習率を制御する", + "Ban EOS Token": "EOSトークンを禁止", + "Ban_EOS_Token_desc": "KoboldCpp の End-of-Sequence (EOS) トークンを禁止します (KoboldAI の他のトークンも禁止される可能性があります)。ストーリー作成には適していますが、チャットや指示モードでは使用しないでください。", + "GBNF Grammar": "GBNF文法", + "Type in the desired custom grammar": "必要なカスタム文法を入力してください", + "Samplers Order": "サンプラーの順序", + "Samplers will be applied in a top-down order. Use with caution.": "サンプラーは上から下への順序で適用されます。注意して使用してください。", + "Tail Free Sampling": "テールフリーサンプリング", + "Load koboldcpp order": "koboldcppオーダーを読み込む", + "Preamble": "前文", + "Use style tags to modify the writing style of the output.": "スタイルタグを使用して、出力の書き方を変更します。", + "Banned Tokens": "禁止されたトークン", + "Sequences you don't want to appear in the output. One per line.": "出力に表示したくないシーケンス。1行に1つ。", + "Logit Bias": "ログのバイアス", + "Add": "追加", + "Helps to ban or reenforce the usage of certain words": "特定の単語の使用を禁止または強化するのに役立ちます", + "CFG Scale": "CFGスケール", + "Negative Prompt": "ネガティブプロンプト", + "Add text here that would make the AI generate things you don't want in your outputs.": "出力に望ましくないものを生成させるAIを作成するテキストをここに追加します。", + "Used if CFG Scale is unset globally, per chat or character": "CFGスケールがグローバル、チャットごと、またはキャラクターごとに設定されていない場合に使用されます", + "Mirostat Tau": "Mirostat Tau", + "Mirostat LR": "ミロスタットLR", + "Min Length": "最小長", + "Top K Sampling": "トップKサンプリング", + "Nucleus Sampling": "核サンプリング", + "Top A Sampling": "トップAサンプリング", + "CFG": "CFG", + "Neutralize Samplers": "サンプラーを中立化する", + "Set all samplers to their neutral/disabled state.": "すべてのサンプラーを中立/無効の状態に設定します。", + "Sampler Select": "サンプラー選択", + "Customize displayed samplers or add custom samplers.": "表示されるサンプラーをカスタマイズするか、カスタム サンプラーを追加します。", + "Epsilon Cutoff": "イプシロンカットオフ", + "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "イプシロンカットオフは、サンプリング対象から除外されるトークンの下限確率を設定します", + "Eta Cutoff": "エタカットオフ", + "Eta_Cutoff_desc": "エータカットオフは、特別なエータサンプリング技術の主要なパラメータです。 1e-4の単位で; 合理的な値は3です。 無効にするには0に設定します。 詳細については、Hewittらによる論文「言語モデルデスムージングの切断サンプリング」(2022)を参照してください。", + "rep.pen decay": "ペンの劣化", + "Encoder Rep. Pen.": "エンコーダー繰り返しペナルティ", + "No Repeat Ngram Size": "繰り返しのないNgramサイズ", + "Skew": "斜め", + "Max Tokens Second": "最大トークン/秒", + "Smooth Sampling": "スムーズサンプリング", + "Smooth_Sampling_desc": "2 次/3 次変換を使用して分布を調整できます。スムージング係数の値を低くすると、よりクリエイティブになります。通常、0.2 ~ 0.3 がスイートスポットです (曲線 = 1 と仮定)。スムージング曲線の値が高くなると、曲線が急勾配になり、確率の低い選択がより積極的に罰せられます。1.0 曲線は、スムージング係数のみを使用するのと同じです。", + "Smoothing Factor": "平滑化係数", + "Smoothing Curve": "スムージングカーブ", + "DRY_Repetition_Penalty_desc": "DRY は、入力の末尾を、入力内で以前に発生したシーケンスに拡張するトークンにペナルティを課します。無効にするには、乗数を 0 に設定します。", + "DRY Repetition Penalty": "DRY繰り返しペナルティ", + "DRY_Multiplier_desc": "DRY を有効にするには、値を 0 より大きく設定します。ペナルティが課される最短シーケンスのペナルティの大きさを制御します。", + "Multiplier": "乗数", + "DRY_Base_desc": "シーケンスの長さの増加に伴ってペナルティが増加する速度を制御します。", + "Base": "ベース", + "DRY_Allowed_Length_desc": "ペナルティなしで繰り返すことができる最長のシーケンス。", + "Allowed Length": "許容長さ", + "Penalty Range": "ペナルティ範囲", + "DRY_Sequence_Breakers_desc": "シーケンスのマッチングが継続されないトークン。引用符で囲まれた文字列のコンマ区切りリストとして指定します。", + "Sequence Breakers": "シーケンスブレーカー", + "JSON-serialized array of strings.": "JSON シリアル化された文字列の配列。", + "Dynamic Temperature": "動的温度", + "Scale Temperature dynamically per token, based on the variation of probabilities": "確率の変動に基づいて、トークンごとに温度を動的にスケーリングします", + "Minimum Temp": "最低温度", + "Maximum Temp": "最大温度", + "Exponent": "指数", + "Mirostat (mode=1 is only for llama.cpp)": "ミロスタット(mode=1はllama.cpp用)", + "Mirostat_desc": "ミロスタットは出力の混乱度のためのサーモスタットです", + "Mirostat Mode": "Mirostatモード", + "Variability parameter for Mirostat outputs": "Mirostat出力の変動パラメータ", + "Mirostat Eta": "Mirostat Eta", + "Learning rate of Mirostat": "Mirostatの学習率", + "Beam search": "ビームサーチ", + "Helpful tip coming soon.": "役立つヒントがすぐに公開されます。", + "Number of Beams": "ビームの数", + "Length Penalty": "長さペナルティ", + "Early Stopping": "早期停止", + "Contrastive search": "対照的な検索", + "Penalty Alpha": "ペナルティアルファ", + "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "コントラスティブサーチの正則化項の強度。CSを無効にするには0に設定します", + "Do Sample": "サンプルを行う", + "Add BOS Token": "BOSトークンを追加", + "Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative": "プロンプトの先頭にbos_tokenを追加します。これを無効にすると、返信がよりクリエイティブになります", + "Ban the eos_token. This forces the model to never end the generation prematurely": "eos_tokenを禁止します。これにより、モデルが生成を早期に終了することがなくなります", + "Ignore EOS Token": "EOSトークンを無視", + "Ignore the EOS Token even if it generates.": "EOS トークンが生成されても無視します。", + "Skip Special Tokens": "特別なトークンをスキップ", + "Temperature Last": "最後の温度", + "Temperature_Last_desc": "最後に温度サンプラを使用します", + "Speculative Ngram": "推測的Nグラム", + "Use a different speculative decoding method without a draft model": "ドラフト モデルなしで、別の推測デコード方法を使用します。ドラフト モデルの使用が推奨されます。推測 ngram はそれほど効果的ではありません。", + "Spaces Between Special Tokens": "特殊トークン間のスペース", + "LLaMA / Mistral / Yi models only": "LLaMA / Mistral / Yiモデルのみ", + "Example: some text [42, 69, 1337]": "例:いくつかのテキスト[42, 69, 1337]", + "Classifier Free Guidance. More helpful tip coming soon": "分類器フリーガイダンス。より役立つヒントが近日公開されます", + "Scale": "スケール", + "JSON Schema": "JSONスキーマ", + "Type in the desired JSON schema": "希望するJSONスキーマを入力します", + "Grammar String": "文法文字列", + "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF または EBNF は、使用するバックエンドによって異なります。これを使用する場合は、どちらであるかを知っておく必要があります。", + "Top P & Min P": "トップPと最小P", + "Load default order": "デフォルトの順序を読み込む", + "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "llama.cpp のみ。サンプラーの順序を決定します。Mirostat モードが 0 でない場合、サンプラーの順序は無視されます。", + "Sampler Priority": "サンプラー優先度", + "Ooba only. Determines the order of samplers.": "Oobaのみ。サンプラーの順序を決定します。", + "Character Names Behavior": "キャラクター名の動作", + "Helps the model to associate messages with characters.": "モデルがメッセージをキャラクターに関連付けるのに役立ちます。", + "None": "なし", + "character_names_default": "グループと過去のペルソナを除きます。それ以外の場合は、プロンプトに名前を必ず入力してください。", + "Don't add character names.": "キャラクター名を追加しないでください。", + "Completion": "完了オブジェクト", + "character_names_completion": "制限事項: ラテン英数字とアンダースコアのみ。すべてのソースで機能するわけではありません。特に、Claude、MistralAI、Google では機能しません。", + "Add character names to completion objects.": "完了オブジェクトにキャラクター名を追加します。", + "Message Content": "メッセージ内容", + "Prepend character names to message contents.": "メッセージの内容の先頭にキャラクター名を追加します。", + "Continue Postfix": "ポストフィックスの継続", + "The next chunk of the continued message will be appended using this as a separator.": "継続メッセージの次のチャンクは、これを区切り文字として使用して追加されます。", + "Space": "空間", + "Newline": "改行", + "Double Newline": "二重改行", + "Wrap user messages in quotes before sending": "送信前にユーザーメッセージを引用符で囲む", + "Wrap in Quotes": "引用符で囲む", + "Wrap entire user message in quotes before sending.": "送信前にユーザーメッセージ全体を引用符で囲みます。", + "Leave off if you use quotes manually for speech.": "発言のために引用符を手動で使用する場合はオフにします。", + "Continue prefill": "プリフィルの継続", + "Continue sends the last message as assistant role instead of system message with instruction.": "続行は、最後のメッセージをシステムメッセージとしてではなく、アシスタントの役割として送信します。", + "Squash system messages": "システムメッセージを結合する", + "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "連続するシステムメッセージを1つに結合します(例のダイアログを除く)。一部のモデルの一貫性を向上させる可能性があります。", + "Enable function calling": "関数呼び出しを有効にする", + "Send inline images": "インライン画像を送信", + "image_inlining_hint_1": "モデルがサポートしている場合(GPT-4V、Claude 3、Llava 13Bなど)、プロンプトで画像を送信します。", + "image_inlining_hint_2": "メッセージに対するアクションまたは", + "image_inlining_hint_3": "チャットに画像ファイルを添付するためのメニュー。", + "Inline Image Quality": "インライン画像品質", + "openai_inline_image_quality_auto": "オート", + "openai_inline_image_quality_low": "低い", + "openai_inline_image_quality_high": "高い", + "Use AI21 Tokenizer": "AI21トークナイザーを使用する", + "Use the appropriate tokenizer for Jurassic models, which is more efficient than GPT's.": "GPT よりも効率的な、ジュラシック モデルに適したトークナイザーを使用します。", + "Use Google Tokenizer": "Googleトークナイザーを使用", + "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "Googleモデル用の適切なトークナイザーを使用します。 API経由で。 処理が遅くなりますが、トークンの数え上げがはるかに正確になります。", + "Use system prompt": "システムプロンプトを使用する", + "(Gemini 1.5 Pro/Flash only)": "(Gemini 1.5 Pro/Flash のみ)", + "Merges_all_system_messages_desc_1": "非システムロールの最初のメッセージまでのすべてのシステムメッセージをマージし、それらを", + "Merges_all_system_messages_desc_2": "分野。", + "Assistant Prefill": "アシスタントプリフィル", + "Start Claude's answer with...": "クロードの回答を...で始める", + "Assistant Impersonation Prefill": "アシスタントのなりすまし事前入力", + "Use system prompt (Claude 2.1+ only)": "システムプロンプトを使用します(クロード2.1以降のみ)", + "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "サポートされているモデルのシステムプロンプトを送信します。無効にすると、ユーザーメッセージがプロンプトの先頭に追加されます。", + "User first message": "ユーザーの最初のメッセージ", + "Restore User first message": "ユーザーの最初のメッセージを復元する", + "Human message": "人間によるメッセージ、指示など。\n空の場合は何も追加されません。つまり、ロール「ユーザー」を持つ新しいプロンプトが必要です。", + "New preset": "新しいプリセット", + "Delete preset": "プリセットを削除", + "View / Edit bias preset": "バイアスプリセットを表示/編集", + "Add bias entry": "バイアスエントリを追加", + "Most tokens have a leading space.": "ほとんどのトークンには先頭にスペースがあります。", + "API Connections": "API接続", + "Text Completion": "テキスト補完", + "Chat Completion": "チャット完了", + "NovelAI": "NovelAI", + "AI Horde": "AI Horde", + "KoboldAI": "KoboldAI", + "Avoid sending sensitive information to the Horde.": "Hordeに機密情報を送信しないでください。", + "Review the Privacy statement": "プライバシー声明を確認する", + "Register a Horde account for faster queue times": "キュー待ち時間を短縮するためにHordeアカウントを登録する", + "Learn how to contribute your idle GPU cycles to the Horde": "アイドルのGPUサイクルをホルドに貢献する方法を学びます", + "Adjust context size to worker capabilities": "ワーカーの能力に応じてコンテキストサイズを調整する", + "Adjust response length to worker capabilities": "ワーカーの能力に応じて応答の長さを調整する", + "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "承認済みの作業者のみをキューに入れることで、悪い応答に対処できます。応答時間が遅くなる場合があります。", + "Trusted workers only": "信頼されたワーカーのみ", + "API key": "APIキー", + "Get it here:": "こちらから入手:", + "Register": "登録", + "View my Kudos": "私の称賛を表示", + "Enter": "入力", + "to use anonymous mode.": "匿名モードを使用するには。", + "Clear your API key": "APIキーをクリア", + "For privacy reasons, your API key will be hidden after you reload the page.": "プライバシーの理由から、ページを再読み込みするとAPIキーが非表示になります。", + "Models": "モデル", + "Refresh models": "モデルをリフレッシュ", + "-- Horde models not loaded --": "-- ホルドモデルがロードされていません --", + "Not connected...": "接続されていません...", + "API url": "API URL", + "Example: http://127.0.0.1:5000/api ": "例:http://127.0.0.1:5000/api", + "Connect": "接続", + "Cancel": "キャンセル", + "Novel API key": "NovelAIのAPIキー", + "Get your NovelAI API Key": "NovelAI APIキーを取得する", + "Enter it in the box below": "以下のボックスに入力してください", + "Novel AI Model": "NovelAIモデル", + "No connection...": "接続なし...", + "API Type": "APIタイプ", + "Default (completions compatible)": "デフォルト [OpenAI /補完互換: oobabooga、LM Studio など]", + "TogetherAI API Key": "TogetherAIのAPIキー", + "TogetherAI Model": "TogetherAIモデル", + "-- Connect to the API --": "-- APIに接続 --", + "OpenRouter API Key": "OpenRouterのAPIキー", + "Click Authorize below or get the key from": "以下の[承認]をクリックするか、キーを取得する", + "View Remaining Credits": "残高を表示", + "OpenRouter Model": "OpenRouterモデル", + "Model Providers": "モデルプロバイダー", + "InfermaticAI API Key": "InfermaticAI API キー", + "InfermaticAI Model": "InfermaticAI モデル", + "DreamGen API key": "DreamGen APIキー", + "DreamGen Model": "ドリームジェンモデル", + "Mancer API key": "MancerのAPIキー", + "Mancer Model": "マンサーモデル", + "Make sure you run it with": "次のように実行していることを確認してください", + "flag": "フラグ", + "API key (optional)": "APIキー(オプション)", + "Server url": "サーバーURL", + "Example: 127.0.0.1:5000": "例: 127.0.0.1:5000", + "Custom model (optional)": "カスタムモデル(オプション)", + "vllm-project/vllm": "vllm-project/vllm (OpenAI API ラッパーモード)", + "vLLM API key": "vLLM API キー", + "Example: 127.0.0.1:8000": "例: http://127.0.0.1:8000", + "vLLM Model": "vLLM モデル", + "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine(OpenAI APIエンドポイントのパッケージングモード)", + "Aphrodite API key": "アフロディーテAPIキー", + "Aphrodite Model": "アフロディーテモデル", + "ggerganov/llama.cpp": "ggerganov/llama.cpp(出力サーバー)", + "Example: 127.0.0.1:8080": "例: 127.0.0.1:8080", + "Example: 127.0.0.1:11434": "例: 127.0.0.1:11434", + "Ollama Model": "Ollamaモデル", + "Download": "ダウンロード", + "Tabby API key": "TabbyのAPIキー", + "koboldcpp API key (optional)": "koboldcpp API キー (オプション)", + "Example: 127.0.0.1:5001": "例: 127.0.0.1:5001", + "Authorize": "承認", + "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "OAuthフローを使用してOpenRouter APIトークンを取得します。 openrouter.aiにリダイレクトされます", + "Bypass status check": "ステータスのチェックをバイパスする", + "Chat Completion Source": "チャット補完ソース", + "Reverse Proxy": "リバースプロキシ", + "Proxy Presets": "プロキシプリセット", + "Saved addresses and passwords.": "保存されたアドレスとパスワード。", + "Save Proxy": "プロキシを保存", + "Delete Proxy": "プロキシを削除", + "Proxy Name": "プロキシ名", + "This will show up as your saved preset.": "これは保存したプリセットとして表示されます。", + "Proxy Server URL": "プロキシサーバー URL", + "Alternative server URL (leave empty to use the default value).": "代替サーバーのURL(デフォルト値を使用するには空白のままにしてください)。", + "Remove your real OAI API Key from the API panel BEFORE typing anything into this box": "このボックスに何か入力する前に、APIパネルから実際のOAI APIキーを削除してください", + "We cannot provide support for problems encountered while using an unofficial OpenAI proxy": "非公式のOpenAIプロキシを使用して問題が発生した場合、サポートを提供することができません", + "Doesn't work? Try adding": "うまくいかない場合は追加してみてください", + "at the end!": "最後に!", + "Proxy Password": "プロキシパスワード", + "Will be used as a password for the proxy instead of API key.": "API キーの代わりにプロキシのパスワードとして使用されます。", + "Peek a password": "パスワードを覗く", + "OpenAI API key": "OpenAI APIキー", + "View API Usage Metrics": "API使用メトリクスを表示", + "Follow": "フォロー", + "these directions": "これらの指示", + "to get your OpenAI API key.": "OpenAIのAPIキーを取得するために。", + "Use Proxy password field instead. This input will be ignored.": "代わりに「プロキシ パスワード」フィールドを使用してください。この入力は無視されます。", + "OpenAI Model": "OpenAIモデル", + "Bypass API status check": "APIステータスのチェックをバイパスする", + "Show External models (provided by API)": "外部モデルを表示(APIで提供される)", + "Get your key from": "キーを取得する", + "Anthropic's developer console": "Anthropicの開発者コンソール", + "Claude Model": "Claudeモデル", + "Window AI Model": "Window AIモデル", + "Model Order": "OpenRouter モデルのソート", + "Alphabetically": "アルファベット順", + "Price": "価格(最安値)", + "Context Size": "コンテキストサイズ", + "Group by vendors": "ベンダー別にグループ化", + "Group by vendors Description": "OpenAI モデルを 1 つのグループに、Anthropic モデルを別のグループに配置するなどします。ソートと組み合わせることができます。", + "Allow fallback routes": "フォールバックルートを許可", + "Allow fallback routes Description": "選択したモデルが要求を満たせない場合、代替モデルが自動的に選択されます。", + "Scale API Key": "ScaleのAPIキー", + "Clear your cookie": "クッキーを消去する", + "Alt Method": "代替手法", + "AI21 API Key": "AI21のAPIキー", + "AI21 Model": "AI21モデル", + "Google AI Studio API Key": "Google AI Studio APIキー", + "Google Model": "Google モデル", + "MistralAI API Key": "MistralAI API キー", + "MistralAI Model": "MistralAI モデル", + "Groq API Key": "Groq API キー", + "Groq Model": "Groq モデル", + "Perplexity API Key": "パープレキシティ API キー", + "Perplexity Model": "困惑モデル", + "Cohere API Key": "Cohere API キー", + "Cohere Model": "Cohereモデル", + "Custom Endpoint (Base URL)": "カスタムエンドポイント (ベース URL)", + "Custom API Key": "カスタム API キー", + "Available Models": "利用可能なモデル", + "Prompt Post-Processing": "迅速な後処理", + "Applies additional processing to the prompt before sending it to the API.": "プロンプトを API に送信する前に追加の処理を適用します。", + "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "短いテストメッセージを送信してAPI接続を検証します。それに対してクレジットが与えられることに注意してください!", + "Test Message": "テストメッセージ", + "Auto-connect to Last Server": "前回のサーバーに自動接続", + "Missing key": "❌ キーがありません", + "Key saved": "✔️ キーを保存しました", + "View hidden API keys": "隠しAPIキーを表示", + "AI Response Formatting": "AI応答の書式設定", + "Advanced Formatting": "高度なフォーマット", + "Context Template": "コンテキストテンプレート", + "Auto-select this preset for Instruct Mode": "Instructモードのためにこのプリセットを自動選択", + "Story String": "ストーリー文字列", + "Example Separator": "例のセパレータ", + "Chat Start": "チャット開始", + "Add Chat Start and Example Separator to a list of stopping strings.": "停止文字列のリストにチャット開始と例の区切り文字を追加します。", + "Use as Stop Strings": "ストップ文字列として使用", + "context_allow_jailbreak": "文字カードで定義されていて、「文字 Jailbreak を優先」が有効になっている場合は、プロンプトの最後に Jailbreak が含まれます。\nこれはテキスト補完モデルには推奨されません。出力が悪くなる可能性があります。", + "Allow Jailbreak": "脱獄を許可する", + "Context Order": "コンテキスト順序", + "Summary": "まとめ", + "Author's Note": "著者の注意", + "Example Dialogues": "対話例", + "Hint": "ヒント:", + "In-Chat Position not affected": "概要と著者のメモの注文は、チャット内の位置が設定されていない場合にのみ影響を受けます。", + "Instruct Mode": "指示モード", + "Enabled": "有効", + "instruct_bind_to_context": "有効にすると、選択した指示テンプレート名または設定に基づいてコンテキスト テンプレートが自動的に選択されます。", + "Bind to Context": "コンテキストにバインド", + "Presets": "プリセット", + "Auto-select this preset on API connection": "API接続時にこのプリセットを自動選択", + "Activation Regex": "アクティベーション正規表現", + "Wrap Sequences with Newline": "シーケンスを改行でラップする", + "Replace Macro in Sequences": "シーケンス内のマクロを置換", + "Skip Example Dialogues Formatting": "例の対話の書式設定をスキップ", + "Include Names": "名前を含める", + "Force for Groups and Personas": "グループと人物用の強制", + "System Prompt": "システムプロンプト", + "Instruct Mode Sequences": "指示モードシーケンス", + "System Prompt Wrapping": "システムプロンプトの折り返し", + "Inserted before a System prompt.": "システムプロンプトの前に挿入されます。", + "System Prompt Prefix": "システムプロンプトプレフィックス", + "Inserted after a System prompt.": "システムプロンプトの後に挿入されます。", + "System Prompt Suffix": "システムプロンプトサフィックス", + "Chat Messages Wrapping": "チャットメッセージの折り返し", + "Inserted before a User message and as a last prompt line when impersonating.": "ユーザー メッセージの前に挿入され、偽装時の最後のプロンプト行として挿入されます。", + "User Message Prefix": "ユーザーメッセージプレフィックス", + "Inserted after a User message.": "ユーザー メッセージの後に挿入されます。", + "User Message Suffix": "ユーザーメッセージサフィックス", + "Inserted before an Assistant message and as a last prompt line when generating an AI reply.": "アシスタント メッセージの前に挿入され、AI 応答を生成するときの最後のプロンプト ラインとして挿入されます。", + "Assistant Message Prefix": "アシスタントメッセージプレフィックス", + "Inserted after an Assistant message.": "アシスタントメッセージの後に挿入されます。", + "Assistant Message Suffix": "アシスタントメッセージサフィックス", + "Inserted before a System (added by slash commands or extensions) message.": "システム (スラッシュ コマンドまたは拡張機能によって追加された) メッセージの前に挿入されます。", + "System Message Prefix": "システムメッセージプレフィックス", + "Inserted after a System message.": "システム メッセージの後に挿入されます。", + "System Message Suffix": "システムメッセージサフィックス", + "If enabled, System Sequences will be the same as User Sequences.": "有効にすると、システム シーケンスはユーザー シーケンスと同じになります。", + "System same as User": "システムとユーザーは同じ", + "Misc. Sequences": "その他のシーケンス", + "Inserted before the first Assistant's message.": "最初のアシスタントのメッセージの前に挿入されます。", + "First Assistant Prefix": "第一アシスタントプレフィックス", + "instruct_last_output_sequence": "最後のアシスタントのメッセージの前に挿入されるか、AI 応答を生成するときの最後のプロンプト ラインとして挿入されます (ニュートラル/システム ロールを除く)。", + "Last Assistant Prefix": "最後のアシスタントプレフィックス", + "Will be inserted as a last prompt line when using system/neutral generation.": "システム/ニュートラル生成を使用する場合、最後のプロンプト行として挿入されます。", + "System Instruction Prefix": "システム命令プレフィックス", + "If a stop sequence is generated, everything past it will be removed from the output (inclusive).": "停止シーケンスが生成されると、それ以降のすべてが出力から削除されます (含む)。", + "Stop Sequence": "停止シーケンス", + "Will be inserted at the start of the chat history if it doesn't start with a User message.": "チャット履歴がユーザー メッセージで始まっていない場合は、チャット履歴の先頭に挿入されます。", + "User Filler Message": "ユーザーフィラーメッセージ", + "Context Formatting": "コンテキストのフォーマット", + "(Saved to Context Template)": "(コンテキストテンプレートに保存)", + "Always add character's name to prompt": "プロンプトにキャラクターの名前を常に追加する", + "Generate only one line per request": "リクエストごとに1行のみ生成", + "Trim Incomplete Sentences": "不完全な文をトリミング", + "Include Newline": "改行を含む", + "Misc. Settings": "その他の設定", + "Collapse Consecutive Newlines": "連続する改行を折りたたむ", + "Trim spaces": "スペースをトリミング", + "Tokenizer": "トークナイザー", + "Token Padding": "トークンのパディング", + "Start Reply With": "返信の開始", + "AI reply prefix": "AI応答のプレフィックス", + "Show reply prefix in chat": "チャットで返信の接頭辞を表示", + "Non-markdown strings": "マークダウン以外の文字列", + "separate with commas w/o space between": "間にスペースのないカンマで区切ります", + "Custom Stopping Strings": "カスタム停止文字列", + "JSON serialized array of strings": "文字列のJSONシリアル化配列", + "Replace Macro in Stop Strings": "カスタム停止文字列内のマクロを置換する", + "Auto-Continue": "自動継続", + "Allow for Chat Completion APIs": "チャット補完APIを許可", + "Target length (tokens)": "ターゲット長さ(トークン)", + "World Info": "世界情報", + "Locked = World Editor will stay open": "ロックされた = ワールドエディターが開いたままになります", + "Worlds/Lorebooks": "ワールド/Lorebook", + "Active World(s) for all chats": "すべてのチャットのアクティブなワールド", + "-- World Info not found --": "-- ワールド情報が見つかりません --", + "Global World Info/Lorebook activation settings": "グローバルワールド情報/Lorebookの有効化設定", + "Click to expand": "クリックして展開", + "Scan Depth": "スキャンの深さ", + "Context %": "コンテキスト%", + "Budget Cap": "予算キャップ", + "(0 = disabled)": "(0 = 無効)", + "Scan chronologically until reached min entries or token budget.": "最小エントリ数またはトークン予算に達するまで時系列でスキャンします。", + "Min Activations": "最小アクティベーション", + "Max Depth": "最大深度", + "(0 = unlimited, use budget)": "(0 = 無制限、予算を使用)", + "Insertion Strategy": "挿入戦略", + "Sorted Evenly": "均等に並べ替え", + "Character Lore First": "キャラクターロアを最初に表示", + "Global Lore First": "グローバルロアを最初に表示", + "Entries can activate other entries by mentioning their keywords": "エントリは、キーワードを言及することで他のエントリをアクティブにできます", + "Recursive Scan": "再帰的スキャン", + "Lookup for the entry keys in the context will respect the case": "コンテキスト内のエントリキーの検索は、ケースを尊重します", + "Case Sensitive": "大文字と小文字を区別する", + "If the entry key consists of only one word, it would not be matched as part of other words": "エントリキーが1つの単語だけで構成されている場合、他の単語の一部として一致しません", + "Match Whole Words": "完全一致", + "Only the entries with the most number of key matches will be selected for Inclusion Group filtering": "包含グループのフィルタリングでは、キー一致数が最も多いエントリのみが選択されます。", + "Use Group Scoring": "グループスコアリングを使用する", + "Alert if your world info is greater than the allocated budget.": "ワールド情報が割り当てられた予算より大きい場合に警告します。", + "Alert On Overflow": "オーバーフロー時に警告", + "New": "新規", + "or": "または", + "--- Pick to Edit ---": "--- 編集するものを選択 ---", + "Rename World Info": "ワールド情報の名前を変更", + "Open all Entries": "すべてのエントリを開く", + "Close all Entries": "すべてのエントリを閉じる", + "New Entry": "新しいエントリ", + "Fill empty Memo/Titles with Keywords": "空のメモ/タイトルにキーワードを入れる", + "Import World Info": "ワールド情報のインポート", + "Export World Info": "ワールド情報のエクスポート", + "Duplicate World Info": "ワールド情報の複製", + "Delete World Info": "ワールド情報を削除", + "Search...": "検索...", + "Search": "検索", + "Priority": "優先度", + "Custom": "カスタム", + "Title A-Z": "タイトルA-Z", + "Title Z-A": "タイトルZ-A", + "Tokens ↗": "トークン ↗", + "Tokens ↘": "トークン ↘", + "Depth ↗": "深さ ↗", + "Depth ↘": "深さ ↘", + "Order ↗": "順序 ↗", + "Order ↘": "順序 ↘", + "UID ↗": "UID ↗", + "UID ↘": "UID ↘", + "Trigger% ↗": "トリガー% ↗", + "Trigger% ↘": "トリガー% ↘", + "Refresh": "更新", + "User Settings": "ユーザー設定", + "Simple": "シンプル", + "Advanced": "高度", + "UI Language": "言語", + "Account": "アカウント", + "Admin Panel": "管理パネル", + "Logout": "ログアウト", + "Search Settings": "検索設定", + "UI Theme": "UIテーマ", + "Import a theme file": "テーマファイルをインポート", + "Export a theme file": "テーマファイルをエクスポート", + "Delete a theme": "テーマを削除する", + "Update a theme file": "テーマファイルを更新", + "Save as a new theme": "新しいテーマとして保存", + "Avatar Style:": "アバタースタイル", + "Circle": "円", + "Square": "正方形", + "Rectangle": "長方形", + "Chat Style:": "チャットスタイル:", + "Flat": "フラット\nバブル\nドキュメント", + "Bubbles": "バブル", + "Document": "文書", + "Specify colors for your theme.": "テーマの色を指定します。", + "Theme Colors": "テーマカラー", + "Main Text": "メインテキスト", + "Italics Text": "イタリックテキスト", + "Underlined Text": "下線付きテキスト", + "Quote Text": "引用テキスト", + "Shadow Color": "シャドウカラー", + "Chat Background": "チャットの背景", + "UI Background": "UIの背景", + "UI Border": "UIの境界", + "User Message Blur Tint": "ユーザーメッセージのぼかし色", + "AI Message Blur Tint": "AIメッセージのぼかし色", + "Chat Width": "チャットの幅", + "Width of the main chat window in % of screen width": "メインチャットウィンドウの幅(画面幅に対する%)", + "Font Scale": "フォントスケール", + "Font size": "フォントサイズ", + "Blur Strength": "ぼかしの強さ", + "Blur strength on UI panels.": "UI パネルのぼかしの強度。", + "Text Shadow Width": "テキストシャドウの幅", + "Strength of the text shadows": "テキストの影の強さ", + "Disables animations and transitions": "アニメーションとトランジションを無効にする", + "Reduced Motion": "動作の軽減", + "removes blur from window backgrounds": "ウィンドウの背景のぼかしを除去する", + "No Blur Effect": "ぼかし効果なし", + "Remove text shadow effect": "テキストの影の効果を削除する", + "No Text Shadows": "テキストシャドウなし", + "Reduce chat height, and put a static sprite behind the chat window": "チャットの高さを縮小し、チャットウィンドウの背後に静的なスプライトを配置する", + "Waifu Mode": "ワイフモード", + "Always show the full list of the Message Actions context items for chat messages, instead of hiding them behind '...'": "チャットメッセージのメッセージアクションコンテキスト項目の完全なリストを常に表示し、それらを '...' の後ろに隠す代わりに", + "Auto-Expand Message Actions": "メッセージアクションを自動展開する", + "Alternative UI for numeric sampling parameters with fewer steps": "より少ないステップで数値サンプリングパラメーターの代替UI", + "Zen Sliders": "禅のスライダー", + "Entirely unrestrict all numeric sampling parameters": "すべての数値サンプリングパラメーターの制限を完全に解除する", + "Mad Lab Mode": "Mad Labモード", + "Time the AI's message generation, and show the duration in the chat log": "AIのメッセージ生成の時間を計測し、チャットログにその期間を表示する", + "Message Timer": "メッセージタイマー", + "Show a timestamp for each message in the chat log": "チャットログ内の各メッセージにタイムスタンプを表示する", + "Chat Timestamps": "チャットのタイムスタンプ", + "Show an icon for the API that generated the message": "メッセージを生成したAPIのアイコンを表示する", + "Model Icon": "モデルアイコン", + "Show sequential message numbers in the chat log": "チャットログに連続したメッセージ番号を表示する", + "Message IDs": "メッセージID", + "Hide avatars in chat messages.": "チャットメッセージ内のアバターを非表示にします。", + "Hide Chat Avatars": "チャットアバターを非表示", + "Show the number of tokens in each message in the chat log": "チャットログ内の各メッセージのトークン数を表示する", + "Show Message Token Count": "メッセージトークンの数を表示", + "Single-row message input area. Mobile only, no effect on PC": "一行のメッセージ入力エリア。モバイル専用で、PCには影響がありません", + "Compact Input Area (Mobile)": "コンパクトな入力エリア(モバイル)", + "In the Character Management panel, show quick selection buttons for favorited characters": "キャラクター管理パネルで、お気に入りのキャラクター用の迅速な選択ボタンを表示する", + "Characters Hotswap": "キャラクターホットスワップ", + "Enable magnification for zoomed avatar display.": "ズームされたアバター表示の拡大を有効にします。", + "Avatar Hover Magnification": "アバターホバー拡大", + "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "チャットでアバターの画像をクリックした後に拡大されたアバターを表示するときに、ホバー時に拡大効果を有効にします。", + "Show tagged character folders in the character list": "キャラクターリストでタグ付きキャラクターフォルダーを表示する", + "Tags as Folders": "タグをフォルダーとして", + "Tags_as_Folders_desc": "最近の変更: タグは、タグ管理メニューでフォルダーとしてマークされて初めてフォルダーとして表示されます。ここをクリックして表示します。", + "Character Handling": "キャラクター処理", + "If set in the advanced character definitions, this field will be displayed in the characters list.": "高度なキャラクター定義で設定されている場合、このフィールドがキャラクターリストに表示されます。", + "Char List Subheader": "キャラクターリストサブヘッダー", + "Character Version": "キャラクターバージョン", + "Created by": "作成者", + "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "曖昧な一致を使用し、名前の部分文字列ではなく、すべてのデータフィールドでリスト内のキャラクターを検索する", + "Advanced Character Search": "高度なキャラクター検索", + "If checked and the character card contains a prompt override (System Prompt), use that instead": "チェックされていてキャラクターカードにプロンプトオーバーライド(システムプロンプト)が含まれている場合、それを代わりに使用します", + "Prefer Character Card Prompt": "キャラクターカードのプロンプトを優先", + "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "チェックされていてキャラクターカードにジェイルブレイクオーバーライド(投稿履歴指示)が含まれている場合、それを代わりに使用します", + "Prefer Character Card Jailbreak": "キャラクターカードのJailbreakを優先", + "never_resize_avatars_tooltip": "インポートした文字画像の切り取りやサイズ変更を避けます。オフにすると、512x768 に切り取り/サイズ変更されます。", + "Never resize avatars": "アバターを常にリサイズしない", + "Show actual file names on the disk, in the characters list display only": "ディスク上の実際のファイル名を表示します。キャラクターリストの表示にのみ", + "Show avatar filenames": "アバターのファイル名を表示", + "Prompt to import embedded card tags on character import. Otherwise embedded tags are ignored": "キャラクターのインポート時に埋め込みカードタグのインポートを促します。それ以外の場合、埋め込みタグは無視されます", + "Import Card Tags": "カードのタグをインポート", + "Hide character definitions from the editor panel behind a spoiler button": "スポイラーボタンの後ろのエディターパネルからキャラクターの定義を非表示にします", + "Spoiler Free Mode": "スポイラーフリーモード", + "Miscellaneous": "その他", + "Reload and redraw the currently open chat": "現在開いているチャットを再読み込みして再描画する", + "Reload Chat": "チャットをリロード", + "Debug Menu": "デバッグメニュー", + "Smooth Streaming": "スムーズなストリーミング", + "Experimental feature. May not work for all backends.": "実験的な機能です。すべてのバックエンドで動作するとは限りません。", + "Slow": "遅い", + "Fast": "速い", + "Play a sound when a message generation finishes": "メッセージ生成が終了したときに音を再生する", + "Message Sound": "メッセージ音", + "Only play a sound when ST's browser tab is unfocused": "STのブラウザタブがフォーカスされていない場合にのみ音を再生する", + "Background Sound Only": "背景音のみ", + "Reduce the formatting requirements on API URLs": "APIのURLの書式要件を緩和する", + "Relaxed API URLS": "リラックスしたAPI URLS", + "Ask to import the World Info/Lorebook for every new character with embedded lorebook. If unchecked, a brief message will be shown instead": "埋め込み式の伝説の書を持つすべての新しいキャラクターのためにWorld Info/Lorebookをインポートするように問い合わせます。チェックされていない場合、代わりに簡潔なメッセージが表示されます", + "Lorebook Import Dialog": "Lorebookインポートダイアログ", + "Restore unsaved user input on page refresh": "ページをリフレッシュすると、保存されていないユーザー入力を復元する", + "Restore User Input": "ユーザー入力の復元", + "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "ドラッグして特定のUI要素の位置を変更できるようにする。PC専用で、モバイルには影響がありません", + "Movable UI Panels": "移動可能なUIパネル", + "MovingUI preset. Predefined/saved draggable positions": "MovingUIプリセット。事前定義/保存されたドラッグ可能な位置", + "MUI Preset": "MUIプリセット", + "Save movingUI changes to a new file": "移動中のUI変更を新しいファイルに保存する", + "Reset MovingUI panel sizes/locations.": "MovingUI パネルのサイズ/位置をリセットします。", + "Apply a custom CSS style to all of the ST GUI": "ST GUI全体にカスタムCSSスタイルを適用する", + "Custom CSS": "カスタムCSS", + "Expand the editor": "エディターを展開する", + "Chat/Message Handling": "チャット/メッセージの処理", + "# Messages to Load": "# 読み込むメッセージ", + "The number of chat history messages to load before pagination.": "ページ区切りの前に読み込むチャット履歴メッセージの数。", + "(0 = All)": "(0 = すべて)", + "Streaming FPS": "ストリーミングFPS", + "Update speed of streamed text.": "ストリーミングテキストの更新速度。", + "Example Messages Behavior": "例のメッセージの振る舞い", + "Gradual push-out": "徐々にプッシュアウト", + "Always include examples": "常に例を含める", + "Never include examples": "決して例を含めない", + "Send on Enter": "Enterキーで送信", + "Disabled": "無効", + "Automatic (PC)": "自動(PC)", + "Press Send to continue": "'送信'を押して続行", + "Show a button in the input area to ask the AI to continue (extend) its last message": "入力エリアにボタンを表示して、AIに最後のメッセージを続行(延長)するように依頼します", + "Quick 'Continue' button": "迅速な「続行」ボタン", + "Show arrow buttons on the last in-chat message to generate alternative AI responses. Both PC and mobile": "最後のチャットメッセージに矢印ボタンを表示して、代替のAI応答を生成します。PCとモバイルの両方", + "Swipes": "スワイプ", + "Allow using swiping gestures on the last in-chat message to trigger swipe generation. Mobile only, no effect on PC": "最後のチャットメッセージでスワイプジェスチャーを使用してスワイプ生成をトリガーできるようにします。モバイル専用で、PCには影響がありません", + "Gestures": "ジェスチャー", + "Auto-load Last Chat": "最後のチャットを自動読み込み", + "Auto-scroll Chat": "チャットの自動スクロール", + "Save edits to messages without confirmation as you type": "入力時に確認なしでメッセージの編集を保存する", + "Auto-save Message Edits": "メッセージ編集の自動保存", + "Confirm message deletion": "メッセージの削除を確認", + "Auto-fix Markdown": "Markdownの自動修正", + "Disallow embedded media from other domains in chat messages": "チャットメッセージの他のドメインからの埋め込みメディアを禁止する", + "Forbid External Media": "外部メディアを禁止", + "Allow {{char}}: in bot messages": "ボットメッセージ内の{{char}}:を許可", + "Allow {{user}}: in bot messages": "ボットメッセージ内の{{user}}:を許可", + "Skip encoding and characters in message text, allowing a subset of HTML markup as well as Markdown": "メッセージテキスト内のエンコーディングおよび文字のスキップ。一部のHTMLマークアップおよびMarkdownを許可します", + "Show tags in responses": "応答でタグを表示", + "Allow AI messages in groups to contain lines spoken by other group members": "グループ内のAIメッセージに、他のグループメンバーによって話された行を含めることを許可する", + "Relax message trim in Groups": "グループ内のメッセージトリムを緩和する", + "Log prompts to console": "プロンプトをコンソールに記録", + "Requests logprobs from the API for the Token Probabilities feature": "トークン確率機能のAPIからのlogprobsをリクエストします", + "Request token probabilities": "トークンの確率を要求", + "Automatically reject and re-generate AI message based on configurable criteria": "設定可能な基準に基づいてAIメッセージを自動的に拒否して再生成します", + "Auto-swipe": "オートスワイプ", + "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "自動スワイプ機能を有効にします。このセクションの設定は、自動スワイプが有効になっている場合にのみ効果があります", + "Minimum generated message length": "生成されたメッセージの最小長", + "If the generated message is shorter than these many characters, trigger an auto-swipe": "生成されたメッセージがこれよりも短い場合、自動スワイプをトリガーします", + "Blacklisted words": "ブラックリストされた単語", + "words you dont want generated separated by comma ','": "コンマ ',' で区切られた生成したくない単語", + "Blacklisted word count to swipe": "スワイプするブラックリストされた単語の数", + "Minimum number of blacklisted words detected to trigger an auto-swipe": "オートスワイプをトリガーするために検出されたブラックリストされた単語の最小数", + "AutoComplete Settings": "オートコンプリート設定", + "Automatically hide details": "詳細を自動的に非表示にする", + "Determines how entries are found for autocomplete.": "オートコンプリートのエントリの検索方法を決定します。", + "Autocomplete Matching": "マッチング", + "Starts with": "前方一致", + "Includes": "部分一致", + "Fuzzy": "ファジー", + "Sets the style of the autocomplete.": "オートコンプリートのスタイルを設定します。", + "Autocomplete Style": "スタイル", + "Follow Theme": "テーマをフォロー", + "Dark": "暗い", + "Sets the font size of the autocomplete.": "オートコンプリートのフォント サイズを設定します。", + "Sets the width of the autocomplete.": "オートコンプリートの幅を設定します。", + "Autocomplete Width": "幅", + "chat input box": "チャット入力ボックス", + "entire chat width": "チャット全体の幅", + "full window width": "ウィンドウ全体の幅", + "STscript Settings": "STscript 設定", + "Sets default flags for the STscript parser.": "STscript パーサーのデフォルト フラグを設定します。", + "Parser Flags": "パーサーフラグ", + "Switch to stricter escaping, allowing all delimiting characters to be escaped with a backslash, and backslashes to be escaped as well.": "より厳密なエスケープに切り替えて、すべての区切り文字をバックスラッシュでエスケープし、バックスラッシュもエスケープできるようにします。", + "STRICT_ESCAPING": "厳格なエスケープ", + "Replace all {{getvar::}} and {{getglobalvar::}} macros with scoped variables to avoid double macro substitution.": "二重のマクロ置換を回避するために、すべての {{getvar::}} および {{getglobalvar::}} マクロをスコープ付き変数に置き換えます。", + "REPLACE_GETVAR": "REPLACE_GETVAR", + "Change Background Image": "背景画像を変更", + "Filter": "フィルター", + "Automatically select a background based on the chat context": "チャットのコンテキストに基づいて背景を自動選択", + "Auto-select": "自動選択", + "System Backgrounds": "システムの背景", + "Chat Backgrounds": "チャットの背景", + "bg_chat_hint_1": "", + "bg_chat_hint_2": "拡張機能で生成したチャットの背景はここに表示されます。", + "Extensions": "拡張機能", + "Notify on extension updates": "拡張機能の更新時に通知", + "Manage extensions": "拡張機能を管理", + "Import Extension From Git Repo": "Gitリポジトリから拡張機能をインポート", + "Install extension": "拡張機能をインストール", + "Extras API:": "追加API:", + "Auto-connect": "自動接続", + "Extras API URL": "エクストラAPI URL", + "Extras API key (optional)": "エクストラAPIキー(オプション)", + "Persona Management": "ペルソナ管理", + "How do I use this?": "これをどのように使用しますか?", + "Click for stats!": "統計をクリック!", + "Usage Stats": "使用状況統計", + "Backup your personas to a file": "キャラクターをファイルにバックアップします", + "Backup": "バックアップ", + "Restore your personas from a file": "ファイルからキャラクターを復元します", + "Restore": "復元", + "Create a dummy persona": "ダミーのペルソナを作成", + "Create": "作成", + "Toggle grid view": "グリッドビューの切り替え", + "No persona description": "[説明なし]", + "Name": "名前", + "Enter your name": "あなたの名前を入力してください", + "Click to set a new User Name": "新しいユーザー名を設定するにはクリック", + "Click to lock your selected persona to the current chat. Click again to remove the lock.": "選択したペルソナを現在のチャットにロックするにはクリックします。 ロックを解除するには、もう一度クリックします。", + "Click to set user name for all messages": "すべてのメッセージにユーザー名を設定するにはクリック", + "Persona Description": "ペルソナの説明", + "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "例:[{{user}}は28歳のルーマニアの猫の少女です。]", + "Tokens persona description": "トークン", + "Position:": "位置:", + "In Story String / Prompt Manager": "ストーリー文字列/プロンプトマネージャー", + "Top of Author's Note": "作者の注意の上部", + "Bottom of Author's Note": "作者の注意の下部", + "In-chat @ Depth": "チャット内 @ Depth", + "Depth:": "深さ:", + "Role:": "役割:", + "System": "システム", + "User": "ユーザー", + "Assistant": "アシスタント", + "Show notifications on switching personas": "ペルソナの切り替え時に通知を表示する", + "Character Management": "キャラクター管理", + "Locked = Character Management panel will stay open": "ロックされました=キャラクター管理パネルは開いたままになります", + "Select/Create Characters": "キャラクターを選択/作成", + "Favorite characters to add them to HotSwaps": "お気に入りのキャラクターを選択してHotSwapsに追加", + "Token counts may be inaccurate and provided just for reference.": "トークン数は不正確かもしれず、参考のために提供されます。", + "Total tokens": "合計トークン", + "Calculating...": "計算中...", + "Tokens": "トークン", + "Permanent tokens": "永久トークン", + "Permanent": "永続", + "About Token 'Limits'": "トークンの「制限」について", + "Toggle character info panel": "キャラクター情報パネルを切り替える", + "Name this character": "このキャラクターに名前を付ける", + "extension_token_counter": "トークン:", + "Click to select a new avatar for this character": "このキャラクターの新しいアバターを選択するにはクリック", + "Add to Favorites": "お気に入りに追加", + "Advanced Definition": "高度な定義", + "Character Lore": "キャラクターロア", + "Chat Lore": "チャットロア", + "Export and Download": "エクスポートとダウンロード", + "Duplicate Character": "キャラクターを複製", + "Create Character": "キャラクターを作成", + "Delete Character": "キャラクターを削除", + "More...": "詳細...", + "Link to World Info": "ワールド情報へのリンク", + "Import Card Lore": "カードの伝説をインポート", + "Scenario Override": "シナリオオーバーライド", + "Convert to Persona": "ペルソナに変換", + "Rename": "名前を変更", + "Link to Source": "ソースへのリンク", + "Replace / Update": "置き換え/更新", + "Import Tags": "タグをインポート", + "Search / Create Tags": "タグを検索/作成", + "View all tags": "すべてのタグを表示", + "Creator's Notes": "作者のメモ", + "Show / Hide Description and First Message": "説明と最初のメッセージを表示/非表示", + "Character Description": "キャラクターの説明", + "Click to allow/forbid the use of external media for this character.": "このキャラクターの外部メディアの使用を許可/禁止するにはクリックします。", + "Ext. Media": "外部メディア", + "Describe your character's physical and mental traits here.": "ここにキャラクターの身体的および精神的特徴を説明します。", + "First message": "最初のメッセージ", + "Click to set additional greeting messages": "追加の挨拶メッセージを設定するにはクリック", + "Alt. Greetings": "他の挨拶", + "This will be the first message from the character that starts every chat.": "これはすべてのチャットを開始するキャラクターからの最初のメッセージになります。", + "Group Controls": "グループコントロール", + "Chat Name (Optional)": "チャット名(任意)", + "Click to select a new avatar for this group": "このグループの新しいアバターを選択するにはクリック", + "Group reply strategy": "グループ返信戦略", + "Natural order": "自然な順序", + "List order": "リストの順序", + "Group generation handling mode": "グループ生成処理モード", + "Swap character cards": "キャラクターカードの交換", + "Join character cards (exclude muted)": "キャラクターカードに参加(ミュートは除く)", + "Join character cards (include muted)": "キャラクターカードに参加(ミュート含む)", + "Inserted before each part of the joined fields.": "結合されたフィールドの各部分の前に挿入されます。", + "Join Prefix": "結合プレフィックス", + "When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and with the name of the part (e.g.: description, personality, scenario, etc.)": "「キャラクターカードを結合」を選択すると、キャラクターのそれぞれのフィールドがすべて結合されます。つまり、たとえばストーリー文字列では、すべてのキャラクターの説明が 1 つの大きなテキストに結合されます。これらのフィールドを分離したい場合は、ここでプレフィックスまたはサフィックスを定義できます。この値は通常のマクロをサポートし、{{char}} を関連するキャラクターの名前に置き換え、 をパーツの名前 (例: 説明、性格、シナリオなど) に置き換えます。", + "Inserted after each part of the joined fields.": "結合されたフィールドの各部分の後に挿入されます。", + "Join Suffix": "結合サフィックス", + "Set a group chat scenario": "グループチャットのシナリオを設定", + "Click to allow/forbid the use of external media for this group.": "このグループに対して外部メディアの使用を許可/禁止するにはクリックします。", + "Restore collage avatar": "コラージュアバターを復元", + "Allow self responses": "自己応答を許可する", + "Auto Mode": "自動モード", + "Auto Mode delay": "自動モードの遅延", + "Hide Muted Member Sprites": "ミュートされたメンバーのスプライトを非表示にする", + "Current Members": "現在のメンバー", + "Add Members": "メンバーを追加する", + "Create New Character": "新しいキャラクターを作成", + "Import Character from File": "ファイルからキャラクターをインポート", + "Import content from external URL": "外部URLからコンテンツをインポート", + "Create New Chat Group": "新しいチャットグループを作成", + "Characters sorting order": "キャラクターのソート順", + "A-Z": "ア-ン", + "Z-A": "ン-ア", + "Newest": "最新", + "Oldest": "最古", + "Favorites": "お気に入り", + "Recent": "最近", + "Most chats": "最も多いチャット", + "Least chats": "最も少ないチャット", + "Most tokens": "最も多いトークン", + "Least tokens": "最も少ないトークン", + "Random": "ランダム", + "Toggle character grid view": "キャラクターグリッドビューの切り替え", + "Bulk_edit_characters": "キャラクターを一括編集", + "Bulk select all characters": "すべての文字を一括選択", + "Bulk delete characters": "キャラクターを一括削除", + "popup-button-save": "保存", + "popup-button-yes": "はい", + "popup-button-no": "いいえ", + "popup-button-cancel": "キャンセル", + "popup-button-import": "インポート", + "Advanced Definitions": "高度な定義", + "Prompt Overrides": "プロンプトのオーバーライド", + "(For Chat Completion and Instruct Mode)": "(チャット補完と指示モード用)", + "Insert {{original}} into either box to include the respective default prompt from system settings.": "システム設定からの対応するデフォルトのプロンプトを含めるには、どちらかのボックスに{{original}}を挿入します。", + "Main Prompt": "メインプロンプト", + "Any contents here will replace the default Main Prompt used for this character. (v2 spec: system_prompt)": "ここにあるコンテンツは、このキャラクターに使用されるデフォルトのメインプロンプトを置き換えます。(v2仕様:system_prompt)", + "Any contents here will replace the default Jailbreak Prompt used for this character. (v2 spec: post_history_instructions)": "ここにあるコンテンツは、このキャラクターに使用されるデフォルトのジェイルブレイクプロンプトを置き換えます。(v2仕様:post_history_instructions)", + "Creator's Metadata (Not sent with the AI prompt)": "作成者のメタデータ(AIプロンプトとは送信されません)", + "Creator's Metadata": "クリエイターのメタデータ", + "(Not sent with the AI Prompt)": "(AIプロンプトでは送信されません)", + "Everything here is optional": "ここにあるすべては任意です", + "(Botmaker's name / Contact Info)": "(ボットメーカーの名前/連絡先情報)", + "(If you want to track character versions)": "(キャラクターバージョンを追跡したい場合)", + "(Describe the bot, give use tips, or list the chat models it has been tested on. This will be displayed in the character list.)": "(ボットを説明し、使用のヒントを与えるか、それがテストされたチャットモデルのリストを示します。これはキャラクターリストに表示されます。)", + "Tags to Embed": "埋め込むタグ", + "(Write a comma-separated list of tags)": "(カンマで区切られたタグのリストを書きます)", + "Personality summary": "人格の要約", + "(A brief description of the personality)": "(人格の簡単な説明)", + "Scenario": "シナリオ", + "(Circumstances and context of the interaction)": "(相互作用の状況と文脈)", + "Character's Note": "キャラクターノート", + "(Text to be inserted in-chat @ designated depth and role)": "(指定された深さと役割でチャットに挿入されるテキスト)", + "@ Depth": "@ 深さ", + "Role": "役割", + "Talkativeness": "話し好き", + "How often the character speaks in group chats!": "キャラクターがグループチャットで話す頻度!", + "How often the character speaks in": "キャラクターが話す頻度", + "group chats!": "グループチャット!", + "Shy": "シャイ", + "Normal": "普通", + "Chatty": "おしゃべり", + "Examples of dialogue": "対話の例", + "Important to set the character's writing style.": "キャラクターの執筆スタイルを設定するのに重要です。", + "(Examples of chat dialog. Begin each example with START on a new line.)": "(チャットダイアログの例。各例を新しい行でSTARTで始めます。)", + "Save": "保存", + "Chat History": "チャット履歴", + "Import Chat": "チャットをインポート", + "Copy to system backgrounds": "システム背景にコピー", + "Rename background": "背景の名前を変更", + "Lock": "ロック", + "Unlock": "ロック解除", + "Delete background": "背景を削除", + "Chat Scenario Override": "チャットシナリオのオーバーライド", + "Remove": "削除", + "Type here...": "ここに入力...", + "Chat Lorebook": "チャットロアブック", + "Chat Lorebook for": "チャットロアブック", + "chat_world_template_txt": "選択したワールド情報はこのチャットにバインドされます。AI の返信を生成する際、\nグローバルおよびキャラクターのロアブックのエントリと結合されます。", + "Select a World Info file for": "次のためにワールド情報ファイルを選択", + "Primary Lorebook": "プライマリロアブック", + "A selected World Info will be bound to this character as its own Lorebook.": "選択したワールド情報は、このキャラクターにその独自のロアブックとしてバインドされます。", + "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "AI応答を生成する際、グローバルワールド情報セレクターのエントリと組み合わされます。", + "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "キャラクターをエクスポートすると、JSONデータに埋め込まれた選択したロアブックファイルもエクスポートされます。", + "Additional Lorebooks": "追加のロアブック", + "Associate one or more auxillary Lorebooks with this character.": "このキャラクターに1つ以上の補助ロアブックを関連付けます。", + "NOTE: These choices are optional and won't be preserved on character export!": "注意:これらの選択肢は任意であり、キャラクターエクスポート時には保存されません!", + "Rename chat file": "チャットファイルの名前を変更", + "Export JSONL chat file": "JSONLチャットファイルをエクスポート", + "Download chat as plain text document": "プレーンテキストドキュメントとしてチャットをダウンロード", + "Delete chat file": "チャットファイルを削除", + "Use tag as folder": "フォルダとしてタグ付け", + "Delete tag": "タグを削除", + "Entry Title/Memo": "エントリータイトル/メモ", + "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized❌ Disabled": "WI エントリ ステータス: 🔵 定数 🟢 通常 🔗 ベクトル化 ❌ 無効", + "WI_Entry_Status_Constant": "絶え間ない", + "WI_Entry_Status_Normal": "普通", + "WI_Entry_Status_Vectorized": "ベクトル化された", + "WI_Entry_Status_Disabled": "無効", + "T_Position": "↑キャラ:キャラクター定義の前\n↓キャラ:キャラクター定義の後\n↑AN:著者のメモの前\n↓AN:著者のメモの後\n@D:深さ", + "Before Char Defs": "キャラクター定義の前", + "After Char Defs": "キャラクター定義の後", + "Before EM": "↑EM", + "After EM": "↓EM", + "Before AN": "著者のメモの前", + "After AN": "著者のメモの後", + "at Depth System": "指定深度(システム)", + "at Depth User": "指定深度(ユーザー)", + "at Depth AI": "指定深度(AI)", + "Depth": "深さ", + "Order:": "順序:", + "Order": "順序:", + "Trigger %:": "発生 %:", + "Probability": "確率", + "Duplicate world info entry": "重複したワールド情報エントリ", + "Delete world info entry": "世界情報エントリを削除", + "Comma separated (required)": "カンマで区切られています(必須)", + "Primary Keywords": "主要キーワード", + "Keywords or Regexes": "キーワードまたは正規表現", + "Comma separated list": "カンマ区切りリスト", + "Switch to plaintext mode": "プレーンテキストモードに切り替える", + "Logic": "論理", + "AND ANY": "AND ANY", + "AND ALL": "AND ALL", + "NOT ALL": "NOT ALL", + "NOT ANY": "NOT ANY", + "(ignored if empty)": "(空の場合は無視されます)", + "Optional Filter": "オプションフィルタ", + "Keywords or Regexes (ignored if empty)": "キーワードまたは正規表現(空の場合は無視されます)", + "Comma separated list (ignored if empty)": "カンマ区切りのリスト(空の場合は無視されます)", + "Use global setting": "グローバル設定を使用", + "Case-Sensitive": "大文字と小文字を区別する", + "Yes": "はい", + "No": "いいえ", + "Can be used to automatically activate Quick Replies": "クイック返信を自動的に有効にするために使用できます", + "Automation ID": "自動化ID", + "( None )": "( なし )", + "Content": "内容", + "Exclude from recursion": "再帰から除外", + "Prevent further recursion (this entry will not activate others)": "それ以上の再帰を防止します(このエントリは他のエントリをアクティブにしません)", + "Delay until recursion (this entry can only be activated on recursive checking)": "再帰まで遅延 (このエントリは再帰チェックでのみ有効になります)", + "What this keyword should mean to the AI, sent verbatim": "このキーワードがAIにとって何を意味するか、そのまま送信されます", + "Filter to Character(s)": "キャラクターにフィルター", + "Character Exclusion": "キャラクターの除外", + "-- Characters not found --": "-- キャラクターが見つかりません --", + "Inclusion Group": "包含グループ", + "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "包含グループにより、複数のエントリがトリガーされた場合、一度に 1 つのグループから 1 つのエントリのみがアクティブ化されます。カンマで区切られた複数のグループをサポートします。ドキュメント: World Info - 包含グループ", + "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "このエントリを優先する: チェックすると、このエントリがすべての選択項目の中で優先されます。複数のエントリを優先する場合は、「順序」が最も高いエントリが選択されます。", + "Only one entry with the same label will be activated": "同じラベルのエントリが1つだけ有効になります", + "A relative likelihood of entry activation within the group": "グループ内でのエントリー活性化の相対的な可能性", + "Group Weight": "グループの重み", + "Selective": "選択的", + "Use Probability": "確率を使用", + "Add Memo": "メモを追加", + "Text or token ids": "テキストまたは[トークンID]", + "close": "閉じる", + "prompt_manager_edit": "編集", + "prompt_manager_name": "名前", + "A name for this prompt.": "このプロンプトの名前。", + "To whom this message will be attributed.": "このメッセージの送信者。", + "AI Assistant": "AIアシスタント", + "prompt_manager_position": "位置", + "Injection position. Next to other prompts (relative) or in-chat (absolute).": "挿入位置。他のプロンプトの隣 (相対) またはチャット内 (絶対)。", + "prompt_manager_relative": "相対的", + "prompt_manager_depth": "深さ", + "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "注入の深さ。0 = 最後のメッセージの後、1 = 最後のメッセージの前など。", + "Prompt": "プロンプト", + "The prompt to be sent.": "送信されるプロンプト。", + "This prompt cannot be overridden by character cards, even if overrides are preferred.": "このプロンプトは、オーバーライドが優先される場合でも、キャラクター カードによってオーバーライドすることはできません。", + "prompt_manager_forbid_overrides": "オーバーライドを禁止する", + "reset": "リセット", + "save": "保存", + "This message is invisible for the AI": "このメッセージはAIには見えません", + "Message Actions": "メッセージアクション", + "Translate message": "メッセージを翻訳", + "Generate Image": "画像を生成", + "Narrate": "語る", + "Exclude message from prompts": "プロンプトからメッセージを除外", + "Include message in prompts": "プロンプトにメッセージを含める", + "Embed file or image": "ファイルまたは画像を埋め込む", + "Create checkpoint": "チェックポイントを作成", + "Create Branch": "ブランチを作成", + "Copy": "コピー", + "Open checkpoint chat": "チェックポイントチャットを開く", + "Edit": "編集", + "Confirm": "確認", + "Copy this message": "このメッセージをコピー", + "Delete this message": "このメッセージを削除", + "Move message up": "メッセージを上に移動", + "Move message down": "メッセージを下に移動", + "Enlarge": "拡大", + "Welcome to SillyTavern!": "SillyTavern へようこそ!", + "welcome_message_part_1": "読む", + "welcome_message_part_2": "公式ドキュメント", + "welcome_message_part_3": "。", + "welcome_message_part_4": "タイプ", + "welcome_message_part_5": "コマンドとマクロについてはチャットで。", + "welcome_message_part_6": "参加する", + "Discord server": "Discordサーバー", + "welcome_message_part_7": "情報とお知らせ。", + "SillyTavern is aimed at advanced users.": "SillyTavern は上級ユーザーを対象としています。", + "If you're new to this, enable the simplified UI mode below.": "初めての場合は、以下の簡易 UI モードを有効にしてください。", + "Change it later in the 'User Settings' panel.": "後で「ユーザー設定」パネルで変更します。", + "Enable simple UI mode": "シンプルUIモードを有効にする", + "Looking for AI characters?": "AIキャラクターをお探しですか?", + "onboarding_import": "インポート", + "from supported sources or view": "サポートされているソースからまたは表示", + "Sample characters": "サンプルキャラクター", + "Your Persona": "あなたのペルソナ", + "Before you get started, you must select a persona name.": "始める前に、ペルソナ名を選択する必要があります。", + "welcome_message_part_8": "これはいつでも変更可能です。", + "welcome_message_part_9": "アイコン。", + "Persona Name:": "ペルソナ名:", + "Temporarily disable automatic replies from this character": "このキャラクターからの自動返信を一時的に無効にする", + "Enable automatic replies from this character": "このキャラクターからの自動返信を有効にする", + "Trigger a message from this character": "このキャラクターからメッセージをトリガーする", + "Move up": "上に移動", + "Move down": "下に移動", + "View character card": "キャラクターカードを表示", + "Remove from group": "グループから削除", + "Add to group": "グループに追加", + "Alternate Greetings": "挨拶のバリエーション", + "Alternate_Greetings_desc": "これらは、新しいチャットを開始するときに最初のメッセージにスワイプとして表示されます。\nグループのメンバーは、そのうちの 1 つを選択して会話を開始できます。", + "Alternate Greetings Hint": "ボタンをクリックして始めましょう!", + "(This will be the first message from the character that starts every chat)": "(これはすべてのチャットを開始するキャラクターからの最初のメッセージになります)", + "Forbid Media Override explanation": "現在のキャラクター/グループがチャットで外部メディアを使用できるかどうか。", + "Forbid Media Override subtitle": "メディア: 画像、ビデオ、オーディオ。外部: ローカル サーバーでホストされていません。", + "Always forbidden": "常に禁止", + "Always allowed": "常に許可されている", + "View contents": "コンテンツを見る", + "Remove the file": "ファイルを削除する", + "Unique to this chat": "このチャットに固有の", + "Checkpoints inherit the Note from their parent, and can be changed individually after that.": "チェックポイントは親からノートを継承し、その後個別に変更できます。", + "Include in World Info Scanning": "世界情報スキャンに含める", + "Before Main Prompt / Story String": "メインプロンプト/ストーリー文字列の前", + "After Main Prompt / Story String": "メインプロンプト/ストーリー文字列の後", + "as": "として", + "Insertion Frequency": "挿入頻度", + "(0 = Disable, 1 = Always)": "(0 = 無効、1 = 常に)", + "User inputs until next insertion:": "次の挿入までのユーザー入力:", + "Character Author's Note (Private)": "キャラクター作者メモ(非公開)", + "Won't be shared with the character card on export.": "エクスポート時にキャラクターカードと共有されません。", + "Will be automatically added as the author's note for this character. Will be used in groups, but can't be modified when a group chat is open.": "このキャラクターの作者のメモとして自動的に追加されます。グループで使用されますが、グループチャットが開いているときは変更できません。", + "Use character author's note": "キャラクター作者のメモを使用する", + "Replace Author's Note": "著者のメモを置き換える", + "Default Author's Note": "デフォルトの著者のメモ", + "Will be automatically added as the Author's Note for all new chats.": "すべての新しいチャットの作成者のメモとして自動的に追加されます。", + "Chat CFG": "チャット CFG", + "1 = disabled": "1 = 無効", + "write short replies, write replies using past tense": "短い返信を書く、過去形を使って返信を書く", + "Positive Prompt": "肯定的なプロンプト", + "Use character CFG scales": "キャラクターCFGスケールを使用する", + "Character CFG": "キャラクターCFG", + "Will be automatically added as the CFG for this character.": "このキャラクターの CFG として自動的に追加されます。", + "Global CFG": "グローバルCFG", + "Will be used as the default CFG options for every chat unless overridden.": "上書きされない限り、すべてのチャットのデフォルトの CFG オプションとして使用されます。", + "CFG Prompt Cascading": "CFG プロンプト カスケード", + "Combine positive/negative prompts from other boxes.": "他のボックスからの肯定的/否定的なプロンプトを組み合わせます。", + "For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string.": "たとえば、チャット、グローバル、およびキャラクターのボックスにチェックを入れると、すべてのネガティブプロンプトがコンマ区切りの文字列に結合されます。", + "Always Include": "常に含めます", + "Chat Negatives": "チャットのネガティブ", + "Character Negatives": "キャラクターのネガティブ", + "Global Negatives": "グローバルネガティブ", + "Custom Separator:": "カスタムセパレーター:", + "Insertion Depth:": "挿入深さ:", + "Token Probabilities": "トークン確率", + "Select a token to see alternatives considered by the AI.": "AI が検討した代替案を表示するには、トークンを選択します。", + "Not connected to API!": "APIに接続されていません!", + "Type a message, or /? for help": "メッセージを入力するか、/? でヘルプを表示してください", + "Continue script execution": "スクリプトの実行を続行する", + "Pause script execution": "スクリプトの実行を一時停止する", + "Abort script execution": "スクリプトの実行を中止する", + "Abort request": "要求を中止", + "Continue the last message": "前回のメッセージを継続", + "Send a message": "メッセージを送信", + "Close chat": "チャットを閉じる", + "Toggle Panels": "パネルを切り替える", + "Back to parent chat": "親チャットに戻る", + "Save checkpoint": "チェックポイントを保存", + "Convert to group": "グループに変換", + "Start new chat": "新しいチャットを開始", + "Manage chat files": "チャットファイルを管理", + "Delete messages": "メッセージを削除", + "Regenerate": "再生成", + "Ask AI to write your message for you": "AIにあなたのメッセージを書くように依頼", + "Impersonate": "擬態する", + "Continue": "続行", + "Bind user name to that avatar": "ユーザー名をそのアバターにバインド", + "Change persona image": "ペルソナ画像を変更", + "Select this as default persona for the new chats.": "これを新しいチャットのデフォルトのペルソナとして選択します。", + "Delete persona": "ペルソナを削除", + "These characters are the winners of character design contests and have outstandable quality.": "これらのキャラクターはキャラクターデザインコンテストの優勝者であり、優れた品質を誇ります。", + "Contest Winners": "コンテスト受賞者", + "These characters are the finalists of character design contests and have remarkable quality.": "これらのキャラクターはキャラクターデザインコンテストのファイナリストであり、優れた品質を誇ります。", + "Featured Characters": "注目キャラクター", + "Attach a File": "ファイルを添付する", + "Open Data Bank": "オープンデータバンク", + "Enter a URL or the ID of a Fandom wiki page to scrape:": "スクレイピングする Fandom Wiki ページの URL または ID を入力してください:", + "Examples:": "例:", + "Example:": "例:", + "Single file": "単一ファイル", + "All articles will be concatenated into a single file.": "すべての記事は 1 つのファイルに連結されます。", + "File per article": "記事ごとのファイル", + "Each article will be saved as a separate file.": "推奨されません。各記事は個別のファイルとして保存されます。", + "Data Bank": "データバンク", + "These files will be available for extensions that support attachments (e.g. Vector Storage).": "これらのファイルは、添付ファイルをサポートする拡張機能 (Vector Storage など) で使用できます。", + "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.": "サポートされているファイルの種類: プレーンテキスト、PDF、Markdown、HTML、EPUB。", + "Drag and drop files here to upload.": "アップロードするには、ファイルをここにドラッグ アンド ドロップします。", + "Date (Newest First)": "日付(新しい順)", + "Date (Oldest First)": "日付(古い順)", + "Name (A-Z)": "名前 (A-Z)", + "Name (Z-A)": "名前 (Z-A)", + "Size (Smallest First)": "サイズ(小さい順)", + "Size (Largest First)": "サイズ(大きい順)", + "Bulk Edit": "一括編集", + "Select All": "すべて選択", + "Select None": "なしを選択", + "Global Attachments": "グローバル添付ファイル", + "These files are available for all characters in all chats.": "これらのファイルは、すべてのチャットのすべてのキャラクターで使用できます。", + "Character Attachments": "キャラクターアタッチメント", + "These files are available the current character in all chats they are in.": "これらのファイルは、現在のキャラクターが参加しているすべてのチャットで利用できます。", + "Saved locally. Not exported.": "ローカルに保存されました。エクスポートされません。", + "Chat Attachments": "チャット添付ファイル", + "These files are available to all characters in the current chat.": "これらのファイルは、現在のチャット内のすべてのキャラクターが利用できます。", + "Enter a base URL of the MediaWiki to scrape.": "スクレイピングする MediaWiki のベース URL を入力します。", + "Don't include the page name!": "ページ名を含めないでください。", + "Enter web URLs to scrape (one per line):": "スクレイピングする Web URL を入力します (1 行に 1 つずつ):", + "Enter a video URL to download its transcript.": "ビデオの URL または ID を入力して、そのトランスクリプトをダウンロードします。", + "Expression API": "ローカル\nエクストラ\nLLM", + "ext_sum_with": "要約:", + "ext_sum_main_api": "メインAPI", + "ext_sum_current_summary": "現在の概要:", + "ext_sum_restore_previous": "前の状態に戻す", + "ext_sum_memory_placeholder": "ここで要約が生成されます...", + "Trigger a summary update right now.": "今すぐ要約", + "ext_sum_force_text": "今すぐ要約", + "Disable automatic summary updates. While paused, the summary remains as-is. You can still force an update by pressing the Summarize now button (which is only available with the Main API).": "自動サマリー更新を無効にします。一時停止中は、サマリーはそのまま残ります。[今すぐサマリーを作成] ボタン (メイン API でのみ使用可能) を押すと、強制的に更新できます。", + "ext_sum_pause": "一時停止", + "Omit World Info and Author's Note from text to be summarized. Only has an effect when using the Main API. The Extras API always omits WI/AN.": "要約するテキストからワールド情報と著者のメモを省略します。メイン API を使用する場合にのみ効果があります。Extras API は常に WI/AN を省略します。", + "ext_sum_no_wi_an": "WI/ANなし", + "ext_sum_settings_tip": "要約プロンプト、挿入位置などを編集します。", + "ext_sum_settings": "概要設定", + "ext_sum_prompt_builder": "プロンプトビルダー", + "ext_sum_prompt_builder_1_desc": "拡張機能は、まだ要約されていないメッセージを使用して独自のプロンプトを作成します。要約が生成されるまでチャットをブロックします。", + "ext_sum_prompt_builder_1": "生、ブロック", + "ext_sum_prompt_builder_2_desc": "拡張機能は、まだ要約されていないメッセージを使用して独自のプロンプトを構築します。要約の生成中はチャットをブロックしません。すべてのバックエンドがこのモードをサポートしているわけではありません。", + "ext_sum_prompt_builder_2": "生の、非ブロッキング", + "ext_sum_prompt_builder_3_desc": "拡張機能は通常のメインプロンプトビルダーを使用し、最後のシステムメッセージとしてサマリー要求を追加します。", + "ext_sum_prompt_builder_3": "クラシック、ブロッキング", + "Summary Prompt": "概要プロンプト", + "ext_sum_restore_default_prompt_tip": "デフォルトのプロンプトを復元する", + "ext_sum_prompt_placeholder": "このプロンプトは、要約の生成を要求するために AI に送信されます。{{words}} は「単語数」パラメータに解決されます。", + "ext_sum_target_length_1": "ターゲット要約の長さ", + "ext_sum_target_length_2": "(", + "ext_sum_target_length_3": "単語)", + "ext_sum_api_response_length_1": "API レスポンスの長さ", + "ext_sum_api_response_length_2": "(", + "ext_sum_api_response_length_3": "トークン)", + "ext_sum_0_default": "0 = デフォルト", + "ext_sum_raw_max_msg": "[生] リクエストあたりの最大メッセージ数", + "ext_sum_0_unlimited": "0 = 無制限", + "Update frequency": "更新頻度", + "ext_sum_update_every_messages_1": "更新する", + "ext_sum_update_every_messages_2": "メッセージ", + "ext_sum_0_disable": "0 = 無効", + "ext_sum_auto_adjust_desc": "チャットのメトリックに基づいて間隔を自動的に調整してみてください。", + "ext_sum_update_every_words_1": "更新する", + "ext_sum_update_every_words_2": "言葉", + "ext_sum_both_sliders": "両方のスライダーがゼロ以外の場合、両方のスライダーがそれぞれの間隔でサマリー更新をトリガーします。", + "ext_sum_injection_template": "インジェクションテンプレート", + "ext_sum_memory_template_placeholder": "{{summary}} は現在の概要コンテンツに解決されます。", + "ext_sum_injection_position": "注入位置", + "How many messages before the current end of the chat.": "現在のチャット終了までのメッセージ数。", + "ext_regex_title": "正規表現", + "ext_regex_new_global_script": "+ グローバル", + "ext_regex_new_scoped_script": "+ スコープ付き", + "ext_regex_import_script": "インポート", + "ext_regex_global_scripts": "グローバルスクリプト", + "ext_regex_global_scripts_desc": "すべてのキャラクターで使用可能。ローカル設定に保存されます。", + "ext_regex_scoped_scripts": "スコープ付きスクリプト", + "ext_regex_scoped_scripts_desc": "このキャラクターのみ使用可能。カードデータに保存されます。", + "Regex Editor": "正規表現エディタ", + "Test Mode": "テストモード", + "ext_regex_desc": "Regex は、正規表現を使用して文字列を検索/置換するツールです。詳細を知りたい場合は、タイトルの横にある [?] をクリックしてください。", + "Input": "入力", + "ext_regex_test_input_placeholder": "ここに入力...", + "Output": "出力", + "ext_regex_output_placeholder": "空の", + "Script Name": "スクリプト名", + "Find Regex": "正規表現を検索", + "Replace With": "と置換する", + "ext_regex_replace_string_placeholder": "正規表現検索から一致したテキストを含めるには {{match}} を使用し、キャプチャ グループには $1、$2 などを使用します。", + "Trim Out": "トリムアウト", + "ext_regex_trim_placeholder": "置換前に、正規表現の一致から不要な部分を全体的にトリミングします。各要素を Enter で区切ります。", + "ext_regex_affects": "影響", + "ext_regex_user_input": "ユーザー入力", + "ext_regex_ai_output": "AI出力", + "Slash Commands": "スラッシュコマンド", + "ext_regex_min_depth_desc": "プロンプトまたはディスプレイに適用すると、少なくとも N レベルの深さのメッセージにのみ影響します。0 = 最後のメッセージ、1 = 最後から 2 番目のメッセージなど。WI エントリ @Depth と使用可能なメッセージ (非表示またはシステムではない) のみをカウントします。", + "Min Depth": "最小深度", + "ext_regex_min_depth_placeholder": "無制限", + "ext_regex_max_depth_desc": "プロンプトまたはディスプレイに適用された場合、N レベル以下の深さのメッセージにのみ影響します。0 = 最後のメッセージ、1 = 最後から 2 番目のメッセージなど。WI エントリ @Depth と使用可能なメッセージ (非表示またはシステムではない) のみをカウントします。", + "ext_regex_other_options": "その他のオプション", + "Only Format Display": "フォーマット表示のみ", + "ext_regex_only_format_prompt_desc": "チャット履歴は変更されず、リクエストが送信されたときのプロンプトのみが変更されます (生成時)。", + "Only Format Prompt (?)": "フォーマットプロンプトのみ", + "Run On Edit": "編集時に実行", + "ext_regex_substitute_regex_desc": "実行する前に、Find Regex で {{macros}} を置き換えてください。", + "Substitute Regex": "正規表現の置換", + "ext_regex_import_target": "インポート先:", + "ext_regex_disable_script": "スクリプトを無効にする", + "ext_regex_enable_script": "スクリプトを有効にする", + "ext_regex_edit_script": "スクリプトを編集", + "ext_regex_move_to_global": "グローバルスクリプトに移動", + "ext_regex_move_to_scoped": "スコープ付きスクリプトに移動する", + "ext_regex_export_script": "エクスポートスクリプト", + "ext_regex_delete_script": "スクリプトを削除", + "Trigger Stable Diffusion": "安定した拡散を誘発する", + "sd_Yourself": "あなた自身", + "sd_Your_Face": "あなたの顔", + "sd_Me": "自分", + "sd_The_Whole_Story": "一部始終", + "sd_The_Last_Message": "最後のメッセージ", + "sd_Raw_Last_Message": "生の最後のメッセージ", + "sd_Background": "背景", + "Image Generation": "画像生成", + "Stop Image Generation": "画像生成を停止", + "Generate Caption": "画像説明を生成", + "sd_refine_mode": "プロンプトを生成 API に送信する前に手動で編集できるようにする", + "sd_refine_mode_txt": "生成前にプロンプ​​トを編集する", + "sd_interactive_mode": "「猫の写真を送ってください」のようなメッセージを送信するときに、画像を自動的に生成します。", + "sd_interactive_mode_txt": "インタラクティブモード", + "sd_multimodal_captioning": "マルチモーダル キャプションを使用して、アバターに基づいてユーザーとキャラクターのポートレートのプロンプトを生成します。", + "sd_multimodal_captioning_txt": "ポートレートにはマルチモーダルキャプションを使用する", + "sd_expand": "テキスト生成モデルを使用してプロンプトを自動的に拡張する", + "sd_expand_txt": "自動強化プロンプト", + "sd_snap": "絶対ピクセル数を維持しながら、強制アスペクト比 (ポートレート、背景) で生成要求を最も近い既知の解像度にスナップします (SDXL に推奨)。", + "sd_snap_txt": "スナップ自動調整解像度", + "Source": "ソース", + "sd_auto_url": "例: {{auto_url}}", + "Authentication (optional)": "認証(オプション)", + "Example: username:password": "例: ユーザー名:パスワード", + "Important:": "重要:", + "sd_auto_auth_warning_1": "SD Web UIを", + "sd_auto_auth_warning_2": "フラグを指定して実行してください! サーバーは SillyTavern ホスト マシンからアクセスできる必要があります。", + "sd_drawthings_url": "例: {{drawthings_url}}", + "sd_drawthings_auth_txt": "UI で HTTP API スイッチを有効にして DrawThings アプリを実行します。サーバーは SillyTavern ホスト マシンからアクセスできる必要があります。", + "sd_vlad_url": "例: {{vlad_url}}", + "The server must be accessible from the SillyTavern host machine.": "サーバーは SillyTavern ホスト マシンからアクセスできる必要があります。", + "Hint: Save an API key in AI Horde API settings to use it here.": "ヒント: ここで使用するには、AI Horde API 設定に API キーを保存してください。", + "Allow NSFW images from Horde": "HordeからのNSFW画像を許可する", + "Sanitize prompts (recommended)": "サニタイズプロンプト(推奨)", + "Automatically adjust generation parameters to ensure free image generations.": "生成パラメータを自動的に調整して、自由な画像生成を保証します。", + "Avoid spending Anlas": "アンラスの支出を避ける", + "Opus tier": "(Opus レベル)", + "View my Anlas": "私のAnlasを見る", + "These settings only apply to DALL-E 3": "これらの設定はDALL-E 3にのみ適用されます", + "Image Style": "画像スタイル", + "Image Quality": "画質", + "Standard": "標準", + "HD": "高解像度", + "sd_comfy_url": "例: {{comfy_url}}", + "Open workflow editor": "ワークフローエディタを開く", + "Create new workflow": "新しいワークフローを作成する", + "Delete workflow": "ワークフローの削除", + "Enhance": "強化する", + "Refine": "リファイン", + "Decrisper": "デクリスパー", + "Sampling steps": "サンプリングステップ数", + "Width": "幅", + "Height": "高さ", + "Resolution": "解像度", + "Model": "モデル", + "Sampling method": "サンプリング方法", + "Karras (not all samplers supported)": "Karras (すべてのサンプラーがサポートされているわけではありません)", + "SMEA versions of samplers are modified to perform better at high resolution.": "SMEA バージョンのサンプラーは、高解像度でより優れたパフォーマンスを発揮するように変更されています。", + "SMEA": "SMEA", + "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "SMEA サンプラーの DYN バリアントは、多くの場合、より多様な出力をもたらしますが、非常に高い解像度では失敗する可能性があります。", + "DYN": "ダイナミック", + "Scheduler": "スケジューラー", + "Restore Faces": "顔の修復", + "Hires. Fix": "高解像度補助", + "Upscaler": "アップスケーラー", + "Upscale by": "アップスケール倍率", + "Denoising strength": "ノイズ除去の強さ", + "Hires steps (2nd pass)": "高解像度でのステップ数", + "Preset for prompt prefix and negative prompt": "プロンプトプレフィックスとネガティブプロンプトのプリセット", + "Style": "スタイル", + "Save style": "スタイルを保存", + "Delete style": "スタイルを削除", + "Common prompt prefix": "共通のプロンプトプレフィックス", + "sd_prompt_prefix_placeholder": "生成されたプロンプトを挿入する場所を指定するには、{prompt}を使用します。", + "Negative common prompt prefix": "共通のネガティブプロンプトプレフィックス", + "Character-specific prompt prefix": "キャラクター固有のプロンプトプレフィックス", + "Won't be used in groups.": "グループでは使用されません。", + "sd_character_prompt_placeholder": "現在選択されているキャラクターを説明する特徴。共通のプロンプトプレフィックスの後に追加されます。\n例: 女性、緑の目、茶色の髪、ピンクのシャツ", + "Character-specific negative prompt prefix": "キャラクター固有のネガティブプロンプトプレフィックス", + "sd_character_negative_prompt_placeholder": "選択したキャラクターに表示されるべきではない特徴。共通のネガティブプロンプトプレフィックスの後に追加されます。\n例: ジュエリー、靴、メガネ", + "Shareable": "共有可能", + "Image Prompt Templates": "画像プロンプトテンプレート", + "Vectors Model Warning": "チャットの途中でモデルを変更する場合は、ベクトルを消去することをお勧めします。そうしないと、標準以下の結果になります。", + "Translate files into English before processing": "処理前にファイルを英語に翻訳する", + "Manager Users": "ユーザーの管理", + "New User": "新しいユーザー", + "Status:": "状態:", + "Created:": "作成した:", + "Display Name:": "表示名:", + "User Handle:": "ユーザーハンドル:", + "Password:": "パスワード:", + "Confirm Password:": "パスワードを認証する:", + "This will create a new subfolder...": "これにより、/data/ ディレクトリに、ユーザーのハンドルをフォルダ名として持つ新しいサブフォルダが作成されます。", + "Current Password:": "現在のパスワード:", + "New Password:": "新しいパスワード:", + "Confirm New Password:": "新しいパスワードを確認:", + "Debug Warning": "このカテゴリの機能は上級ユーザー専用です。結果がわからない場合は何もクリックしないでください。", + "Execute": "実行する", + "Are you sure you want to delete this user?": "このユーザーを削除してもよろしいですか?", + "Deleting:": "削除中:", + "Also wipe user data.": "ユーザーデータも消去します。", + "Warning:": "警告:", + "This action is irreversible.": "この操作は元に戻せません。", + "Type the user's handle below to confirm:": "確認するには、以下のユーザーのハンドルを入力してください。", + "Import Characters": "キャラクターをインポートする", + "Enter the URL of the content to import": "インポートするコンテンツの URL を入力します", + "Supported sources:": "サポートされているソース:", + "char_import_1": "Chub キャラクター (直接リンクまたはID)", + "char_import_example": "例:", + "char_import_2": "Chub ロアブック (直接リンクまたは ID)", + "char_import_3": "JanitorAI キャラクター (直接リンクまたは UUID)", + "char_import_4": "Pygmalion.chat キャラクター (直接リンクまたは UUID)", + "char_import_5": "AICharacterCards.com キャラクター (直接リンクまたは ID)", + "char_import_6": "直接PNGリンク(参照", + "char_import_7": "許可されたホストの場合)", + "char_import_8": "RisuRealm キャラクター (直接リンク)", + "Supports importing multiple characters.": "複数のキャラクターのインポートをサポートします。", + "Write each URL or ID into a new line.": "各 URL または ID を新しい行に入力します。", + "Export for character": "キャラクターのエクスポート", + "Export prompts for this character, including their order.": "このキャラクターのプロンプトを順序も含めてエクスポートします。", + "Export all": "すべてをエクスポート", + "Export all your prompts to a file": "すべてのプロンプトをファイルにエクスポートする", + "Insert prompt": "プロンプトを挿入", + "Delete prompt": "プロンプトを削除", + "Import a prompt list": "プロンプトリストをインポート", + "Export this prompt list": "このプロンプトリストをエクスポート", + "Reset current character": "現在のキャラクターをリセット", + "New prompt": "新しいプロンプト", + "Prompts": "プロンプト", + "Total Tokens:": "総トークン数:", + "prompt_manager_tokens": "トークン", + "Are you sure you want to reset your settings to factory defaults?": "設定を工場出荷時のデフォルトにリセットしてもよろしいですか?", + "Don't forget to save a snapshot of your settings before proceeding.": "続行する前に、設定のスナップショットを保存することを忘れないでください。", + "Settings Snapshots": "設定スナップショット", + "Record a snapshot of your current settings.": "現在の設定のスナップショットを記録します。", + "Make a Snapshot": "スナップショットを作成する", + "Restore this snapshot": "このスナップショットを復元する", + "Hi,": "こんにちは、", + "To enable multi-account features, restart the SillyTavern server with": "マルチアカウント機能を有効にするには、SillyTavernサーバーを再起動します。", + "set to true in the config.yaml file.": "config.yaml ファイルで true に設定します。", + "Account Info": "アカウント情報", + "To change your user avatar, use the buttons below or select a default persona in the Persona Management menu.": "ユーザー アバターを変更するには、下のボタンを使用するか、ペルソナ管理メニューでデフォルトのペルソナを選択します。", + "Set your custom avatar.": "カスタムアバターを設定します。", + "Remove your custom avatar.": "カスタムアバターを削除します。", + "Handle:": "ハンドル:", + "This account is password protected.": "このアカウントはパスワードで保護されています。", + "This account is not password protected.": "このアカウントはパスワードで保護されていません。", + "Account Actions": "アカウントアクション", + "Change Password": "パスワードを変更する", + "Manage your settings snapshots.": "設定のスナップショットを管理します。", + "Download a complete backup of your user data.": "ユーザーデータの完全なバックアップをダウンロードします。", + "Download Backup": "バックアップをダウンロード", + "Danger Zone": "危険区域", + "Reset your settings to factory defaults.": "設定を工場出荷時の状態にリセットします。", + "Reset Settings": "設定をリセット", + "Wipe all user data and reset your account to factory settings.": "すべてのユーザーデータを消去し、アカウントを工場出荷時の設定にリセットします。", + "Reset Everything": "すべてをリセット", + "Reset Code:": "リセットコード:", + "Want to update?": "更新しますか?", + "How to start chatting?": "チャットを開始する方法は?", + "Click _space": "クリック", + "and select a": "そして選択します ", + "Chat API": "チャットAPI", + "and pick a character.": "キャラクターを選択します。", + "You can browse a list of bundled characters in the": "バンドルされているキャラクターのリストは、", + "Download Extensions & Assets": "拡張機能とアセットをダウンロード", + "menu within": "メニュー内", + "Confused or lost?": "混乱していますか?迷っていますか?", + "click these icons!": "これらのアイコンをクリックしてください!", + "in the chat bar": "チャットバーで", + "SillyTavern Documentation Site": "SillyTavernドキュメントサイト", + "Extras Installation Guide": "エクストラインストールガイド", + "Still have questions?": "まだ質問がありますか?", + "Join the SillyTavern Discord": "SillyTavernのDiscordに参加", + "Post a GitHub issue": "GitHubの問題を投稿", + "Contact the developers": "開発者に連絡", + "Stop Inspecting": "検査を停止", + "Inspect Prompts": "プロンプトを検査", + "Toggle prompt inspection": "プロンプト検査の切り替え" +} diff --git a/jiuguan2025cc/public/locales/ko-kr.json b/jiuguan2025cc/public/locales/ko-kr.json new file mode 100644 index 0000000000000000000000000000000000000000..eb1bbcf13ac919355c3d76e9c01590303e600823 --- /dev/null +++ b/jiuguan2025cc/public/locales/ko-kr.json @@ -0,0 +1,1625 @@ +{ + "Favorite": "가장 좋아하는", + "Tag": "태그", + "Duplicate": "복제하기", + "Persona": "페르소나", + "Delete": "삭제", + "AI Response Configuration": "AI 응답 구성", + "AI Configuration panel will stay open": "AI 구성 패널이 열린 상태로 유지됩니다", + "clickslidertips": "수동으로 값을 입력하려면 클릭하세요.", + "MAD LAB MODE ON": "미치광이 연구실 모드 켜짐", + "Documentation on sampling parameters": "샘플링 매개 변수에 대한 문서", + "kobldpresets": "코볼드 사전 설정", + "guikoboldaisettings": "KoboldAI 인터페이스 설정", + "Update current preset": "현재 프리셋 업데이트", + "Save preset as": "프리셋으로 저장", + "Import preset": "프리셋 가져오기", + "Export preset": "프리셋 내보내기", + "Restore current preset": "현재 프리셋 복원", + "Delete the preset": "프리셋 삭제", + "novelaipresets": "NovelAI 사전 설정", + "Default": "기본값", + "openaipresets": "OpenAI 사전 설정", + "Text Completion presets": "텍스트 완성 프리셋", + "AI Module": "AI 모듈", + "Changes the style of the generated text.": "생성된 텍스트의 스타일을 변경합니다.", + "No Module": "모듈 없음", + "Instruct": "지시", + "Prose Augmenter": "산문 증강기", + "Text Adventure": "텍스트 어드벤처", + "response legth(tokens)": "응답 길이 (토큰)", + "Streaming": "스트리밍", + "Streaming_desc": "생성되는대로 응답을 조금씩 표시하세요", + "context size(tokens)": "컨텍스트 크기 (토큰)", + "unlocked": "잠금 해제됨", + "Only enable this if your model supports context sizes greater than 8192 tokens": "모델이 8192 토큰보다 큰 컨텍스트 크기를 지원하는 경우에만 활성화하세요", + "Max prompt cost:": "최대 프롬프트 비용:", + "Display the response bit by bit as it is generated.": "생성되는 대답을 조금씩 표시합니다.", + "When this is off, responses will be displayed all at once when they are complete.": "이 기능이 꺼져 있으면 대답은 완료되면 한 번에 모두 표시됩니다.", + "Temperature": "온도", + "rep.pen": "반복 페널티", + "Rep. Pen. Range.": "반복 페널티 범위", + "Rep. Pen. Slope": "대표적 페널티 기울기", + "Rep. Pen. Freq.": "반복 페널티 빈도", + "Rep. Pen. Presence": "반복 페널티 존재", + "TFS": "TFS", + "Phrase Repetition Penalty": "구절 반복 페널티", + "Off": "끄기", + "Very light": "매우 가벼운", + "Light": "가벼운", + "Medium": "중간", + "Aggressive": "공격적", + "Very aggressive": "매우 공격적", + "Unlocked Context Size": "잠금 해제된 컨텍스트 크기", + "Unrestricted maximum value for the context slider": "컨텍스트 슬라이더에 대한 제한 없는 최대값", + "Context Size (tokens)": "컨텍스트 크기 (토큰)", + "Max Response Length (tokens)": "최대 응답 길이 (토큰)", + "Multiple swipes per generation": "세대당 다중 스와이프", + "Enable OpenAI completion streaming": "OpenAI 완성 스트리밍 활성화", + "Frequency Penalty": "빈도 페널티", + "Presence Penalty": "존재 페널티", + "Count Penalty": "카운트 페널티", + "Top K": "상위 K", + "Top P": "상위 P", + "Repetition Penalty": "반복 페널티", + "Min P": "최소 P", + "Top A": "상위 A", + "Quick Prompts Edit": "빠른 프롬프트 편집", + "Main": "주요", + "NSFW": "NSFW", + "Jailbreak": "탈옥", + "Utility Prompts": "유틸리티 프롬프트", + "Impersonation prompt": "사칭 프롬프트", + "Restore default prompt": "기본 프롬프트 복원", + "Prompt that is used for Impersonation function": "사칭 기능에 사용되는 프롬프트", + "World Info Format Template": "월드 인포 형식 템플릿", + "Restore default format": "기본 형식 복원", + "Wraps activated World Info entries before inserting into the prompt.": "프롬프트에 삽입하기 전에 활성화된 월드 인포 항목을 래핑합니다.", + "scenario_format_template_part_1": "사용", + "scenario_format_template_part_2": "내용이 삽입된 위치를 표시합니다.", + "Scenario Format Template": "시나리오 형식 템플릿", + "Personality Format Template": "성격 형식 템플릿", + "Group Nudge Prompt Template": "그룹 너지 프롬프트 템플릿", + "Sent at the end of the group chat history to force reply from a specific character.": "특정 캐릭터의 답장을 강제하기 위해 그룹 채팅 기록 마지막에 전송됩니다.", + "New Chat": "새 채팅", + "Restore new chat prompt": "새 채팅 메시지 복원", + "Set at the beginning of the chat history to indicate that a new chat is about to start.": "새 채팅이 곧 시작될 것임을 나타내기 위해 채팅 기록 시작 부분에 설정합니다.", + "New Group Chat": "새 그룹 채팅", + "Restore new group chat prompt": "기본 프롬프트 복원", + "Set at the beginning of the chat history to indicate that a new group chat is about to start.": "새 그룹 채팅이 곧 시작될 것임을 나타내기 위해 채팅 기록 시작 부분에 설정합니다.", + "New Example Chat": "새로운 예시 채팅", + "Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.": "새로운 예시 채팅이 곧 시작될 것임을 나타내기 위해 대화 예시의 시작 부분에 설정합니다.", + "Continue nudge": "계속 넛지", + "Set at the end of the chat history when the continue button is pressed.": "계속 버튼을 누르면 채팅 기록이 끝날 때 설정됩니다.", + "Replace empty message": "빈 메시지 대체", + "Send this text instead of nothing when the text box is empty.": "텍스트 상자가 비어 있을 때 이 텍스트를 아무것도 없이 보내세요.", + "Seed": "시드", + "Set to get deterministic results. Use -1 for random seed.": "결정적인 결과를 얻으려면 설정하세요. 무작위 시드를 위해서는 -1 값을 사용합니다.", + "Temperature controls the randomness in token selection": "온도는 토큰 선택에서의 무작위성을 제어합니다.", + "Top_K_desc": "Top K는 선택할 수 있는 최대 상위 토큰 양을 설정합니다.", + "Top_P_desc": "Top P (일명 핵심 샘플링)", + "Typical P": "전형적인 P", + "Typical_P_desc": "전형적인 P 샘플링은 집합의 평균 엔트로피와의 편차를 기반으로 토큰에 우선순위를 부여합니다.", + "Min_P_desc": "Min P는 기본 최소 확률을 설정합니다.", + "Top_A_desc": "Top A는 가장 높은 토큰 확률의 제곱에 기반하여 토큰 선택에 대한 임계값을 설정합니다.", + "Tail_Free_Sampling_desc": "꼬리 제거 샘플링 (TFS)", + "rep.pen range": "반복 페널티 범위", + "Mirostat": "Mirostat", + "Mode": "모드", + "Mirostat_Mode_desc": "값이 0이면 Mirostat가 완전히 비활성화됩니다. 1은 Mirostat 1.0용이고 2는 Mirostat 2.0용입니다.", + "Tau": "Tau", + "Mirostat_Tau_desc": "Mirostat 출력의 가변성을 제어합니다.", + "Eta": "Eta", + "Mirostat_Eta_desc": "Mirostat의 학습률을 제어합니다.", + "Ban EOS Token": "EOS 토큰 금지", + "Ban_EOS_Token_desc": "KoboldCpp가 포함된 EOS(End-of-Sequence) 토큰(및 KoboldAI가 포함된 다른 토큰도 가능)을 금지합니다.\r스토리 작성에 적합하지만 채팅 및 교육 모드에는 사용하면 안 됩니다.", + "GBNF Grammar": "GBNF 문법", + "Type in the desired custom grammar": "원하는 사용자 정의 문법을 입력하세요.", + "Samplers Order": "샘플러 순서", + "Samplers will be applied in a top-down order. Use with caution.": "샘플러는 위에서 아래로 적용됩니다. 주의하여 사용하세요.", + "Tail Free Sampling": "Tail Free 샘플링", + "Load koboldcpp order": "kobold CPP 순서로 로드", + "Preamble": "서두", + "Use style tags to modify the writing style of the output.": "스타일 태그를 사용하여 출력의 쓰기 스타일을 수정하세요.", + "Banned Tokens": "금지된 토큰", + "Sequences you don't want to appear in the output. One per line.": "출력에 나타나지 않길 원하는 시퀀스입니다. 한 줄에 하나씩.", + "Logit Bias": "Logit 편향", + "Add": "추가", + "Helps to ban or reenforce the usage of certain words": "특정 단어의 사용을 금지하거나 강화하는데 도움이 됩니다.", + "CFG Scale": "CFG 스케일", + "Negative Prompt": "부정적 프롬프트", + "Add text here that would make the AI generate things you don't want in your outputs.": "AI가 출력에서 원하지 않는 것을 생성하도록하는 텍스트를 여기에 추가하세요.", + "Used if CFG Scale is unset globally, per chat or character": "CFG 스케일이 전역적으로 설정되지 않은 경우, 각 채팅 또는 각 캐릭터마다 사용됩니다.", + "Mirostat Tau": "Mirostat Tau", + "Mirostat LR": "Mirostat LR", + "Min Length": "최소 길이", + "Top K Sampling": "상위 K 샘플링", + "Nucleus Sampling": "Nucleus 샘플링", + "Top A Sampling": "상위 A 샘플링", + "CFG": "CFG", + "Neutralize Samplers": "샘플러 중화", + "Set all samplers to their neutral/disabled state.": "모든 샘플러를 중립/비활성 상태로 설정하세요.", + "Sampler Select": "샘플러 선택", + "Customize displayed samplers or add custom samplers.": "표시된 샘플러를 사용자 정의하거나 사용자 정의 샘플러를 추가하세요.", + "Epsilon Cutoff": "Epsilon 자르기", + "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "Epsilon 절단은 토큰이 샘플링에서 제외되는 확률 하한선을 설정합니다.", + "Eta Cutoff": "Eta 자르기", + "Eta_Cutoff_desc": "Eta 절단은 특별한 Eta 샘플링 기술의 주요 매개 변수입니다. 1e-4 단위로; 합리적인 값은 3입니다. 비활성화하려면 0으로 설정하세요. 자세한 내용은 Hewitt et al. (2022)의 Truncation Sampling as Language Model Desmoothing 논문을 참조하세요.", + "rep.pen decay": "반복 페널티 붕괴", + "Encoder Rep. Pen.": "인코더 반복 페널티", + "No Repeat Ngram Size": "반복 없는 Ngram 크기", + "Skew": "비스듬한", + "Max Tokens Second": "초당 최대 토큰", + "Smooth Sampling": "부드러운 샘플링", + "Smooth_Sampling_desc": "2차/3차 변환을 사용하여 분포를 조정할 수 있습니다. 평활화 요소 값이 낮을수록 더 창의적이 됩니다. 일반적으로 0.2-0.3 사이가 가장 적합합니다(곡선 = 1로 가정). 평활화 곡선 값이 높을수록 곡선이 더 가파르게 변하고 확률이 낮은 선택을 더욱 적극적으로 처벌하게 됩니다. 1.0 곡선은 Smoothing Factor만 사용하는 것과 같습니다.", + "Smoothing Factor": "평활화 요소", + "Smoothing Curve": "평활화 곡선", + "DRY_Repetition_Penalty_desc": "DRY는 입력의 끝을 이전에 입력에서 발생한 시퀀스로 확장하는 토큰에 페널티를 적용합니다. 비활성화하려면 승수를 0으로 설정하세요.", + "DRY Repetition Penalty": "DRY 반복 페널티", + "DRY_Multiplier_desc": "DRY를 활성화하려면 값 > 0으로 설정하세요. 가장 짧은 페널티를 받는 시퀀스에 대한 페널티의 크기를 제어합니다.", + "Multiplier": "승수", + "DRY_Base_desc": "시퀀스 길이가 증가함에 따라 페널티가 증가하는 속도를 제어합니다.", + "Base": "베이스", + "DRY_Allowed_Length_desc": "불이익을 받지 않고 반복할 수 있는 가장 긴 시퀀스입니다.", + "Allowed Length": "허용되는 길이", + "Penalty Range": "페널티 범위", + "DRY_Sequence_Breakers_desc": "시퀀스 일치가 계속되지 않는 토큰입니다. 따옴표로 묶인 문자열의 쉼표로 구분된 목록으로 지정됩니다.", + "Sequence Breakers": "시퀀스 차단기", + "JSON-serialized array of strings.": "JSON으로 직렬화된 문자열 배열입니다.", + "Dynamic Temperature": "동적 온도", + "Scale Temperature dynamically per token, based on the variation of probabilities": "확률의 변동을 기반으로 토큰마다 온도를 동적으로 조정합니다.", + "Minimum Temp": "최소 온도", + "Maximum Temp": "최대 온도", + "Exponent": "지수", + "Mirostat (mode=1 is only for llama.cpp)": "Mirostat (mode=1은 llama.cpp 전용입니다)", + "Mirostat_desc": "Mirostat은 언어 모델의 출력 텍스트의 복잡도(perplexity)를 직접 제어하여 더 자연스러운 텍스트를 생성하도록 하는 적응형 샘플링 알고리즘입니다", + "Mirostat Mode": "Mirostat 모드", + "Variability parameter for Mirostat outputs": "Mirostat 출력의 변동성 매개변수", + "Mirostat Eta": "Mirostat Eta", + "Learning rate of Mirostat": "Mirostat 학습률", + "Beam search": "빔 검색", + "Helpful tip coming soon.": "유용한 팁을 곧 알려드리겠습니다.", + "Number of Beams": "빔의 수", + "Length Penalty": "길이 페널티", + "Early Stopping": "조기 중지", + "Contrastive search": "대조적 검색", + "Penalty Alpha": "페널티 알파", + "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "대조적 검색 정규화 항의 강도입니다. CS를 비활성화하려면 0으로 설정하세요.", + "Do Sample": "샘플", + "Add BOS Token": "BOS 토큰 추가", + "Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative": "프롬프트의 시작 부분에 bos_token을 추가하세요. 이를 비활성화하면 응답이 더 창의적으로 될 수 있습니다.", + "Ban the eos_token. This forces the model to never end the generation prematurely": "eos_token을 금지하세요. 이는 모델이 생성을 이르게 종료하지 않도록 합니다", + "Ignore EOS Token": "EOS 토큰 무시", + "Ignore the EOS Token even if it generates.": "EOS 토큰이 생성되더라도 무시하세요.", + "Skip Special Tokens": "특수 토큰 건너뛰기", + "Temperature Last": "마지막 온도", + "Temperature_Last_desc": "마지막으로 온도 샘플러를 사용합니다.", + "Speculative Ngram": "투기적 Ngram", + "Use a different speculative decoding method without a draft model": "초안 모델 없이 다른 추측적 디코딩 방법을 사용합니다.\r초안 모델을 사용하는 것이 좋습니다. 투기적 ngram은 그다지 효과적이지 않습니다.", + "Spaces Between Special Tokens": "특수 토큰 사이의 공백", + "LLaMA / Mistral / Yi models only": "LLaMA / Mistral / Yi 모델 전용", + "Example: some text [42, 69, 1337]": "예: 일부 텍스트 [42, 69, 1337]", + "Classifier Free Guidance. More helpful tip coming soon": "분류기 무료 안내. 더 유용한 팁이 곧 제공됩니다.", + "Scale": "스케일", + "JSON Schema": "JSON 스키마", + "Type in the desired JSON schema": "원하는 JSON 스키마를 입력하세요.", + "Grammar String": "문법 문자열", + "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF 또는 EBNF는 사용 중인 백엔드에 따라 다릅니다. 이것을 사용한다면 어느 것이 무엇인지 알아야합니다.", + "Top P & Min P": "상위 P 및 최소 P", + "Load default order": "기본 순서로 로드", + "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "llama.cpp만 가능합니다. 샘플러의 순서를 결정합니다. Mirostat 모드가 0이 아닌 경우 샘플러 순서는 무시됩니다.", + "Sampler Priority": "샘플러 우선 순위", + "Ooba only. Determines the order of samplers.": "Ooba 전용. 샘플러의 순서를 결정합니다.", + "Character Names Behavior": "캐릭터 이름 동작", + "character_names_none": "캐릭터 이름 접두사를 추가하지 않습니다. 그룹 채팅에서는 좋지 않을 수 있으므로, 이 설정을 선택할 때는 주의해야 합니다.", + "Helps the model to associate messages with characters.": "모델이 메시지를 캐릭터와 연관시키는 데 도움이 됩니다.", + "None": "없음", + "None (not injected)": "없음 (삽입되지 않음)", + "character_names_default": "그룹과 과거 페르소나에 대해 접두사를 추가합니다. 그 외의 경우에는 프롬프트에 이름을 직접 제공해야 합니다.", + "Don't add character names.": "캐릭터 이름을 추가하지 마세요.", + "Completion": "완료 객체", + "character_names_completion": "제한 사항이 적용됩니다. 라틴 알파벳, 숫자, 밑줄만 사용 가능합니다. 모든 소스, 특히 Claude, MistralAI, Google에서 작동하지 않습니다.", + "Add character names to completion objects.": "완성 객체에 캐릭터 이름을 추가합니다.", + "Message Content": "메시지 내용", + "Prepend character names to message contents.": "메시지 내용 앞에 캐릭터의 이름을 추가합니다.", + "Continue Postfix": "계속하기 접미사", + "The next chunk of the continued message will be appended using this as a separator.": "계속되는 메시지의 다음 청크는 이를 구분 기호로 사용하여 추가됩니다.", + "Space": "한 칸 띄우기", + "Newline": "새로운 줄", + "Double Newline": "이중 줄", + "Wrap user messages in quotes before sending": "전송 전에 사용자 메시지를 따옴표로 둘러싸기", + "Wrap in Quotes": "따옴표로 메시지 감싸기", + "Wrap entire user message in quotes before sending.": "사용자 메시지 전체를 보내기 전에 따옴표로 감싸집니다.", + "Leave off if you use quotes manually for speech.": "말하기 위해 수동으로 따옴표를 사용하는 경우 체크하지 마세요.", + "Continue prefill": "사전 작성 계속", + "Continue sends the last message as assistant role instead of system message with instruction.": "계속하면 지시와 함께 시스템 메시지 대신 마지막 메시지를 어시스턴트 역할로 보냅니다.", + "Squash system messages": "시스템 메시지 압축", + "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "연속된 시스템 메시지를 하나로 결합합니다(예제 대화 제외). 일부 모델의 일관성을 향상시킬 수 있습니다.", + "Enable function calling": "함수 호출 활성화", + "Send inline images": "인라인 이미지 전송", + "image_inlining_hint_1": "모델이 지원하는 경우 메시지로 이미지를 보냅니다(예: GPT-4V, Claude 3 또는 Llava 13B).\n 사용", + "image_inlining_hint_2": "메시지에 대한 조치 또는", + "image_inlining_hint_3": "채팅에 이미지 파일을 첨부하는 메뉴입니다.", + "Inline Image Quality": "인라인 이미지 품질", + "openai_inline_image_quality_auto": "자동", + "openai_inline_image_quality_low": "낮은", + "openai_inline_image_quality_high": "높은", + "Use AI21 Tokenizer": "AI21 토크나이저 사용", + "Use the appropriate tokenizer for Jurassic models, which is more efficient than GPT's.": "GPT보다 효율적인 Jurassic 모델에 적합한 토크나이저를 사용하세요.", + "Use Google Tokenizer": "구글 토크나이저 사용", + "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "Google 모델용 적절한 토크나이저를 사용하여 API를 통해 제공됩니다. 더 느린 프롬프트 처리지만 훨씬 정확한 토큰 계산을 제공합니다.", + "Use system prompt": "시스템 프롬프트 사용", + "(Gemini 1.5 Pro/Flash only)": "(Gemini 1.5 Pro/Flash 전용)", + "Merges_all_system_messages_desc_1": "비시스템 역할이 있는 첫 번째 메시지까지 모든 시스템 메시지를 병합하여", + "Merges_all_system_messages_desc_2": "필드.", + "Assistant Prefill": "어시스턴트 프리필", + "Start Claude's answer with...": "클로드의 답변 시작하기...", + "Assistant Impersonation Prefill": "어시스턴트 사칭 프리필", + "Use system prompt (Claude 2.1+ only)": "시스템 프롬프트 사용 (클로드 2.1+ 전용)", + "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "지원되는 모델에 대한 시스템 프롬프트를 보냅니다. 비활성화된 경우 사용자 메시지가 프롬프트의 처음에 추가됩니다.", + "User first message": "사용자 첫 번째 메시지", + "Restore User first message": "사용자의 첫 번째 메시지 복원", + "Human message": "인간 메시지, 지시 등\n비어 있으면 아무것도 추가하지 않습니다. 즉, '사용자' 역할이 있는 새 프롬프트가 필요합니다.", + "New preset": "새 프리셋", + "Delete preset": "프리셋 삭제", + "View / Edit bias preset": "바이어스 프리셋 보기/편집", + "Add bias entry": "바이어스 항목 추가", + "Most tokens have a leading space.": "대부분의 토큰에는 선행 공백이 있습니다.", + "API Connections": "API 연결", + "Text Completion": "Text Completion", + "Chat Completion": "Chat Completion", + "NovelAI": "NovelAI", + "AI Horde": "AI Horde", + "KoboldAI": "KoboldAI", + "Avoid sending sensitive information to the Horde.": "민감한 정보를 Horde에 보내지 않도록 합니다.", + "Review the Privacy statement": "개인 정보 보호 정책 검토", + "Register a Horde account for faster queue times": "대기 시간 감축을 원한다면 Horde 계정을 등록하세요.", + "Learn how to contribute your idle GPU cycles to the Horde": "여유로운 GPU 주기를 Horde에 기여하는 방법 배우기", + "Adjust context size to worker capabilities": "컨텍스트 크기를 작업자 기능에 맞게 조정합니다.", + "Adjust response length to worker capabilities": "응답 길이를 작업자 기능에 맞게 조정합니다.", + "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "승인된 작업자만을 대기열에 넣어 나쁜 응답을 처리할 수 있습니다. 응답 시간이 느려질 수 있습니다.", + "Trusted workers only": "신뢰할 수 있는 작업자만 허용", + "API key": "API 키", + "Get it here:": "여기에서 얻으세요:", + "Register": "등록", + "View my Kudos": "내 Kudos 보기", + "Enter": "입력", + "to use anonymous mode.": "익명 모드를 사용하려면.", + "Clear your API key": "API 키 지우기", + "For privacy reasons, your API key will be hidden after you reload the page.": "개인 정보 보호를 위해 페이지를 다시로드한 후에는 API 키가 숨겨집니다.", + "Models": "모델", + "Refresh models": "모델 새로 고침", + "-- Horde models not loaded --": "-- Horde 모델 로드되지 않음 --", + "Not connected...": "연결되지 않음...", + "API url": "API URL", + "Example: http://127.0.0.1:5000/api ": "예시: http://127.0.0.1:5000/api", + "Connect": "연결", + "Cancel": "취소", + "Novel API key": "NovelAPI 키", + "Get your NovelAI API Key": "NovelAI API 키 가져오기", + "Enter it in the box below": "아래 칸에 복사한 API 키를 입력하세요.", + "Novel AI Model": "Novel AI 모델", + "No connection...": "연결 되지 않음...", + "API Type": "API 유형", + "Default (completions compatible)": "기본값 [OpenAI /완성 호환: oobabooga, LM Studio 등]", + "TogetherAI API Key": "TogetherAI API 키", + "TogetherAI Model": "TogetherAI 모델", + "-- Connect to the API --": "-- API에 연결 --", + "OpenRouter API Key": "OpenRouter API 키", + "Click Authorize below or get the key from": "아래의 인증을 클릭하거나 다음에서 키를 받으세요", + "View Remaining Credits": "남은 크레딧 보기", + "OpenRouter Model": "OpenRouter 모델", + "Model Providers": "모델 제공자", + "InfermaticAI API Key": "InfermaticAI API 키", + "InfermaticAI Model": "InfermaticAI 모델", + "DreamGen API key": "DreamGen API 키", + "DreamGen Model": "DreamGen 모델", + "Mancer API key": "Mancer API 키", + "Mancer Model": "Mancer 모델", + "Make sure you run it with": "실행하는지 확인하세요", + "flag": "깃발", + "API key (optional)": "API 키 (선택 사항)", + "Server url": "서버 URL", + "Example: 127.0.0.1:5000": "예시: 127.0.0.1:5000", + "Custom model (optional)": "사용자 정의 모델 (선택 사항)", + "vllm-project/vllm": "vllm-project/vllm(OpenAI API 래퍼 모드)", + "vLLM API key": "vLLM API 키", + "Example: 127.0.0.1:8000": "예: http://127.0.0.1:8000", + "vLLM Model": "vLLM 모델", + "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (OpenAI API의 래퍼 모드)", + "Aphrodite API key": "Aphrodite API 키", + "Aphrodite Model": "Aphrodite 모델", + "ggerganov/llama.cpp": "ggerganov/llama.cpp (출력 서버)", + "Example: 127.0.0.1:8080": "예: 127.0.0.1:8080", + "Example: 127.0.0.1:11434": "예: 127.0.0.1:11434", + "Ollama Model": "Ollama 모델", + "Download": "다운로드", + "Tabby API key": "Tabby API 키", + "koboldcpp API key (optional)": "koboldcpp API 키(선택사항)", + "Example: 127.0.0.1:5001": "예: 127.0.0.1:5001", + "Authorize": "승인하기", + "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "OAuth 플로우를 사용하여 OpenRouter API 토큰을 가져옵니다. openrouter.ai로 리디렉션됩니다.", + "Legacy API (pre-OAI, no streaming)": "레거시 API (OAI 이전, 스트리밍 없음)", + "Bypass status check": "상태 확인 우회", + "Chat Completion Source": "채팅 완성 근원", + "Reverse Proxy": "역방향 프록시", + "Proxy Presets": "프록시 사전 설정", + "Saved addresses and passwords.": "저장된 주소와 비밀번호.", + "Save Proxy": "프록시 저장", + "Delete Proxy": "프록시 삭제", + "Proxy Name": "프록시 이름", + "Allow reverse proxy": "역방향 프록시 허용", + "This will show up as your saved preset.": "이는 저장된 사전 설정으로 표시됩니다.", + "Proxy Server URL": "프록시 서버 URL", + "Alternative server URL (leave empty to use the default value).": "대체 서버 URL (기본값 사용을 원할 경우 비워 둡니다).", + "Remove your real OAI API Key from the API panel BEFORE typing anything into this box": "이 입력란에 어떤 것이든 입력하기 전에 반드시 실제 OAI API 키를 API 패널에서 제거하세요.", + "We cannot provide support for problems encountered while using an unofficial OpenAI proxy": "개발진은 비공식 OpenAI 프록시를 사용하는 동안 발생하는 문제에 대한 지원을 제공할 수 없습니다.", + "Doesn't work? Try adding": "작동하지 않나요? 추가해 보세요", + "at the end!": "마지막에!", + "Proxy Password": "프록시 비밀번호", + "Will be used as a password for the proxy instead of API key.": "API 키 대신 프록시의 비밀번호로 사용됩니다.", + "Peek a password": "비밀번호를 엿보세요", + "OpenAI API key": "OpenAI API 키", + "View API Usage Metrics": "API 사용 지표 보기", + "Follow": "OpenAI API 키를 얻으려면", + "these directions": "이 지시 사항", + "to get your OpenAI API key.": "을 따르세요.", + "Use Proxy password field instead. This input will be ignored.": "대신 \"프록시 비밀번호\" 필드를 사용하세요. 이 입력은 무시됩니다.", + "OpenAI Model": "OpenAI 모델", + "Bypass API status check": "API 상태 확인 우회", + "Show External models (provided by API)": "외부 모델 표시 (API 제공)", + "Get your key from": "다음에서 키를 받으세요", + "Anthropic's developer console": "Anthropic의 개발자 콘솔", + "Slack and Poe cookies will not work here, do not bother trying.": "Slack과 Poe 쿠키는 여기서 작동하지 않습니다. 시도하지 마세요.", + "Claude Model": "Claude 모델", + "Window AI Model": "Window AI 모델", + "Model Order": "OpenRouter 모델 정렬", + "Alphabetically": "알파벳순", + "Price": "가격(가장 저렴)", + "Context Size": "컨텍스트 크기", + "Group by vendors": "공급업체별 그룹화", + "Group by vendors Description": "OpenAI 모델을 한 그룹에 넣고, Anthropic 모델을 다른 그룹에 두는 등 정렬을 통해 결합할 수 있습니다.", + "Allow fallback routes": "fallback 허용", + "Allow fallback routes Description": "선택한 모델이 요청을 처리할 수 없는 경우 대체 모델이 자동으로 선택됩니다.", + "openrouter_force_instruct": "이 옵션은 오래되었으며 향후 제거될 예정입니다. 지시 형식을 사용하려면 대신 Text Completion API에서 OpenRouter로 전환하세요.", + "LEGACY": "유산", + "Force Instruct Mode formatting": "강제 지시 모드 형식", + "Force_Instruct_Mode_formatting_Description": "Instruct Mode와 이 모드가 모두 활성화된 경우 프롬프트는 SillyTavern에 의해 현재 형식을 사용하여 형식화됩니다.\n 고급 형식 설정(시스템 프롬프트 지시 제외) 비활성화된 경우 프롬프트는 OpenRouter에 의해 형식화됩니다.", + "Scale API Key": "Scale API 키", + "Clear your cookie": "쿠키 지우기", + "Alt Method": "대체 방법", + "AI21 API Key": "AI21 API 키", + "AI21 Model": "AI21 모델", + "Google AI Studio API Key": "Google AI Studio API 키", + "Google Model": "구글 모델", + "MistralAI API Key": "MistralAI API 키", + "MistralAI Model": "MistralAI 모델", + "Groq API Key": "Groq API 키", + "Groq Model": "Groq 모델", + "Perplexity API Key": "Perplexity API 키", + "Perplexity Model": "Perplexity 모델", + "Cohere API Key": "Cohere API 키", + "Cohere Model": "Cohere 모델", + "Custom Endpoint (Base URL)": "사용자 정의 엔드포인트(기본 URL)", + "Custom API Key": "커스텀 API 키", + "Available Models": "사용 가능한 모델", + "Prompt Post-Processing": "신속한 후처리", + "api_no_connection": "연결이 되지 않았습니다...", + "Applies additional processing to the prompt before sending it to the API.": "API로 보내기 전에 프롬프트에 추가 처리를 적용합니다.", + "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "짧은 테스트 메시지를 보내어 API 연결을 확인합니다. 이에 대해 유료 크레딧이 지불될 수 있음을 인식하세요!", + "Test Message": "테스트 메시지", + "Auto-connect to Last Server": "마지막 서버에 자동으로 연결", + "Missing key": "❌ 현재 저장된 키가 존재하지 않습니다.", + "Key saved": "✔️ 키 저장됨.", + "View hidden API keys": "숨겨진 API 키 보기", + "AI Response Formatting": "AI 응답 형식 지정", + "Advanced Formatting": "고급 서식", + "Context Template": "컨텍스트 템플릿", + "Auto-select this preset for Instruct Mode": "지시 모드에 대해 이 프리셋 자동 선택", + "Story String": "이야기 문자열", + "Example Separator": "예시 대화 구분자", + "Chat Start": "채팅 시작", + "Add Chat Start and Example Separator to a list of stopping strings.": "중지 문자열 목록에 채팅 시작 및 예제 구분 기호를 추가합니다.", + "Use as Stop Strings": "중지 문자열로 사용", + "context_allow_jailbreak": "캐릭터 카드에 정의되어 있고 ''Prefer Char. Jailbreak''가 활성화되어 있는 경우 프롬프트 끝에 Jailbreak를 포함합니다.\n이는 텍스트 완성 모델에 권장되지 않으며, 나쁜 출력으로 이어질 수 있습니다.", + "Allow Jailbreak": "탈옥 허용", + "Context Order": "컨텍스트 순서", + "Summary": "요약", + "Author's Note": "작가 노트", + "Example Dialogues": "예시 대화", + "Hint": "힌트:", + "In-Chat Position not affected": "요약 및 작가 노트 삽입 순서는 In-Chat 위치가 설정되지 않은 경우에만 영향을 받습니다.", + "Instruct Mode": "지시 모드", + "Enabled": "활성화됨", + "instruct_bind_to_context": "활성화되면 선택한 지시 템플릿 이름이나 기본 설정에 따라 컨텍스트 템플릿이 자동으로 선택됩니다.", + "Bind to Context": "컨텍스트에 바인딩", + "Presets": "프리셋", + "Auto-select this preset on API connection": "API 연결 시 이 프리셋 자동 선택", + "Activation Regex": "활성화 정규식", + "Wrap Sequences with Newline": "새 줄로 시퀀스 감싸기", + "Replace Macro in Sequences": "시퀀스에서 매크로 대체", + "Skip Example Dialogues Formatting": "예제 대화 형식 건너뛰기", + "Include Names": "이름 포함", + "Force for Groups and Personas": "그룹 및 페르소나에 대한 강제 적용", + "System Prompt": "시스템 프롬프트", + "Instruct Mode Sequences": "지시 모드 시퀀스", + "System Prompt Wrapping": "시스템 프롬프트 래핑", + "Inserted before a System prompt.": "시스템 프롬프트 앞에 삽입됩니다.", + "System Prompt Prefix": "시스템 프롬프트 접두사", + "Inserted after a System prompt.": "시스템 프롬프트 뒤에 삽입됩니다.", + "System Prompt Suffix": "시스템 프롬프트 접미사", + "Chat Messages Wrapping": "채팅 메시지 래핑", + "Inserted before a User message and as a last prompt line when impersonating.": "사용자 메시지 앞에 삽입되고 가장할 때 마지막 프롬프트 줄로 삽입됩니다.", + "User Message Prefix": "사용자 메시지 접두사", + "Inserted after a User message.": "사용자 메시지 뒤에 삽입됩니다.", + "User Message Suffix": "사용자 메시지 접미사", + "Inserted before an Assistant message and as a last prompt line when generating an AI reply.": "어시스턴트 메시지 앞에 삽입되고 AI 답장을 생성할 때 마지막 프롬프트 라인으로 삽입됩니다.", + "Assistant Message Prefix": "어시스턴트 메시지 접두사", + "Inserted after an Assistant message.": "어시스턴트 메시지 뒤에 삽입됩니다.", + "Assistant Message Suffix": "어시스턴트 메시지 접미사", + "Inserted before a System (added by slash commands or extensions) message.": "시스템(슬래시 명령 또는 확장으로 추가) 메시지 앞에 삽입됩니다.", + "System Message Prefix": "시스템 메시지 접두사", + "Inserted after a System message.": "시스템 메시지 뒤에 삽입됩니다.", + "System Message Suffix": "시스템 메시지 접미사", + "If enabled, System Sequences will be the same as User Sequences.": "이 기능을 활성화하면, 시스템 시퀀스가 ​​사용자 시퀀스와 동일해집니다.", + "System same as User": "사용자와 동일한 시스템", + "Misc. Sequences": "기타 시퀀스", + "Inserted before the first Assistant's message.": "어시스턴트의 첫 번째 메시지 앞에 삽입됩니다.", + "First Assistant Prefix": "첫 번째 어시스턴트 접두어", + "instruct_last_output_sequence": "마지막 어시스턴트 메시지 앞에 삽입되거나 AI 응답을 생성할 때 마지막 프롬프트 줄로 삽입됩니다(중립/시스템 역할 제외).", + "Last Assistant Prefix": "마지막 어시스턴트 접두사", + "Will be inserted as a last prompt line when using system/neutral generation.": "시스템/중립 생성을 사용할 때 마지막 프롬프트 라인으로 삽입됩니다.", + "System Instruction Prefix": "시스템 명령어 접두사", + "If a stop sequence is generated, everything past it will be removed from the output (inclusive).": "정지 시퀀스가 ​​생성되면 그 이후의 모든 항목이 출력에서 ​​제거됩니다(포함).", + "Stop Sequence": "중지 시퀀스", + "Will be inserted at the start of the chat history if it doesn't start with a User message.": "사용자 메시지로 시작하지 않는 경우 채팅 기록 시작 부분에 삽입됩니다.", + "User Filler Message": "사용자 필러 메시지", + "Context Formatting": "컨텍스트 서식", + "(Saved to Context Template)": "(컨텍스트 템플릿에 저장됨)", + "Always add character's name to prompt": "항상 캐릭터의 이름을 프롬프트에 추가", + "Generate only one line per request": "요청당 한 줄만 생성", + "Trim Incomplete Sentences": "불완전한 문장 자르기", + "Include Newline": "새 줄 포함", + "Misc. Settings": "기타 설정", + "Collapse Consecutive Newlines": "연속적인 새 줄 축소", + "Trim spaces": "공백 자르기", + "Tokenizer": "토크나이저", + "Token Padding": "토큰 패딩", + "Start Reply With": "응답 시작", + "AI reply prefix": "AI 답변 접두사", + "Show reply prefix in chat": "채팅에서 응답 접두사 표시", + "Non-markdown strings": "마크다운이 아닌 문자열", + "separate with commas w/o space between": "쉼표로 구분 (공백 없이)", + "Custom Stopping Strings": "사용자 정의 중지 문자열", + "JSON serialized array of strings": "문자열의 JSON 직렬화된 배열", + "Replace Macro in Stop Strings": "사용자 정의 중단 문자열에서 매크로 교체", + "Auto-Continue": "자동 계속하기", + "Allow for Chat Completion APIs": "채팅 완성 API 허용", + "Target length (tokens)": "대상 길이 (토큰)", + "World Info": "월드 인포", + "Locked = World Editor will stay open": "잠금 = 월드 편집기가 열린 상태로 유지됩니다", + "Worlds/Lorebooks": "월드 인포/로어북", + "Active World(s) for all chats": "모든 채팅에 대한 활성화된 월드 인포(들)", + "-- World Info not found --": "-- 월드 인포를 찾을 수 없음 --", + "Global World Info/Lorebook activation settings": "글로벌 월드 인포/로어북 활성화 설정", + "Click to expand": "펼치려면 클릭하세요.", + "Scan Depth": "스캔 깊이", + "Context %": "컨텍스트 %", + "Budget Cap": "예산 한도", + "(0 = disabled)": "(0 = 비활성화됨)", + "Scan chronologically until reached min entries or token budget.": "최소 항목 또는 토큰 예산에 도달할 때까지 시간순으로 검색합니다.", + "Min Activations": "최소 활성화", + "Max Depth": "최대 깊이", + "(0 = unlimited, use budget)": "(0 = 무제한, 예산 사용)", + "Insertion Strategy": "삽입 전략", + "Sorted Evenly": "균일하게 정렬됨", + "Character Lore First": "캐릭터 로어 우선", + "Global Lore First": "글로벌 로어 우선", + "Entries can activate other entries by mentioning their keywords": "항목은 키워드를 언급하여 다른 항목을 활성화할 수 있습니다", + "Recursive Scan": "재귀 스캔", + "Lookup for the entry keys in the context will respect the case": "컨텍스트에서 항목 키를 검색할 때 대소문자를 지켜줍니다", + "Case Sensitive": "대소문자 구분", + "If the entry key consists of only one word, it would not be matched as part of other words": "항목 키가 하나의 단어로만 구성된 경우 다른 단어의 일부로 일치하지 않습니다", + "Match Whole Words": "전체 단어 일치", + "Only the entries with the most number of key matches will be selected for Inclusion Group filtering": "포함 그룹 필터링을 위해 키 일치 수가 가장 많은 항목만 선택됩니다.", + "Use Group Scoring": "그룹 점수 사용", + "Alert if your world info is greater than the allocated budget.": "귀하의 월드 인포가 할당된 예산보다 큰 경우 경고합니다.", + "Alert On Overflow": "오버플로우 알림", + "New": "새 월드인포", + "or": "또는", + "--- Pick to Edit ---": "--- 편집할 항목 선택 ---", + "Rename World Info": "월드 인포 이름 바꾸기", + "Open all Entries": "모든 항목 열기", + "Close all Entries": "모든 항목 닫기", + "New Entry": "새 항목", + "Fill empty Memo/Titles with Keywords": "비어 있는 메모/제목을 키워드로 채우기", + "Import World Info": "월드 인포 가져오기", + "Export World Info": "월드 인포 내보내기", + "Duplicate World Info": "월드 인포 복제", + "Delete World Info": "월드 인포 삭제", + "Search...": "검색...", + "Search": "찾기", + "Priority": "우선 순위", + "Custom": "사용자 정의", + "Title A-Z": "제목 A-Z", + "Title Z-A": "제목 Z-A", + "Tokens ↗": "토큰 ↗", + "Tokens ↘": "토큰 ↘", + "Depth ↗": "깊이 ↗", + "Depth ↘": "깊이 ↘", + "Order ↗": "순서 ↗", + "Order ↘": "순서 ↘", + "UID ↗": "UID ↗", + "UID ↘": "UID ↘", + "Trigger% ↗": "발동 확률% ↗", + "Trigger% ↘": "발동 확률% ↘", + "Refresh": "새로 고침", + "User Settings": "사용자 설정", + "Simple": "간단한", + "Advanced": "고급", + "UI Language": "UI 언어", + "Account": "계정", + "Admin Panel": "관리자 패널", + "Logout": "로그 아웃", + "Search Settings": "검색 설정", + "UI Theme": "UI 테마", + "Import a theme file": "테마 파일 가져오기", + "Export a theme file": "테마 파일 내보내기", + "Delete a theme": "테마 삭제", + "Update a theme file": "테마 파일 업데이트", + "Save as a new theme": "새 테마로 저장", + "Avatar Style:": "캐릭터 프로필 스타일", + "Circle": "원", + "Square": "정사각형", + "Rectangle": "사각형", + "Chat Style:": "채팅 스타일:", + "Flat": "플랫\n버블\n문서", + "Bubbles": "말풍선", + "Document": "문서", + "Specify colors for your theme.": "테마의 색상을 지정하세요.", + "Theme Colors": "테마 색상", + "Main Text": "주요 텍스트", + "Italics Text": "이탤릭체 텍스트", + "Underlined Text": "밑줄 텍스트", + "Quote Text": "인용 텍스트", + "Shadow Color": "그림자 색상", + "Chat Background": "채팅 배경", + "UI Background": "UI 배경", + "UI Border": "UI 테두리", + "User Message Blur Tint": "사용자 메시지 흐림 틴트", + "AI Message Blur Tint": "AI 메시지 흐림 틴트", + "Chat Width": "채팅창 폭", + "Width of the main chat window in % of screen width": "화면 너비의 %로 표시되는 기본 채팅창 너비", + "Font Scale": "글꼴 크기", + "Font size": "글꼴 크기", + "Blur Strength": "흐림 강도", + "Blur strength on UI panels.": "UI 패널의 흐림 강도.", + "Text Shadow Width": "텍스트 그림자 너비", + "Strength of the text shadows": "텍스트 그림자의 강도", + "Disables animations and transitions": "애니메이션 및 전환 비활성화", + "Reduced Motion": "움직임 줄임", + "removes blur from window backgrounds": "창 배경의 흐림 제거", + "No Blur Effect": "흐림 효과 없음", + "Remove text shadow effect": "텍스트 그림자 효과 제거", + "No Text Shadows": "텍스트 그림자 없음", + "Reduce chat height, and put a static sprite behind the chat window": "채팅 높이를 줄이고, 채팅 창 뒤에 정적 스프라이트를 넣습니다", + "Waifu Mode": "와이프 모드", + "Always show the full list of the Message Actions context items for chat messages, instead of hiding them behind '...'": "채팅 메시지의 메시지 액션 컨텍스트 항목의 전체 목록을 항상 표시하세요. 대신 '...' 뒤에 숨기지 않습니다.", + "Auto-Expand Message Actions": "메시지 액션 자동 확장", + "Alternative UI for numeric sampling parameters with fewer steps": "단계가 적은 숫자 샘플링 매개변수에 대한 대체 UI", + "Zen Sliders": "젠 슬라이더", + "Entirely unrestrict all numeric sampling parameters": "모든 숫자 샘플링 매개변수를 완전히 제한하지 않음", + "Mad Lab Mode": "미치광이 연구실 모드", + "Time the AI's message generation, and show the duration in the chat log": "AI의 메시지 생성 시간을 측정하고, 채팅 로그에 지속 시간을 표시합니다", + "Message Timer": "메시지 도착 시간 측정", + "Show a timestamp for each message in the chat log": "채팅 로그의 각 메시지에 타임스탬프 표시", + "Chat Timestamps": "채팅 타임스탬프", + "Show an icon for the API that generated the message": "메시지를 생성한 API에 대한 아이콘 표시", + "Model Icon": "모델 아이콘 표시", + "Show sequential message numbers in the chat log": "채팅 로그에 순차적인 메시지 번호 표시", + "Message IDs": "메시지 ID", + "Hide avatars in chat messages.": "채팅 메시지에서 아바타 숨김.", + "Hide Chat Avatars": "캐릭터 프로필 숨기기", + "Show the number of tokens in each message in the chat log": "채팅 로그의 각 메시지에 토큰 수 표시", + "Show Message Token Count": "메시지 토큰 개수 표시", + "Single-row message input area. Mobile only, no effect on PC": "한 줄짜리 메시지 입력 영역. 모바일 전용, PC에는 영향 없음", + "Compact Input Area (Mobile)": "조그마한 입력 영역 (모바일)", + "Swipe # for All Messages": "모든 스와이프 메시지에 대해 번호 매기기", + "Display swipe numbers for all messages, not just the last.": "마지막 메시지만이 아니라 모든 메시지에 대한 스와이프 번호를 표시합니다.", + "In the Character Management panel, show quick selection buttons for favorited characters": "캐릭터 관리 패널에서 즐겨찾는 캐릭터에 대한 빠른 선택 버튼을 표시합니다", + "Characters Hotswap": "캐릭터 핫스왑", + "Enable magnification for zoomed avatar display.": "마우스 포인터를 아바타 위에 올려두면 아바타가 확대 됩니다.", + "Avatar Hover Magnification": "마우스를 올리면 아바타 확대", + "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "채팅에서 아바타 이미지를 클릭한 후 확대된 아바타를 표시할 때 마우스 오버 시 확대 효과를 활성화합니다.", + "Show tagged character folders in the character list": "캐릭터 목록에서 태그가 지정된 캐릭터 폴더 표시", + "Tags as Folders": "태그를 폴더로 설정", + "Tags_as_Folders_desc": "최근 변경 사항: 태그는 태그 관리 메뉴에서 폴더로 표시되어야 폴더로 표시됩니다. 여기를 클릭해 불러오세요.", + "Background Image": "채팅 배경 이미지", + "Character Handling": "캐릭터 처리", + "If set in the advanced character definitions, this field will be displayed in the characters list.": "고급 캐릭터 정의에서 설정된 경우 이 필드가 캐릭터 목록에 표시됩니다.", + "Char List Subheader": "캐릭터 목록 하위 제목", + "Character Version": "캐릭터 버전", + "Created by": "제작자", + "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "퍼지 매칭을 사용하고 이름 하위 문자열뿐만 아니라 모든 데이터 필드로 목록에서 캐릭터를 검색합니다", + "Advanced Character Search": "고급 캐릭터 검색", + "If checked and the character card contains a prompt override (System Prompt), use that instead": "선택되어 있고 캐릭터 카드에 프롬프트(시스템 프롬프트) 재정의가 포함 된 경우, 그것을 대신 사용합니다", + "Prefer Character Card Prompt": "캐릭터 카드 프롬프트 선호", + "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "선택되어 있고 캐릭터 카드에 (Post-History 지시)탈옥 재정의가 포함 된 경우, 그것을 대신 사용합니다.", + "Prefer Character Card Jailbreak": "캐릭터 카드 탈옥 선호", + "never_resize_avatars_tooltip": "가져온 캐릭터 이미지를 자르거나 크기를 조정하지 마세요. 꺼져 있으면 512x768로 자르거나 크기를 조정합니다.", + "Never resize avatars": "아바타 크기 변경하지 않음", + "Show actual file names on the disk, in the characters list display only": "실제 파일 이름을 디스크에 표시하며 캐릭터 목록 디스플레이에만", + "Show avatar filenames": "아바타 파일 이름 표시", + "Prompt to import embedded card tags on character import. Otherwise embedded tags are ignored": "캐릭터 가져오기시 내장된 카드 태그를 가져 오도록 요청하세요. 그렇지 않으면 내장된 태그가 무시됩니다", + "Import Card Tags": "카드 태그 가져오기", + "Hide character definitions from the editor panel behind a spoiler button": "스포일러 버튼 뒤에 편집기 패널에서 캐릭터 정의를 숨깁니다", + "Spoiler Free Mode": "스포일러 무료 모드", + "Miscellaneous": "기타", + "Reload and redraw the currently open chat": "현재 열려 있는 채팅을 다시로드하고 다시 그립니다", + "Reload Chat": "채팅 다시 로드", + "Debug Menu": "디버그 메뉴", + "Smooth Streaming": "부드러운 스트리밍", + "Experimental feature. May not work for all backends.": "실험적인 기능으로, 모든 백엔드에서 작동이 보장되지는 않을 수 있습니다.", + "Slow": "느린", + "Fast": "빠른", + "Play a sound when a message generation finishes": "메시지 생성이 완료될 때 소리 재생", + "Message Sound": "메시지 소리", + "Only play a sound when ST's browser tab is unfocused": "ST의 브라우저 탭이 초점을 잃으면 소리를 재생합니다.", + "Background Sound Only": "배경 소리만", + "Reduce the formatting requirements on API URLs": "API URL의 서식 요구 사항 감소", + "Relaxed API URLS": "완화된 API URLS", + "Ask to import the World Info/Lorebook for every new character with embedded lorebook. If unchecked, a brief message will be shown instead": "내장된 로어북이있는 모든 새 캐릭터에 대해 월드 인포/로어북을 가져 오도록 요청하세요. 선택 해제하면 대신 간단한 메시지가 표시됩니다", + "Lorebook Import Dialog": "로어북 가져오기 대화 상자", + "Restore unsaved user input on page refresh": "페이지 새로 고침시 저장되지 않은 사용자 입력 복원", + "Restore User Input": "사용자 입력 복원", + "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "드래그하여 특정 UI 요소의 위치를 조정할 수 있습니다. PC 전용, 모바일에는 영향을주지 않습니다", + "Movable UI Panels": "이동 가능한 UI 패널", + "MovingUI preset. Predefined/saved draggable positions": "MovingUI 사전 설정. 미리 정의된/저장된 드래그 가능한 위치", + "MUI Preset": "MUI 프리셋", + "Save movingUI changes to a new file": "새 파일로 movingUI 변경 사항 저장", + "Reset MovingUI panel sizes/locations.": "MovingUI 패널 크기/위치를 재설정합니다.", + "Apply a custom CSS style to all of the ST GUI": "ST GUI의 모든 곳에 사용자 정의 CSS 스타일 적용", + "Custom CSS": "사용자 정의 CSS", + "Expand the editor": "편집기 확장", + "Chat/Message Handling": "채팅/메시지 처리", + "# Messages to Load": "로딩할 메시지 수", + "The number of chat history messages to load before pagination.": "페이지를 매기기 전에 로드할 채팅 기록 메시지 수입니다.", + "(0 = All)": "(0 = 모두)", + "Streaming FPS": "스트리밍 FPS", + "Update speed of streamed text.": "스트리밍된 텍스트의 속도를 업데이트합니다.", + "Example Messages Behavior": "예제 메시지 동작", + "Gradual push-out": "토큰 초과 시 점진적 밀어내기", + "Always include examples": "항상 컨텍스트에 예제 포함", + "Never include examples": "절대로 예제 포함 안 함", + "Send on Enter": "Enter로 전송", + "Disabled": "비활성화됨", + "Automatic (PC)": "자동 (PC)", + "Press Send to continue": "계속하려면 보내기를 누르세요", + "Show a button in the input area to ask the AI to continue (extend) its last message": "입력 영역에 AI에게 마지막 메시지를 계속 (확장)하도록 요청하는 버튼을 표시합니다", + "Quick 'Continue' button": "빠른 '계속' 버튼", + "Show arrow buttons on the last in-chat message to generate alternative AI responses. Both PC and mobile": "대체 AI 응답을 생성하는 마지막 채팅 메시지에 화살표 버튼을 표시합니다. PC 및 모바일 모두", + "Swipes": "스와이프", + "Allow using swiping gestures on the last in-chat message to trigger swipe generation. Mobile only, no effect on PC": "마지막 채팅 메시지에서 스와이프 생성을 트리거하기 위해 스와이핑 제스처 사용을 허용합니다. 모바일 전용, PC에는 영향이 없습니다", + "Gestures": "제스처", + "Auto-load Last Chat": "마지막 채팅 자동로드", + "Auto-scroll Chat": "채팅 자동 스크롤", + "Save edits to messages without confirmation as you type": "입력하는 동안 확인없이 메시지에 대한 편집 사항 저장", + "Auto-save Message Edits": "메시지 편집 자동 저장", + "Confirm message deletion": "메시지 삭제 확인", + "Auto-fix Markdown": "마크다운 자동 수정", + "Render LaTeX and AsciiMath equation notation in chat messages. Powered by KaTeX": "채팅 메시지에서 LaTeX 및 AsciiMath 방정식 표기법을 렌더링합니다. KaTeX 제공", + "Render Formulas": "수식 렌더링", + "Disallow embedded media from other domains in chat messages": "채팅 메시지에 다른 도메인의 삽입된 미디어를 허용하지 않습니다.", + "Forbid External Media": "외부 미디어 금지", + "Allow {{char}}: in bot messages": "봇 메시지에서 {{char}}: 허용", + "Allow {{user}}: in bot messages": "봇 메시지에서 {{user}}: 허용", + "Skip encoding and characters in message text, allowing a subset of HTML markup as well as Markdown": "메시지 텍스트에서 인코딩 및 문자를 건너 뛰어 일부 HTML 마크업 및 Markdown을 허용합니다", + "Show tags in responses": "응답에서 태그 표시", + "Allow AI messages in groups to contain lines spoken by other group members": "그룹의 AI 메시지가 다른 그룹 멤버가 말한 줄을 포함 할 수 있도록 허용", + "Relax message trim in Groups": "그룹에서 메시지 트리밍 완화", + "Log prompts to console": "콘솔에 프롬프트 기록", + "Requests logprobs from the API for the Token Probabilities feature": "토큰 확률 기능에 대한 API에서 로그 확률 요청", + "Request token probabilities": "토큰 확률 요청", + "Automatically reject and re-generate AI message based on configurable criteria": "구성 가능한 기준에 따라 AI 메시지를 자동으로 거부하고 다시 생성", + "Auto-swipe": "자동 스와이프", + "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "자동 스와이프 기능을 활성화합니다. 이 섹션의 설정은 자동 스와이프가 활성화되었을 때만 영향을 미칩니다", + "Minimum generated message length": "생성된 메시지 최소 길이", + "If the generated message is shorter than these many characters, trigger an auto-swipe": "생성된 메시지가이보다 짧으면 자동 스와이프를 트리거합니다", + "Blacklisted words": "금지어", + "words you dont want generated separated by comma ','": "쉼표로 구분된 생성하지 않으려는 단어", + "Blacklisted word count to swipe": "스와이프할 금지어 개수", + "Minimum number of blacklisted words detected to trigger an auto-swipe": "자동 스와이프를 트리거하는 검출된 금지어의 최소 개수", + "AutoComplete Settings": "자동 완성 설정", + "Automatically hide details": "세부정보 자동 숨기기", + "Determines how entries are found for autocomplete.": "자동 완성을 위해 항목을 찾는 방법을 결정합니다.", + "Autocomplete Matching": "자동 완성 매칭", + "Starts with": "시작하는 단어로", + "Includes": "포함하는", + "Fuzzy": "퍼지 매칭", + "Sets the style of the autocomplete.": "자동완성 스타일을 설정합니다.", + "Autocomplete Style": "자동 완성 스타일", + "Follow Theme": "테마 적용", + "Dark": "다크 모드", + "Sets the font size of the autocomplete.": "자동 완성 글꼴 크기 설정", + "Sets the width of the autocomplete.": "자동 완성의 너비를 설정합니다.", + "Autocomplete Width": "자동 완성 너비 조절", + "chat input box": "채팅 입력 상자", + "entire chat width": "전체 채팅 폭", + "full window width": "전체 창 너비", + "STscript Settings": "STscript 설정", + "Sets default flags for the STscript parser.": "STscript Parser 기본 플래그 설정", + "Parser Flags": "Parser 플래그 설정", + "Switch to stricter escaping, allowing all delimiting characters to be escaped with a backslash, and backslashes to be escaped as well.": "모든 구분자를 백슬래시로 이스케이핑하고, 백슬래시 자체도 이스케이프할 수 있도록 엄격한 방식으로 전환합니다.", + "STRICT_ESCAPING": "STRICT_ESCAPING", + "Replace all {{getvar::}} and {{getglobalvar::}} macros with scoped variables to avoid double macro substitution.": "이중 매크로 대체를 방지하려면 모든 {{getvar::}} 및 {{getglobalvar::}} 매크로를 범위 변수로 바꾸세요.", + "REPLACE_GETVAR": "REPLACE_GETVAR", + "Change Background Image": "배경 이미지 변경", + "Filter": "필터", + "Automatically select a background based on the chat context": "채팅 컨텍스트를 기반으로 자동으로 배경 선택", + "Auto-select": "자동 선택", + "System Backgrounds": "시스템 배경", + "Chat Backgrounds": "채팅 배경", + "bg_chat_hint_1": "다음으로 생성된 채팅 배경", + "bg_chat_hint_2": "확장 프로그램이 여기에 표시됩니다.", + "Extensions": "확장", + "Notify on extension updates": "확장 프로그램 업데이트 알림", + "Manage extensions": "확장 프로그램 관리", + "Import Extension From Git Repo": "Git 리포지토리에서 확장 프로그램 가져오기", + "Install extension": "확장 프로그램 설치", + "Extras API:": "외부 API:", + "Auto-connect": "자동 연결", + "Extras API URL": "엑스트라 API URL", + "Extras API key (optional)": "Extras API 키 (선택 사항)", + "Persona Management": "페르소나 관리", + "How do I use this?": "어떻게 사용하나요?", + "Click for stats!": "통계 보기!", + "Usage Stats": "사용 통계", + "Backup your personas to a file": "개인정보를 파일로 백업합니다.", + "Backup": "백업", + "Restore your personas from a file": "파일에서 개인정보를 복원합니다.", + "Restore": "복원", + "Create a dummy persona": "더미 페르소나 만들기", + "Create": "만들기", + "Toggle grid view": "그리드 보기 전환", + "No persona description": "[설명 없음]", + "Name": "이름", + "Enter your name": "이름을 입력하세요", + "Click to set a new User Name": "새 사용자 이름 설정을 저장합니다.", + "Click to lock your selected persona to the current chat. Click again to remove the lock.": "선택한 페르소나를 현재 채팅에 잠그려면 클릭하세요. 잠금을 제거하려면 다시 클릭하세요.", + "Click to set user name for all messages": "모든 메시지를 현재 선택된 사용자 이름으로 설정하려면 클릭하세요", + "Persona Description": "페르소나 설명", + "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "예: [{{user}}는 28세의 루마니아 고양이 소녀입니다.]", + "Tokens persona description": "페르소나 설명 토큰", + "Position:": "위치:", + "None (disabled)": "없음 (비활성화됨)", + "In Story String / Prompt Manager": "이야기 문자열 / 프롬프트 관리자", + "Top of Author's Note": "작가 노트 상단", + "Bottom of Author's Note": "작가 노트 하단", + "In-chat @ Depth": "채팅 내 @ Depth", + "Depth:": "깊이:", + "Role:": "역할:", + "System": "시스템", + "User": "사용자", + "Assistant": "어시스턴트", + "Show notifications on switching personas": "페르소나 전환시 알림 표시", + "Character Management": "캐릭터 관리", + "Locked = Character Management panel will stay open": "잠금 = 캐릭터 관리 패널이 열린 상태로 유지됩니다", + "Select/Create Characters": "캐릭터 선택/생성", + "Favorite characters to add them to HotSwaps": "즐겨찾는 캐릭터를 HotSwaps에 추가", + "Token counts may be inaccurate and provided just for reference.": "토큰 수가 정확하지 않을 수 있으며 참조 용도로만 제공됩니다.", + "Total tokens": "총 토큰", + "Calculating...": "계산 중...", + "Tokens": "토큰", + "Permanent tokens": "영구 토큰", + "Permanent": "영구적인", + "About Token 'Limits'": "토큰 '한도' 정보", + "Toggle character info panel": "캐릭터 정보 패널 전환", + "Name this character": "이 캐릭터의 이름을 지정하세요", + "extension_token_counter": "토큰:", + "Click to select a new avatar for this character": "이 캐릭터의 새 아바타를 선택하려면 클릭하세요", + "Add to Favorites": "즐겨찾기에 추가", + "Advanced Definition": "고급 정의", + "Character Lore": "캐릭터 로어북", + "Chat Lore": "채팅 로어북", + "Export and Download": "내보내기 및 다운로드", + "Duplicate Character": "캐릭터 복제", + "Create Character": "캐릭터 생성", + "Delete Character": "캐릭터 삭제", + "More...": "추가 설정들...", + "Link to World Info": "월드 인포에 연결", + "Import Card Lore": "카드 로어북 가져오기", + "Scenario Override": "시나리오 재정의", + "Convert to Persona": "페르소나로 변환", + "Rename": "이름 변경", + "Link to Source": "소스 링크", + "Replace / Update": "교체/업데이트", + "Import Tags": "태그 가져오기", + "Search / Create Tags": "검색 / 태그 생성", + "View all tags": "모든 태그 보기", + "Creator's Notes": "제작자의 메모", + "Show / Hide Description and First Message": "설명 및 첫 번째 메시지 표시/숨기기", + "Character Description": "캐릭터 설명", + "Click to allow/forbid the use of external media for this character.": "이 캐릭터에 대한 외부 미디어 사용을 허용/금지하려면 클릭하세요.", + "Ext. Media": "외부 미디어", + "Describe your character's physical and mental traits here.": "여기에 캐릭터의 신체적, 정신적 특성을 설명하세요.", + "First message": "첫 번째 메시지", + "Click to set additional greeting messages": "첫 번째 메시지를 추가로 설정하려면 클릭하세요.", + "Alt. Greetings": "대체. 첫 메시지", + "This will be the first message from the character that starts every chat.": "이것은 모든 채팅을 시작할 때 캐릭터의 첫 번째 메시지가 됩니다.", + "Group Controls": "그룹 제어", + "Chat Name (Optional)": "채팅 이름 (선택 사항)", + "Click to select a new avatar for this group": "이 그룹의 새 아바타를 선택하려면 클릭하세요", + "Group reply strategy": "그룹 응답 전략", + "Natural order": "자연스러운 순서", + "List order": "목록에 배정된 순서", + "Group generation handling mode": "그룹 생성 처리 모드", + "Swap character cards": "캐릭터 카드 바꾸기", + "Join character cards (exclude muted)": "캐릭터 카드 가입 (뮤트 제외)", + "Join character cards (include muted)": "캐릭터 카드 가입 (뮤트 포함)", + "Inserted before each part of the joined fields.": "결합된 필드의 각 부분 앞에 삽입됩니다.", + "Join Prefix": "접두사 가입", + "When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and with the name of the part (e.g.: description, personality, scenario, etc.)": "'캐릭터 카드 합치기'를 선택하면 캐릭터의 모든 해당 필드가 합쳐집니다. 즉, 스토리 문자열에서 예를 들어 모든 캐릭터 설명이 하나의 큰 텍스트로 합쳐집니다. 이러한 필드를 분리하려면 여기에서 접두사나 접미사를 정의할 수 있습니다. 이 값은 일반 매크로를 지원하고 {{char}}를 해당 캐릭터의 이름으로, 을 해당 부분의 이름(예: 설명, 성격, 시나리오 등)으로 대체합니다.", + "Inserted after each part of the joined fields.": "결합된 필드의 각 부분 뒤에 삽입됩니다.", + "Join Suffix": "접미사 가입", + "Set a group chat scenario": "그룹 채팅 시나리오 설정", + "Click to allow/forbid the use of external media for this group.": "이 그룹에 대한 외부 미디어 사용을 허용/금지하려면 클릭하세요.", + "Restore collage avatar": "콜라주 아바타 복원", + "Allow self responses": "자체 응답 허용", + "Auto Mode": "자동 모드", + "Auto Mode delay": "자동 모드 지연", + "Hide Muted Member Sprites": "음소거된 멤버 스프라이트 숨기기", + "Current Members": "현재 멤버", + "Add Members": "멤버 추가", + "Create New Character": "새 캐릭터 만들기", + "Import Character from File": "파일에서 캐릭터 가져오기", + "Import content from external URL": "외부 URL에서 콘텐츠 가져오기", + "Create New Chat Group": "새 채팅 그룹 만들기", + "Characters sorting order": "캐릭터 정렬 순서", + "A-Z": "A-Z", + "Z-A": "Z-A", + "Newest": "최신순", + "Oldest": "가장 오래된 순", + "Favorites": "즐겨찾기", + "Recent": "최근", + "Most chats": "대화가 가장 많은", + "Least chats": "대화가 가장 적은", + "Most tokens": "가장 많은 토큰", + "Least tokens": "가장 적은 토큰", + "Random": "랜덤", + "Toggle character grid view": "캐릭터 그리드 보기 전환", + "Bulk_edit_characters": "대량 캐릭터 편집", + "Bulk select all characters": "모든 문자 일괄 선택", + "Bulk delete characters": "대량 캐릭터 삭제", + "popup-button-save": "저장하기", + "popup-button-yes": "네", + "popup-button-no": "아니요", + "popup-button-cancel": "취소", + "popup-button-import": "불러오기", + "Advanced Definitions": "고급 정의", + "Prompt Overrides": "프롬프트 무시", + "(For Chat Completion and Instruct Mode)": "(채팅 완료 및 지시 모드의 경우)", + "Insert {{original}} into either box to include the respective default prompt from system settings.": "{{original}}를 해당 상자에 넣어 시스템 설정의 기본 프롬프트를 포함합니다.", + "Main Prompt": "주요 프롬프트", + "Any contents here will replace the default Main Prompt used for this character. (v2 spec: system_prompt)": "여기에 있는 모든 내용은 이 캐릭터에 사용된 기본 메인 프롬프트를 대체합니다. (v2 사양: system_prompt)", + "Any contents here will replace the default Jailbreak Prompt used for this character. (v2 spec: post_history_instructions)": "여기에 있는 모든 내용은 이 캐릭터에 사용된 기본 탈옥 프롬프트를 대체합니다. (v2 사양: post_history_instructions)", + "Creator's Metadata (Not sent with the AI prompt)": "제작자의 메타데이터 (AI 프롬프트와 함께 전송되지 않음)", + "Creator's Metadata": "제작자의 메타데이터", + "(Not sent with the AI Prompt)": "(AI 프롬프트와 함께 전송되지 않음)", + "Everything here is optional": "여기 있는 모든 것은 선택 사항입니다", + "(Botmaker's name / Contact Info)": "(봇 제작자 이름 / 연락처 정보)", + "(If you want to track character versions)": "(캐릭터 버전을 추적하려는 경우)", + "(Describe the bot, give use tips, or list the chat models it has been tested on. This will be displayed in the character list.)": "(봇을 설명하고 사용 팁을 제공하거나 테스트된 채팅 모델을 나열합니다. 이 내용은 캐릭터 목록에 표시됩니다.)", + "Tags to Embed": "포함할 태그", + "(Write a comma-separated list of tags)": "(쉼표로 구분된 태그 목록 작성)", + "Personality summary": "성격 요약", + "(A brief description of the personality)": "(성격에 대한 간단한 설명)", + "Scenario": "시나리오", + "(Circumstances and context of the interaction)": "(상호 작용의 상황과 맥락)", + "Character's Note": "캐릭터 노트", + "(Text to be inserted in-chat @ designated depth and role)": "(채팅에 삽입되는 텍스트@지정된 깊이와 역할)", + "@ Depth": "@ 깊이", + "Role": "역할", + "Talkativeness": "수다스러움", + "How often the character speaks in group chats!": "캐릭터가 그룹 채팅에서 얼마나 자주 말할지 설정해보세요!", + "How often the character speaks in": "캐릭터가 말하는 빈도", + "group chats!": "그룹 채팅!", + "Shy": "수줍음", + "Normal": "평범함", + "Chatty": "수다쟁이", + "Examples of dialogue": "대화 예시", + "Important to set the character's writing style.": "캐릭터의 글쓰기 스타일을 설정하는 것이 중요합니다.", + "(Examples of chat dialog. Begin each example with START on a new line.)": "(채팅 대화의 예제입니다. 각 예제를 새 줄에서 START로 시작하세요.)", + "Save": "저장", + "Chat History": "채팅 기록", + "Import Chat": "채팅 가져오기", + "Copy to system backgrounds": "시스템 배경에 복사", + "Rename background": "배경 이름 바꾸기", + "Lock": "잠금", + "Unlock": "잠금 해제", + "Delete background": "배경 삭제", + "Chat Scenario Override": "채팅 시나리오 재정의", + "Remove": "제거", + "Type here...": "여기에 입력하세요...", + "Chat Lorebook": "채팅 로어북", + "Chat Lorebook for": "채팅 로어북", + "chat_world_template_txt": "선택한 월드 인포가 이 채팅에 연결됩니다. AI 응답을 생성할 때,\n 글로벌 및 캐릭터 로어북의 항목과 결합됩니다.", + "Select a World Info file for": "다음을 위해 월드 인포 파일 선택:", + "Primary Lorebook": "기본 로어북", + "A selected World Info will be bound to this character as its own Lorebook.": "선택한 월드 정보가 이 캐릭터에게 자체 로어북으로 바인딩됩니다.", + "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "AI 응답을 생성할 때 전역 월드 정보 선택기의 항목과 결합됩니다.", + "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "캐릭터를 내보내면 JSON 데이터에 포함된 선택한 로어북 파일도 내보냅니다.", + "Additional Lorebooks": "추가 로어북", + "Associate one or more auxillary Lorebooks with this character.": "하나 이상의 보조 로어북을 이 캐릭터와 연관시킵니다.", + "NOTE: These choices are optional and won't be preserved on character export!": "참고: 이 선택 사항은 선택 사항이며 캐릭터 내보내기 시 유지되지 않습니다!", + "Rename chat file": "채팅 파일 이름 바꾸기", + "Export JSONL chat file": "JSONL 채팅 파일 내보내기", + "Download chat as plain text document": "일반 텍스트 문서로 채팅 다운로드", + "Delete chat file": "채팅 파일 삭제", + "Use tag as folder": "폴더로 태그 지정", + "Delete tag": "태그 삭제", + "Entry Title/Memo": "항목 제목/메모", + "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized❌ Disabled": "WI 입국 상태:\r🔵 상시\r🟢 조건 만족시\r🔗 벡터화됨\r❌ 비활성화", + "WI_Entry_Status_Constant": "상시 활성화", + "WI_Entry_Status_Normal": "정상", + "WI_Entry_Status_Vectorized": "벡터화됨", + "WI_Entry_Status_Disabled": "비활성화됨", + "T_Position": "↑Char: 캐릭터 정의 전\n↓Char: 캐릭터 정의 후\n↑AN: 작가 노트 전\n↓AN: 작가노트 후\n@D: 깊이", + "Before Char Defs": "캐릭터 정의 전", + "After Char Defs": "캐릭터 정의 후", + "Before EM": "↑EM", + "After EM": "↓EM", + "Before AN": "작가 노트 전", + "After AN": "작가 노트 후", + "at Depth System": "@D ⚙️", + "at Depth User": "@D 👤", + "at Depth AI": "@D 🤖", + "Depth": "깊이", + "Order:": "순서:", + "Order": "순서:", + "Trigger %:": "발동 확률 %:", + "Probability": "개연성", + "Duplicate world info entry": "중복된 월드 인포 항목", + "Delete world info entry": "월드 인포 항목 삭제", + "Comma separated (required)": "쉼표로 구분 (필수)", + "Primary Keywords": "기본 키워드", + "Keywords or Regexes": "키워드 또는 정규식", + "Comma separated list": "쉼표로 구분된 목록", + "Switch to plaintext mode": "일반 텍스트 모드로 전환", + "Logic": "논리 구조", + "AND ANY": "AND ANY", + "AND ALL": "AND ALL", + "NOT ALL": "NOT ALL", + "NOT ANY": "NOT ANY", + "(ignored if empty)": "(비어 있으면 무시됨)", + "Optional Filter": "선택적 필터", + "Keywords or Regexes (ignored if empty)": "키워드 또는 정규 표현식(비어 있으면 무시됨)", + "Comma separated list (ignored if empty)": "쉼표로 구분된 목록(비어 있으면 무시됨)", + "Use global setting": "전역 설정 사용", + "Case-Sensitive": "대소문자 구분", + "Yes": "예", + "No": "아니오", + "Quick Reply": "빠른 답장", + "Can be used to automatically activate Quick Replies": "빠른 답장을 자동으로 활성화하는 데 사용할 수 있습니다.", + "Automation ID": "자동화 ID", + "( None )": "( 없음 )", + "Content": "콘텐츠", + "Exclude from recursion": "재귀에서 제외", + "Prevent further recursion (this entry will not activate others)": "추가 재귀 방지(이 항목은 다른 항목을 활성화하지 않습니다)", + "Delay until recursion (this entry can only be activated on recursive checking)": "재귀까지 지연(이 항목은 재귀 검사에서만 활성화될 수 있음)", + "What this keyword should mean to the AI, sent verbatim": "AI에게 이 키워드가 무엇을 의미하는지를 원래 그대로 보냄", + "Filter to Character(s)": "캐릭터로 필터링", + "Character Exclusion": "캐릭터 제외", + "-- Characters not found --": "-- 캐릭터를 찾을 수 없음 --", + "Inclusion Group": "포함 그룹", + "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "포함 그룹은 여러 항목이 트리거되는 경우 그룹에서 한 번에 하나의 항목만 활성화되도록 합니다.\r쉼표로 구분된 여러 그룹을 지원합니다.\r\r문서: 월드 인포 - 포함 그룹", + "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "이 항목 우선순위 지정: 선택하면 모든 선택 항목 중에서 이 항목의 우선순위가 지정됩니다.\r여러 항목의 우선순위가 높은 경우 '순서'가 가장 높은 항목이 선택됩니다.", + "Only one entry with the same label will be activated": "동일한 라벨을 가진 항목은 하나만 활성화됩니다", + "A relative likelihood of entry activation within the group": "그룹 내 항목 활성화의 상대적 가능성", + "Group Weight": "그룹 가중치", + "Selective": "선택적", + "Use Probability": "확률 사용", + "Add Memo": "메모 추가", + "Text or token ids": "텍스트 또는 [토큰 ID]", + "close": "닫다", + "prompt_manager_edit": "프롬프트 편집", + "prompt_manager_name": "이름", + "A name for this prompt.": "이 프롬프트의 이름입니다.", + "To whom this message will be attributed.": "해당 프롬프트에 부여할 역할은 무엇인가요?", + "AI Assistant": "AI 어시스턴트", + "prompt_manager_position": "위치", + "Injection position. Next to other prompts (relative) or in-chat (absolute).": "주입 위치. 다른 프롬프트 옆(상대적) 또는 채팅 내(절대적).", + "prompt_manager_relative": "상대적인", + "prompt_manager_in_chat": "깊이에 따라", + "prompt_manager_depth": "깊이", + "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "주입 깊이. 0 = 마지막 메시지 뒤, 1 = 마지막 메시지 앞 등", + "Prompt": "프롬프트", + "The prompt to be sent.": "보내질 프롬프트 내용을 작성하는 부분입니다.", + "This prompt cannot be overridden by character cards, even if overrides are preferred.": "이 프롬프트는 고급 정의에서 재정의가 선호되는 경우에도 재정의될 수 없습니다.", + "prompt_manager_forbid_overrides": "재정의 금지", + "reset": "초기화", + "save": "저장", + "This message is invisible for the AI": "이 메시지는 AI에게 보이지 않습니다", + "Message Actions": "메시지 작업", + "Translate message": "메시지 번역", + "Generate Image": "이미지 생성", + "Narrate": "나레이션 하기", + "Exclude message from prompts": "프롬프트에서 메시지 제외", + "Include message in prompts": "프롬프트에 메시지 포함", + "Embed file or image": "파일 또는 이미지 삽입", + "Create checkpoint": "체크포인트 만들기", + "Create Branch": "분기 생성", + "Copy": "복사", + "Open checkpoint chat": "체크포인트 채팅 오픈", + "Edit": "편집", + "Confirm": "확인", + "Copy this message": "이 메시지 복사", + "Delete this message": "이 메시지 삭제", + "Move message up": "메시지를 위로 이동", + "Move message down": "메시지를 아래로 이동", + "Enlarge": "확대", + "Welcome to SillyTavern!": "SillyTavern에 오신 것을 환영합니다!", + "welcome_message_part_1": "자세한 설명 읽기:", + "welcome_message_part_2": "공식 문서", + "welcome_message_part_3": null, + "welcome_message_part_4": "유형", + "welcome_message_part_5": "명령과 매크로에 대한 채팅.", + "welcome_message_part_6": "공식", + "Discord server": "디스코드 서버", + "welcome_message_part_7": "에서 정보 및 공지사항을 확인하세요.", + "SillyTavern is aimed at advanced users.": "SillyTavern은 고급 사용자를 대상으로 합니다.", + "If you're new to this, enable the simplified UI mode below.": "처음 사용하는 경우 아래의 단순화된 UI 모드를 활성화하세요.", + "Change it later in the 'User Settings' panel.": "나중에 '사용자 설정' 패널에서 변경하세요.", + "Enable simple UI mode": "단순 UI 모드 활성화", + "Looking for AI characters?": "AI 캐릭터를 찾고 계십니까?", + "onboarding_import": "가져오기", + "from supported sources or view": "지원되는 소스 또는 보기에서", + "Sample characters": "샘플 캐릭터", + "Your Persona": "당신의 페르소나", + "Before you get started, you must select a persona name.": "시작하기 전에 페르소나 이름을 선택해야 합니다.", + "welcome_message_part_8": "이는 언제든지 변경될 수 있습니다. 변경을 원한다면", + "welcome_message_part_9": "아이콘을 누르세요.", + "Persona Name:": "페르소나 이름:", + "Temporarily disable automatic replies from this character": "이 캐릭터의 자동 응답 일시적으로 비활성화", + "Enable automatic replies from this character": "이 캐릭터의 자동 응답 활성화", + "Trigger a message from this character": "이 캐릭터에서 메시지 트리거", + "Move up": "위로 이동", + "Move down": "아래로 이동", + "View character card": "캐릭터 카드 보기", + "Remove from group": "그룹에서 제거", + "Add to group": "그룹에 추가", + "Alternate Greetings": "대체 인사말", + "Alternate_Greetings_desc": "이는 새 채팅을 시작할 때 첫 번째 메시지에 스와이프로 표시됩니다.\n 그룹 구성원은 그 중 하나를 선택하여 대화를 시작할 수 있습니다.", + "Alternate Greetings Hint": "시작하려면 버튼을 클릭하세요!", + "(This will be the first message from the character that starts every chat)": "(이것은 모든 채팅을 시작하는 캐릭터의 첫 번째 메시지가 됩니다)", + "Forbid Media Override explanation": "현재 캐릭터/그룹이 채팅에서 외부 미디어를 사용할 수 있는 능력입니다.", + "Forbid Media Override subtitle": "미디어: 이미지, 비디오, 오디오. 외부: 로컬 서버에서 호스팅되지 않습니다.", + "Always forbidden": "항상 금지", + "Always allowed": "항상 허용됨", + "View contents": "내용 보기", + "Remove the file": "파일을 제거하세요", + "Unique to this chat": "이 채팅에만 고유함", + "Checkpoints inherit the Note from their parent, and can be changed individually after that.": "체크포인트는 상위 항목으로부터 메모를 상속받으며 이후 개별적으로 변경될 수 있습니다.", + "Include in World Info Scanning": "월드인포를 스캔 대상에 포함", + "Before Main Prompt / Story String": "메인 프롬프트 전/스토리 문자열", + "After Main Prompt / Story String": "메인 프롬프트 이후 / 스토리 문자열", + "as": "~처럼", + "Insertion Frequency": "삽입 빈도", + "(0 = Disable, 1 = Always)": "(0 = 비활성화, 1 = 항상)", + "User inputs until next insertion:": "다음 삽입까지 사용자 입력:", + "Character Author's Note (Private)": "캐릭터 작가의 메모 (비공개)", + "Won't be shared with the character card on export.": "내보내기 시 캐릭터 카드와 공유되지 않습니다.", + "Will be automatically added as the author's note for this character. Will be used in groups, but can't be modified when a group chat is open.": "해당 캐릭터에 대한 작가 노트로 자동 추가됩니다. 그룹으로 사용되지만\n 그룹 채팅이 열려 있으면 수정할 수 없습니다.", + "Use character author's note": "캐릭터 작가 노트 사용", + "Replace Author's Note": "작가 노트 자리를 대체하기", + "Default Author's Note": "기본 작가 노트", + "Will be automatically added as the Author's Note for all new chats.": "모든 새 채팅에 대한 작가 노트로 자동으로 추가됩니다.", + "Chat CFG": "채팅CFG", + "1 = disabled": "1 = 비활성화됨", + "write short replies, write replies using past tense": "짧은 답장 쓰기, 과거 시제를 사용하여 답장 쓰기", + "Positive Prompt": "긍정적 프롬프트", + "Use character CFG scales": "캐릭터 CFG 스케일 사용", + "Character CFG": "캐릭터 CFG", + "Will be automatically added as the CFG for this character.": "해당 캐릭터의 CFG로 자동 추가됩니다.", + "Global CFG": "글로벌 CFG", + "Will be used as the default CFG options for every chat unless overridden.": "재정의되지 않는 한 모든 채팅에 대해 기본 CFG 옵션으로 사용됩니다.", + "CFG Prompt Cascading": "CFG 프롬프트 세분화", + "Combine positive/negative prompts from other boxes.": "다른 상자의 긍정적/부정적 프롬프트를 결합합니다.", + "For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string.": "예를 들어, 채팅, 글로벌, 문자 상자를 체크하면 모든 부정 프롬프트가 쉼표로 구분된 문자열로 결합됩니다.", + "Always Include": "항상 포함", + "Chat Negatives": "채팅 부정적인 내용", + "Character Negatives": "문자 네거티브", + "Global Negatives": "글로벌 네거티브", + "Custom Separator:": "맞춤 구분 기호:", + "Insertion Depth:": "삽입 깊이:", + "Token Probabilities": "토큰 확률", + "Select a token to see alternatives considered by the AI.": "AI가 고려하는 대안을 보려면 토큰을 선택하세요.", + "Not connected to API!": "API에 연결되지 않았습니다!", + "Type a message, or /? for help": "메시지를 입력하거나 /? 도와주기 위해", + "Continue script execution": "스크립트 실행 계속", + "Pause script execution": "스크립트 실행 일시 중지", + "Abort script execution": "스크립트 실행 중단", + "Abort request": "요청 중단", + "Continue the last message": "마지막 메시지 계속하기", + "Send a message": "메시지 보내기", + "Close chat": "채팅 닫기", + "Toggle Panels": "토글 패널", + "Back to parent chat": "부모 채팅으로 돌아가기", + "Save checkpoint": "체크포인트 저장", + "Convert to group": "그룹 채팅으로 변환", + "Start new chat": "새로운 채팅 시작", + "Manage chat files": "채팅 파일 관리", + "Delete messages": "메시지 삭제", + "Regenerate": "재생성", + "Ask AI to write your message for you": "AI에게 메시지를 대신 작성하도록 요청", + "Impersonate": "사칭", + "Continue": "계속 생성하기", + "Bind user name to that avatar": "그 아바타에 사용자 이름 바인딩", + "Change persona image": "페르소나 이미지 변경", + "Select this as default persona for the new chats.": "새 채팅의 기본 페르소나로 선택합니다.", + "Delete persona": "페르소나 삭제", + "These characters are the winners of character design contests and have outstandable quality.": "캐릭터 디자인 공모전에서 당선된 캐릭터로, 뛰어난 퀄리티를 자랑하는 캐릭터입니다.", + "Contest Winners": "콘테스트 우승자", + "These characters are the finalists of character design contests and have remarkable quality.": "이 캐릭터들은 캐릭터 디자인 공모전의 최종 후보로, 뛰어난 퀄리티를 자랑합니다.", + "Featured Characters": "독립된 캐릭터", + "Attach a File": "파일 첨부하기", + "Open Data Bank": "오픈데이터뱅크", + "Enter a URL or the ID of a Fandom wiki page to scrape:": "스크랩할 Fandom 위키 페이지의 URL이나 ID를 입력하세요:", + "Examples:": "예:", + "Example:": "예:", + "Single file": "단일 파일", + "All articles will be concatenated into a single file.": "모든 기사는 단일 파일로 연결됩니다.", + "File per article": "기사당 파일", + "Each article will be saved as a separate file.": "권장되지 않습니다. 각 기사는 별도의 파일로 저장됩니다.", + "Data Bank": "데이터 저장소", + "These files will be available for extensions that support attachments (e.g. Vector Storage).": "이러한 파일은 첨부 파일을 지원하는 확장 프로그램(예: 벡터 저장소)에 사용할 수 있습니다.", + "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.": "지원되는 파일 유형: 일반 텍스트, PDF, Markdown, HTML, EPUB.", + "Drag and drop files here to upload.": "여기에 파일을 끌어다 놓아 업로드하세요.", + "Date (Newest First)": "날짜(최신순)", + "Date (Oldest First)": "날짜(오래된 것부터)", + "Name (A-Z)": "이름(A~Z)", + "Name (Z-A)": "이름(Z-A)", + "Size (Smallest First)": "크기(가장 작은 것부터)", + "Size (Largest First)": "크기(큰 것부터)", + "Bulk Edit": "대량 편집", + "Select All": "모두 선택", + "Select None": "없음을 선택하세요", + "Global Attachments": "전역 첨부", + "These files are available for all characters in all chats.": "이 파일은 모든 채팅의 모든 캐릭터에 사용할 수 있습니다.", + "Character Attachments": "캐릭터 부착물", + "These files are available the current character in all chats they are in.": "이 파일은 해당 파일이 속한 모든 채팅에서 현재 캐릭터에서 사용할 수 있습니다.", + "Saved locally. Not exported.": "로컬에 저장됨. 내보내지 않음.", + "Chat Attachments": "채팅 첨부파일", + "These files are available to all characters in the current chat.": "이 파일은 현재 채팅의 모든 캐릭터가 사용할 수 있습니다.", + "Enter a base URL of the MediaWiki to scrape.": "스크래핑할 미디어위키의 기본 URL을 입력하세요.", + "Don't include the page name!": "페이지 이름을 포함하지 마세요!", + "Enter web URLs to scrape (one per line):": "스크랩할 웹 URL을 입력하세요(한 줄에 하나씩):", + "Enter a video URL to download its transcript.": "스크립트를 다운로드하려면 동영상 URL 또는 ID를 입력하세요.", + "Expression API": "표현\n엑스트라\nAPI", + "ext_sum_current_summary": "현재 요약:", + "ext_sum_restore_previous": "이전 복원", + "ext_sum_memory_placeholder": "여기에 요약이 생성됩니다...", + "Trigger a summary update right now.": "지금 요약하세요", + "ext_sum_force_text": "지금 요약하세요", + "Disable automatic summary updates. While paused, the summary remains as-is. You can still force an update by pressing the Summarize now button (which is only available with the Main API).": "자동 요약 업데이트를 비활성화합니다. 일시 중지된 동안 요약은 그대로 유지됩니다. 지금 요약 버튼(기본 API에서만 사용 가능)을 눌러 강제로 업데이트할 수 있습니다.", + "ext_sum_pause": "요약 정지시키기", + "Omit World Info and Author's Note from text to be summarized. Only has an effect when using the Main API. The Extras API always omits WI/AN.": "요약할 텍스트에서 World Info 및 Author's Note를 생략합니다. Main API를 사용할 때만 효과가 있습니다. Extras API는 항상 WI/AN을 생략합니다.", + "ext_sum_no_wi_an": "WI/AN 없음", + "ext_sum_settings_tip": "요약 프롬프트, 삽입 위치 등을 편집합니다.", + "ext_sum_settings": "요약 설정", + "ext_sum_prompt_builder": "프롬프트 빌더", + "ext_sum_prompt_builder_1_desc": "확장 프로그램은 아직 요약되지 않은 메시지를 사용하여 자체 프롬프트를 작성합니다. 요약이 생성될 때까지 채팅을 차단합니다.", + "ext_sum_prompt_builder_1": "원시, 차단", + "ext_sum_prompt_builder_2_desc": "확장 프로그램은 아직 요약되지 않은 메시지를 사용하여 자체 프롬프트를 작성합니다. 요약이 생성되는 동안 채팅을 차단하지 않습니다. 하지만 모든 백엔드가 이 모드를 지원하는 것은 아닙니다.", + "ext_sum_prompt_builder_2": "원시, 비차단", + "ext_sum_prompt_builder_3_desc": "확장은 일반 기본 프롬프트 빌더를 사용하고 요약 요청을 마지막 시스템 메시지로 추가합니다.", + "ext_sum_prompt_builder_3": "클래식, 차단", + "Summary Prompt": "요약 프롬프트", + "ext_sum_restore_default_prompt_tip": "기본 프롬프트 복원", + "ext_sum_prompt_placeholder": "이 프롬프트는 요약 생성을 요청하기 위해 AI로 전송됩니다. {{words}}는 '단어 수' 매개변수로 해석됩니다.", + "ext_sum_target_length_1": "목표 요약 길이", + "ext_sum_target_length_2": null, + "ext_sum_target_length_3": "단어)", + "ext_sum_api_response_length_1": "API 응답 길이", + "ext_sum_api_response_length_2": "(( ...", + "ext_sum_api_response_length_3": "토큰)", + "ext_sum_0_default": "0 = 기본값", + "ext_sum_raw_max_msg": "[원시] 요청당 최대 메시지 수", + "ext_sum_0_unlimited": "0 = 무제한", + "Update frequency": "업데이트 빈도", + "ext_sum_update_every_messages_1": "업데이트 간격", + "ext_sum_update_every_messages_2": "메시지", + "ext_sum_0_disable": "0 = 비활성화", + "ext_sum_auto_adjust_desc": "채팅 지표에 따라 간격을 자동으로 조정해 보세요.", + "ext_sum_update_every_words_1": "매 업데이트", + "ext_sum_update_every_words_2": "단어", + "ext_sum_both_sliders": "두 슬라이더가 모두 0이 아닌 경우 둘 다 해당 간격으로 요약 업데이트를 트리거합니다.", + "ext_sum_injection_template": "주입 템플릿", + "ext_sum_memory_template_placeholder": "{{summary}}는 현재 요약 내용으로 해석됩니다.", + "ext_sum_injection_position": "주입 위치", + "How many messages before the current end of the chat.": "현재 채팅이 끝나기 전의 메시지 수입니다.", + "ext_regex_title": "정규식", + "ext_regex_new_global_script": "+ 글로벌", + "ext_regex_new_scoped_script": "+ 범위 지정", + "ext_regex_import_script": "불러오기", + "ext_regex_global_scripts": "글로벌 스크립트", + "ext_regex_global_scripts_desc": "모든 캐릭터에 사용 가능합니다. 로컬 설정에 저장되었습니다.", + "ext_regex_scoped_scripts": "범위가 지정된 스크립트", + "ext_regex_scoped_scripts_desc": "해당 캐릭터에만 사용 가능합니다. 카드 데이터에 저장됩니다.", + "Regex Editor": "정규식 편집기", + "Test Mode": "테스트 모드", + "ext_regex_desc": "Regex는 정규식을 사용하여 문자열을 찾거나 바꾸는 도구입니다. 자세한 내용을 보려면 ?를 클릭하세요. 제목 옆에.", + "Input": "입력", + "ext_regex_test_input_placeholder": "여기에 입력하세요...", + "Output": "산출", + "ext_regex_output_placeholder": "비어 있는", + "Script Name": "스크립트 이름", + "Find Regex": "정규식 찾기", + "Replace With": "다음으로 바꾸기", + "ext_regex_replace_string_placeholder": "정규 표현식 찾기 또는 캡처 그룹의 경우 $1, $2 등에서 일치하는 텍스트를 포함하려면 {{match}}를 사용하세요.", + "Trim Out": "트림아웃", + "ext_regex_trim_placeholder": "교체하기 전에 정규식 일치에서 원하지 않는 부분을 전체적으로 잘라냅니다. 각 요소를 Enter로 구분하세요.", + "ext_regex_affects": "영향을 미침", + "ext_regex_user_input": "사용자 입력", + "ext_regex_ai_output": "AI 출력", + "Slash Commands": "슬래시 명령", + "ext_regex_min_depth_desc": "프롬프트 또는 표시에 적용하면 최소 N 수준 깊이의 메시지에만 영향을 미칩니다. 0 = 마지막 메시지, 1 = 끝에서 두 번째 메시지 등. WI 항목 @Depth 및 사용 가능한 메시지만 계산합니다. 즉, 숨겨진 메시지나 시스템 메시지는 계산하지 않습니다.", + "Min Depth": "최소 깊이", + "ext_regex_min_depth_placeholder": "제한 없는", + "ext_regex_max_depth_desc": "프롬프트나 표시에 적용하면 N 수준 이하의 메시지에만 영향을 미칩니다. 0 = 마지막 메시지, 1 = 끝에서 두 번째 메시지 등. WI 항목 @Depth 및 사용 가능한 메시지만 계산합니다. 즉, 숨겨진 메시지나 시스템 메시지는 계산하지 않습니다.", + "ext_regex_other_options": "다른 옵션", + "Only Format Display": "형식 표시만", + "ext_regex_only_format_prompt_desc": "채팅 기록은 변경되지 않으며 요청이 전송될 때 메시지만 생성됩니다.", + "Only Format Prompt (?)": "형식 프롬프트만", + "Run On Edit": "편집 실행", + "ext_regex_substitute_regex_desc": "실행하기 전에 Find Regex에서 {{macros}}를 대체하세요.", + "Substitute Regex": "정규식 대체", + "ext_regex_import_target": "가져오기 대상:", + "ext_regex_disable_script": "스크립트 비활성화", + "ext_regex_enable_script": "스크립트 활성화", + "ext_regex_edit_script": "스크립트 편집", + "ext_regex_move_to_global": "전역 스크립트로 이동", + "ext_regex_move_to_scoped": "범위가 지정된 스크립트로 이동", + "ext_regex_export_script": "스크립트 내보내기", + "ext_regex_delete_script": "스크립트 삭제", + "Trigger Stable Diffusion": "트리거 안정 확산", + "sd_Yourself": "당신 자신", + "sd_Your_Face": "너의 얼굴", + "sd_Me": "나", + "sd_The_Whole_Story": "전체 스토리", + "sd_The_Last_Message": "마지막 메시지", + "sd_Raw_Last_Message": "원시 마지막 메시지", + "sd_Background": "배경", + "Image Generation": "이미지 생성", + "sd_refine_mode": "프롬프트를 생성 API로 보내기 전에 수동으로 편집할 수 있도록 허용", + "sd_refine_mode_txt": "생성 전에 프롬프트 편집", + "sd_interactive_mode": "'고양이 사진 보내주세요'와 같은 메시지를 보낼 때 자동으로 이미지를 생성합니다.", + "sd_interactive_mode_txt": "대화에 따른 자동 이미지 생성 모드", + "sd_multimodal_captioning": "다중 모달 캡션을 사용하여 아바타를 기반으로 사용자 및 캐릭터 초상화에 대한 프롬프트를 생성합니다.", + "sd_multimodal_captioning_txt": "인물 사진에 다중 모드 캡션 사용", + "sd_expand": "텍스트 생성 모델을 사용하여 프롬프트 자동 확장", + "sd_expand_txt": "자동 강화 프롬프트", + "sd_snap": "강제 종횡비(인물 사진, 배경)를 사용하여 가장 가까운 알려진 해상도로 스냅 생성을 요청하는 동시에 절대 픽셀 수를 유지하려고 합니다(SDXL에 권장).", + "sd_snap_txt": "스냅 자동 조정 해상도", + "Source": "근원", + "Horde": "Horde", + "sd_auto_url": "예: {{auto_url}}", + "Authentication (optional)": "인증(선택사항)", + "Example: username:password": "예: 사용자 이름:비밀번호", + "Important:": "중요한:", + "sd_auto_auth_warning_1": "SD 웹 UI를 실행하세요", + "sd_auto_auth_warning_2": "Flag! SillyTavern 호스트 시스템에서 서버에 액세스할 수 있어야 합니다.", + "sd_drawthings_url": "예: {{drawthings_url}}", + "sd_drawthings_auth_txt": "UI에서 HTTP API 스위치가 활성화된 상태에서 DrawThings 앱을 실행하세요! SillyTavern 호스트 시스템에서 서버에 액세스할 수 있어야 합니다.", + "sd_vlad_url": "예: {{vlad_url}}", + "The server must be accessible from the SillyTavern host machine.": "SillyTavern 호스트 시스템에서 서버에 액세스할 수 있어야 합니다.", + "Hint: Save an API key in AI Horde API settings to use it here.": "힌트: 여기에서 사용하려면 AI Horde API 설정에 API 키를 저장하세요.", + "Allow NSFW images from Horde": "Horde의 NSFW 이미지 허용", + "Sanitize prompts (recommended)": "프롬프트 삭제(권장)", + "Automatically adjust generation parameters to ensure free image generations.": "무료 이미지 생성을 보장하기 위해 생성 매개변수를 자동으로 조정합니다.", + "Avoid spending Anlas": "Anlas 지출을 피하세요", + "Opus tier": "(오푸스 티어)", + "View my Anlas": "내 Anlas 보기", + "These settings only apply to DALL-E 3": "이 설정은 DALL-E 3에만 적용됩니다.", + "Image Style": "이미지 스타일", + "Image Quality": "이미지 품질", + "Standard": "기준", + "HD": "HD(고화질)", + "sd_comfy_url": "예: {{comfy_url}}", + "Open workflow editor": "워크플로우로 편집기 열기", + "Create new workflow": "새 워크플로우 만들기", + "Delete workflow": "워크플로우 삭제", + "Enhance": "향상시키다", + "Refine": "구체화", + "Decrisper": "더 명확하게", + "Sampling steps": "샘플링 단계 ()", + "Width": "너비 ()", + "Height": "높이 ()", + "Resolution": "해상도", + "Model": "모델", + "Ask every time": "매번 물어보기", + "Sampling method": "샘플링 방법", + "Message Template": "메시지 템플릿", + "Karras (not all samplers supported)": "Karras(일부 샘플러는 지원되지 않음)", + "SMEA versions of samplers are modified to perform better at high resolution.": "샘플러의 SMEA 버전은 고해상도에서 더 나은 성능을 발휘하도록 수정되었습니다.", + "SMEA": "SMEA", + "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "SMEA 샘플러의 DYN 변형은 종종 더 다양한 출력으로 이어지지만 매우 높은 해상도에서는 실패할 수 있습니다.", + "DYN": "DYN", + "Scheduler": "스케줄러", + "Restore Faces": "얼굴 디테일 복원", + "Hires. Fix": "고해상도 업스케일", + "Upscaler": "업스케일러", + "Upscale by": "고급화", + "Denoising strength": "노이즈 제거 강도", + "Hires steps (2nd pass)": "고용 단계(2차 패스)", + "Preset for prompt prefix and negative prompt": "프롬프트 접두사 및 부정적인 프롬프트에 대한 사전 설정", + "Style": "스타일", + "Save style": "스타일 저장", + "Delete style": "스타일 삭제", + "Common prompt prefix": "공통 프롬프트 접두사", + "sd_prompt_prefix_placeholder": "생성된 프롬프트가 삽입될 위치를 지정하려면 {prompt}를 사용하세요.", + "Negative common prompt prefix": "부정 공통 프롬프트 접두사", + "Character-specific prompt prefix": "문자별 프롬프트 접두사", + "Won't be used in groups.": "그룹에서는 사용되지 않습니다.", + "sd_character_prompt_placeholder": "현재 선택된 캐릭터를 설명하는 모든 특성입니다. 공통 프롬프트 접두사 뒤에 추가됩니다.\n예: 여성, 녹색 눈, 갈색 머리, 분홍색 셔츠", + "Character-specific negative prompt prefix": "문자별 부정적인 프롬프트 접두사", + "sd_character_negative_prompt_placeholder": "선택한 캐릭터에 나타나서는 안 되는 특성입니다. 부정적인 공통 프롬프트 접두사 뒤에 추가됩니다.\n예: 보석, 신발, 안경", + "Shareable": "공유 가능", + "Image Prompt Templates": "이미지 프롬프트 템플릿", + "Vectors Model Warning": "채팅 중에 모델을 변경할 때 벡터를 제거하는 것이 좋습니다. 그렇지 않으면 하위 수준의 결과가 발생합니다.", + "Translate files into English before processing": "처리하기 전에 파일을 영어로 번역하세요", + "Manager Users": "사용자 관리", + "New User": "새로운 사용자", + "Status:": "상태:", + "Created:": "만들어진:", + "Display Name:": "이름 표시하기:", + "User Handle:": "사용자 핸들:", + "Password:": "비밀번호:", + "Confirm Password:": "비밀번호 확인:", + "This will create a new subfolder...": "이렇게 하면 사용자 핸들을 폴더 이름으로 사용하여 /data/ 디렉터리에 새 하위 폴더가 생성됩니다.", + "Current Password:": "현재 비밀번호:", + "New Password:": "새 비밀번호:", + "Confirm New Password:": "새 암호를 확인합니다:", + "Debug Warning": "이 범주의 기능은 고급 사용자만을 위한 것입니다. 결과가 확실하지 않으면 아무 것도 클릭하지 마세요.", + "Execute": "실행하다", + "Are you sure you want to delete this user?": "이 사용자를 삭제하시겠습니까?", + "Deleting:": "삭제 중:", + "Also wipe user data.": "사용자 데이터도 삭제하세요.", + "Warning:": "경고:", + "This action is irreversible.": "이 작업은 되돌릴 수 없습니다.", + "Type the user's handle below to confirm:": "확인하려면 아래에 사용자 핸들을 입력하세요.", + "Import Characters": "캐릭터 가져오기", + "Enter the URL of the content to import": "가져올 콘텐츠의 URL을 입력하세요.", + "Supported sources:": "지원되는 소스:", + "char_import_1": "Chub 캐릭터 (다이렉트 링크 또는 ID)", + "char_import_example": "예:", + "char_import_2": "Chub Lorebook(직접 링크 또는 ID)", + "char_import_3": "JanitorAI 캐릭터(직접 링크 또는 UUID)", + "char_import_4": "Pygmalion.chat 문자(직접 링크 또는 UUID)", + "char_import_5": "AICharacterCards.com 캐릭터(직접 링크 또는 ID)", + "char_import_6": "직접 PNG 링크(참조", + "char_import_7": "허용된 호스트의 경우)", + "char_import_8": "RisuRealm 캐릭터 (직접링크)", + "Supports importing multiple characters.": "여러 문자 가져오기를 지원합니다.", + "Write each URL or ID into a new line.": "각 URL 또는 ID를 새 줄에 작성합니다.", + "Export for character": "캐릭터 내보내기", + "Export prompts for this character, including their order.": "내보내기는 순서를 포함하여 이 캐릭터에 대한 프롬프트를 표시합니다.", + "Export all": "모두 내보내기", + "Export all your prompts to a file": "모든 프롬프트를 파일로 내보내기", + "Insert prompt": "프롬프트 삽입", + "Delete prompt": "프롬프트 삭제", + "Import a prompt list": "프롬프트 목록 가져오기", + "Export this prompt list": "이 프롬프트 목록 내보내기", + "Reset current character": "현재 캐릭터 재설정", + "New prompt": "새로운 프롬프트", + "Prompts": "프롬프트", + "Total Tokens:": "총 토큰:", + "prompt_manager_tokens": "토큰", + "Are you sure you want to reset your settings to factory defaults?": "설정을 공장 기본값으로 재설정하시겠습니까?", + "Don't forget to save a snapshot of your settings before proceeding.": "계속하기 전에 설정의 스냅샷을 저장하는 것을 잊지 마세요.", + "Settings Snapshots": "설정 스냅샷", + "Record a snapshot of your current settings.": "현재 설정의 스냅샷을 기록하세요.", + "Make a Snapshot": "스냅샷 만들기", + "Restore this snapshot": "이 스냅샷 복원", + "Hi,": "안녕,", + "To enable multi-account features, restart the SillyTavern server with": "다중 계정 기능을 활성화하려면 SillyTavern 서버를 다시 시작하세요.", + "set to true in the config.yaml file.": "config.yaml 파일에서 true로 설정됩니다.", + "Account Info": "계정 정보", + "To change your user avatar, use the buttons below or select a default persona in the Persona Management menu.": "사용자 아바타를 변경하려면 아래 버튼을 사용하거나 페르소나 관리 메뉴에서 기본 페르소나를 선택하세요.", + "Set your custom avatar.": "맞춤형 아바타를 설정하세요.", + "Remove your custom avatar.": "맞춤 아바타를 삭제하세요.", + "Handle:": "핸들:", + "This account is password protected.": "이 계정은 비밀번호로 보호되어 있습니다.", + "This account is not password protected.": "이 계정은 비밀번호로 보호되어 있지 않습니다.", + "Account Actions": "계정 작업", + "Change Password": "비밀번호 변경", + "Manage your settings snapshots.": "설정 스냅샷을 관리하세요.", + "Download a complete backup of your user data.": "사용자 데이터의 전체 백업을 다운로드하세요.", + "Download Backup": "백업 다운로드", + "Danger Zone": "위험지대", + "Reset your settings to factory defaults.": "설정을 공장 기본값으로 재설정하세요.", + "Reset Settings": "설정 초기화", + "Wipe all user data and reset your account to factory settings.": "모든 사용자 데이터를 지우고 계정을 공장 설정으로 재설정하세요.", + "Reset Everything": "모든 것을 재설정", + "Reset Code:": "재설정 코드:", + "Want to update?": "업데이트 하시겠습니까?", + "How to start chatting?": "어떻게 채팅을 시작할 수 있나요?", + "Click _space": "해당 아이콘을 클릭하세요.", + "and connect to an": "그리고 API를 해당 탭에서 연결하세요.", + "and select a": "그리고 선택하세요.", + "Chat API": "채팅 API", + "and pick a character.": "그리고 원하는 캐릭터를 선택하세요.", + "You can browse a list of bundled characters in the": "번들 캐릭터 목록을 검색할 수 있습니다.", + "Download Extensions & Assets": "확장 프로그램 및 에셋 다운로드", + "Character Expressions": "캐릭터 감정 표현들", + "ext_translate_title": "채팅 번역", + "ext_translate_auto_mode": "자동 번역 모드", + "ext_translate_mode_none": "없음", + "ext_translate_mode_responses": "응답 자동 번역", + "ext_translate_mode_inputs": "입력 자동 번역", + "ext_translate_mode_both": "응답과 입력 모두 번역", + "ext_translate_mode_provider": "번역 공급자", + "ext_translate_target_lang": "번역 도착 언어", + "ext_translate_clear": "번역 지우기", + "ext_sum_title": "채팅 요약", + "ext_sum_with": "요약에 사용될 API:", + "ext_sum_main_api": "메인 API", + "Vector Storage": "벡터 저장소", + "menu within": "내의 메뉴", + "Translate text to English before classification": "분류 전에 텍스트를 영어로 번역합니다.", + "Show default images (emojis) if sprite missing": "해당하는 스프라이트가 없으면 기본 이미지 (이모지들)을 표시합니다.", + "Classifier API": "분류를 위한 API", + "Select the API for classifying expressions.": "감정 이미지들을 분류할 API를 선택하세요.", + "Local": "로컬", + "Extras": "외부", + "LLM": "대형 언어 모델(LLM)", + "LLM Prompt": "LLM 프롬프트", + "Will be used if the API doesn't support JSON schemas or function calling.": "API가 JSON 스키마나 함수 호출을 지원하지 않는 경우 사용됩니다.", + "Default / Fallback Expression": "기본 / 대체 감정들", + "Set the default and fallback expression being used when no matching expression is found.": "일치하는 표현이 없을 때 사용되는 기본 및 대체 표현을 설정합니다.", + "Custom Expressions": "커스텀 감정들", + "Can be set manually or with an _space": "수동으로 설정하거나 또는", + "space_ slash command.": "슬래시 명령어로 설정할 수 있습니다.", + "Open a chat to see the character expressions.": "캐릭터 감정을 보려면 채팅창을 열어주세요.", + "Sprite Folder Override": "스프라이트 폴더 덮어쓰기", + "Upload sprite pack (ZIP)": "스프라이트 압축팩 (ZIP) 업로드하기", + "Remove all image overrides": "모든 이미지 재정의 제거하기", + "Hint:": "힌트:", + "Create new folder in the _space": "사용자 데이터 경로에 있는", + "folder of your user data directory and name it as the name of the character.": "폴더에 새 폴더를 만들고 해당 폴더의 이름을 캐릭터의 이름으로 지정하세요.", + "Put images with expressions there. File names should follow the pattern:": "그리고 그곳에 표정이 담긴 이미지를 넣으세요. 파일 이름은 다음 패턴을 따라야 합니다:", + "Sprite set:": "스프라이트 세트:", + "sd_free_extend_txt": "무료 모드 프롬프트 확장", + "Confused or lost?": "혼란스러우시거나 길을 잃으셨나요?", + "click these icons!": "이 아이콘을 클릭하세요!", + "in the chat bar": "채팅 바에서", + "SillyTavern Documentation Site": "SillyTavern 공식 문서 사이트", + "Extras Installation Guide": "Extras 설치 안내서", + "Still have questions?": "아직 질문이 있으신가요?", + "Join the SillyTavern Discord": "SillyTavern 디스코드에 참여하세요", + "Post a GitHub issue": "GitHub 이슈 게시", + "Contact the developers": "개발자에게 연락하기", + "enable_functions_desc_1": "다양한 확장 프로그램에서 추가 기능을 제공하기 위한", + "enable_functions_desc_2": "기능 도구", + "enable_functions_desc_3": "를 사용할 수 있게 합니다.", + "Injection position. Relative (to other prompts in prompt manager) or In-chat @ Depth.": "삽입 깊이. 상대적인 (프롬프트 관리 목록에 있는 다른 프롬프트들에 비해) 또는 @Depth 깊이에 따라.", + "Instruct Template": "지시 템플릿", + "System Message Sequences": "시스템 메시지 시퀀스", + "System Prompt Sequences": "시스템 프롬프트 시퀀스", + "First User Prefix": "첫 번째 유저 접두사", + "Last User Prefix": "마지막 유저 접두사", + "System Prefix": "시스템 메시지 접두사", + "System Suffix": "시스템 메시지 접미사", + "Assistant Message Sequences": "어시스턴트 메시지 시퀀스", + "Assistant Prefix": "어시스턴트 메시지 접두사", + "Assistant Suffix": "어시스턴트 메시지 접미사", + "User Message Sequences": "유저 메시지 시퀀스", + "User Prefix": "유저 메시지 접미사", + "User Suffix": "유저 메시지 접두사", + "Groups and Past Personas": "그룹과 과거 페르소나들", + "Never": "절대 추가하지 않음", + "Always": "항상 추가함", + "Separators as Stop Strings": "구분 기호를 정지 문자열로 사용하기", + "Names as Stop Strings": "캐릭터의 이름들을 정지 문자열로 사용하기", + "Allow Post-History Instructions": "Post-History 지침 허용", + "Image Captioning": "이미지 캡셔닝", + "Automatically caption images": "자동으로 이미지에 대한 설명 문장으로 나타내기", + "Edit captions before saving": "저장하기 전에 이미지에 대한 설명 문장 편집하기", + "Enable Quick Replies": "빠른 답장 활성화", + "Combine Quick Replies": "빠른 답장 결합하기", + "Show Popout Button": "팝아웃 버튼 표시 (데스크톱에서)", + "Global Quick Reply Sets": "글로벌 빠른 답장 세트들", + "Edit Quick Replies": "빠른 답변 편집하기", + "Disable send (insert into input field)": "보내기 비활성화 (입력 필드에 삽입)", + "Place quick reply before input": "인풋 전에 빠른 답변 위치하게 하기", + "Inject user input automatically": "사용자 인풋 자동으로 주입하기", + "(if disabled, use ": "비활성화된 경우,", + "macro for manual injection)": "매크로를 사용하여 수동으로 주입하세요.", + "Only apply color as accent": "색상은 오직 강조로써만 적용됩니다", + "qr--colorClear": "색상 지우기", + "Color": "색상", + "world_button_title": "캐릭터 로어. 클릭하여 로드하세요. Shift를 클릭하면 '월드 인포 링크' 팝업이 열립니다.", + "Select TTS Provider": "TTS 공급자 선택", + "tts_enabled": "활성화", + "Narrate user messages": "사용자 메시지 나레이션", + "Auto Generation": "자동 생성", + "Requires auto generation to be enabled.": "자동 생성이 활성화 된 상태여야 합니다.", + "Narrate by paragraphs (when streaming)": "(스트리밍이 진행 중일 때) 단락 별로 설명하기", + "Only narrate quotes": "대사만 나레이션 하기", + "Ignore text, even quotes, inside asterisk": "대사나 별표에 관계없이 모든 텍스트를 무시하기", + "Narrate only the translated text": "오직 번역된 텍스트만 나레이션", + "Skip codeblocks": "코드 블럭 안의 내용 읽지 않기", + "Skip tagged blocks": "태그 안의 내용 읽지 않기", + "Pass Asterisks to TTS Engine": "TTS 엔진에 별표 전달하기", + "Audio Playback Speed": "음성 재생 속도", + "Vectorization Model": "벡터화 모델", + "Keep model in memory": "모델을 메모리에 유지하기", + "Hint: Set the URL in the API connection settings.": "힌트: API 연결 설정에서 URL을 설정하세요.", + "The server MUST be started with the --embedding flag to use this feature!": "이 기능을 사용하려면 서버를 --embedding 플래그와 함께 시작해야 합니다!", + "Click to set": "설정하려면 클릭하세요", + "Chunk boundary": "청크 바운더리", + "World Info settings": "월드인포 설정", + "Enable for World Info": "월드인포에 활성화", + "Vectorization Source": "벡터화 근원", + "File vectorization settings": "파일 벡터화 설정", + "Enable for files": "파일에 활성화", + "Chat vectorization settings": "채팅 벡터화 설정", + "Enabled for chat messages": "채팅 메시지에 활성화", + "Injection Position": "삽입 깊이", + "Chunk size (chars)": "청크 사이즈 (단위: 문자당)", + "Vector Summarization": "벡터 요약", + "Summarize chat messages for vector generation": "벡터 생성을 위한 채팅 메시지 요약하기", + "Warning: This will slow down vector generation drastically, as all messages have to be summarized first.": "경고: 모든 메시지를 먼저 요약해야 하므로 벡터 생성 속도가 크게 느려질 것입니다.", + "Summarize chat messages when sending": "채팅 메시지를 전송할 때 요약하기", + "Warning: This might cause your sent messages to take a bit to process and slow down response time.": "경고: 이로 인해 전송한 메시지가 처리되는 데 시간이 걸리고 응답 속도가 느려질 수 있습니다.", + "Summarize with:": "요약을 위해 사용:", + "Summary Prompt:": "요약 프롬프트", + "Only used when Main API or WebLLM Extension is selected.": "메인 API 또는 WebLLM 확장이 선택될 때만 사용됩니다.", + "Old messages are vectorized gradually as you chat. To process all previous messages, click the button below.": "이전 메시지는 채팅하는 동안 점진적으로 벡터화됩니다. 모든 이전 메시지를 처리하려면 아래 버튼을 클릭하세요.", + "Vectorize All": "전부 벡터화", + "Purge Vectors": "벡터 정리", + "View Stats": "상태 확인", + "Connection Profile": "연결 프로필", + "Prompt Content": "프롬프트 내용", + "Instruct Sequences": "지시 시퀀스", + "Prefer Character Card Instructions": "캐릭터 카드의 지시사항을 선호", + "If checked and the character card contains a Post-History Instructions override, use that instead": "활성화 된 경우, 캐릭터 카드에 Post-History 지시 무시 항목이 포함되어 있으면, 카드 지시사항의 내용으로 대신 사용합니다.", + "Auto-select Input Text": "입력 텍스트 자동 선택", + "Enable auto-select of input text in some text fields when clicking/selecting them. Applies to popup input textboxes, and possible other custom input fields.": "일부 텍스트 필드를 클릭하거나 선택할 때 자동으로 입력된 텍스트가 선택되도록 설정합니다. 팝업 입력창과 기타 커스텀 입력 필드에 적용됩니다.", + "Markdown Hotkeys": "마크다운 입력 단축키", + "markdown_hotkeys_desc": "특정 텍스트 입력창에서 마크다운 형식 문자를 입력하기 위한 단축키를 활성화합니다. '/help hotkeys'를 참고하세요.", + "Show group chat queue": "그룹 채팅 대기열 표시", + "In group chat, highlight the character(s) that are currently queued to generate responses and the order in which they will respond.": "그룹 채팅에서 응답을 생성하기 위해 현재 대기 중인 캐릭터와 응답할 순서를 강조 표시합니다.", + "Quick 'Impersonate' button": "빠른 '사칭' 버튼", + "Show a button in the input area to ask the AI to impersonate your character for a single message": "입력 영역에 AI에게 한 메시지 동안 당신의 캐릭터 연기를 사칭하도록 요청하는 버튼을 표시합니다.", + "Injection Template": "삽입 템플릿", + "Query messages": "쿼리 메시지 수", + "Score threshold": "점수 임계값", + "ext_sum_include_wi_scan": "월드 인포를 요약 범위에 포함", + "(use _space": "이", + "macro)": "매크로를 사용하세요", + "Disable Send (Insert Into Input Field)": "전송 비활성화 (입력 필드에 삽입)", + "Place Quick Reply Before Input": "빠른 답변을 입력란 앞에 배치", + "Chat Message Visibility (by source)": "채팅 메시지 가시성 (근원별)", + "Uncheck to hide the extension's messages in chat prompts.": "체크를 해제하여 채팅 프롬프트에서 확장 프로그램의 메시지를 숨기세요.", + "Extensions Menu": "확장 메뉴", + "Slash Command": "슬래시 명령어", + "Interactive Mode": "인터랙티브 모드", + "Load a custom asset list or select": "커스텀 에셋 목록을 불러오거나", + "to install 3rd party extensions.": "를 선택하여 3rd 파티 확장 프로그램을 설치하세요.", + "Assets URL": "에셋 URL", + "Load an asset list": "에셋 목록을 불러옵니다.", + "ext_translate_btn_chat": "채팅 번역하기", + "ext_translate_btn_input": "입력 번역하기", + "Ask": "묻기", + "tag_import_none": "불러오지 않음", + "tag_import_all": "전부", + "tag_import_existing": "기존 태그 참조", + "You can add more": "원한다면", + "or_welcome": "또는", + "from other websites": "를 통해 다른 웹사이트들로부터 불러올 수 있습니다.", + "Go to the": "추가 기능 설치를 하려면", + "to install additional features.": "으로 가세요.", + "Master Import": "마스터 불러오기", + "Master Export": "마스터 내보내기", + "Chat Quick Reply Sets": "채팅 빠른 답장 세트들" +} diff --git a/jiuguan2025cc/public/locales/lang.json b/jiuguan2025cc/public/locales/lang.json new file mode 100644 index 0000000000000000000000000000000000000000..5da4de4acf1249e5e65ec3331c685cdc1b91e2b5 --- /dev/null +++ b/jiuguan2025cc/public/locales/lang.json @@ -0,0 +1,17 @@ +[ + { "lang": "ar-sa", "display": "عربي (Arabic)" }, + { "lang": "zh-cn", "display": "简体中文 (Chinese) (Simplified)" }, + { "lang": "zh-tw", "display": "繁體中文 (Chinese) (Taiwan)" }, + { "lang": "nl-nl", "display": "Nederlands (Dutch)" }, + { "lang": "de-de", "display": "Deutsch (German)" }, + { "lang": "fr-fr", "display": "Français (French)" }, + { "lang": "is-is", "display": "íslenska (Icelandic)" }, + { "lang": "it-it", "display": "Italiano (Italian)" }, + { "lang": "ja-jp", "display": "日本語 (Japanese)" }, + { "lang": "ko-kr", "display": "한국어 (Korean)" }, + { "lang": "pt-pt", "display": "Português (Portuguese brazil)" }, + { "lang": "ru-ru", "display": "Русский (Russian)" }, + { "lang": "es-es", "display": "Español (Spanish)" }, + { "lang": "uk-ua", "display": "Yкраїнська (Ukrainian)" }, + { "lang": "vi-vn", "display": "Tiếng Việt (Vietnamese)" } +] \ No newline at end of file diff --git a/jiuguan2025cc/public/locales/nl-nl.json b/jiuguan2025cc/public/locales/nl-nl.json new file mode 100644 index 0000000000000000000000000000000000000000..b34b21a64996dfd90413975ebef56b8f96aa8301 --- /dev/null +++ b/jiuguan2025cc/public/locales/nl-nl.json @@ -0,0 +1,1443 @@ +{ + "Favorite": "Favoriet", + "Tag": "Label", + "Duplicate": "Duplicaat", + "Persona": "Persona", + "Delete": "Verwijderen", + "AI Response Configuration": "AI-responsconfiguratie", + "AI Configuration panel will stay open": "Het AI-configuratiescherm blijft open", + "clickslidertips": "Klik om waarden handmatig in te voeren.", + "MAD LAB MODE ON": "MAD LAB-MODUS AAN", + "Documentation on sampling parameters": "Documentatie over steekproefparameters", + "kobldpresets": "Kobold voorinstellingen", + "guikoboldaisettings": "KoboldAI-interface-instellingen", + "Update current preset": "Huidige voorinstelling bijwerken", + "Save preset as": "Instellingen opslaan als", + "Import preset": "Voorinstelling importeren", + "Export preset": "Voorinstelling exporteren", + "Restore current preset": "Herstel huidige voorinstelling", + "Delete the preset": "De voorinstelling verwijderen", + "novelaipresets": "NovelAI-voorinstellingen", + "Default": "Standaard", + "openaipresets": "OpenAI-voorinstellingen", + "Text Completion presets": "Tekstvervolledigingsvoorinstellingen", + "AI Module": "AI-module", + "Changes the style of the generated text.": "Verandert de stijl van de gegenereerde tekst.", + "No Module": "Geen module", + "Instruct": "Instrueren", + "Prose Augmenter": "Proza Augmenter", + "Text Adventure": "Tekst avontuur", + "response legth(tokens)": "Reactielengte (tokens)", + "Streaming": "Streaming", + "Streaming_desc": "Toon de reactie beetje bij beetje zoals deze wordt gegenereerd", + "context size(tokens)": "Contextgrootte (tokens)", + "unlocked": "Ontgrendeld", + "Only enable this if your model supports context sizes greater than 8192 tokens": "Schakel dit alleen in als uw model contextgroottes ondersteunt groter dan 8192 tokens", + "Max prompt cost:": "Maximale promptkosten:", + "Display the response bit by bit as it is generated.": "Toon het antwoord stuk voor stuk terwijl het wordt gegenereerd.", + "When this is off, responses will be displayed all at once when they are complete.": "Als dit uit staat, worden reacties in één keer weergegeven wanneer ze compleet zijn.", + "Temperature": "Temperatuur", + "rep.pen": "Herhalingsstraf", + "Rep. Pen. Range.": "Herh. Pen. Bereik.", + "Rep. Pen. Slope": "Helling van de herhalingsstraf", + "Rep. Pen. Freq.": "Herh. Pen. Frequentie.", + "Rep. Pen. Presence": "Herh. Pen. Aanwezigheid", + "TFS": "TFS", + "Phrase Repetition Penalty": "Straf voor zinsherhaling", + "Off": "Uit", + "Very light": "Zeer licht", + "Light": "Licht", + "Medium": "Gemiddeld", + "Aggressive": "Agressief", + "Very aggressive": "Zeer agressief", + "Unlocked Context Size": "Ontgrendelde Context Grootte", + "Unrestricted maximum value for the context slider": "Onbeperkte maximale waarde voor de contextschuifregelaar", + "Context Size (tokens)": "Contextgrootte (tokens)", + "Max Response Length (tokens)": "Maximale lengte van het antwoord (tokens)", + "Multiple swipes per generation": "Meerdere swipes per generatie", + "Enable OpenAI completion streaming": "OpenAI voltooiingsstreaming inschakelen", + "Frequency Penalty": "Frequentieboete", + "Presence Penalty": "Aanwezigheidsboete", + "Count Penalty": "Tel straf", + "Top K": "Top K", + "Top P": "Top P", + "Repetition Penalty": "Herhaling Straf", + "Min P": "Min P", + "Top A": "Top A", + "Quick Prompts Edit": "Snelle Prompt Bewerking", + "Main": "Hoofd", + "NSFW": "NSFW", + "Jailbreak": "Jailbreak", + "Utility Prompts": "Hulpprogramma Prompts", + "Impersonation prompt": "Imitatie-prompt", + "Restore default prompt": "Standaardprompt herstellen", + "Prompt that is used for Impersonation function": "Prompt die wordt gebruikt voor de imitatie-functie", + "World Info Format Template": "Wereldinfo-formaat sjabloon", + "Restore default format": "Standaardformaat herstellen", + "Wraps activated World Info entries before inserting into the prompt.": "Verpakt geactiveerde Wereldinfo-items voordat deze in de prompt worden ingevoegd.", + "scenario_format_template_part_1": "Gebruik", + "scenario_format_template_part_2": "om een ​​plaats te markeren waar de inhoud wordt ingevoegd.", + "Scenario Format Template": "Sjabloon voor scenario-indeling", + "Personality Format Template": "Sjabloon voor persoonlijkheidsformaat", + "Group Nudge Prompt Template": "Sjabloon voor groepsaanmoedigingsprompt", + "Sent at the end of the group chat history to force reply from a specific character.": "Verzonden aan het einde van de geschiedenis van de groepschat om een ​​antwoord van een specifiek personage af te dwingen.", + "New Chat": "Nieuw gesprek", + "Restore new chat prompt": "Herstel nieuwe chatprompt", + "Set at the beginning of the chat history to indicate that a new chat is about to start.": "Ingesteld aan het begin van de chatgeschiedenis om aan te geven dat er een nieuwe chat gaat starten.", + "New Group Chat": "Nieuwe groepschat", + "Restore new group chat prompt": "Standaardprompt herstellen", + "Set at the beginning of the chat history to indicate that a new group chat is about to start.": "Ingesteld aan het begin van de chatgeschiedenis om aan te geven dat er een nieuwe groepschat gaat starten.", + "New Example Chat": "Nieuwe voorbeeldchat", + "Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.": "Ingesteld aan het begin van Dialoogvoorbeelden om aan te geven dat er een nieuwe voorbeeldchat gaat starten.", + "Continue nudge": "Ga door met duwen", + "Set at the end of the chat history when the continue button is pressed.": "Ingesteld aan het einde van de chatgeschiedenis wanneer op de knop Doorgaan wordt gedrukt.", + "Replace empty message": "Vervang leeg bericht", + "Send this text instead of nothing when the text box is empty.": "Stuur deze tekst in plaats van niets wanneer het tekstvak leeg is.", + "Seed": "Zaad", + "Set to get deterministic results. Use -1 for random seed.": "Ingesteld om deterministische resultaten te verkrijgen. Gebruik -1 voor willekeurig zaad.", + "Temperature controls the randomness in token selection": "Temperatuur regelt de willekeurigheid bij het selecteren van tokens", + "Top_K_desc": "Top K stelt een maximumhoeveelheid top tokens in die kunnen worden gekozen", + "Top_P_desc": "Top P (ook bekend als kernsampling)", + "Typical P": "Typisch P", + "Typical_P_desc": "Typische P-sampling geeft prioriteit aan tokens op basis van hun afwijking van de gemiddelde entropie van de set", + "Min_P_desc": "Min P stelt een basismimimumkans in", + "Top_A_desc": "Top A stelt een drempel in voor tokenselectie op basis van het kwadraat van de hoogste tokenkans", + "Tail_Free_Sampling_desc": "Staartvrije sampling (TFS)", + "rep.pen range": "Herhalingsstrafbereik", + "Mirostat": "Mirosta", + "Mode": "Modus", + "Mirostat_Mode_desc": "Een waarde van 0 schakelt Mirostat volledig uit. 1 is voor Mirostat 1.0 en 2 is voor Mirostat 2.0", + "Tau": "Tau", + "Mirostat_Tau_desc": "Regelt de variabiliteit van Mirostat-uitvoer", + "Eta": "Eta", + "Mirostat_Eta_desc": "Regelt de leersnelheid van Mirostat", + "Ban EOS Token": "Ban EOS-token", + "Ban_EOS_Token_desc": "Verbied het End-of-Sequence (EOS) token met KoboldCpp (en mogelijk ook andere tokens met KoboldAI).\rGoed voor het schrijven van verhalen, maar mag niet worden gebruikt voor chat- en instructiemodus.", + "GBNF Grammar": "GBNF Grammatica", + "Type in the desired custom grammar": "Typ de gewenste aangepaste grammatica", + "Samplers Order": "Samplers Volgorde", + "Samplers will be applied in a top-down order. Use with caution.": "Samplers worden toegepast in een top-down volgorde. Gebruik met voorzichtigheid.", + "Tail Free Sampling": "Staartvrije sampling", + "Load koboldcpp order": "Laad koboldcpp-bestelling", + "Preamble": "Preambule", + "Use style tags to modify the writing style of the output.": "Gebruik stijltags om de schrijfstijl van de uitvoer te wijzigen.", + "Banned Tokens": "Verboden tokens", + "Sequences you don't want to appear in the output. One per line.": "Sequenties die je niet in de uitvoer wilt laten verschijnen. Één per regel.", + "Logit Bias": "Logit Bias", + "Add": "Toevoegen", + "Helps to ban or reenforce the usage of certain words": "Helpt bij het verbieden of versterken van het gebruik van bepaalde woorden", + "CFG Scale": "CFG Schaal", + "Negative Prompt": "Negatieve prompt", + "Add text here that would make the AI generate things you don't want in your outputs.": "Voeg hier tekst toe die ervoor zou zorgen dat de AI dingen genereert die je niet wilt in je uitvoer.", + "Used if CFG Scale is unset globally, per chat or character": "Wordt gebruikt als CFG-schaal wereldwijd, per chat of karakter niet is ingesteld.", + "Mirostat Tau": "Mirostat Tau", + "Mirostat LR": "Mirostat LR", + "Min Length": "Minimale lengte", + "Top K Sampling": "Top K-Bemonstering", + "Nucleus Sampling": "Nucleus Bemonstering", + "Top A Sampling": "Top A-Bemonstering", + "CFG": "CFG", + "Neutralize Samplers": "Neutraliseer Samplers", + "Set all samplers to their neutral/disabled state.": "Stel alle samplers in op hun neutrale/uitgeschakelde toestand.", + "Sampler Select": "Sampler selecteren", + "Customize displayed samplers or add custom samplers.": "Pas weergegeven samplers aan of voeg aangepaste samplers toe.", + "Epsilon Cutoff": "Epsilon-afkapwaarde", + "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "Epsilon-cutoff stelt een kansdrempel in waaronder tokens worden uitgesloten van bemonstering", + "Eta Cutoff": "Eta-afkapwaarde", + "Eta_Cutoff_desc": "Eta-cutoff is de belangrijkste parameter van de speciale Eta Bemonsteringstechniek. In eenheden van 1e-4; een redelijke waarde is 3. Stel in op 0 om uit te schakelen. Zie het artikel Truncation Sampling as Language Model Desmoothing van Hewitt et al. (2022) voor details.", + "rep.pen decay": "Rep-pen verval", + "Encoder Rep. Pen.": "Encoder herhalingsstraf", + "No Repeat Ngram Size": "Geen herhaalde ngram-grootte", + "Skew": "Scheef", + "Max Tokens Second": "Maximale Tokens per Seconde", + "Smooth Sampling": "Vlotte bemonstering", + "Smooth_Sampling_desc": "Hiermee kunt u kwadratische/kubieke transformaties gebruiken om de verdeling aan te passen. Lagere waarden voor de afvlakkingsfactor zullen creatiever zijn, meestal tussen 0,2 en 0,3 is de sweetspot (ervan uitgaande dat de curve = 1 is). Hogere waarden voor de Smoothing Curve maken de curve steiler, waardoor keuzes met een lage waarschijnlijkheid agressiever worden bestraft. Een curve van 1,0 komt overeen met alleen het gebruik van de afvlakkingsfactor.", + "Smoothing Factor": "Gladstrijkfactor", + "Smoothing Curve": "Gladmakende curve", + "DRY_Repetition_Penalty_desc": "DRY bestraft tokens die het einde van de invoer zouden verlengen in een reeks die eerder in de invoer heeft plaatsgevonden. Zet de vermenigvuldiger op 0 om uit te schakelen.", + "DRY Repetition Penalty": "DROOG Herhalingsstraf", + "DRY_Multiplier_desc": "Stel in op waarde > 0 om DROGEN in te schakelen. Regelt de omvang van de straf voor de kortst bestrafte reeksen.", + "Multiplier": "Vermenigvuldiger", + "DRY_Base_desc": "Bepaalt hoe snel de straf toeneemt naarmate de reeks langer wordt.", + "Base": "Baseren", + "DRY_Allowed_Length_desc": "De langste reeks die kan worden herhaald zonder te worden bestraft.", + "Allowed Length": "Toegestane lengte", + "Penalty Range": "Strafbereik", + "DRY_Sequence_Breakers_desc": "Tokens waarover het matchen van de reeksen niet wordt voortgezet. Opgegeven als een door komma's gescheiden lijst met tekenreeksen tussen aanhalingstekens.", + "Sequence Breakers": "Sequentiebrekers", + "JSON-serialized array of strings.": "JSON-geserialiseerde reeks strings.", + "Dynamic Temperature": "Dynamische Temperatuur", + "Scale Temperature dynamically per token, based on the variation of probabilities": "Pas temperatuur dynamisch toe per token, op basis van de variatie van kansen", + "Minimum Temp": "Minimale temperatuur", + "Maximum Temp": "Maximale temperatuur", + "Exponent": "Exponent", + "Mirostat (mode=1 is only for llama.cpp)": "Mirostat (modus=1 is alleen voor llama.cpp)", + "Mirostat_desc": "Mirostat is een thermostaat voor de outputperplexiteit", + "Mirostat Mode": "Mirostat-modus", + "Variability parameter for Mirostat outputs": "Variabiliteitsparameter voor Mirostat-uitvoer", + "Mirostat Eta": "Mirostat Eta", + "Learning rate of Mirostat": "Leersnelheid van Mirostat", + "Beam search": "Beam-zoeken", + "Helpful tip coming soon.": "Handige tip volgt binnenkort.", + "Number of Beams": "Aantal beams", + "Length Penalty": "Lengteboete", + "Early Stopping": "Vroegtijdig stoppen", + "Contrastive search": "Contrastieve zoekopdracht", + "Penalty Alpha": "Straf alfa", + "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "Sterkte van de regulariseringsterm voor contrastieve zoekopdrachten. Stel in op 0 om CS uit te schakelen.", + "Do Sample": "Monster", + "Add BOS Token": "Voeg BOS-token toe", + "Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative": "Voeg het BOS-token toe aan het begin van prompts. Het uitschakelen hiervan kan de antwoorden creatiever maken", + "Ban the eos_token. This forces the model to never end the generation prematurely": "Ban het EOS-token. Dit dwingt het model om de generatie nooit voortijdig te beëindigen", + "Ignore EOS Token": "Negeer EOS-token", + "Ignore the EOS Token even if it generates.": "Negeer het EOS-token, zelfs als het wordt gegenereerd.", + "Skip Special Tokens": "Speciale tokens overslaan", + "Temperature Last": "Laatste temperatuur", + "Temperature_Last_desc": "Gebruik de temperatuursampler als laatste", + "Speculative Ngram": "Speculatieve Ngram", + "Use a different speculative decoding method without a draft model": "Gebruik een andere speculatieve decoderingsmethode zonder conceptmodel.\rHet gebruik van een conceptmodel heeft de voorkeur. Speculatief ngram is niet zo effectief.", + "Spaces Between Special Tokens": "Ruimten tussen speciale tokens", + "LLaMA / Mistral / Yi models only": "Alleen LLaMA / Mistral / Yi-modellen", + "Example: some text [42, 69, 1337]": "Voorbeeld: wat tekst [42, 69, 1337]", + "Classifier Free Guidance. More helpful tip coming soon": "Klassificatorvrije begeleiding. Meer nuttige tips volgen binnenkort", + "Scale": "Schaal", + "JSON Schema": "JSON-schema", + "Type in the desired JSON schema": "Typ het gewenste JSON-schema", + "Grammar String": "Grammaticareeks", + "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF of EBNF, hangt af van de gebruikte backend. Als u dit gebruikt, moet u weten welke.", + "Top P & Min P": "Top P & Min P", + "Load default order": "Standaardvolgorde laden", + "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "alleen lama.cpp. Bepaalt de volgorde van de samplers. Als de Mirostat-modus niet 0 is, wordt de samplervolgorde genegeerd.", + "Sampler Priority": "Prioriteit van de sampler", + "Ooba only. Determines the order of samplers.": "Alleen Ooba. Bepaalt de volgorde van samplers.", + "Character Names Behavior": "Karakternamen Gedrag", + "Helps the model to associate messages with characters.": "Helpt het model berichten aan karakters te koppelen.", + "None": "Geen", + "character_names_default": "Behalve voor groepen en vroegere persona's. Zorg er anders voor dat u namen opgeeft in de prompt.", + "Don't add character names.": "Voeg geen namen van personages toe.", + "Completion": "Voltooiingsobject", + "character_names_completion": "Er zijn beperkingen van toepassing: alleen Latijnse alfanumerieke tekens en onderstrepingstekens. Werkt niet voor alle bronnen, met name: Claude, MistralAI, Google.", + "Add character names to completion objects.": "Voeg karakternamen toe aan voltooiingsobjecten.", + "Message Content": "Berichtinhoud", + "Prepend character names to message contents.": "Voeg tekennamen toe aan de inhoud van het bericht.", + "Continue Postfix": "Ga door met Postfix", + "The next chunk of the continued message will be appended using this as a separator.": "Het volgende deel van het vervolgbericht wordt toegevoegd en gebruikt dit als scheidingsteken.", + "Space": "Ruimte", + "Newline": "Nieuwe lijn", + "Double Newline": "Dubbele nieuwe lijn", + "Wrap user messages in quotes before sending": "Wikkel gebruikersberichten in aanhalingstekens voordat u ze verzendt", + "Wrap in Quotes": "In Quotes plaatsen", + "Wrap entire user message in quotes before sending.": "Wikkel het volledige gebruikersbericht in aanhalingstekens voordat u het verzendt.", + "Leave off if you use quotes manually for speech.": "Laat dit weg als u handmatig aanhalingstekens gebruikt voor spraak.", + "Continue prefill": "Doorgaan met voorvullen", + "Continue sends the last message as assistant role instead of system message with instruction.": "Doorgaan stuurt het laatste bericht als assistentrol in plaats van een systeembericht met instructie.", + "Squash system messages": "Systeemberichten samenvoegen", + "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Combineert opeenvolgende systeemberichten tot één (exclusief voorbeeld dialogen). Kan de coherentie verbeteren voor sommige modellen.", + "Enable function calling": "Schakel functieaanroepen in", + "Send inline images": "Inline afbeeldingen verzenden", + "image_inlining_hint_1": "Verzendt afbeeldingen in prompts als het model dit ondersteunt (bijvoorbeeld GPT-4V, Claude 3 of Llava 13B).\n Gebruik de", + "image_inlining_hint_2": "actie op elk bericht of de", + "image_inlining_hint_3": "menu om een ​​afbeeldingsbestand aan de chat toe te voegen.", + "Inline Image Quality": "Inline-beeldkwaliteit", + "openai_inline_image_quality_auto": "Auto", + "openai_inline_image_quality_low": "Laag", + "openai_inline_image_quality_high": "Hoog", + "Use AI21 Tokenizer": "Gebruik AI21 Tokenizer", + "Use the appropriate tokenizer for Jurassic models, which is more efficient than GPT's.": "Gebruik de juiste tokenizer voor Jurassic-modellen, die efficiënter is dan GPT's.", + "Use Google Tokenizer": "Google Tokenizer gebruiken", + "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "Gebruik de juiste tokenizer voor Google-modellen via hun API. Langzamere promptverwerking, maar biedt veel nauwkeuriger token-telling.", + "Use system prompt": "Gebruik systeemprompt", + "(Gemini 1.5 Pro/Flash only)": "(alleen Gemini 1.5 Pro/Flash)", + "Merges_all_system_messages_desc_1": "Voegt alle systeemberichten samen tot aan het eerste bericht met een niet-systeemrol, en verzendt ze in een", + "Merges_all_system_messages_desc_2": "veld.", + "Assistant Prefill": "Assistent Voorvullen", + "Start Claude's answer with...": "Start het antwoord van Claude met...", + "Assistant Impersonation Prefill": "Vooraf invullen van assistent-imitatie", + "Use system prompt (Claude 2.1+ only)": "Gebruik systeemprompt (alleen Claude 2.1+)", + "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "Verzend de systeemprompt voor ondersteunde modellen. Als dit is uitgeschakeld, wordt het gebruikersbericht toegevoegd aan het begin van de prompt.", + "User first message": "Bericht van de gebruiker eerst", + "Restore User first message": "Herstel gebruiker eerste bericht", + "Human message": "Menselijke boodschap, instructie, enz.\nVoegt niets toe als het leeg is, d.w.z. vereist een nieuwe prompt met de rol 'gebruiker'.", + "New preset": "Nieuwe voorinstelling", + "Delete preset": "Voorinstelling verwijderen", + "View / Edit bias preset": "Biasvoorinstelling bekijken / bewerken", + "Add bias entry": "Biasvermelding toevoegen", + "Most tokens have a leading space.": "De meeste tokens hebben een leidende spatie.", + "API Connections": "API-verbindingen", + "Text Completion": "Tekstvoltooiing", + "Chat Completion": "Chat-voltooiing", + "NovelAI": "NovelAI", + "AI Horde": "AI Horde", + "KoboldAI": "KoboldAI", + "Avoid sending sensitive information to the Horde.": "Vermijd het verzenden van gevoelige informatie naar de Horde.", + "Review the Privacy statement": "Bekijk de privacyverklaring", + "Register a Horde account for faster queue times": "Registreer een Horde-account voor snellere wachttijden", + "Learn how to contribute your idle GPU cycles to the Horde": "Leer hoe je je ongebruikte GPU-cycli kunt bijdragen aan de Horde", + "Adjust context size to worker capabilities": "Pas de contextgrootte aan aan de mogelijkheden van de werknemer", + "Adjust response length to worker capabilities": "Pas de lengte van de reactie aan aan de mogelijkheden van de werknemer", + "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "Kan helpen bij slechte reacties door alleen de goedgekeurde werknemers in de wachtrij te zetten. Kan de responstijd vertragen.", + "Trusted workers only": "Alleen vertrouwde werknemers", + "API key": "API-sleutel", + "Get it here:": "Haal het hier:", + "Register": "Registreren", + "View my Kudos": "Mijn Kudos bekijken", + "Enter": "Invoeren", + "to use anonymous mode.": "om de anonieme modus te gebruiken.", + "Clear your API key": "Wis uw API-sleutel", + "For privacy reasons, your API key will be hidden after you reload the page.": "Om privacyredenen wordt uw API-sleutel verborgen nadat u de pagina opnieuw hebt geladen.", + "Models": "Modellen", + "Refresh models": "Modellen vernieuwen", + "-- Horde models not loaded --": "-- Horde-modellen niet geladen --", + "Not connected...": "Niet verbonden...", + "API url": "API-url", + "Example: http://127.0.0.1:5000/api ": "Voorbeeld: http://127.0.0.1:5000/api", + "Connect": "Verbinden", + "Cancel": "Annuleren", + "Novel API key": "NovelAPI-sleutel", + "Get your NovelAI API Key": "Ontvang uw NovelAI API-sleutel", + "Enter it in the box below": "Voer het in het vak hieronder in", + "Novel AI Model": "Novel AI-model", + "No connection...": "Geen verbinding...", + "API Type": "API-type", + "Default (completions compatible)": "Standaard [OpenAI /completions compatibel: oobabooga, LM Studio, etc.]", + "TogetherAI API Key": "TogetherAI API-sleutel", + "TogetherAI Model": "TogetherAI-model", + "-- Connect to the API --": "-- Verbinding maken met de API --", + "OpenRouter API Key": "OpenRouter API-sleutel", + "Click Authorize below or get the key from": "Klik op Autoriseren hieronder of haal de sleutel op bij", + "View Remaining Credits": "Bekijk het resterende krediet", + "OpenRouter Model": "OpenRouter-model", + "Model Providers": "Modelaanbieders", + "InfermaticAI API Key": "InfermaticAI API-sleutel", + "InfermaticAI Model": "InfermaticAI-model", + "DreamGen API key": "DreamGen API-sleutel", + "DreamGen Model": "DreamGen-model", + "Mancer API key": "Mancer API-sleutel", + "Mancer Model": "Mancer-model", + "Make sure you run it with": "Zorg ervoor dat u het uitvoert met", + "flag": "vlag", + "API key (optional)": "API-sleutel (optioneel)", + "Server url": "Server-URL", + "Example: 127.0.0.1:5000": "Voorbeeld: 127.0.0.1:5000", + "Custom model (optional)": "Aangepast model (optioneel)", + "vllm-project/vllm": "vllm-project/vllm (OpenAI API-wrappermodus)", + "vLLM API key": "vLLM API-sleutel", + "Example: 127.0.0.1:8000": "Voorbeeld: http://127.0.0.1:8000", + "vLLM Model": "vLLM-model", + "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (Wrappermodus voor OpenAI API)", + "Aphrodite API key": "Aphrodite API-sleutel", + "Aphrodite Model": "Aphrodite-model", + "ggerganov/llama.cpp": "ggerganov/llama.cpp (Output-server)", + "Example: 127.0.0.1:8080": "Voorbeeld: 127.0.0.1:8080", + "Example: 127.0.0.1:11434": "Voorbeeld: 127.0.0.1:11434", + "Ollama Model": "Ollama-model", + "Download": "Downloaden", + "Tabby API key": "Tabby API-sleutel", + "koboldcpp API key (optional)": "koboldcpp API-sleutel (optioneel)", + "Example: 127.0.0.1:5001": "Voorbeeld: 127.0.0.1:5001", + "Authorize": "Toestemming geven", + "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Haal uw OpenRouter API-token op met behulp van OAuth-flow. U wordt doorgestuurd naar openrouter.ai", + "Bypass status check": "Omzeil statuscontrole", + "Chat Completion Source": "Bron voor Chatvoltooiing", + "Reverse Proxy": "Omgekeerde proxy", + "Proxy Presets": "Proxy-voorinstellingen", + "Saved addresses and passwords.": "Opgeslagen adressen en wachtwoorden.", + "Save Proxy": "Proxy opslaan", + "Delete Proxy": "Proxy verwijderen", + "Proxy Name": "Proxy-naam", + "This will show up as your saved preset.": "Dit wordt weergegeven als uw opgeslagen voorinstelling.", + "Proxy Server URL": "URL van proxyserver", + "Alternative server URL (leave empty to use the default value).": "Alternatieve server-URL (laat leeg om de standaardwaarde te gebruiken).", + "Remove your real OAI API Key from the API panel BEFORE typing anything into this box": "Verwijder je echte OAI API-sleutel uit het API-paneel VOORDAT je iets in dit vak typt", + "We cannot provide support for problems encountered while using an unofficial OpenAI proxy": "We kunnen geen ondersteuning bieden voor problemen die zich voordoen bij het gebruik van een niet-officiële OpenAI-proxy", + "Doesn't work? Try adding": "Werkt niet? Probeer toe te voegen", + "at the end!": "aan het einde!", + "Proxy Password": "Proxywachtwoord", + "Will be used as a password for the proxy instead of API key.": "Wordt gebruikt als wachtwoord voor de proxy in plaats van API-sleutel.", + "Peek a password": "Zoek een wachtwoord", + "OpenAI API key": "OpenAI API-sleutel", + "View API Usage Metrics": "Bekijk API-gebruiksstatistieken", + "Follow": "Volgen", + "these directions": "deze instructies", + "to get your OpenAI API key.": "om uw OpenAI API-sleutel te krijgen.", + "Use Proxy password field instead. This input will be ignored.": "Gebruik in plaats daarvan het veld 'Proxywachtwoord'. Deze invoer wordt genegeerd.", + "OpenAI Model": "OpenAI-model", + "Bypass API status check": "Omzeil API-statuscontrole", + "Show External models (provided by API)": "Externe modellen weergeven (geleverd door API)", + "Get your key from": "Haal je sleutel op bij", + "Anthropic's developer console": "Anthropic's ontwikkelaarsconsole", + "Claude Model": "Claude-model", + "Window AI Model": "Window AI-model", + "Model Order": "Sorteren van OpenRouter-modellen", + "Alphabetically": "Alfabetisch", + "Price": "Prijs (goedkoopste)", + "Context Size": "Contextgrootte", + "Group by vendors": "Groeperen op leveranciers", + "Group by vendors Description": "Plaats OpenAI-modellen in één groep, antropische modellen in een andere groep, enz. Kan worden gecombineerd met sorteren.", + "Allow fallback routes": "Fallback-routes toestaan", + "Allow fallback routes Description": "Het alternatieve model wordt automatisch gekozen als het geselecteerde model niet aan uw verzoek kan voldoen.", + "Scale API Key": "Scale API-sleutel", + "Clear your cookie": "Wis uw cookie", + "Alt Method": "Alternatieve methode", + "AI21 API Key": "AI21 API-sleutel", + "AI21 Model": "AI21-model", + "MakerSuite API Key": "MakerSuite API-sleutel", + "Google Model": "Google-model", + "MistralAI API Key": "MistralAI API-sleutel", + "MistralAI Model": "MistralAI-model", + "Groq API Key": "Groq API-sleutel", + "Groq Model": "Groq-model", + "Perplexity API Key": "Perplexity API-sleutel", + "Perplexity Model": "Verbijstering Model", + "Cohere API Key": "Cohere API-sleutel", + "Cohere Model": "Cohere-model", + "Custom Endpoint (Base URL)": "Aangepast eindpunt (basis-URL)", + "Custom API Key": "Aangepaste API-sleutel", + "Available Models": "Beschikbare modellen", + "Prompt Post-Processing": "Snelle naverwerking", + "Applies additional processing to the prompt before sending it to the API.": "Past extra verwerking toe op de prompt voordat deze naar de API wordt verzonden.", + "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "Verifieert uw API-verbinding door een kort testbericht te verzenden. Wees ervan bewust dat u hiervoor wordt gecrediteerd!", + "Test Message": "Testbericht", + "Auto-connect to Last Server": "Automatisch verbinden met de laatste server", + "Missing key": "❌ Ontbrekende sleutel", + "Key saved": "✔️ Sleutel opgeslagen", + "View hidden API keys": "Verborgen API-sleutels bekijken", + "AI Response Formatting": "AI-respons opmaken", + "Advanced Formatting": "Geavanceerd opmaken", + "Context Template": "Contextsjabloon", + "Auto-select this preset for Instruct Mode": "Automatisch deze voorinstelling selecteren voor Instructiemodus", + "Story String": "Verhaalstring", + "Example Separator": "Voorbeeldscheider", + "Chat Start": "Chatstart", + "Add Chat Start and Example Separator to a list of stopping strings.": "Voeg Chat Start en Voorbeeldscheidingsteken toe aan een lijst met stoptekenreeksen.", + "Use as Stop Strings": "Gebruik als stopreeksen", + "context_allow_jailbreak": "Inclusief jailbreak aan het einde van de prompt, indien gedefinieerd in de karakterkaart EN ''Prefer Char. Jailbreak'' is ingeschakeld.\nDIT WORDT NIET AANBEVOLEN VOOR MODELLEN VOOR HET INVOEREN VAN TEKST. KAN TOT SLECHTE UITVOER LEIDEN.", + "Allow Jailbreak": "Jailbreak toestaan", + "Context Order": "Contextvolgorde", + "Summary": "Samenvatting", + "Author's Note": "Aantekening van de auteur", + "Example Dialogues": "Voorbeelddialogen", + "Hint": "Tip:", + "In-Chat Position not affected": "Bestellingen met samenvattingen en notities van de auteur worden alleen beïnvloed als er geen in-chatpositie voor is ingesteld.", + "Instruct Mode": "Instructiemodus", + "Enabled": "Ingeschakeld", + "instruct_bind_to_context": "Indien ingeschakeld, worden contextsjablonen automatisch geselecteerd op basis van de geselecteerde Instruct-sjabloonnaam of op basis van uw voorkeur.", + "Bind to Context": "Binden aan context", + "Presets": "Voorinstellingen", + "Auto-select this preset on API connection": "Automatisch deze voorinstelling selecteren bij API-verbinding", + "Activation Regex": "Activeringsregex", + "Wrap Sequences with Newline": "Sequenties omwikkelen met nieuwe regel", + "Replace Macro in Sequences": "Macro vervangen in sequenties", + "Skip Example Dialogues Formatting": "Opmaak van voorbeelddialogen overslaan", + "Include Names": "Namen opnemen", + "Force for Groups and Personas": "Forceer voor groepen en persona's", + "System Prompt": "Systeemprompt", + "Instruct Mode Sequences": "Sequenties in instructiemodus", + "System Prompt Wrapping": "Systeempromptverpakking", + "Inserted before a System prompt.": "Ingevoegd vóór een systeemprompt.", + "System Prompt Prefix": "Systeempromptvoorvoegsel", + "Inserted after a System prompt.": "Ingevoegd na een systeemprompt.", + "System Prompt Suffix": "Achtervoegsel voor systeemprompt", + "Chat Messages Wrapping": "Chatberichten inpakken", + "Inserted before a User message and as a last prompt line when impersonating.": "Wordt ingevoegd vóór een gebruikersbericht en als laatste promptregel bij het nabootsen van identiteit.", + "User Message Prefix": "Voorvoegsel voor gebruikersbericht", + "Inserted after a User message.": "Ingevoegd na een gebruikersbericht.", + "User Message Suffix": "Achtervoegsel voor gebruikersbericht", + "Inserted before an Assistant message and as a last prompt line when generating an AI reply.": "Wordt ingevoegd vóór een Assistent-bericht en als laatste promptregel bij het genereren van een AI-antwoord.", + "Assistant Message Prefix": "Assistent-berichtvoorvoegsel", + "Inserted after an Assistant message.": "Ingevoegd na een Assistent-bericht.", + "Assistant Message Suffix": "Assistent-berichtachtervoegsel", + "Inserted before a System (added by slash commands or extensions) message.": "Ingevoegd vóór een Systeembericht (toegevoegd door slash-opdrachten of extensies).", + "System Message Prefix": "Systeemberichtvoorvoegsel", + "Inserted after a System message.": "Ingevoegd na een systeembericht.", + "System Message Suffix": "Systeemberichtachtervoegsel", + "If enabled, System Sequences will be the same as User Sequences.": "Indien ingeschakeld, zijn Systeemreeksen hetzelfde als Gebruikersreeksen.", + "System same as User": "Systeem hetzelfde als Gebruiker", + "Misc. Sequences": "Diversen Opeenvolgingen", + "Inserted before the first Assistant's message.": "Ingevoegd vóór het eerste bericht van de Assistent.", + "First Assistant Prefix": "Eerste assistent-voorvoegsel", + "instruct_last_output_sequence": "Ingevoegd vóór het laatste bericht van de Assistent of als laatste promptregel bij het genereren van een AI-antwoord (behalve een neutrale/systeemrol).", + "Last Assistant Prefix": "Laatste assistent-voorvoegsel", + "Will be inserted as a last prompt line when using system/neutral generation.": "Wordt ingevoegd als laatste promptregel bij gebruik van systeem/neutrale generatie.", + "System Instruction Prefix": "Systeeminstructievoorvoegsel", + "If a stop sequence is generated, everything past it will be removed from the output (inclusive).": "Als er een stopreeks wordt gegenereerd, wordt alles daarboven uit de uitvoer verwijderd (inclusief).", + "Stop Sequence": "Stopsequentie", + "Will be inserted at the start of the chat history if it doesn't start with a User message.": "Wordt aan het begin van de chatgeschiedenis ingevoegd als deze niet begint met een gebruikersbericht.", + "User Filler Message": "Bericht van de gebruiker-invuller", + "Context Formatting": "Contextopmaak", + "(Saved to Context Template)": "(Opgeslagen in contextsjabloon)", + "Always add character's name to prompt": "Voeg altijd de naam van het personage toe aan de prompt", + "Generate only one line per request": "Genereer slechts één regel per verzoek", + "Trim Incomplete Sentences": "Onvolledige Zinnen Trimmen", + "Include Newline": "Nieuwe Regel Inclusief", + "Misc. Settings": "Diverse instellingen", + "Collapse Consecutive Newlines": "Samenvouwen van opeenvolgende nieuwe regels", + "Trim spaces": "Spaties trimmen", + "Tokenizer": "Tokenizer", + "Token Padding": "Token-vulling", + "Start Reply With": "Begin antwoord met", + "AI reply prefix": "AI antwoord voorvoegsel", + "Show reply prefix in chat": "Toon antwoordvoorvoegsel in chat", + "Non-markdown strings": "Niet-markdown-strings", + "separate with commas w/o space between": "gescheiden met komma's zonder spatie ertussen", + "Custom Stopping Strings": "Aangepaste Stopreeksen", + "JSON serialized array of strings": "JSON geserialiseerde reeks van strings", + "Replace Macro in Stop Strings": "Macro vervangen in aangepaste stopreeksen", + "Auto-Continue": "Automatisch doorgaan", + "Allow for Chat Completion APIs": "Chatvervolledigings-API's toestaan", + "Target length (tokens)": "Doellengte (tokens)", + "World Info": "Wereldinformatie", + "Locked = World Editor will stay open": "Vergrendeld = Wereldeditor blijft open", + "Worlds/Lorebooks": "Werelden/Lorebooks", + "Active World(s) for all chats": "Actieve Wereld(en) voor alle chats", + "-- World Info not found --": "-- Wereldinformatie niet gevonden --", + "Global World Info/Lorebook activation settings": "Global World Info/Lorebook-activeringsinstellingen", + "Click to expand": "Klik om uit te breiden", + "Scan Depth": "Scandiepte", + "Context %": "Context %", + "Budget Cap": "Budgetplafond", + "(0 = disabled)": "(0 = uitgeschakeld)", + "Scan chronologically until reached min entries or token budget.": "Scan chronologisch tot het minimum aantal inzendingen of het tokenbudget is bereikt.", + "Min Activations": "Minimale activeringen", + "Max Depth": "Maximale diepte", + "(0 = unlimited, use budget)": "(0 = onbeperkt, gebruik budget)", + "Insertion Strategy": "Invoegstrategie", + "Sorted Evenly": "Gelijkmatig gesorteerd", + "Character Lore First": "Karakter Lore Eerst", + "Global Lore First": "Globale Lore Eerst", + "Entries can activate other entries by mentioning their keywords": "Items kunnen andere items activeren door hun trefwoorden te vermelden", + "Recursive Scan": "Recursieve Scan", + "Lookup for the entry keys in the context will respect the case": "Opzoeken van de itemtoetsen in de context zal de zaak respecteren", + "Case Sensitive": "Hoofdlettergevoelig", + "If the entry key consists of only one word, it would not be matched as part of other words": "Als de itemtoets uit slechts één woord bestaat, wordt deze niet gematcht als onderdeel van andere woorden", + "Match Whole Words": "Hele woorden matchen", + "Only the entries with the most number of key matches will be selected for Inclusion Group filtering": "Alleen de inzendingen met het grootste aantal sleutelovereenkomsten worden geselecteerd voor het filteren van Inclusiegroepen", + "Use Group Scoring": "Gebruik groepsscores", + "Alert if your world info is greater than the allocated budget.": "Waarschuw als uw wereldinformatie groter is dan het toegewezen budget.", + "Alert On Overflow": "Waarschuwing bij overloop", + "New": "Nieuw", + "or": "of", + "--- Pick to Edit ---": "--- Kies om te bewerken ---", + "Rename World Info": "Wereldinformatie hernoemen", + "Open all Entries": "Alle items openen", + "Close all Entries": "Alle items sluiten", + "New Entry": "Nieuw item", + "Fill empty Memo/Titles with Keywords": "Vul lege Memo/Titels in met trefwoorden", + "Import World Info": "Wereldinformatie importeren", + "Export World Info": "Wereldinformatie exporteren", + "Duplicate World Info": "Wereldinformatie dupliceren", + "Delete World Info": "Wereldinformatie verwijderen", + "Search...": "Zoeken...", + "Search": "Zoekopdracht", + "Priority": "Prioriteit", + "Custom": "Aangepast", + "Title A-Z": "Titel A-Z", + "Title Z-A": "Titel Z-A", + "Tokens ↗": "Tokens ↗", + "Tokens ↘": "Tokens ↘", + "Depth ↗": "Diepte ↗", + "Depth ↘": "Diepte ↘", + "Order ↗": "Bestelling ↗", + "Order ↘": "Bestelling ↘", + "UID ↗": "UID ↗", + "UID ↘": "UID ↘", + "Trigger% ↗": "Trigger% ↗", + "Trigger% ↘": "Trigger% ↘", + "Refresh": "Vernieuwen", + "User Settings": "Gebruikersinstellingen", + "Simple": "Eenvoudig", + "Advanced": "Geavanceerd", + "UI Language": "Taal", + "Account": "Rekening", + "Admin Panel": "Administratie Paneel", + "Logout": "Uitloggen", + "Search Settings": "Zoekinstellingen", + "UI Theme": "UI-thema", + "Import a theme file": "Importeer een themabestand", + "Export a theme file": "Exporteer een themabestand", + "Delete a theme": "Verwijder een thema", + "Update a theme file": "Werk een themabestand bij", + "Save as a new theme": "Opslaan als nieuw thema", + "Avatar Style:": "Avatarstijl", + "Circle": "Cirkel", + "Square": "Vierkant", + "Rectangle": "Rechthoek", + "Chat Style:": "Chatstijl:", + "Flat": "Vlak\nBubbels\nDocument", + "Bubbles": "Bubbels", + "Document": "Document", + "Specify colors for your theme.": "Geef kleuren op voor uw thema.", + "Theme Colors": "Thema kleuren", + "Main Text": "Hoofdtekst", + "Italics Text": "Schuine tekst", + "Underlined Text": "Onderstreepte tekst", + "Quote Text": "Quote-tekst", + "Shadow Color": "Schaduwkleur", + "Chat Background": "Chat achtergrond", + "UI Background": "UI-achtergrond", + "UI Border": "UI-grens", + "User Message Blur Tint": "Gebruikersbericht Blur Tint", + "AI Message Blur Tint": "AI-bericht Blur Tint", + "Chat Width": "Chatbreedte", + "Width of the main chat window in % of screen width": "Breedte van het hoofdchatvenster in % van de schermbreedte", + "Font Scale": "Lettertype schaal", + "Font size": "Lettertypegrootte", + "Blur Strength": "Vervagingssterkte", + "Blur strength on UI panels.": "Vervagingssterkte op UI-panelen.", + "Text Shadow Width": "Tekstschaduwbreedte", + "Strength of the text shadows": "Sterkte van de tekstschaduwen", + "Disables animations and transitions": "Schakelt animaties en overgangen uit", + "Reduced Motion": "Verminderde beweging", + "removes blur from window backgrounds": "Verwijdert vervaging van vensterachtergronden", + "No Blur Effect": "Geen vervagingseffect", + "Remove text shadow effect": "Verwijder tekstschaduweffect", + "No Text Shadows": "Geen tekstschaduwen", + "Reduce chat height, and put a static sprite behind the chat window": "Verlaag de hoogte van de chat en plaats een statische sprite achter het chatvenster", + "Waifu Mode": "Waifu-modus", + "Always show the full list of the Message Actions context items for chat messages, instead of hiding them behind '...'": "Toon altijd de volledige lijst met berichtacties voor chatberichten, in plaats van ze te verbergen achter '...' ", + "Auto-Expand Message Actions": "Automatisch uitbreiden van berichtacties", + "Alternative UI for numeric sampling parameters with fewer steps": "Alternatieve UI voor numerieke bemonsteringsparameters met minder stappen", + "Zen Sliders": "Zen-schuiven", + "Entirely unrestrict all numeric sampling parameters": "Volledig alle numerieke bemonsteringsparameters onbeperkt maken", + "Mad Lab Mode": "Mad Lab-modus", + "Time the AI's message generation, and show the duration in the chat log": "Time de berichtgeneratie van de AI en toon de duur in het chatlogboek", + "Message Timer": "Berichtentimer", + "Show a timestamp for each message in the chat log": "Toon een tijdstempel voor elk bericht in het chatlogboek", + "Chat Timestamps": "Chat-tijdstempels", + "Show an icon for the API that generated the message": "Toon een pictogram voor de API die het bericht heeft gegenereerd", + "Model Icon": "Modelpictogram", + "Show sequential message numbers in the chat log": "Toon opeenvolgende berichtnummers in het chatlogboek", + "Message IDs": "Bericht-IDs", + "Hide avatars in chat messages.": "Verberg avatars in chatberichten.", + "Hide Chat Avatars": "Chatavatars verbergen", + "Show the number of tokens in each message in the chat log": "Toon het aantal tokens in elk bericht in het chatlogboek", + "Show Message Token Count": "Toon bericht token tellen", + "Single-row message input area. Mobile only, no effect on PC": "Enkele rij bericht invoergebied. Alleen mobiel, geen effect op pc", + "Compact Input Area (Mobile)": "Compacte invoergebied (Mobiel)", + "In the Character Management panel, show quick selection buttons for favorited characters": "In het karakterbeheerpaneel, toon snelle selectieknoppen voor favoriete karakters", + "Characters Hotswap": "Personages Hotswap", + "Enable magnification for zoomed avatar display.": "Schakel vergroting in voor ingezoomde avatarweergave.", + "Avatar Hover Magnification": "Vergroting van avatar-zweving", + "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "Schakelt een vergrotingseffect in bij het aanwijzen van de muis wanneer u de ingezoomde avatar weergeeft nadat u in de chat op de afbeelding van een avatar hebt geklikt.", + "Show tagged character folders in the character list": "Toon gemarkeerde karaktermappen in de lijst met personages", + "Tags as Folders": "Tags als mappen", + "Tags_as_Folders_desc": "Recente wijziging: Tags moeten als mappen worden gemarkeerd in het menu Tagbeheer om als zodanig te verschijnen. Klik hier om het naar voren te brengen.", + "Character Handling": "Personagebehandeling", + "If set in the advanced character definitions, this field will be displayed in the characters list.": "Als dit is ingesteld in de geavanceerde karakterdefinities, wordt dit veld weergegeven in de lijst met personages.", + "Char List Subheader": "Subkop van Char-lijst", + "Character Version": "Karakterversie", + "Created by": "Gemaakt door", + "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "Gebruik fuzzy-matching en zoek personages in de lijst op alle gegevensvelden, niet alleen op een naamsubreeks", + "Advanced Character Search": "Geavanceerd personage zoeken", + "If checked and the character card contains a prompt override (System Prompt), use that instead": "Als aangevinkt en de karakterkaart bevat een prompt-override (Systeemprompt), gebruik die in plaats daarvan", + "Prefer Character Card Prompt": "Voorkeur karakterkaart prompt", + "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Als aangevinkt en de karakterkaart bevat een jailbreak-override (Post History Instruction), gebruik die in plaats daarvan", + "Prefer Character Card Jailbreak": "Voorkeur karakterkaart jailbreak", + "never_resize_avatars_tooltip": "Vermijd het bijsnijden en vergroten/verkleinen van geïmporteerde karakterafbeeldingen. Indien uitgeschakeld, bijsnijden/formaat wijzigen naar 512 x 768.", + "Never resize avatars": "Avatars nooit verkleinen", + "Show actual file names on the disk, in the characters list display only": "Toon de werkelijke bestandsnamen op de schijf, alleen in de weergave van de lijst met personages", + "Show avatar filenames": "Toon avatar bestandsnamen", + "Prompt to import embedded card tags on character import. Otherwise embedded tags are ignored": "Prompt om ingesloten kaarttags te importeren bij het importeren van personages. Anders worden ingesloten tags genegeerd", + "Import Card Tags": "Kaart tags importeren", + "Hide character definitions from the editor panel behind a spoiler button": "Verberg karakterdefinities uit het bewerkingspaneel achter een spoilerknop", + "Spoiler Free Mode": "Spoiler Free-modus", + "Miscellaneous": "Diversen", + "Reload and redraw the currently open chat": "Laad de momenteel geopende chat opnieuw en teken opnieuw", + "Reload Chat": "Chat herladen", + "Debug Menu": "Debugmenu", + "Smooth Streaming": "Vlotte streaming", + "Experimental feature. May not work for all backends.": "Experimentele functie. Werkt mogelijk niet voor alle backends.", + "Slow": "Langzaam", + "Fast": "Snel", + "Play a sound when a message generation finishes": "Speel een geluid af wanneer een berichtgeneratie is voltooid", + "Message Sound": "Berichtgeluid", + "Only play a sound when ST's browser tab is unfocused": "Speel alleen een geluid af wanneer het browsertabblad van ST niet gefocust is", + "Background Sound Only": "Alleen achtergrondgeluid", + "Reduce the formatting requirements on API URLs": "Verminder de opmaakvereisten voor API-URL's", + "Relaxed API URLS": "Ontspannen API URL'S", + "Ask to import the World Info/Lorebook for every new character with embedded lorebook. If unchecked, a brief message will be shown instead": "Vraag om de Wereldinformatie/Lorebook te importeren voor elke nieuwe karakter met ingesloten lorebook. Als dit niet is aangevinkt, wordt in plaats daarvan een kort bericht weergegeven", + "Lorebook Import Dialog": "Lorebook-import dialoogvenster", + "Restore unsaved user input on page refresh": "Herstel niet-opgeslagen gebruikersinvoer bij het vernieuwen van de pagina", + "Restore User Input": "Gebruikersinvoer herstellen", + "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "Sta het verplaatsen van bepaalde UI-elementen toe door ze te slepen. Alleen pc, geen effect op mobiel", + "Movable UI Panels": "Verplaatsbare UI-panelen", + "MovingUI preset. Predefined/saved draggable positions": "MovingUI-voorinstelling. Voorgedefinieerde/opgeslagen sleepbare posities", + "MUI Preset": "MUI-voorinstelling", + "Save movingUI changes to a new file": "Sla de wijzigingen van MovingUI op in een nieuw bestand", + "Reset MovingUI panel sizes/locations.": "Reset MovingUI-paneelformaten/locaties.", + "Apply a custom CSS style to all of the ST GUI": "Pas een aangepaste CSS-stijl toe op de hele ST GUI", + "Custom CSS": "Aangepaste CSS", + "Expand the editor": "De editor uitbreiden", + "Chat/Message Handling": "Chat-/berichtafhandeling", + "# Messages to Load": "# Bericht Laden", + "The number of chat history messages to load before pagination.": "Het aantal chatgeschiedenisberichten dat moet worden geladen vóór paginering.", + "(0 = All)": "(0 = Alles)", + "Streaming FPS": "Streaming FPS", + "Update speed of streamed text.": "Update de snelheid van gestreamde tekst.", + "Example Messages Behavior": "Gedrag voorbeeldberichten", + "Gradual push-out": "Geleidelijke uitstoot", + "Always include examples": "Altijd voorbeelden opnemen", + "Never include examples": "Nooit voorbeelden opnemen", + "Send on Enter": "Verzenden bij Enter", + "Disabled": "Uitgeschakeld", + "Automatic (PC)": "Automatisch (PC)", + "Press Send to continue": "Druk op Verzenden om door te gaan", + "Show a button in the input area to ask the AI to continue (extend) its last message": "Toon een knop in het invoergebied om de AI te vragen om door te gaan (uit te breiden) met zijn laatste bericht", + "Quick 'Continue' button": "Snelle 'Doorgaan' knop", + "Show arrow buttons on the last in-chat message to generate alternative AI responses. Both PC and mobile": "Toon pijlknoppen op het laatste in-chatbericht om alternatieve AI-responses te genereren. Zowel pc als mobiel", + "Swipes": "Veegbewegingen", + "Allow using swiping gestures on the last in-chat message to trigger swipe generation. Mobile only, no effect on PC": "Sta het gebruik van veeggebaren toe op het laatste in-chatbericht om swipe-generatie te activeren. Alleen mobiel, geen effect op pc", + "Gestures": "Gebaren", + "Auto-load Last Chat": "Laatste chat automatisch laden", + "Auto-scroll Chat": "Automatisch scrollen chat", + "Save edits to messages without confirmation as you type": "Sla bewerkingen op berichten op zonder bevestiging terwijl u typt", + "Auto-save Message Edits": "Automatisch opslaan van berichtbewerkingen", + "Confirm message deletion": "Bevestig bericht verwijdering", + "Auto-fix Markdown": "Automatisch repareren van Markdown", + "Disallow embedded media from other domains in chat messages": "Ingesloten media van andere domeinen niet toestaan ​​in chatberichten.", + "Forbid External Media": "Externe media verbieden", + "Allow {{char}}: in bot messages": "Toestaan {{char}}: in botberichten", + "Allow {{user}}: in bot messages": "Toestaan {{user}}: in botberichten", + "Skip encoding and characters in message text, allowing a subset of HTML markup as well as Markdown": "Codering en -tekens overslaan in berichttekst, waardoor een subset van HTML-opmaak en Markdown wordt toegestaan", + "Show tags in responses": "Tags weergeven in reacties", + "Allow AI messages in groups to contain lines spoken by other group members": "Sta toe dat AI-berichten in groepen regels bevatten die zijn uitgesproken door andere groepsleden", + "Relax message trim in Groups": "Trimbericht ontspannen in groepen", + "Log prompts to console": "Logt prompts naar console", + "Requests logprobs from the API for the Token Probabilities feature": "Vraagt logprobs aan van de API voor de Token Probabilities-functie", + "Request token probabilities": "Aanvraag tokenkansen", + "Automatically reject and re-generate AI message based on configurable criteria": "Automatisch AI-bericht afwijzen en opnieuw genereren op basis van configureerbare criteria", + "Auto-swipe": "Automatisch vegen", + "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Schakel de automatische-vegen functie in. Instellingen in dit gedeelte hebben alleen effect wanneer automatisch vegen is ingeschakeld", + "Minimum generated message length": "Minimale gegenereerde berichtlengte", + "If the generated message is shorter than these many characters, trigger an auto-swipe": "Als het gegenereerde bericht korter is dan dit, activeer dan een automatische veeg", + "Blacklisted words": "Verboden woorden", + "words you dont want generated separated by comma ','": "woorden die je niet gegenereerd wilt hebben gescheiden door komma ','", + "Blacklisted word count to swipe": "Aantal verboden woorden om te vegen", + "Minimum number of blacklisted words detected to trigger an auto-swipe": "Minimaal aantal gedetecteerde verboden woorden om een automatische veeg te activeren", + "AutoComplete Settings": "Instellingen voor automatisch aanvullen", + "Automatically hide details": "Details automatisch verbergen", + "Determines how entries are found for autocomplete.": "Bepaalt hoe vermeldingen worden gevonden voor automatisch aanvullen.", + "Autocomplete Matching": "Bij elkaar passen", + "Starts with": "Begint met", + "Includes": "Inclusief", + "Fuzzy": "Wazig", + "Sets the style of the autocomplete.": "Stelt de stijl van het automatisch aanvullen in.", + "Autocomplete Style": "Stijl", + "Follow Theme": "Volg Thema", + "Dark": "Donker", + "Sets the font size of the autocomplete.": "Stelt de lettergrootte van automatisch aanvullen in.", + "Sets the width of the autocomplete.": "Stelt de breedte van het automatisch aanvullen in.", + "Autocomplete Width": "Breedte", + "chat input box": "chat-invoervak", + "entire chat width": "gehele chatbreedte", + "full window width": "volledige raambreedte", + "STscript Settings": "STscript-instellingen", + "Sets default flags for the STscript parser.": "Stelt standaardvlaggen in voor de STscript-parser.", + "Parser Flags": "Parser-vlaggen", + "Switch to stricter escaping, allowing all delimiting characters to be escaped with a backslash, and backslashes to be escaped as well.": "Schakel over naar een strengere ontsnapping, waardoor alle begrenzende tekens kunnen worden geëscaped met een backslash, en ook backslashes kunnen worden geëscaped.", + "STRICT_ESCAPING": "STRICT_ESCAPING", + "Replace all {{getvar::}} and {{getglobalvar::}} macros with scoped variables to avoid double macro substitution.": "Vervang alle {{getvar::}} en {{getglobalvar::}} macro's door variabelen met een bereik om dubbele macrovervanging te voorkomen.", + "REPLACE_GETVAR": "VERVANG_GETVAR", + "Change Background Image": "Achtergrondafbeelding wijzigen", + "Filter": "Filter", + "Automatically select a background based on the chat context": "Automatisch een achtergrond selecteren op basis van de chatcontext", + "Auto-select": "Automatisch selecteren", + "System Backgrounds": "Systeemachtergronden", + "Chat Backgrounds": "Achtergronden chat", + "bg_chat_hint_1": "Chatachtergronden gegenereerd met de", + "bg_chat_hint_2": "extensie zal hier verschijnen.", + "Extensions": "Uitbreidingen", + "Notify on extension updates": "Op de hoogte stellen van extensie-updates", + "Manage extensions": "Beheer extensies", + "Import Extension From Git Repo": "Extensie importeren vanuit Git Repository", + "Install extension": "Installeer extensie", + "Extras API:": "Extra's API:", + "Auto-connect": "Automatisch verbinden", + "Extras API URL": "Extra's API-URL", + "Extras API key (optional)": "Extra API-sleutel (optioneel)", + "Persona Management": "Persoonbeheer", + "How do I use this?": "Hoe gebruik ik dit?", + "Click for stats!": "Klik voor statistieken!", + "Usage Stats": "Gebruiksstatistieken", + "Backup your personas to a file": "Maak een back-up van je persona's naar een bestand", + "Backup": "Back-up", + "Restore your personas from a file": "Herstel je persona's uit een bestand", + "Restore": "Herstellen", + "Create a dummy persona": "Maak een dummy-persona", + "Create": "Creëren", + "Toggle grid view": "Rasterweergave omzetten", + "No persona description": "[Geen beschrijving]", + "Name": "Naam", + "Enter your name": "Voer je naam in", + "Click to set a new User Name": "Klik om een nieuwe gebruikersnaam in te stellen", + "Click to lock your selected persona to the current chat. Click again to remove the lock.": "Klik om uw geselecteerde persona aan de huidige chat te vergrendelen. Klik opnieuw om het slot te verwijderen.", + "Click to set user name for all messages": "Klik om een gebruikersnaam in te stellen voor alle berichten", + "Persona Description": "Persoonbeschrijving", + "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "Voorbeeld: [{{user}} is een 28-jarig Roemeens kattemeisje.]", + "Tokens persona description": "Beschrijving van tokens", + "Position:": "Positie:", + "In Story String / Prompt Manager": "In Verhaalreeks / Prompt Manager", + "Top of Author's Note": "Bovenste deel van Auteur's Notitie", + "Bottom of Author's Note": "Onderste deel van Auteur's Notitie", + "In-chat @ Depth": "In-chat @ Diepte", + "Depth:": "Diepte:", + "Role:": "Rol:", + "System": "Systeem", + "User": "Gebruiker", + "Assistant": "Assistent", + "Show notifications on switching personas": "Notificaties tonen bij het wisselen van personages", + "Character Management": "Personagebeheer", + "Locked = Character Management panel will stay open": "Vergrendeld = Paneel voor personagebeheer blijft open", + "Select/Create Characters": "Personages selecteren/maken", + "Favorite characters to add them to HotSwaps": "Favoriete personages toevoegen aan HotSwaps", + "Token counts may be inaccurate and provided just for reference.": "Token-tellingen kunnen onnauwkeurig zijn en worden alleen ter referentie verstrekt.", + "Total tokens": "Totaal tokens", + "Calculating...": "Berekenen...", + "Tokens": "Tokens", + "Permanent tokens": "Permanente tokens", + "Permanent": "Permanent", + "About Token 'Limits'": "Over token 'limieten'", + "Toggle character info panel": "Schakel het karakterinformatiepaneel in of uit", + "Name this character": "Geef dit personage een naam", + "extension_token_counter": "Munten:", + "Click to select a new avatar for this character": "Klik om een nieuwe avatar voor dit personage te selecteren", + "Add to Favorites": "Toevoegen aan favorieten", + "Advanced Definition": "Geavanceerde definitie", + "Character Lore": "Personage-achtergrondverhaal", + "Chat Lore": "Chat Lore", + "Export and Download": "Exporteren en downloaden", + "Duplicate Character": "Personage dupliceren", + "Create Character": "Personage maken", + "Delete Character": "Personage verwijderen", + "More...": "Meer...", + "Link to World Info": "Link naar Wereldinformatie", + "Import Card Lore": "Kaart Lore Importeren", + "Scenario Override": "Scenario Overschrijving", + "Convert to Persona": "Converteren naar Persona", + "Rename": "Hernoemen", + "Link to Source": "Link naar bron", + "Replace / Update": "Vervangen/bijwerken", + "Import Tags": "Importeer labels", + "Search / Create Tags": "Zoeken / Tags maken", + "View all tags": "Alle tags bekijken", + "Creator's Notes": "Maker's Notities", + "Show / Hide Description and First Message": "Beschrijving en eerste bericht weergeven/verbergen", + "Character Description": "Karakterbeschrijving", + "Click to allow/forbid the use of external media for this character.": "Klik om het gebruik van externe media voor dit personage toe te staan/te verbieden.", + "Ext. Media": "Ext. Media", + "Describe your character's physical and mental traits here.": "Beschrijf hier de fysieke en mentale eigenschappen van je personage.", + "First message": "Eerste bericht", + "Click to set additional greeting messages": "Klik om extra begroetingsberichten in te stellen", + "Alt. Greetings": "Alt. Groeten", + "This will be the first message from the character that starts every chat.": "Dit zal het eerste bericht zijn van het personage dat elke chat begint.", + "Group Controls": "Groepsbesturing", + "Chat Name (Optional)": "Chat Naam (Optioneel)", + "Click to select a new avatar for this group": "Klik om een nieuwe avatar voor deze groep te selecteren", + "Group reply strategy": "Groepsantwoordstrategie", + "Natural order": "Natuurlijke volgorde", + "List order": "Lijstvolgorde", + "Group generation handling mode": "Verwerkingsmodus voor het genereren van groepen", + "Swap character cards": "Wissel karakterkaarten uit", + "Join character cards (exclude muted)": "Sluit je aan bij karakterkaarten (exclusief gedempt)", + "Join character cards (include muted)": "Sluit je aan bij karakterkaarten (inclusief gedempt)", + "Inserted before each part of the joined fields.": "Ingevoegd vóór elk deel van de samengevoegde velden.", + "Join Prefix": "Sluit je aan bij Voorvoegsel", + "When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and with the name of the part (e.g.: description, personality, scenario, etc.)": "Wanneer 'Verbind karakterkaarten' is geselecteerd, worden alle respectieve velden van de karakters samengevoegd.\rDit betekent dat in de verhaalreeks bijvoorbeeld alle karakterbeschrijvingen worden samengevoegd tot één grote tekst.\rAls u wilt dat deze velden gescheiden worden, kunt u hier een voor- of achtervoegsel definiëren.\r\rDeze waarde ondersteunt normale macro's en zal ook {{char}} vervangen door de relevante naam van het char en door de naam van het onderdeel (bijvoorbeeld: beschrijving, persoonlijkheid, scenario, etc.)", + "Inserted after each part of the joined fields.": "Ingevoegd na elk deel van de samengevoegde velden.", + "Join Suffix": "Sluit je aan bij het achtervoegsel", + "Set a group chat scenario": "Stel een scenario voor groepschat in", + "Click to allow/forbid the use of external media for this group.": "Klik om het gebruik van externe media voor deze groep toe te staan/te verbieden.", + "Restore collage avatar": "Collage-avatar herstellen", + "Allow self responses": "Zelfreacties toestaan", + "Auto Mode": "Automatische modus", + "Auto Mode delay": "Vertraging automatische modus", + "Hide Muted Member Sprites": "Verberg gedempte ledensprites", + "Current Members": "Huidige leden", + "Add Members": "Leden toevoegen", + "Create New Character": "Nieuw personage maken", + "Import Character from File": "Personage importeren uit bestand", + "Import content from external URL": "Inhoud importeren van externe URL", + "Create New Chat Group": "Nieuwe chatgroep maken", + "Characters sorting order": "Sorteervolgorde van personages", + "A-Z": "A-Z", + "Z-A": "Z-A", + "Newest": "Nieuwste", + "Oldest": "Oudste", + "Favorites": "Favorieten", + "Recent": "Recent", + "Most chats": "Meeste chats", + "Least chats": "Minste chats", + "Most tokens": "Meeste tokens", + "Least tokens": "Minste tokens", + "Random": "Willekeurig", + "Toggle character grid view": "Wissel weergave roosterkarakter", + "Bulk_edit_characters": "Massaal bewerken personages", + "Bulk select all characters": "Selecteer alle tekens in bulk", + "Bulk delete characters": "Massaal verwijderen personages", + "popup-button-save": "Redden", + "popup-button-yes": "Ja", + "popup-button-no": "Nee", + "popup-button-cancel": "Annuleren", + "popup-button-import": "Importeren", + "Advanced Definitions": "Geavanceerde definities", + "Prompt Overrides": "Prompt-overschrijvingen", + "(For Chat Completion and Instruct Mode)": "(Voor voltooiing van chat en instructiemodus)", + "Insert {{original}} into either box to include the respective default prompt from system settings.": "Voeg {{original}} in in elk vak in om de respectievelijke standaardprompt vanuit systeeminstellingen op te nemen.", + "Main Prompt": "Hoofd Prompt", + "Any contents here will replace the default Main Prompt used for this character. (v2 spec: system_prompt)": "Elke inhoud hier zal de standaard Hoofd Prompt vervangen die wordt gebruikt voor dit personage. (v2 spec: systeem_prompt)", + "Any contents here will replace the default Jailbreak Prompt used for this character. (v2 spec: post_history_instructions)": "Elke inhoud hier zal de standaard Jailbreak Prompt vervangen die wordt gebruikt voor dit personage. (v2 spec: post_history_instructions)", + "Creator's Metadata (Not sent with the AI prompt)": "Maker's Metadata (Niet verzonden met de AI prompt)", + "Creator's Metadata": "Metagegevens van de maker", + "(Not sent with the AI Prompt)": "(Niet verzonden met de AI-prompt)", + "Everything here is optional": "Alles hier is optioneel", + "(Botmaker's name / Contact Info)": "(Naam van Botmaker / Contactgegevens)", + "(If you want to track character versions)": "(Als je versies van het personage wilt bijhouden)", + "(Describe the bot, give use tips, or list the chat models it has been tested on. This will be displayed in the character list.)": "(Beschrijf de bot, geef gebruikstips, of lijst de chatmodellen op waarop het is getest. Dit zal worden weergegeven in de lijst met personages.)", + "Tags to Embed": "In te sluiten Tags", + "(Write a comma-separated list of tags)": "(Schrijf een komma-gescheiden lijst met tags)", + "Personality summary": "Persoonlijkheidssamenvatting", + "(A brief description of the personality)": "(Een korte beschrijving van de persoonlijkheid)", + "Scenario": "Scenario", + "(Circumstances and context of the interaction)": "(Omstandigheden en context van de interactie)", + "Character's Note": "Karakternotitie", + "(Text to be inserted in-chat @ designated depth and role)": "(Tekst die in de chat moet worden ingevoegd @ aangegeven diepte en rol)", + "@ Depth": "@ Diepte", + "Role": "Rol", + "Talkativeness": "Spraakzaamheid", + "How often the character speaks in group chats!": "Hoe vaak het personage spreekt in groepschats!", + "How often the character speaks in": "Hoe vaak het personage spreekt", + "group chats!": "groepschats!", + "Shy": "Verlegen", + "Normal": "Normaal", + "Chatty": "Kletserig", + "Examples of dialogue": "Voorbeelden van dialoog", + "Important to set the character's writing style.": "Belangrijk om de schrijfstijl van het personage in te stellen.", + "(Examples of chat dialog. Begin each example with START on a new line.)": "(Voorbeelden van chatdialogen. Begin elk voorbeeld met START op een nieuwe regel.)", + "Save": "Opslaan", + "Chat History": "Chatgeschiedenis", + "Import Chat": "Chat importeren", + "Copy to system backgrounds": "Kopiëren naar systeemachtergronden", + "Rename background": "Achtergrond hernoemen", + "Lock": "Slot", + "Unlock": "Ontgrendelen", + "Delete background": "Achtergrond verwijderen", + "Chat Scenario Override": "Chatscenario negeren", + "Remove": "Verwijderen", + "Type here...": "Typ hier...", + "Chat Lorebook": "Chat Loreboek voor", + "Chat Lorebook for": "Chat Loreboek voor", + "chat_world_template_txt": "Een geselecteerde Wereldinfo wordt aan deze chat gekoppeld. Bij het genereren van een AI-antwoord,\n het zal worden gecombineerd met de inzendingen uit globale en karakterboeken.", + "Select a World Info file for": "Selecteer een Wereldinformatiebestand voor", + "Primary Lorebook": "Primaire Verhalenboek", + "A selected World Info will be bound to this character as its own Lorebook.": "Een geselecteerde Wereldinformatie zal aan dit personage worden gekoppeld als zijn eigen Verhalenboek.", + "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "Bij het genereren van een AI-antwoord zal het worden gecombineerd met de invoer uit een wereldwijde Wereldinformatie-selector.", + "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "Het exporteren van een personage zou ook het geselecteerde Verhalenboekbestand exporteren dat is ingebed in de JSON-gegevens.", + "Additional Lorebooks": "Extra Verhalenboeken", + "Associate one or more auxillary Lorebooks with this character.": "Koppel een of meer extra Verhalenboeken aan dit personage.", + "NOTE: These choices are optional and won't be preserved on character export!": "LET OP: Deze keuzes zijn optioneel en worden niet behouden bij het exporteren van het personage!", + "Rename chat file": "Chatbestand hernoemen", + "Export JSONL chat file": "Exporteer JSONL-chatbestand", + "Download chat as plain text document": "Download chat als plat tekstbestand", + "Delete chat file": "Chatbestand verwijderen", + "Use tag as folder": "Taggen als map", + "Delete tag": "Tag verwijderen", + "Entry Title/Memo": "Titel/Memo", + "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized❌ Disabled": "WI-invoerstatus:\r🔵Constant\r🟢 Normaal\r🔗 Gevectoriseerd\r❌ Uitgeschakeld", + "WI_Entry_Status_Constant": "Constante", + "WI_Entry_Status_Normal": "Normaal", + "WI_Entry_Status_Vectorized": "Gevectoriseerd", + "WI_Entry_Status_Disabled": "Gehandicapt", + "T_Position": "↑Char: voor karakterdefinities\n↓Char: na karakterdefinities\n↑AN: voor aantekeningen auteur\n↓AN: na aantekeningen auteur\n@D: op diepte", + "Before Char Defs": "Voor karakterdefinities", + "After Char Defs": "Na karakterdefinities", + "Before EM": "↑EM", + "After EM": "↓EM", + "Before AN": "Voor AN", + "After AN": "Na AN", + "at Depth System": "@D⚙️", + "at Depth User": "@D👤", + "at Depth AI": "@D🤖", + "Depth": "Diepte", + "Order:": "Bestelling:", + "Order": "Bestelling:", + "Trigger %:": "Trekker %:", + "Probability": "Waarschijnlijkheid", + "Duplicate world info entry": "Dubbele invoer van wereldinformatie", + "Delete world info entry": "Verwijder wereldinfo-item", + "Comma separated (required)": "Komma gescheiden (vereist)", + "Primary Keywords": "Primaire trefwoorden", + "Keywords or Regexes": "Trefwoorden of Regexes", + "Comma separated list": "Door komma's gescheiden lijst", + "Switch to plaintext mode": "Schakel over naar de leesbare tekstmodus", + "Logic": "Logica", + "AND ANY": "EN ENIGE", + "AND ALL": "EN ALLES", + "NOT ALL": "NIET ALLES", + "NOT ANY": "NIET ENIGE", + "(ignored if empty)": "(genegeerd indien leeg)", + "Optional Filter": "Optioneel filter", + "Keywords or Regexes (ignored if empty)": "Trefwoorden of Regexes (genegeerd indien leeg)", + "Comma separated list (ignored if empty)": "Door komma's gescheiden lijst (genegeerd als leeg)", + "Use global setting": "Gebruik de algemene instelling", + "Case-Sensitive": "Hoofdlettergevoelig", + "Yes": "Ja", + "No": "Nee", + "Can be used to automatically activate Quick Replies": "Kan worden gebruikt om Quick Replies automatisch te activeren", + "Automation ID": "Automatiserings-ID", + "( None )": "( Geen )", + "Content": "Inhoud", + "Exclude from recursion": "Uitsluiten van recursie", + "Prevent further recursion (this entry will not activate others)": "Voorkom verdere recursie (dit item activeert andere niet)", + "Delay until recursion (this entry can only be activated on recursive checking)": "Vertraging tot recursie (deze invoer kan alleen worden geactiveerd bij recursieve controle)", + "What this keyword should mean to the AI, sent verbatim": "Wat dit trefwoord voor de AI zou moeten betekenen, woordelijk verzonden", + "Filter to Character(s)": "Filteren op personage(s)", + "Character Exclusion": "Personage uitsluiting", + "-- Characters not found --": "-- Personages niet gevonden --", + "Inclusion Group": "Insluitingsgroep", + "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "Inclusiegroepen zorgen ervoor dat slechts één item uit een groep tegelijk wordt geactiveerd, als er meerdere worden geactiveerd.\rOndersteunt meerdere door komma's gescheiden groepen.\r\rDocumentatie: World Info - Inclusion Group", + "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "Geef prioriteit aan deze invoer: Als dit selectievakje is aangevinkt, krijgt deze invoer prioriteit boven alle selecties. Als er meerdere items prioriteit hebben, wordt de invoer met de hoogste 'volgorde' gekozen.", + "Only one entry with the same label will be activated": "Slechts één item met hetzelfde label zal worden geactiveerd", + "A relative likelihood of entry activation within the group": "Een relatieve waarschijnlijkheid van activatie binnen de groep", + "Group Weight": "Groepsgewicht", + "Selective": "Selectief", + "Use Probability": "Gebruik Waarschijnlijkheid", + "Add Memo": "Memo toevoegen", + "Text or token ids": "Tekst of [token-ID's]", + "close": "dichtbij", + "prompt_manager_edit": "Bewerking", + "prompt_manager_name": "Naam", + "A name for this prompt.": "Een naam voor deze prompt.", + "To whom this message will be attributed.": "Aan wie dit bericht wordt toegeschreven.", + "AI Assistant": "AI-assistent", + "prompt_manager_position": "Positie", + "Injection position. Next to other prompts (relative) or in-chat (absolute).": "Injectiepositie. Naast andere prompts (relatief) of in-chat (absoluut).", + "prompt_manager_relative": "Familielid", + "prompt_manager_depth": "Diepte", + "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "Injectiediepte. 0 = na het laatste bericht, 1 = voor het laatste bericht, etc.", + "Prompt": "Prompt", + "The prompt to be sent.": "De prompt die verzonden moet worden.", + "This prompt cannot be overridden by character cards, even if overrides are preferred.": "Deze prompt kan niet worden overschreven door karakterkaarten, zelfs als overschrijvingen de voorkeur hebben.", + "prompt_manager_forbid_overrides": "Overschrijvingen verbieden", + "reset": "opnieuw instellen", + "save": "redden", + "This message is invisible for the AI": "Dit bericht is onzichtbaar voor de AI", + "Message Actions": "Berichtacties", + "Translate message": "Bericht vertalen", + "Generate Image": "Afbeelding genereren", + "Narrate": "Vertellen", + "Exclude message from prompts": "Bericht uitsluiten van prompts", + "Include message in prompts": "Bericht opnemen in prompts", + "Embed file or image": "Bestand of afbeelding insluiten", + "Create checkpoint": "Controlepunt maken", + "Create Branch": "Vertakking maken", + "Copy": "Kopiëren", + "Open checkpoint chat": "Open controlepostchat", + "Edit": "Bewerken", + "Confirm": "Bevestigen", + "Copy this message": "Dit bericht kopiëren", + "Delete this message": "Dit bericht verwijderen", + "Move message up": "Bericht omhoog verplaatsen", + "Move message down": "Bericht omlaag verplaatsen", + "Enlarge": "Vergroten", + "Welcome to SillyTavern!": "Welkom bij SillyTavern!", + "welcome_message_part_1": "Lees de", + "welcome_message_part_2": "Officiële documentatie", + "welcome_message_part_3": null, + "welcome_message_part_4": "Type", + "welcome_message_part_5": "in de chat voor opdrachten en macro's.", + "welcome_message_part_6": "Sluit je aan bij de", + "Discord server": "Discord-server", + "welcome_message_part_7": "voor info en aankondigingen.", + "SillyTavern is aimed at advanced users.": "SillyTavern is gericht op gevorderde gebruikers.", + "If you're new to this, enable the simplified UI mode below.": "Als dit nieuw voor je is, schakel dan de vereenvoudigde UI-modus hieronder in.", + "Change it later in the 'User Settings' panel.": "Wijzig het later in het paneel 'Gebruikersinstellingen'.", + "Enable simple UI mode": "Schakel de eenvoudige UI-modus in", + "Looking for AI characters?": "Op zoek naar AI-personages?", + "onboarding_import": "Importeren", + "from supported sources or view": "van ondersteunde bronnen of weergave", + "Sample characters": "Voorbeeld karakters", + "Your Persona": "Je Personage", + "Before you get started, you must select a persona name.": "Voordat u aan de slag gaat, moet u een personanaam selecteren.", + "welcome_message_part_8": "Dit kunt u op ieder moment wijzigen via de", + "welcome_message_part_9": "icoon.", + "Persona Name:": "Personanaam:", + "Temporarily disable automatic replies from this character": "Tijdelijk automatische antwoorden van dit personage uitschakelen", + "Enable automatic replies from this character": "Automatische antwoorden van dit personage inschakelen", + "Trigger a message from this character": "Een bericht activeren van dit personage", + "Move up": "Omhoog verplaatsen", + "Move down": "Omlaag verplaatsen", + "View character card": "Bekijk personagekaart", + "Remove from group": "Verwijderen uit groep", + "Add to group": "Toevoegen aan groep", + "Alternate Greetings": "Alternatieve groeten", + "Alternate_Greetings_desc": "Deze worden weergegeven als veegbewegingen in het eerste bericht wanneer u een nieuwe chat start.\n Groepsleden kunnen een van hen selecteren om het gesprek te starten.", + "Alternate Greetings Hint": "Klik op de knop om aan de slag te gaan!", + "(This will be the first message from the character that starts every chat)": "(Dit zal het eerste bericht zijn van het personage dat elke chat begint)", + "Forbid Media Override explanation": "Mogelijkheid van het huidige personage/groep om externe media te gebruiken in chats.", + "Forbid Media Override subtitle": "Media: afbeeldingen, video's, audio. Extern: niet gehost op de lokale server.", + "Always forbidden": "Altijd verboden", + "Always allowed": "altijd toegestaan", + "View contents": "Bekijk de inhoud", + "Remove the file": "Verwijder het bestand", + "Unique to this chat": "Uniek aan deze chat", + "Checkpoints inherit the Note from their parent, and can be changed individually after that.": "Controlepunten nemen de notitie over van hun ouder en kunnen daarna afzonderlijk worden gewijzigd.", + "Include in World Info Scanning": "Opnemen in World Info Scannen", + "Before Main Prompt / Story String": "Vóór de hoofdprompt / verhaalreeks", + "After Main Prompt / Story String": "Na de hoofdprompt / verhaalreeks", + "as": "als", + "Insertion Frequency": "Inbrengfrequentie", + "(0 = Disable, 1 = Always)": "(0 = Uitschakelen, 1 = Altijd)", + "User inputs until next insertion:": "Gebruikersinvoer tot de volgende invoeging:", + "Character Author's Note (Private)": "Notitie van de auteur van het personage (privé)", + "Won't be shared with the character card on export.": "Wordt bij het exporteren niet gedeeld met de karakterkaart.", + "Will be automatically added as the author's note for this character. Will be used in groups, but can't be modified when a group chat is open.": "Wordt automatisch toegevoegd als auteursnotitie voor dit personage. Zal in groepen worden gebruikt, maar\n kan niet worden gewijzigd wanneer een groepschat geopend is.", + "Use character author's note": "Gebruik de notitie van de auteur van het personage", + "Replace Author's Note": "Vervang de opmerking van de auteur", + "Default Author's Note": "Standaardnotitie van de auteur", + "Will be automatically added as the Author's Note for all new chats.": "Wordt automatisch toegevoegd als notitie van de auteur voor alle nieuwe chats.", + "Chat CFG": "Chat CFG", + "1 = disabled": "1 = uitgeschakeld", + "write short replies, write replies using past tense": "schrijf korte antwoorden, schrijf antwoorden in de verleden tijd", + "Positive Prompt": "Positieve prompt", + "Use character CFG scales": "Gebruik karakter CFG-schalen", + "Character CFG": "Karakter CFG", + "Will be automatically added as the CFG for this character.": "Wordt automatisch toegevoegd als de CFG voor dit personage.", + "Global CFG": "Mondiale CFG", + "Will be used as the default CFG options for every chat unless overridden.": "Wordt gebruikt als de standaard CFG-opties voor elke chat, tenzij deze wordt overschreven.", + "CFG Prompt Cascading": "CFG-promptcascadering", + "Combine positive/negative prompts from other boxes.": "Combineer positieve/negatieve aanwijzingen uit andere vakken.", + "For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string.": "Als u bijvoorbeeld de vakjes chat, globaal en teken aanvinkt, worden alle negatieve prompts samengevoegd tot een door komma's gescheiden tekenreeks.", + "Always Include": "Altijd opnemen", + "Chat Negatives": "Chat-negatieven", + "Character Negatives": "Negatieven van het karakter", + "Global Negatives": "Mondiale negatieven", + "Custom Separator:": "Aangepaste scheidingsteken:", + "Insertion Depth:": "Insteekdiepte:", + "Token Probabilities": "Token-kansen", + "Select a token to see alternatives considered by the AI.": "Selecteer een token om alternatieven te zien die door de AI worden overwogen.", + "Not connected to API!": "Niet verbonden met API!", + "Type a message, or /? for help": "Typ een bericht, of /? voor hulp", + "Continue script execution": "Ga door met de uitvoering van het script", + "Pause script execution": "Pauzeer de uitvoering van het script", + "Abort script execution": "Uitvoering van script afbreken", + "Abort request": "Verzoek annuleren", + "Continue the last message": "Ga door met het laatste bericht", + "Send a message": "Een bericht versturen", + "Close chat": "Chat sluiten", + "Toggle Panels": "Schakel tussen panelen", + "Back to parent chat": "Terug naar ouderlijke chat", + "Save checkpoint": "Controlepunt opslaan", + "Convert to group": "Converteren naar groep", + "Start new chat": "Nieuwe chat starten", + "Manage chat files": "Beheer chatbestanden", + "Delete messages": "Berichten verwijderen", + "Regenerate": "Regenereren", + "Ask AI to write your message for you": "Vraag de AI om je bericht voor je te schrijven", + "Impersonate": "Imiteren", + "Continue": "Doorgaan", + "Bind user name to that avatar": "Gebruikersnaam aan die avatar binden", + "Change persona image": "Afbeelding van persona wijzigen", + "Select this as default persona for the new chats.": "Selecteer dit als standaardpersona voor de nieuwe chats.", + "Delete persona": "Persona verwijderen", + "These characters are the winners of character design contests and have outstandable quality.": "Deze karakters zijn de winnaars van karakterontwerpwedstrijden en hebben een uitstekende kwaliteit.", + "Contest Winners": "Winnaars van de wedstrijd", + "These characters are the finalists of character design contests and have remarkable quality.": "Deze karakters zijn de finalisten van karakterontwerpwedstrijden en hebben een opmerkelijke kwaliteit.", + "Featured Characters": "Uitgelichte personages", + "Attach a File": "Voeg een bestand toe", + "Open Data Bank": "Open databank", + "Enter a URL or the ID of a Fandom wiki page to scrape:": "Voer een URL of de ID in van een Fandom-wikipagina die u wilt schrapen:", + "Examples:": "Voorbeelden:", + "Example:": "Voorbeeld:", + "Single file": "Enkel bestand", + "All articles will be concatenated into a single file.": "Alle artikelen worden samengevoegd in één bestand.", + "File per article": "Bestand per artikel", + "Each article will be saved as a separate file.": "Niet aangeraden. Elk artikel wordt als apart bestand opgeslagen.", + "Data Bank": "Data bank", + "These files will be available for extensions that support attachments (e.g. Vector Storage).": "Deze bestanden zijn beschikbaar voor extensies die bijlagen ondersteunen (bijvoorbeeld Vector Storage).", + "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.": "Ondersteunde bestandstypen: platte tekst, PDF, Markdown, HTML, EPUB.", + "Drag and drop files here to upload.": "Sleep bestanden hierheen om ze te uploaden.", + "Date (Newest First)": "Datum (Nieuwste eerst)", + "Date (Oldest First)": "Datum (oudste eerst)", + "Name (A-Z)": "Naam (A-Z)", + "Name (Z-A)": "Naam (Z-A)", + "Size (Smallest First)": "Grootte (kleinste eerst)", + "Size (Largest First)": "Grootte (grootste eerst)", + "Bulk Edit": "Bulkbewerking", + "Select All": "Selecteer alles", + "Select None": "Selecteer Geen", + "Global Attachments": "Globale bijlagen", + "These files are available for all characters in all chats.": "Deze bestanden zijn beschikbaar voor alle personages in alle chats.", + "Character Attachments": "Karakterbijlagen", + "These files are available the current character in all chats they are in.": "Deze bestanden zijn beschikbaar voor het huidige karakter in alle chats waarin ze zich bevinden.", + "Saved locally. Not exported.": "Lokaal opgeslagen. Niet geëxporteerd.", + "Chat Attachments": "Chatbijlagen", + "These files are available to all characters in the current chat.": "Deze bestanden zijn beschikbaar voor alle personages in de huidige chat.", + "Enter a base URL of the MediaWiki to scrape.": "Voer een basis-URL in van de MediaWiki die u wilt schrapen.", + "Don't include the page name!": "Vermeld de paginanaam niet!", + "Enter web URLs to scrape (one per line):": "Voer web-URL's in om te schrapen (één per regel):", + "Enter a video URL to download its transcript.": "Voer een video-URL of ID in om het transcript ervan te downloaden.", + "Expression API": "Lokaal\nExtra's\nLLM", + "ext_sum_with": "Samenvatten met:", + "ext_sum_main_api": "Hoofd-API", + "ext_sum_current_summary": "Huidig ​​overzicht:", + "ext_sum_restore_previous": "Herstel vorige", + "ext_sum_memory_placeholder": "Hier wordt een samenvatting gegenereerd...", + "Trigger a summary update right now.": "Vat nu samen", + "ext_sum_force_text": "Vat nu samen", + "Disable automatic summary updates. While paused, the summary remains as-is. You can still force an update by pressing the Summarize now button (which is only available with the Main API).": "Schakel automatische samenvattingsupdates uit. Tijdens de pauze blijft de samenvatting zoals ze is. Je kunt nog steeds een update forceren door op de knop Nu samenvatten te drukken (die alleen beschikbaar is met de hoofd-API).", + "ext_sum_pause": "Pauze", + "Omit World Info and Author's Note from text to be summarized. Only has an effect when using the Main API. The Extras API always omits WI/AN.": "Laat wereldinformatie en de notitie van de auteur weg uit de samen te vatten tekst. Heeft alleen effect bij gebruik van de Main API. De Extras API laat WI/AN altijd weg.", + "ext_sum_no_wi_an": "Geen WI/AN", + "ext_sum_settings_tip": "Bewerk de samenvattingsprompt, invoegpositie, enz.", + "ext_sum_settings": "Samenvattingsinstellingen", + "ext_sum_prompt_builder": "Snelle bouwer", + "ext_sum_prompt_builder_1_desc": "De extensie bouwt zijn eigen prompt op met behulp van berichten die nog niet zijn samengevat. Blokkeert de chat totdat de samenvatting is gegenereerd.", + "ext_sum_prompt_builder_1": "Rauw, blokkerend", + "ext_sum_prompt_builder_2_desc": "De extensie bouwt zijn eigen prompt op met behulp van berichten die nog niet zijn samengevat. Blokkeert de chat niet terwijl de samenvatting wordt gegenereerd. Niet alle backends ondersteunen deze modus.", + "ext_sum_prompt_builder_2": "Rauw, niet-blokkerend", + "ext_sum_prompt_builder_3_desc": "De extensie gebruikt de reguliere hoofdpromptbouwer en voegt het samenvattingsverzoek eraan toe als het laatste systeembericht.", + "ext_sum_prompt_builder_3": "Klassiek, blokkerend", + "Summary Prompt": "Samenvatting Prompt", + "ext_sum_restore_default_prompt_tip": "Standaardprompt herstellen", + "ext_sum_prompt_placeholder": "Deze prompt wordt naar AI gestuurd om het genereren van een samenvatting aan te vragen. {{words}} wordt omgezet naar de parameter 'Aantal woorden'.", + "ext_sum_target_length_1": "Doelsamenvattingslengte", + "ext_sum_target_length_2": null, + "ext_sum_target_length_3": "woorden)", + "ext_sum_api_response_length_1": "Lengte van de API-reactie", + "ext_sum_api_response_length_2": null, + "ext_sum_api_response_length_3": "Munten)", + "ext_sum_0_default": "0 = standaard", + "ext_sum_raw_max_msg": "[Raw] Max. aantal berichten per verzoek", + "ext_sum_0_unlimited": "0 = onbeperkt", + "Update frequency": "Frequentie bijwerken", + "ext_sum_update_every_messages_1": "Elke update", + "ext_sum_update_every_messages_2": "berichten", + "ext_sum_0_disable": "0 = uitschakelen", + "ext_sum_auto_adjust_desc": "Probeer het interval automatisch aan te passen op basis van de chatstatistieken.", + "ext_sum_update_every_words_1": "Update elke", + "ext_sum_update_every_words_2": "woorden", + "ext_sum_both_sliders": "Als beide schuifregelaars niet nul zijn, activeren beide met hun respectievelijke intervallen samenvattingsupdates.", + "ext_sum_injection_template": "Injectiesjabloon", + "ext_sum_memory_template_placeholder": "{{summary}} wordt omgezet naar de huidige samenvattingsinhoud.", + "ext_sum_injection_position": "Injectiepositie", + "How many messages before the current end of the chat.": "Hoeveel berichten vóór het huidige einde van de chat.", + "ext_regex_title": "Regex", + "ext_regex_new_global_script": "+ Globaal", + "ext_regex_new_scoped_script": "+ Bereik", + "ext_regex_import_script": "Importeren", + "ext_regex_global_scripts": "Globale scripts", + "ext_regex_global_scripts_desc": "Beschikbaar voor alle karakters. Opgeslagen in lokale instellingen.", + "ext_regex_scoped_scripts": "Scoped-scripts", + "ext_regex_scoped_scripts_desc": "Alleen beschikbaar voor dit personage. Opgeslagen in de kaartgegevens.", + "Regex Editor": "Regex-editor", + "Test Mode": "Testmodus", + "ext_regex_desc": "Regex is een hulpmiddel om tekenreeksen te vinden/vervangen met behulp van reguliere expressies. Wilt u meer weten, klik dan op de ? naast de titel.", + "Input": "Invoer", + "ext_regex_test_input_placeholder": "Typ hier...", + "Output": "Uitvoer", + "ext_regex_output_placeholder": "Leeg", + "Script Name": "Scriptnaam", + "Find Regex": "Zoek Regex", + "Replace With": "Vervangen door", + "ext_regex_replace_string_placeholder": "Gebruik {{match}} om de overeenkomende tekst uit de Find Regex of $1, $2, enz. op te nemen voor capture-groepen.", + "Trim Out": "Uitsnijden", + "ext_regex_trim_placeholder": "Verwijdert globaal alle ongewenste onderdelen uit een regex-match voordat deze worden vervangen. Scheid elk element door een enter.", + "ext_regex_affects": "Beïnvloedt", + "ext_regex_user_input": "Gebruikers invoer", + "ext_regex_ai_output": "AI-uitvoer", + "Slash Commands": "Slash-opdrachten", + "ext_regex_min_depth_desc": "Wanneer toegepast op aanwijzingen of weergave, heeft dit alleen invloed op berichten die ten minste N niveaus diep zijn. 0 = laatste bericht, 1 = voorlaatste bericht, etc. Telt alleen WI-invoer @Depth en bruikbare berichten, d.w.z. niet verborgen of systeem.", + "Min Depth": "Minimale diepte", + "ext_regex_min_depth_placeholder": "Onbeperkt", + "ext_regex_max_depth_desc": "Wanneer toegepast op aanwijzingen of weergave, heeft dit alleen invloed op berichten die niet dieper zijn dan N niveaus. 0 = laatste bericht, 1 = voorlaatste bericht, etc. Telt alleen WI-invoer @Depth en bruikbare berichten, d.w.z. niet verborgen of systeem.", + "ext_regex_other_options": "Andere opties", + "Only Format Display": "Alleen formaatweergave", + "ext_regex_only_format_prompt_desc": "De chatgeschiedenis verandert niet, alleen de prompt waarop het verzoek wordt verzonden (bij het genereren).", + "Only Format Prompt (?)": "Alleen formatteringsprompt", + "Run On Edit": "Uitvoeren op Bewerken", + "ext_regex_substitute_regex_desc": "Vervang {{macros}} in Find Regex voordat u het uitvoert", + "Substitute Regex": "Vervang Regex", + "ext_regex_import_target": "Importeren naar:", + "ext_regex_disable_script": "Script uitschakelen", + "ext_regex_enable_script": "Script inschakelen", + "ext_regex_edit_script": "Script bewerken", + "ext_regex_move_to_global": "Ga naar globale scripts", + "ext_regex_move_to_scoped": "Overstappen op scripts met een bepaald bereik", + "ext_regex_export_script": "Script exporteren", + "ext_regex_delete_script": "Script verwijderen", + "Trigger Stable Diffusion": "Trigger stabiele diffusie", + "sd_Yourself": "Jezelf", + "sd_Your_Face": "Je gezicht", + "sd_Me": "Mij", + "sd_The_Whole_Story": "Het hele verhaal", + "sd_The_Last_Message": "Het laatste bericht", + "sd_Raw_Last_Message": "Rauw laatste bericht", + "sd_Background": "Achtergrond", + "Image Generation": "Beeld genereren", + "sd_refine_mode": "Sta toe dat prompts handmatig worden bewerkt voordat ze naar de generatie-API worden verzonden", + "sd_refine_mode_txt": "Bewerk aanwijzingen vóór het genereren", + "sd_interactive_mode": "Genereer automatisch afbeeldingen bij het verzenden van berichten zoals 'stuur mij een foto van de kat'.", + "sd_interactive_mode_txt": "Interactieve modus", + "sd_multimodal_captioning": "Gebruik multimodale ondertiteling om aanwijzingen te genereren voor gebruikers- en karakterportretten op basis van hun avatars.", + "sd_multimodal_captioning_txt": "Gebruik multimodale ondertiteling voor portretten", + "sd_expand": "Breid prompts automatisch uit met behulp van het tekstgeneratiemodel", + "sd_expand_txt": "Automatisch verbeteren van prompts", + "sd_snap": "Genereer verzoeken met een geforceerde beeldverhouding (portretten, achtergronden) tot de dichtstbijzijnde bekende resolutie, terwijl u probeert het absolute aantal pixels te behouden (aanbevolen voor SDXL).", + "sd_snap_txt": "Maak automatisch aangepaste resoluties", + "Source": "Bron", + "sd_auto_url": "Voorbeeld: {{auto_url}}", + "Authentication (optional)": "Authenticatie (optioneel)", + "Example: username:password": "Voorbeeld: gebruikersnaam:wachtwoord", + "Important:": "Belangrijk:", + "sd_auto_auth_warning_1": "voer SD Web UI uit met de", + "sd_auto_auth_warning_2": "vlag! De server moet toegankelijk zijn vanaf de SillyTavern-hostmachine.", + "sd_drawthings_url": "Voorbeeld: {{drawthings_url}}", + "sd_drawthings_auth_txt": "voer de DrawThings-app uit met HTTP API-switch ingeschakeld in de gebruikersinterface! De server moet toegankelijk zijn vanaf de SillyTavern-hostmachine.", + "sd_vlad_url": "Voorbeeld: {{vlad_url}}", + "The server must be accessible from the SillyTavern host machine.": "De server moet toegankelijk zijn vanaf de SillyTavern-hostmachine.", + "Hint: Save an API key in AI Horde API settings to use it here.": "Tip: sla een API-sleutel op in de AI Horde API-instellingen om deze hier te gebruiken.", + "Allow NSFW images from Horde": "Sta NSFW-afbeeldingen van Horde toe", + "Sanitize prompts (recommended)": "Ontsmettingsmeldingen (aanbevolen)", + "Automatically adjust generation parameters to ensure free image generations.": "Pas de generatieparameters automatisch aan om vrije beeldgeneraties te garanderen.", + "Avoid spending Anlas": "Vermijd het uitgeven van Anlas", + "Opus tier": "(Opus-niveau)", + "View my Anlas": "Bekijk mijn Anna's", + "These settings only apply to DALL-E 3": "Deze instellingen zijn alleen van toepassing op DALL-E 3", + "Image Style": "Afbeeldingsstijl", + "Image Quality": "Beeldkwaliteit", + "Standard": "Standaard", + "HD": "HD", + "sd_comfy_url": "Voorbeeld: {{comfy_url}}", + "Open workflow editor": "Open de werkstroomeditor", + "Create new workflow": "Creëer een nieuwe werkstroom", + "Delete workflow": "Workflow verwijderen", + "Enhance": "Uitbreiden", + "Refine": "Verfijnen", + "Decrisper": "Ontscherper", + "Sampling steps": "Bemonsteringsstappen ()", + "Width": "Breedte ()", + "Height": "Hoogte ()", + "Resolution": "Oplossing", + "Model": "Model", + "Sampling method": "Bemonsteringsmethode", + "Karras (not all samplers supported)": "Karras (niet alle samplers worden ondersteund)", + "SMEA versions of samplers are modified to perform better at high resolution.": "SMEA-versies van samplers zijn aangepast om beter te presteren bij hoge resolutie.", + "SMEA": "SMEA", + "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "DYN-varianten van SMEA-samplers leiden vaak tot een gevarieerdere output, maar kunnen mislukken bij zeer hoge resoluties.", + "DYN": "DYN", + "Scheduler": "Planner", + "Restore Faces": "Gezichten herstellen", + "Hires. Fix": "Huurt in. Repareren", + "Upscaler": "Upscaler", + "Upscale by": "Opschalen door", + "Denoising strength": "Denoiserende kracht", + "Hires steps (2nd pass)": "Huurt stappen (2e pas)", + "Preset for prompt prefix and negative prompt": "Voorinstelling voor promptvoorvoegsel en negatieve prompt", + "Style": "Stijl", + "Save style": "Stijl opslaan", + "Delete style": "Stijl verwijderen", + "Common prompt prefix": "Algemeen promptvoorvoegsel", + "sd_prompt_prefix_placeholder": "Gebruik {prompt} om op te geven waar de gegenereerde prompt moet worden ingevoegd", + "Negative common prompt prefix": "Negatief gemeenschappelijk promptvoorvoegsel", + "Character-specific prompt prefix": "Tekenspecifiek promptvoorvoegsel", + "Won't be used in groups.": "Wordt niet in groepen gebruikt.", + "sd_character_prompt_placeholder": "Alle kenmerken die het momenteel geselecteerde teken beschrijven. Wordt toegevoegd na een algemeen promptvoorvoegsel.\nVoorbeeld: vrouw, groene ogen, bruin haar, roze shirt", + "Character-specific negative prompt prefix": "Tekenspecifiek negatief promptvoorvoegsel", + "sd_character_negative_prompt_placeholder": "Alle kenmerken die niet mogen verschijnen voor het geselecteerde teken. Wordt toegevoegd na een negatief algemeen promptvoorvoegsel.\nVoorbeeld: sieraden, schoenen, brillen", + "Shareable": "Deelbaar", + "Image Prompt Templates": "Sjablonen voor beeldprompts", + "Vectors Model Warning": "Het wordt aanbevolen om vectoren te verwijderen wanneer u tijdens de chat van model verandert. Anders leidt dit tot ondermaatse resultaten.", + "Translate files into English before processing": "Vertaal bestanden naar het Engels voordat ze worden verwerkt", + "Manager Users": "Gebruikers beheren", + "New User": "Nieuwe gebruiker", + "Status:": "Toestand:", + "Created:": "Gemaakt:", + "Display Name:": "Weergavenaam:", + "User Handle:": "Gebruikershandvat:", + "Password:": "Wachtwoord:", + "Confirm Password:": "Bevestig wachtwoord:", + "This will create a new subfolder...": "Hierdoor wordt een nieuwe submap gemaakt in de map /data/ met de gebruikersnaam als mapnaam.", + "Current Password:": "Huidig ​​wachtwoord:", + "New Password:": "Nieuw paswoord:", + "Confirm New Password:": "Bevestig nieuw wachtwoord:", + "Debug Warning": "Functies in deze categorie zijn alleen voor gevorderde gebruikers. Klik nergens op als u niet zeker bent van de gevolgen.", + "Execute": "Uitvoeren", + "Are you sure you want to delete this user?": "Weet u zeker dat u deze gebruiker wilt verwijderen?", + "Deleting:": "Verwijderen:", + "Also wipe user data.": "Wis ook gebruikersgegevens.", + "Warning:": "Waarschuwing:", + "This action is irreversible.": "Deze actie is onomkeerbaar.", + "Type the user's handle below to confirm:": "Typ hieronder de gebruikersnaam van de gebruiker om te bevestigen:", + "Import Characters": "Tekens importeren", + "Enter the URL of the content to import": "Voer de URL in van de inhoud die u wilt importeren", + "Supported sources:": "Ondersteunde bronnen:", + "char_import_1": "Kopvoorn-karakter (directe link of ID)", + "char_import_example": "Voorbeeld:", + "char_import_2": "Chub Lorebook (directe link of ID)", + "char_import_3": "JanitorAI-personage (directe link of UUID)", + "char_import_4": "Pygmalion.chat-teken (directe link of UUID)", + "char_import_5": "AICharacterCards.com-teken (directe link of ID)", + "char_import_6": "Directe PNG-link (zie", + "char_import_7": "voor toegestane hosts)", + "char_import_8": "RisuRealm-personage (directe link)", + "Supports importing multiple characters.": "Ondersteunt het importeren van meerdere tekens.", + "Write each URL or ID into a new line.": "Schrijf elke URL of ID op een nieuwe regel.", + "Export for character": "Exporteren voor karakter", + "Export prompts for this character, including their order.": "Exporteer prompts voor dit personage, inclusief hun volgorde.", + "Export all": "Alles exporteren", + "Export all your prompts to a file": "Exporteer al uw prompts naar een bestand", + "Insert prompt": "Prompt invoegen", + "Delete prompt": "Prompt verwijderen", + "Import a prompt list": "Een promptlijst importeren", + "Export this prompt list": "Deze promptlijst exporteren", + "Reset current character": "Huidig karakter resetten", + "New prompt": "Nieuwe prompt", + "Prompts": "Prompts", + "Total Tokens:": "Totale Tokens:", + "prompt_manager_tokens": "Munten", + "Are you sure you want to reset your settings to factory defaults?": "Weet u zeker dat u uw instellingen wilt terugzetten naar de fabrieksinstellingen?", + "Don't forget to save a snapshot of your settings before proceeding.": "Vergeet niet een momentopname van uw instellingen op te slaan voordat u doorgaat.", + "Settings Snapshots": "Instellingen Momentopnamen", + "Record a snapshot of your current settings.": "Maak een momentopname van uw huidige instellingen.", + "Make a Snapshot": "Maak een momentopname", + "Restore this snapshot": "Herstel deze momentopname", + "Hi,": "Hoi,", + "To enable multi-account features, restart the SillyTavern server with": "Om functies voor meerdere accounts in te schakelen, start u de SillyTavern-server opnieuw op met", + "set to true in the config.yaml file.": "ingesteld op true in het bestand config.yaml.", + "Account Info": "Account informatie", + "To change your user avatar, use the buttons below or select a default persona in the Persona Management menu.": "Om uw gebruikersavatar te wijzigen, gebruikt u de onderstaande knoppen of selecteert u een standaardpersona in het menu Personabeheer.", + "Set your custom avatar.": "Stel uw aangepaste avatar in.", + "Remove your custom avatar.": "Verwijder uw aangepaste avatar.", + "Handle:": "Hendel:", + "This account is password protected.": "Dit account is beveiligd met een wachtwoord.", + "This account is not password protected.": "Dit account is niet beveiligd met een wachtwoord.", + "Account Actions": "Accountacties", + "Change Password": "Verander wachtwoord", + "Manage your settings snapshots.": "Beheer uw momentopnamen van instellingen.", + "Download a complete backup of your user data.": "Download een volledige back-up van uw gebruikersgegevens.", + "Download Backup": "Back-up downloaden", + "Danger Zone": "Gevarenzone", + "Reset your settings to factory defaults.": "Reset uw instellingen naar de fabrieksinstellingen.", + "Reset Settings": "Reset instellingen", + "Wipe all user data and reset your account to factory settings.": "Wis alle gebruikersgegevens en reset uw account naar de fabrieksinstellingen.", + "Reset Everything": "Alles opnieuw instellen", + "Reset Code:": "Reset code:", + "Want to update?": "Wil je SillyTavern updaten?", + "How to start chatting?": "Hoe begin je met chatten?", + "Click _space": "Klik", + "and select a": " en selecteer een", + "Chat API": " Chat-API", + "and pick a character.": "en kies een personage.", + "You can browse a list of bundled characters in the": "U kunt door een lijst met gebundelde karakters bladeren in de", + "Download Extensions & Assets": "Extensies en middelen downloaden", + "menu within": "menu binnen", + "Confused or lost?": "In de war of verdwaald?", + "click these icons!": "klik op deze pictogrammen!", + "in the chat bar": " in de chatbalk", + "SillyTavern Documentation Site": "SillyTavern Documentatiesite", + "Extras Installation Guide": "Extra Installatiegids", + "Still have questions?": "Heb je nog vragen?", + "Join the SillyTavern Discord": "Word lid van de SillyTavern Discord", + "Post a GitHub issue": "Plaats een GitHub-probleem", + "Contact the developers": "Neem contact op met de ontwikkelaars" +} diff --git a/jiuguan2025cc/public/locales/pt-pt.json b/jiuguan2025cc/public/locales/pt-pt.json new file mode 100644 index 0000000000000000000000000000000000000000..5a424bbdf6a3405fffe0e1853ff4bccb589942a3 --- /dev/null +++ b/jiuguan2025cc/public/locales/pt-pt.json @@ -0,0 +1,1443 @@ +{ + "Favorite": "Favorito", + "Tag": "Marcação", + "Duplicate": "Duplicado", + "Persona": "Pessoa", + "Delete": "Excluir", + "AI Response Configuration": "Configuração de resposta da IA", + "AI Configuration panel will stay open": "O painel de configuração da IA permanecerá aberto", + "clickslidertips": "Clique para inserir valores manualmente.", + "MAD LAB MODE ON": "MODO MAD LAB ON", + "Documentation on sampling parameters": "Documentação sobre parâmetros de amostragem", + "kobldpresets": "Configurações predefinidas do Kobold", + "guikoboldaisettings": "Configurações da interface do KoboldAI", + "Update current preset": "Atualizar predefinição atual", + "Save preset as": "Salvar predefinição como", + "Import preset": "Importar predefinição", + "Export preset": "Exportar predefinição", + "Restore current preset": "Restaurar a configuração atual", + "Delete the preset": "Excluir a predefinição", + "novelaipresets": "Configurações predefinidas do NovelAI", + "Default": "Padrão", + "openaipresets": "Configurações predefinidas do OpenAI", + "Text Completion presets": "Configurações predefinidas de conclusão de texto", + "AI Module": "Módulo de IA", + "Changes the style of the generated text.": "Altera o estilo do texto gerado.", + "No Module": "Nenhum módulo", + "Instruct": "Instruir", + "Prose Augmenter": "Aumentador de prosa", + "Text Adventure": "Aventura de texto", + "response legth(tokens)": "Comprimento da resposta (tokens)", + "Streaming": "Streaming", + "Streaming_desc": "Exibir a resposta pouco a pouco conforme ela é gerada", + "context size(tokens)": "Tamanho do contexto (tokens)", + "unlocked": "Desbloqueado", + "Only enable this if your model supports context sizes greater than 8192 tokens": "Ative isso apenas se seu modelo suportar tamanhos de contexto maiores que 8192 tokens", + "Max prompt cost:": "Custo imediato máximo:", + "Display the response bit by bit as it is generated.": "Exibir a resposta bit a bit conforme é gerada.", + "When this is off, responses will be displayed all at once when they are complete.": "Quando isso estiver desligado, as respostas serão exibidas de uma vez quando estiverem completas.", + "Temperature": "Temperatura", + "rep.pen": "Pena de repetição", + "Rep. Pen. Range.": "Faixa de Pen. Rep.", + "Rep. Pen. Slope": "Inclinação da Pena de Rep.", + "Rep. Pen. Freq.": "Freq. Pen. Rep.", + "Rep. Pen. Presence": "Presença de Pen. Rep.", + "TFS": "TFS-Sistema de Segurança", + "Phrase Repetition Penalty": "Pena de Repetição de Frase", + "Off": "Desligado", + "Very light": "Muito leve", + "Light": "Leve", + "Medium": "Médio", + "Aggressive": "Agressivo", + "Very aggressive": "Muito agressivo", + "Unlocked Context Size": "Tamanho do Contexto Desbloqueado", + "Unrestricted maximum value for the context slider": "Valor máximo irrestrito para o controle deslizante de contexto", + "Context Size (tokens)": "Tamanho do Contexto (tokens)", + "Max Response Length (tokens)": "Comprimento Máximo da Resposta (tokens)", + "Multiple swipes per generation": "Vários furtos por geração", + "Enable OpenAI completion streaming": "Ativar streaming de conclusão do OpenAI", + "Frequency Penalty": "Pena de Frequência", + "Presence Penalty": "Pena de Presença", + "Count Penalty": "Contar penalidade", + "Top K": "Top K", + "Top P": "Top P", + "Repetition Penalty": "Penalidade de repetição", + "Min P": "P mínimo", + "Top A": "Top A", + "Quick Prompts Edit": "Edição Rápida de Prompts", + "Main": "Principal", + "NSFW": "Não recomendado para menores de 18 anos", + "Jailbreak": "Jailbreak", + "Utility Prompts": "Prompts de Utilidade", + "Impersonation prompt": "Prompt de Impersonação", + "Restore default prompt": "Restaurar prompt padrão", + "Prompt that is used for Impersonation function": "Prompt usado para a função de Impersonação", + "World Info Format Template": "Modelo de formato de informações mundiais", + "Restore default format": "Restaurar formato padrão", + "Wraps activated World Info entries before inserting into the prompt.": "Envolve entradas de informações do mundo ativadas antes de inseri-las no prompt.", + "scenario_format_template_part_1": "Usar", + "scenario_format_template_part_2": "para marcar um local onde o conteúdo é inserido.", + "Scenario Format Template": "Modelo de formato de cenário", + "Personality Format Template": "Modelo de formato de personalidade", + "Group Nudge Prompt Template": "Modelo de prompt de incentivo de grupo", + "Sent at the end of the group chat history to force reply from a specific character.": "Enviado no final do histórico do chat em grupo para forçar a resposta de um personagem específico.", + "New Chat": "Novo chat", + "Restore new chat prompt": "Restaurar novo prompt de bate-papo", + "Set at the beginning of the chat history to indicate that a new chat is about to start.": "Definido no início do histórico de bate-papo para indicar que um novo bate-papo está prestes a começar.", + "New Group Chat": "Novo bate-papo em grupo", + "Restore new group chat prompt": "Restaurar prompt padrão", + "Set at the beginning of the chat history to indicate that a new group chat is about to start.": "Definido no início do histórico de bate-papo para indicar que um novo bate-papo em grupo está prestes a começar.", + "New Example Chat": "Novo exemplo de bate-papo", + "Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.": "Definido no início dos exemplos de Diálogo para indicar que um novo exemplo de bate-papo está prestes a começar.", + "Continue nudge": "Continuar cutucar", + "Set at the end of the chat history when the continue button is pressed.": "Definido no final do histórico de bate-papo quando o botão continuar é pressionado.", + "Replace empty message": "Substituir mensagem vazia", + "Send this text instead of nothing when the text box is empty.": "Enviar este texto em vez de nada quando a caixa de texto estiver vazia.", + "Seed": "Semente", + "Set to get deterministic results. Use -1 for random seed.": "Definido para obter resultados determinísticos. Use -1 para sementes aleatórias.", + "Temperature controls the randomness in token selection": "A temperatura controla a aleatoriedade na seleção de tokens", + "Top_K_desc": "Top K define uma quantidade máxima de tokens principais que podem ser escolhidos", + "Top_P_desc": "Top P (também conhecido como amostragem de núcleo)", + "Typical P": "P Típico", + "Typical_P_desc": "A amostragem típica de P prioriza tokens com base em sua divergência da entropia média do conjunto", + "Min_P_desc": "Min P define uma probabilidade mínima base", + "Top_A_desc": "Top A define um limiar para seleção de token com base no quadrado da maior probabilidade de token", + "Tail_Free_Sampling_desc": "Amostragem sem cauda (TFS)", + "rep.pen range": "Intervalo de pena de repetição", + "Mirostat": "Mirostat", + "Mode": "Modo", + "Mirostat_Mode_desc": "Um valor 0 desativa totalmente o Mirostat. 1 é para Mirostat 1.0 e 2 é para Mirostat 2.0", + "Tau": "Tau", + "Mirostat_Tau_desc": "Controla a variabilidade das saídas do Mirostat", + "Eta": "Eta", + "Mirostat_Eta_desc": "Controla a taxa de aprendizagem do Mirostat", + "Ban EOS Token": "Banir Token EOS", + "Ban_EOS_Token_desc": "Banir o token End-of-Sequence (EOS) com KoboldCpp (e possivelmente também outros tokens com KoboldAI).\rBom para escrever histórias, mas não deve ser usado no modo chat e instrução.", + "GBNF Grammar": "Gramática GBNF", + "Type in the desired custom grammar": "Digite a gramática personalizada desejada", + "Samplers Order": "Ordem dos samplers", + "Samplers will be applied in a top-down order. Use with caution.": "Os samplers serão aplicados em ordem de cima para baixo. Use com cautela.", + "Tail Free Sampling": "Amostragem Livre de Cauda", + "Load koboldcpp order": "Carregar ordem koboldcpp", + "Preamble": "Preâmbulo", + "Use style tags to modify the writing style of the output.": "Use tags de estilo para modificar o estilo de escrita da saída.", + "Banned Tokens": "Tokens Proibidos", + "Sequences you don't want to appear in the output. One per line.": "Sequências que você não quer que apareçam na saída. Uma por linha.", + "Logit Bias": "Viés de Logit", + "Add": "Adicionar", + "Helps to ban or reenforce the usage of certain words": "Ajuda a proibir ou reforçar o uso de certas palavras", + "CFG Scale": "Escala CFG", + "Negative Prompt": "Prompt Negativo", + "Add text here that would make the AI generate things you don't want in your outputs.": "Adicione aqui texto que faria a IA gerar coisas que você não quer em suas saídas.", + "Used if CFG Scale is unset globally, per chat or character": "Usado se a Escala CFG não estiver definida globalmente, por chat ou caractere", + "Mirostat Tau": "Tau Mirostat", + "Mirostat LR": "Mirostat LR", + "Min Length": "Comprimento Mínimo", + "Top K Sampling": "Amostragem dos Principais K", + "Nucleus Sampling": "Amostragem de Núcleo", + "Top A Sampling": "Amostragem dos Principais A", + "CFG": "CFG", + "Neutralize Samplers": "Neutralizar Amostradores", + "Set all samplers to their neutral/disabled state.": "Defina todos os amostradores para seu estado neutro/desativado.", + "Sampler Select": "Seleção de amostrador", + "Customize displayed samplers or add custom samplers.": "Personalize os samplers exibidos ou adicione samplers personalizados.", + "Epsilon Cutoff": "Limite Epsilon", + "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "O corte de epsilon define um limite de probabilidade abaixo do qual os tokens são excluídos da amostragem", + "Eta Cutoff": "Limite Eta", + "Eta_Cutoff_desc": "O corte Eta é o principal parâmetro da técnica especial de Amostragem Eta. Em unidades de 1e-4; um valor razoável é 3. Defina como 0 para desativar. Consulte o artigo Truncation Sampling as Language Model Desmoothing de Hewitt et al. (2022) para mais detalhes.", + "rep.pen decay": "Decadência da caneta representante", + "Encoder Rep. Pen.": "Pena de Rep. do Codificador", + "No Repeat Ngram Size": "Tamanho de Ngrama sem repetição", + "Skew": "Inclinar", + "Max Tokens Second": "Máximo de Tokens por Segundo", + "Smooth Sampling": "Amostragem Suave", + "Smooth_Sampling_desc": "Permite usar transformações quadráticas/cúbicas para ajustar a distribuição. Valores mais baixos do fator de suavização serão mais criativos, geralmente entre 0,2-0,3 é o ponto ideal (assumindo que a curva = 1). Valores mais altos da curva de suavização tornarão a curva mais íngreme, o que punirá as escolhas de baixa probabilidade de forma mais agressiva. A curva 1.0 equivale a usar apenas o fator de suavização.", + "Smoothing Factor": "Fator de Suavização", + "Smoothing Curve": "Curva de suavização", + "DRY_Repetition_Penalty_desc": "DRY penaliza tokens que estenderiam o fim da entrada em uma sequência que ocorreu anteriormente na entrada. Defina o multiplicador como 0 para desabilitar.", + "DRY Repetition Penalty": "Penalidade de Repetição SECA", + "DRY_Multiplier_desc": "Defina para valor > 0 para ativar DRY. Controla a magnitude da penalidade para as sequências penalizadas mais curtas.", + "Multiplier": "Multiplicador", + "DRY_Base_desc": "Controla a rapidez com que a penalidade aumenta com o aumento do comprimento da sequência.", + "Base": "Base", + "DRY_Allowed_Length_desc": "A sequência mais longa que pode ser repetida sem ser penalizada.", + "Allowed Length": "Comprimento permitido", + "Penalty Range": "Faixa de Penalidade", + "DRY_Sequence_Breakers_desc": "Tokens nos quais a correspondência de sequência não é continuada. Especificado como uma lista separada por vírgulas de cadeias de caracteres entre aspas.", + "Sequence Breakers": "Quebradores de sequência", + "JSON-serialized array of strings.": "Matriz de strings serializada em JSON.", + "Dynamic Temperature": "Temperatura Dinâmica", + "Scale Temperature dynamically per token, based on the variation of probabilities": "Escala de temperatura dinamicamente por token, com base na variação de probabilidades", + "Minimum Temp": "Temperatura Mínima", + "Maximum Temp": "Temperatura Máxima", + "Exponent": "Expoente", + "Mirostat (mode=1 is only for llama.cpp)": "Mirostat (modo=1 é apenas para llama.cpp)", + "Mirostat_desc": "Mirostat é um termostato para perplexidade de saída", + "Mirostat Mode": "Modo Mirostat", + "Variability parameter for Mirostat outputs": "Parâmetro de variabilidade para saídas Mirostat", + "Mirostat Eta": "Eta Mirostat", + "Learning rate of Mirostat": "Taxa de aprendizado de Mirostat", + "Beam search": "Busca de feixe", + "Helpful tip coming soon.": "Dica útil em breve.", + "Number of Beams": "Número de Feixes", + "Length Penalty": "Pena de Comprimento", + "Early Stopping": "Parada Antecipada", + "Contrastive search": "Busca Contrastiva", + "Penalty Alpha": "Alfa de Penalidade", + "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "Força do termo de regularização de busca contrastante. Defina como 0 para desativar o CS.", + "Do Sample": "Amostra", + "Add BOS Token": "Adicionar Token BOS", + "Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative": "Adicione o token BOS ao início das prompts. Desativar isso pode tornar as respostas mais criativas", + "Ban the eos_token. This forces the model to never end the generation prematurely": "Banir o token eos_token. Isso faz com que o modelo nunca termine a geração prematuramente", + "Ignore EOS Token": "Ignorar token EOS", + "Ignore the EOS Token even if it generates.": "Ignore o token EOS mesmo que ele seja gerado.", + "Skip Special Tokens": "Pular Tokens Especiais", + "Temperature Last": "Temperatura Final", + "Temperature_Last_desc": "Usar o amostrador de temperatura por último", + "Speculative Ngram": "Ngram especulativo", + "Use a different speculative decoding method without a draft model": "Use um método de decodificação especulativa diferente sem um modelo preliminar.\rÉ preferível usar um modelo de rascunho. O ngram especulativo não é tão eficaz.", + "Spaces Between Special Tokens": "Espaços entre tokens especiais", + "LLaMA / Mistral / Yi models only": "Apenas modelos LLaMA / Mistral / Yi", + "Example: some text [42, 69, 1337]": "Exemplo: algum texto [42, 69, 1337]", + "Classifier Free Guidance. More helpful tip coming soon": "Orientação sem classificador. Mais dicas úteis em breve", + "Scale": "Escala", + "JSON Schema": "Esquema JSON", + "Type in the desired JSON schema": "Digite o esquema JSON desejado", + "Grammar String": "Cadeia de Gramática", + "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF ou EBNF, depende do backend em uso. Se você estiver usando isso, você deve saber qual.", + "Top P & Min P": "P superior e P mínimo", + "Load default order": "Carregar ordem padrão", + "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "apenas lhama.cpp. Determina a ordem dos amostradores. Se o modo Mirostat não for 0, a ordem do amostrador será ignorada.", + "Sampler Priority": "Prioridade do amostrador", + "Ooba only. Determines the order of samplers.": "Apenas Ooba. Determina a ordem dos amostradores.", + "Character Names Behavior": "Comportamento dos nomes dos personagens", + "Helps the model to associate messages with characters.": "Ajuda o modelo a associar mensagens a personagens.", + "None": "Nenhum", + "character_names_default": "Exceto para grupos e personas passadas. Caso contrário, certifique-se de fornecer nomes no prompt.", + "Don't add character names.": "Não adicione nomes de personagens.", + "Completion": "Objeto de conclusão", + "character_names_completion": "Aplicam-se restrições: apenas alfanuméricos latinos e sublinhados. Não funciona para todas as fontes, nomeadamente: Claude, MistralAI, Google.", + "Add character names to completion objects.": "Adicione nomes de personagens a objetos de conclusão.", + "Message Content": "Conteúdo da mensagem", + "Prepend character names to message contents.": "Anexe nomes de caracteres ao conteúdo da mensagem.", + "Continue Postfix": "Continuar Postfix", + "The next chunk of the continued message will be appended using this as a separator.": "O próximo pedaço da mensagem continuada será anexado usando-o como separador.", + "Space": "Espaço", + "Newline": "Nova linha", + "Double Newline": "Nova linha dupla", + "Wrap user messages in quotes before sending": "Envolver mensagens do usuário entre aspas antes de enviar", + "Wrap in Quotes": "Envolver em Aspas", + "Wrap entire user message in quotes before sending.": "Envolver toda a mensagem do usuário em aspas antes de enviar.", + "Leave off if you use quotes manually for speech.": "Deixe desativado se você usar aspas manualmente para fala.", + "Continue prefill": "Continuar com preenchimento prévio", + "Continue sends the last message as assistant role instead of system message with instruction.": "Continuar envia a última mensagem como papel de assistente em vez de mensagem do sistema com instrução.", + "Squash system messages": "Agrupar mensagens do sistema", + "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Combina mensagens do sistema consecutivas em uma (excluindo diálogos de exemplo). Pode melhorar a coerência para alguns modelos.", + "Enable function calling": "Habilitar chamada de função", + "Send inline images": "Enviar imagens inline", + "image_inlining_hint_1": "Envia imagens em prompts se o modelo suportar (por exemplo, GPT-4V, Claude 3 ou Llava 13B).\n Use o", + "image_inlining_hint_2": "ação em qualquer mensagem ou", + "image_inlining_hint_3": "menu para anexar um arquivo de imagem ao chat.", + "Inline Image Quality": "Qualidade de imagem embutida", + "openai_inline_image_quality_auto": "Auto", + "openai_inline_image_quality_low": "Baixo", + "openai_inline_image_quality_high": "Alto", + "Use AI21 Tokenizer": "Use o tokenizador AI21", + "Use the appropriate tokenizer for Jurassic models, which is more efficient than GPT's.": "Use o tokenizer apropriado para modelos Jurássicos, que é mais eficiente que o GPT.", + "Use Google Tokenizer": "Usar Tokenizer do Google", + "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "Use o tokenizador apropriado para modelos do Google via sua API. Processamento de prompt mais lento, mas oferece contagem de token muito mais precisa.", + "Use system prompt": "Usar prompt do sistema", + "(Gemini 1.5 Pro/Flash only)": "(Somente Gemini 1.5 Pro/Flash)", + "Merges_all_system_messages_desc_1": "Mescla todas as mensagens do sistema até a primeira mensagem com uma função que não seja do sistema e as envia em um", + "Merges_all_system_messages_desc_2": "campo.", + "Assistant Prefill": "Preenchimento prévio do assistente", + "Start Claude's answer with...": "Iniciar resposta de Claude com...", + "Assistant Impersonation Prefill": "Pré-preenchimento de representação do assistente", + "Use system prompt (Claude 2.1+ only)": "Usar prompt do sistema (apenas Claude 2.1+)", + "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "Enviar o prompt do sistema para modelos suportados. Se desativado, a mensagem do usuário é adicionada ao início do prompt.", + "User first message": "Primeira mensagem do usuário", + "Restore User first message": "Restaurar a primeira mensagem do usuário", + "Human message": "Mensagem humana, instrução, etc.\nNão adiciona nada quando vazio, ou seja, requer um novo prompt com a função 'usuário'.", + "New preset": "Nova predefinição", + "Delete preset": "Excluir predefinição", + "View / Edit bias preset": "Ver / Editar predefinição de viés", + "Add bias entry": "Adicionar entrada de viés", + "Most tokens have a leading space.": "A maioria dos tokens tem um espaço à esquerda.", + "API Connections": "Conexões da API", + "Text Completion": "Conclusão de texto", + "Chat Completion": "Conclusão do bate-papo", + "NovelAI": "NovelAI", + "AI Horde": "AI Horde", + "KoboldAI": "KoboldAI", + "Avoid sending sensitive information to the Horde.": "Evite enviar informações sensíveis para a Horda.", + "Review the Privacy statement": "Reveja a declaração de privacidade", + "Register a Horde account for faster queue times": "Registre uma conta Horde para tempos de fila mais rápidos", + "Learn how to contribute your idle GPU cycles to the Horde": "Saiba como contribuir com seus ciclos de GPU inativos para a Horda", + "Adjust context size to worker capabilities": "Ajustar o tamanho do contexto às capacidades do trabalhador", + "Adjust response length to worker capabilities": "Ajustar o comprimento da resposta às capacidades do trabalhador", + "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "Pode ajudar com respostas ruins, enfileirando apenas os trabalhadores aprovados. Pode diminuir a velocidade de resposta.", + "Trusted workers only": "Apenas trabalhadores confiáveis", + "API key": "Chave da API", + "Get it here:": "Obtenha aqui:", + "Register": "Registrar", + "View my Kudos": "Ver meus Kudos", + "Enter": "Entrar", + "to use anonymous mode.": "para usar o modo anônimo.", + "Clear your API key": "Limpar sua chave da API", + "For privacy reasons, your API key will be hidden after you reload the page.": "Por motivos de privacidade, sua chave de API será ocultada depois que você recarregar a página.", + "Models": "Modelos", + "Refresh models": "Atualizar modelos", + "-- Horde models not loaded --": "-- Modelos da Horda não carregados --", + "Not connected...": "Não conectado...", + "API url": "URL da API", + "Example: http://127.0.0.1:5000/api ": "Exemplo: http://127.0.0.1:5000/api", + "Connect": "Conectar", + "Cancel": "Cancelar", + "Novel API key": "Chave da API do Novell", + "Get your NovelAI API Key": "Obtenha sua chave de API NovelAI", + "Enter it in the box below": "Digite-o na caixa abaixo", + "Novel AI Model": "Modelo Novel AI", + "No connection...": "Sem conexão...", + "API Type": "Tipo de API", + "Default (completions compatible)": "Padrão [compatível com OpenAI /conclusões: oobabooga, LM Studio, etc.]", + "TogetherAI API Key": "Chave da API TogetherAI", + "TogetherAI Model": "Modelo TogetherAI", + "-- Connect to the API --": "-- Conectar-se à API --", + "OpenRouter API Key": "Chave da API OpenRouter", + "Click Authorize below or get the key from": "Clique em Autorizar abaixo ou obtenha a chave de", + "View Remaining Credits": "Ver créditos restantes", + "OpenRouter Model": "Modelo OpenRouter", + "Model Providers": "Provedores de modelos", + "InfermaticAI API Key": "Chave API InfermaticAI", + "InfermaticAI Model": "Modelo InfermaticAI", + "DreamGen API key": "Chave da API DreamGen", + "DreamGen Model": "Modelo DreamGen", + "Mancer API key": "Chave da API Mancer", + "Mancer Model": "Modelo Mancer", + "Make sure you run it with": "Certifique-se de executá-lo com", + "flag": "bandeira", + "API key (optional)": "Chave da API (opcional)", + "Server url": "URL do servidor", + "Example: 127.0.0.1:5000": "Exemplo: 127.0.0.1:5000", + "Custom model (optional)": "Modelo personalizado (opcional)", + "vllm-project/vllm": "vllm-project/vllm (modo wrapper da API OpenAI)", + "vLLM API key": "Chave de API vLLM", + "Example: 127.0.0.1:8000": "Exemplo: http://127.0.0.1:8000", + "vLLM Model": "Modelo vLLM", + "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (Modo Wrapper para API OpenAI)", + "Aphrodite API key": "Chave da API Aphrodite", + "Aphrodite Model": "Modelo Afrodite", + "ggerganov/llama.cpp": "ggerganov/llama.cpp (Servidor de Saída)", + "Example: 127.0.0.1:8080": "Exemplo: 127.0.0.1:8080", + "Example: 127.0.0.1:11434": "Exemplo: 127.0.0.1:11434", + "Ollama Model": "Modelo Ollama", + "Download": "Baixar", + "Tabby API key": "Chave da API do Tabby", + "koboldcpp API key (optional)": "Chave API koboldcpp (opcional)", + "Example: 127.0.0.1:5001": "Exemplo: 127.0.0.1:5001", + "Authorize": "Autorizar", + "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Obtenha seu token da API do OpenRouter usando o fluxo OAuth. Você será redirecionado para openrouter.ai", + "Bypass status check": "Ignorar verificação de status", + "Chat Completion Source": "Fonte de conclusão de chat", + "Reverse Proxy": "Proxy reverso", + "Proxy Presets": "Predefinições de proxy", + "Saved addresses and passwords.": "Endereços e senhas salvos.", + "Save Proxy": "Salvar Proxy", + "Delete Proxy": "Excluir proxy", + "Proxy Name": "Nome do proxy", + "This will show up as your saved preset.": "Isso aparecerá como sua predefinição salva.", + "Proxy Server URL": "URL do servidor proxy", + "Alternative server URL (leave empty to use the default value).": "URL do servidor alternativo (deixe em branco para usar o valor padrão).", + "Remove your real OAI API Key from the API panel BEFORE typing anything into this box": "Remova sua verdadeira chave de API OAI do painel de API ANTES de digitar algo nesta caixa", + "We cannot provide support for problems encountered while using an unofficial OpenAI proxy": "Não podemos fornecer suporte para problemas encontrados ao usar um proxy não oficial da OpenAI", + "Doesn't work? Try adding": "Não funciona? Tente adicionar", + "at the end!": "no final!", + "Proxy Password": "Senha do proxy", + "Will be used as a password for the proxy instead of API key.": "Será usado como senha do proxy em vez da chave API.", + "Peek a password": "Espie uma senha", + "OpenAI API key": "Chave da API OpenAI", + "View API Usage Metrics": "Ver métricas de uso da API", + "Follow": "Seguir", + "these directions": "estas direções", + "to get your OpenAI API key.": "para obter sua chave da API do OpenAI.", + "Use Proxy password field instead. This input will be ignored.": "Use o campo \"Senha do proxy\". Esta entrada será ignorada.", + "OpenAI Model": "Modelo OpenAI", + "Bypass API status check": "Ignorar verificação de status da API", + "Show External models (provided by API)": "Mostrar modelos externos (fornecidos pela API)", + "Get your key from": "Obtenha sua chave de", + "Anthropic's developer console": "console de desenvolvedor da Anthropic", + "Claude Model": "Modelo Claude", + "Window AI Model": "Modelo Window AI", + "Model Order": "Classificação de modelo OpenRouter", + "Alphabetically": "Alfabeticamente", + "Price": "Preço (mais barato)", + "Context Size": "Tamanho do contexto", + "Group by vendors": "Agrupar por fornecedores", + "Group by vendors Description": "Coloque os modelos OpenAI em um grupo, os modelos antrópicos em outro grupo, etc.", + "Allow fallback routes": "Permitir rotas de fallback", + "Allow fallback routes Description": "O modelo alternativo será escolhido automaticamente se o modelo selecionado não puder atender à sua solicitação.", + "Scale API Key": "Chave da API Scale", + "Clear your cookie": "Limpe seu cookie", + "Alt Method": "Método Alternativo", + "AI21 API Key": "Chave da API AI21", + "AI21 Model": "Modelo AI21", + "Google AI Studio API Key": "Chave API Google AI Studio", + "Google Model": "Modelo Google", + "MistralAI API Key": "Chave de API MistralAI", + "MistralAI Model": "Modelo MistralAI", + "Groq API Key": "Chave API Groq", + "Groq Model": "Modelo Groq", + "Perplexity API Key": "Chave de API de perplexidade", + "Perplexity Model": "Modelo de Perplexidade", + "Cohere API Key": "Chave da API Cohere", + "Cohere Model": "Modelo Coere", + "Custom Endpoint (Base URL)": "Endpoint personalizado (URL base)", + "Custom API Key": "Chave de API personalizada", + "Available Models": "Modelos Disponíveis", + "Prompt Post-Processing": "Pós-processamento imediato", + "Applies additional processing to the prompt before sending it to the API.": "Aplica processamento adicional ao prompt antes de enviá-lo para a API.", + "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "Verifica sua conexão com a API enviando uma mensagem de teste curta. Esteja ciente de que você será creditado por isso!", + "Test Message": "Mensagem de Teste", + "Auto-connect to Last Server": "Conectar-se automaticamente ao último servidor", + "Missing key": "❌ Chave faltando", + "Key saved": "✔️ Chave salva", + "View hidden API keys": "Ver chaves de API ocultas", + "AI Response Formatting": "Formatação de resposta da IA", + "Advanced Formatting": "Formatação Avançada", + "Context Template": "Modelo de Contexto", + "Auto-select this preset for Instruct Mode": "Selecionar automaticamente esta predefinição para o Modo de Instrução", + "Story String": "String de História", + "Example Separator": "Separador de Exemplo", + "Chat Start": "Início do Chat", + "Add Chat Start and Example Separator to a list of stopping strings.": "Adicione o início do bate-papo e o separador de exemplo a uma lista de strings de parada.", + "Use as Stop Strings": "Usar como Strings de Parada", + "context_allow_jailbreak": "Inclui Jailbreak no final do prompt, se definido no cartão de personagem E ''Prefer Char. Jailbreak'' está habilitado.\nISTO NÃO É RECOMENDADO PARA MODELOS DE COMPLEMENTAÇÃO DE TEXTO, PODE LEVAR A UMA SAÍDA RUIM.", + "Allow Jailbreak": "Permitir jailbreak", + "Context Order": "Ordem de Contexto", + "Summary": "Resumo", + "Author's Note": "Nota do autor", + "Example Dialogues": "Diálogos de exemplo", + "Hint": "Dica:", + "In-Chat Position not affected": "Os pedidos de Resumo e Nota do Autor só são afetados quando não possuem uma posição no Chat definida.", + "Instruct Mode": "Modo de Instrução", + "Enabled": "Ativado", + "instruct_bind_to_context": "Se ativado, os modelos de contexto serão selecionados automaticamente com base no nome do modelo de instrução selecionado ou por preferência.", + "Bind to Context": "Vincular ao Contexto", + "Presets": "Predefinições", + "Auto-select this preset on API connection": "Selecionar automaticamente esta predefinição na conexão da API", + "Activation Regex": "Regex de Ativação", + "Wrap Sequences with Newline": "Envolver Sequências com Nova Linha", + "Replace Macro in Sequences": "Substituir Macro em Sequências", + "Skip Example Dialogues Formatting": "Pular formatação de diálogos de exemplo", + "Include Names": "Incluir Nomes", + "Force for Groups and Personas": "Forçar para Grupos e Personas", + "System Prompt": "Prompt do Sistema", + "Instruct Mode Sequences": "Sequências de Modo de Instrução", + "System Prompt Wrapping": "Envolvimento de prompt do sistema", + "Inserted before a System prompt.": "Inserido antes de um prompt do sistema.", + "System Prompt Prefix": "Prefixo do prompt do sistema", + "Inserted after a System prompt.": "Inserido após um prompt do sistema.", + "System Prompt Suffix": "Sufixo de prompt do sistema", + "Chat Messages Wrapping": "Encerramento de mensagens de bate-papo", + "Inserted before a User message and as a last prompt line when impersonating.": "Inserido antes de uma mensagem do usuário e como última linha de prompt ao representar.", + "User Message Prefix": "Prefixo da mensagem do usuário", + "Inserted after a User message.": "Inserido após uma mensagem do usuário.", + "User Message Suffix": "Sufixo da mensagem do usuário", + "Inserted before an Assistant message and as a last prompt line when generating an AI reply.": "Inserido antes de uma mensagem do Assistente e como última linha de prompt ao gerar uma resposta de IA.", + "Assistant Message Prefix": "Prefixo da mensagem do assistente", + "Inserted after an Assistant message.": "Inserido após uma mensagem do Assistente.", + "Assistant Message Suffix": "Sufixo de mensagem do assistente", + "Inserted before a System (added by slash commands or extensions) message.": "Inserido antes de uma mensagem do Sistema (adicionada por comandos de barra ou extensões).", + "System Message Prefix": "Prefixo de mensagem do sistema", + "Inserted after a System message.": "Inserido após uma mensagem do sistema.", + "System Message Suffix": "Sufixo de mensagem do sistema", + "If enabled, System Sequences will be the same as User Sequences.": "Se ativado, as sequências do sistema serão iguais às sequências do usuário.", + "System same as User": "Sistema igual ao Usuário", + "Misc. Sequences": "Diversos. Sequências", + "Inserted before the first Assistant's message.": "Inserido antes da primeira mensagem do Assistente.", + "First Assistant Prefix": "Prefixo do primeiro assistente", + "instruct_last_output_sequence": "Inserido antes da última mensagem do Assistente ou como última linha de prompt ao gerar uma resposta de IA (exceto uma função neutra/de sistema).", + "Last Assistant Prefix": "Último prefixo do assistente", + "Will be inserted as a last prompt line when using system/neutral generation.": "Será inserido como última linha de prompt ao usar geração de sistema/neutro.", + "System Instruction Prefix": "Prefixo de instrução do sistema", + "If a stop sequence is generated, everything past it will be removed from the output (inclusive).": "Se uma sequência de parada for gerada, tudo que passar dela será removido da saída (inclusive).", + "Stop Sequence": "Sequência de Parada", + "Will be inserted at the start of the chat history if it doesn't start with a User message.": "Será inserido no início do histórico do chat se não começar com uma mensagem do usuário.", + "User Filler Message": "Mensagem de preenchimento do usuário", + "Context Formatting": "Formatação de Contexto", + "(Saved to Context Template)": "(Salvo no Modelo de Contexto)", + "Always add character's name to prompt": "Sempre adicionar nome do personagem à prompt", + "Generate only one line per request": "Gerar apenas uma linha por solicitação", + "Trim Incomplete Sentences": "Remover Frases Incompletas", + "Include Newline": "Incluir Nova Linha", + "Misc. Settings": "Configurações Diversas", + "Collapse Consecutive Newlines": "Colapsar Nova Linha Consecutiva", + "Trim spaces": "Remover espaços", + "Tokenizer": "Tokenizador", + "Token Padding": "Preenchimento de Token", + "Start Reply With": "Iniciar Resposta Com", + "AI reply prefix": "Prefixo de resposta da IA", + "Show reply prefix in chat": "Mostrar prefixo de resposta no chat", + "Non-markdown strings": "Cadeias de caracteres não Markdown", + "separate with commas w/o space between": "separe com vírgulas sem espaço entre", + "Custom Stopping Strings": "Cadeias de parada personalizadas", + "JSON serialized array of strings": "Matriz de strings serializada em JSON", + "Replace Macro in Stop Strings": "Substituir Macro em Strings de Parada Personalizadas", + "Auto-Continue": "Auto-Continuar", + "Allow for Chat Completion APIs": "Permitir APIs de Completar Chat", + "Target length (tokens)": "Comprimento alvo (tokens)", + "World Info": "Informações do Mundo", + "Locked = World Editor will stay open": "Trancado = Editor Mundial permanecerá aberto", + "Worlds/Lorebooks": "Mundos/Livros de Histórias", + "Active World(s) for all chats": "Mundo(s) ativo(s) para todos os chats", + "-- World Info not found --": "-- Informações do Mundo não encontradas --", + "Global World Info/Lorebook activation settings": "Configurações de ativação do Global World Info/Lorebook", + "Click to expand": "Clique para expandir", + "Scan Depth": "Profundidade de Digitalização", + "Context %": "Contexto %", + "Budget Cap": "Limite de Orçamento", + "(0 = disabled)": "(0 = desativado)", + "Scan chronologically until reached min entries or token budget.": "Faça a varredura cronologicamente até atingir o mínimo de entradas ou o orçamento de tokens.", + "Min Activations": "Ativações mínimas", + "Max Depth": "Profundidade máxima", + "(0 = unlimited, use budget)": "(0 = ilimitado, usar orçamento)", + "Insertion Strategy": "Estratégia de Inserção", + "Sorted Evenly": "Ordenado Uniformemente", + "Character Lore First": "Lore do Personagem Primeiro", + "Global Lore First": "Lore Global Primeiro", + "Entries can activate other entries by mentioning their keywords": "As entradas podem ativar outras entradas mencionando suas palavras-chave", + "Recursive Scan": "Verificação Recursiva", + "Lookup for the entry keys in the context will respect the case": "A busca pelas chaves de entrada no contexto respeitará a caixa", + "Case Sensitive": "Sensível a Maiúsculas", + "If the entry key consists of only one word, it would not be matched as part of other words": "Se a chave de entrada consistir apenas em uma palavra, ela não será correspondida como parte de outras palavras", + "Match Whole Words": "Corresponder Palavras Inteiras", + "Only the entries with the most number of key matches will be selected for Inclusion Group filtering": "Somente as entradas com o maior número de correspondências de chave serão selecionadas para filtragem do Grupo de Inclusão", + "Use Group Scoring": "Usar pontuação de grupo", + "Alert if your world info is greater than the allocated budget.": "Alerte se as informações do seu mundo forem maiores que o orçamento alocado.", + "Alert On Overflow": "Alerta em Overflow", + "New": "Novo", + "or": "ou", + "--- Pick to Edit ---": "--- Escolha para Editar ---", + "Rename World Info": "Renomear informações do mundo", + "Open all Entries": "Abrir todas as entradas", + "Close all Entries": "Fechar todas as entradas", + "New Entry": "Nova entrada", + "Fill empty Memo/Titles with Keywords": "Preencher Memo/Títulos vazios com palavras-chave", + "Import World Info": "Importar informações do mundo", + "Export World Info": "Exportar informações do mundo", + "Duplicate World Info": "Duplicar informações do mundo", + "Delete World Info": "Excluir informações do mundo", + "Search...": "Pesquisar...", + "Search": "Procurar", + "Priority": "Prioridade", + "Custom": "Personalizado", + "Title A-Z": "Título A-Z", + "Title Z-A": "Título Z-A", + "Tokens ↗": "Tokens ↗", + "Tokens ↘": "Tokens ↘", + "Depth ↗": "Profundidade ↗", + "Depth ↘": "Profundidade ↘", + "Order ↗": "Ordem ↗", + "Order ↘": "Ordem ↘", + "UID ↗": "UID ↗", + "UID ↘": "UID ↘", + "Trigger% ↗": "Desencadear% ↗", + "Trigger% ↘": "Desencadear% ↘", + "Refresh": "Atualizar", + "User Settings": "Configurações do Usuário", + "Simple": "Simples", + "Advanced": "Avançado", + "UI Language": "Idioma da UI", + "Account": "Conta", + "Admin Panel": "Painel de administração", + "Logout": "Sair", + "Search Settings": "Configurações de Busca", + "UI Theme": "Tema da interface do usuário", + "Import a theme file": "Importar um arquivo de tema", + "Export a theme file": "Exportar um arquivo de tema", + "Delete a theme": "Excluir um tema", + "Update a theme file": "Atualizar um arquivo de tema", + "Save as a new theme": "Salvar como um novo tema", + "Avatar Style:": "Estilo de Avatar", + "Circle": "Círculo", + "Square": "Quadrado", + "Rectangle": "Retângulo", + "Chat Style:": "Estilo do Chat:", + "Flat": "Plano\nBolhas\nDocumento", + "Bubbles": "Bolhas", + "Document": "Documento", + "Specify colors for your theme.": "Especifique as cores do seu tema.", + "Theme Colors": "Cores do tema", + "Main Text": "Texto Principal", + "Italics Text": "Texto em Itálico", + "Underlined Text": "Texto sublinhado", + "Quote Text": "Texto de Citação", + "Shadow Color": "Cor da Sombra", + "Chat Background": "Fundo de Chat", + "UI Background": "Fundo da Interface", + "UI Border": "Borda da Interface", + "User Message Blur Tint": "Tom de Desfoque de Mensagem do Usuário", + "AI Message Blur Tint": "Tom de Desfoque de Mensagem da IA", + "Chat Width": "Largura do bate-papo", + "Width of the main chat window in % of screen width": "Largura da janela principal do chat em % da largura da tela", + "Font Scale": "Escala de Fonte", + "Font size": "Tamanho da fonte", + "Blur Strength": "Força do Desfoque", + "Blur strength on UI panels.": "Força de desfoque nos painéis da IU.", + "Text Shadow Width": "Largura da Sombra do Texto", + "Strength of the text shadows": "Força das sombras do texto", + "Disables animations and transitions": "Desativa animações e transições", + "Reduced Motion": "Movimento reduzido", + "removes blur from window backgrounds": "remove o desfoque dos fundos das janelas", + "No Blur Effect": "Sem Efeito de Desfoque", + "Remove text shadow effect": "Remover efeito de sombra de texto", + "No Text Shadows": "Sem Sombras de Texto", + "Reduce chat height, and put a static sprite behind the chat window": "Reduzir a altura do chat e colocar um sprite estático atrás da janela do chat", + "Waifu Mode": "Modo Waifu", + "Always show the full list of the Message Actions context items for chat messages, instead of hiding them behind '...'": "Sempre mostrar a lista completa dos itens de contexto de Ações de Mensagem para mensagens de chat, em vez de escondê-los atrás de '...'", + "Auto-Expand Message Actions": "Expansão Automática de Ações de Mensagem", + "Alternative UI for numeric sampling parameters with fewer steps": "Interface alternativa para parâmetros de amostragem numérica com menos etapas", + "Zen Sliders": "Controles Zen", + "Entirely unrestrict all numeric sampling parameters": "Desrestringir completamente todos os parâmetros de amostragem numérica", + "Mad Lab Mode": "Modo Mad Lab", + "Time the AI's message generation, and show the duration in the chat log": "Temporizar a geração de mensagens da IA e mostrar a duração no registro de chat", + "Message Timer": "Temporizador de Mensagens", + "Show a timestamp for each message in the chat log": "Mostrar um carimbo de data/hora para cada mensagem no registro de chat", + "Chat Timestamps": "Carimbos de Data/Hora do Chat", + "Show an icon for the API that generated the message": "Mostrar um ícone para a API que gerou a mensagem", + "Model Icon": "Ícone do Modelo", + "Show sequential message numbers in the chat log": "Mostrar números sequenciais de mensagem no registro de chat", + "Message IDs": "IDs de Mensagem", + "Hide avatars in chat messages.": "Oculte avatares em mensagens de bate-papo.", + "Hide Chat Avatars": "Ocultar avatares de bate-papo", + "Show the number of tokens in each message in the chat log": "Mostrar o número de tokens em cada mensagem no registro de chat", + "Show Message Token Count": "Mostrar Contagem de Tokens da Mensagem", + "Single-row message input area. Mobile only, no effect on PC": "Área de entrada de mensagem de uma única linha. Apenas móvel, sem efeito no PC", + "Compact Input Area (Mobile)": "Área de Entrada Compacta (Móvel)", + "In the Character Management panel, show quick selection buttons for favorited characters": "No painel de Gerenciamento de Personagens, mostrar botões de seleção rápida para personagens favoritos", + "Characters Hotswap": "Substituição de Personagens a Quente", + "Enable magnification for zoomed avatar display.": "Ative a ampliação para exibição de avatar ampliada.", + "Avatar Hover Magnification": "Ampliação de foco do avatar", + "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "Ativa um efeito de ampliação ao passar o mouse quando você exibe o avatar ampliado após clicar na imagem de um avatar no bate-papo.", + "Show tagged character folders in the character list": "Mostrar pastas de personagens marcados na lista de personagens", + "Tags as Folders": "Tags como Pastas", + "Tags_as_Folders_desc": "Mudança recente: as tags devem ser marcadas como pastas no menu Gerenciamento de tags para aparecerem como tal. Clique aqui para trazê-lo à tona.", + "Character Handling": "Tratamento de Personagem", + "If set in the advanced character definitions, this field will be displayed in the characters list.": "Se definido nas definições avançadas de personagem, este campo será exibido na lista de personagens.", + "Char List Subheader": "Subcabeçalho da lista de caracteres", + "Character Version": "Versão do personagem", + "Created by": "Criado por", + "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "Usar correspondência fuzzy e pesquisar personagens na lista por todos os campos de dados, não apenas por uma subcadeia de nome", + "Advanced Character Search": "Pesquisa Avançada de Personagens", + "If checked and the character card contains a prompt override (System Prompt), use that instead": "Se marcado e o cartão de personagem contiver uma substituição de prompt (Prompt do Sistema), use isso em vez disso", + "Prefer Character Card Prompt": "Preferir Prompt do Cartão de Personagem", + "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Se marcado e o cartão de personagem contiver uma substituição de jailbreak (Instrução de Histórico de Postagens), use isso em vez disso", + "Prefer Character Card Jailbreak": "Preferir Jailbreak do Cartão de Personagem", + "never_resize_avatars_tooltip": "Evite cortar e redimensionar imagens de personagens importados. Quando desativado, corte/redimensione para 512x768.", + "Never resize avatars": "Nunca redimensionar avatares", + "Show actual file names on the disk, in the characters list display only": "Mostrar nomes de arquivo reais no disco, apenas na exibição da lista de personagens", + "Show avatar filenames": "Mostrar nomes de arquivo de avatar", + "Prompt to import embedded card tags on character import. Otherwise embedded tags are ignored": "Solicitar a importação de tags de cartão incorporadas na importação de personagens. Caso contrário, as tags incorporadas são ignoradas", + "Import Card Tags": "Importar Tags de Cartão", + "Hide character definitions from the editor panel behind a spoiler button": "Ocultar definições de personagens do painel do editor atrás de um botão de spoiler", + "Spoiler Free Mode": "Modo Sem Spoilers", + "Miscellaneous": "Diversos", + "Reload and redraw the currently open chat": "Recarregar e redesenhar o chat atualmente aberto", + "Reload Chat": "Recarregar Chat", + "Debug Menu": "Menu de Depuração", + "Smooth Streaming": "Transmissão Suave", + "Experimental feature. May not work for all backends.": "Recurso experimental. Pode não funcionar para todos os back-ends.", + "Slow": "Lento", + "Fast": "Rápido", + "Play a sound when a message generation finishes": "Reproduzir um som quando a geração de mensagem termina", + "Message Sound": "Som da mensagem", + "Only play a sound when ST's browser tab is unfocused": "Reproduzir um som apenas quando a guia do navegador de ST não estiver focada", + "Background Sound Only": "Apenas Som de Fundo", + "Reduce the formatting requirements on API URLs": "Reduzir os requisitos de formatação nos URLs da API", + "Relaxed API URLS": "URLs da API Relaxadas", + "Ask to import the World Info/Lorebook for every new character with embedded lorebook. If unchecked, a brief message will be shown instead": "Pergunte se deseja importar as Informações Mundiais/Livro de Histórias para cada novo personagem com lorebook incorporado. Se não estiver marcado, será exibida uma breve mensagem em vez disso", + "Lorebook Import Dialog": "Diálogo de Importação de Livro de Histórias", + "Restore unsaved user input on page refresh": "Restaurar a entrada do usuário não salva ao atualizar a página", + "Restore User Input": "Restaurar Entrada do Usuário", + "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "Permitir reposicionamento de certos elementos da interface do usuário arrastando-os. Apenas PC, sem efeito no móvel", + "Movable UI Panels": "Painéis de UI Móveis", + "MovingUI preset. Predefined/saved draggable positions": "Predefinição MovingUI. Posições arrastáveis predefinidas/salvas", + "MUI Preset": "Predefinição de MUI", + "Save movingUI changes to a new file": "Salvar as alterações de MovingUI em um novo arquivo", + "Reset MovingUI panel sizes/locations.": "Redefinir tamanhos/locais do painel MovingUI.", + "Apply a custom CSS style to all of the ST GUI": "Aplicar um estilo CSS personalizado a toda a GUI do ST", + "Custom CSS": "CSS Personalizado", + "Expand the editor": "Expanda o editor", + "Chat/Message Handling": "Tratamento de Chat/Mensagem", + "# Messages to Load": "# Msg. para carregar", + "The number of chat history messages to load before pagination.": "O número de mensagens do histórico de bate-papo a serem carregadas antes da paginação.", + "(0 = All)": "(0 = Todos)", + "Streaming FPS": "FPS de Streaming", + "Update speed of streamed text.": "Atualizar a velocidade do texto transmitido.", + "Example Messages Behavior": "Comportamento de Mensagens de Exemplo", + "Gradual push-out": "Empurrão gradual", + "Always include examples": "Sempre incluir exemplos", + "Never include examples": "Nunca incluir exemplos", + "Send on Enter": "Enviar ao Pressionar Enter", + "Disabled": "Desativado", + "Automatic (PC)": "Automático (PC)", + "Press Send to continue": "Pressione Enviar para continuar", + "Show a button in the input area to ask the AI to continue (extend) its last message": "Mostrar um botão na área de entrada para pedir à IA que continue (estenda) sua última mensagem", + "Quick 'Continue' button": "Botão 'Continuar' rápido", + "Show arrow buttons on the last in-chat message to generate alternative AI responses. Both PC and mobile": "Mostrar botões de seta na última mensagem no chat para gerar respostas alternativas da IA. Tanto no PC quanto no celular", + "Swipes": "Swipes", + "Allow using swiping gestures on the last in-chat message to trigger swipe generation. Mobile only, no effect on PC": "Permitir o uso de gestos de deslizamento na última mensagem no chat para acionar a geração de deslize. Apenas móvel, sem efeito no PC", + "Gestures": "Gestos", + "Auto-load Last Chat": "Carregar automaticamente o último Chat", + "Auto-scroll Chat": "Chat de Rolagem Automática", + "Save edits to messages without confirmation as you type": "Salvar edições em mensagens sem confirmação enquanto você digita", + "Auto-save Message Edits": "Salvar automaticamente Edições de Mensagem", + "Confirm message deletion": "Confirmar exclusão de mensagem", + "Auto-fix Markdown": "Corrigir Markdown automaticamente", + "Disallow embedded media from other domains in chat messages": "Proibir mídia incorporada de outros domínios em mensagens de bate-papo.", + "Forbid External Media": "Proibir Mídia Externa", + "Allow {{char}}: in bot messages": "Permitir {{char}}: em mensagens de bot", + "Allow {{user}}: in bot messages": "Permitir {{user}}: em mensagens de bot", + "Skip encoding and characters in message text, allowing a subset of HTML markup as well as Markdown": "Pular a codificação de caracteres em texto de mensagem, permitindo um subconjunto de marcação HTML, bem como Markdown", + "Show tags in responses": "Mostrar tags em respostas", + "Allow AI messages in groups to contain lines spoken by other group members": "Permitir que mensagens de IA em grupos contenham linhas faladas por outros membros do grupo", + "Relax message trim in Groups": "Reduzir corte de mensagem em Grupos", + "Log prompts to console": "Registrar prompts no console", + "Requests logprobs from the API for the Token Probabilities feature": "Solicita logprobs da API para o recurso de Probabilidades de Token", + "Request token probabilities": "Solicitar probabilidades de token", + "Automatically reject and re-generate AI message based on configurable criteria": "Rejeitar automaticamente e recriar mensagem de IA com base em critérios configuráveis", + "Auto-swipe": "Auto-swipe", + "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Ativar a função de auto-swipe. As configurações nesta seção só têm efeito quando o auto-swipe está ativado", + "Minimum generated message length": "Comprimento mínimo da mensagem gerada", + "If the generated message is shorter than these many characters, trigger an auto-swipe": "Se a mensagem gerada for mais curta que isso, acione um auto-swipe", + "Blacklisted words": "Palavras proibidas", + "words you dont want generated separated by comma ','": "palavras que você não quer geradas separadas por vírgula ','", + "Blacklisted word count to swipe": "Contagem de palavras proibidas para swipe", + "Minimum number of blacklisted words detected to trigger an auto-swipe": "Número mínimo de palavras proibidas detectadas para acionar um auto-swipe", + "AutoComplete Settings": "Configurações de preenchimento automático", + "Automatically hide details": "Ocultar detalhes automaticamente", + "Determines how entries are found for autocomplete.": "Determina como as entradas são encontradas para preenchimento automático.", + "Autocomplete Matching": "Coincidindo", + "Starts with": "Começa com", + "Includes": "Inclui", + "Fuzzy": "Difuso", + "Sets the style of the autocomplete.": "Define o estilo do preenchimento automático.", + "Autocomplete Style": "Estilo", + "Follow Theme": "Seguir tema", + "Dark": "Escuro", + "Sets the font size of the autocomplete.": "Define o tamanho da fonte do preenchimento automático.", + "Sets the width of the autocomplete.": "Define a largura do preenchimento automático.", + "Autocomplete Width": "Largura", + "chat input box": "caixa de entrada de bate-papo", + "entire chat width": "largura total do chat", + "full window width": "largura total da janela", + "STscript Settings": "Configurações STscript", + "Sets default flags for the STscript parser.": "Define sinalizadores padrão para o analisador STscript.", + "Parser Flags": "Sinalizadores de analisador", + "Switch to stricter escaping, allowing all delimiting characters to be escaped with a backslash, and backslashes to be escaped as well.": "Mude para um escape mais estrito, permitindo que todos os caracteres delimitadores sejam escapados com uma barra invertida e que as barras invertidas também sejam escapadas.", + "STRICT_ESCAPING": "STRICT_ESCAPING", + "Replace all {{getvar::}} and {{getglobalvar::}} macros with scoped variables to avoid double macro substitution.": "Substitua todas as macros {{getvar::}} e {{getglobalvar::}} por variáveis ​​com escopo definido para evitar substituição dupla de macros.", + "REPLACE_GETVAR": "REPLACE_GETVAR", + "Change Background Image": "Alterar imagem de fundo", + "Filter": "Filtro", + "Automatically select a background based on the chat context": "Selecionar automaticamente um plano de fundo com base no contexto do chat", + "Auto-select": "Seleção automática", + "System Backgrounds": "Fundos do Sistema", + "Chat Backgrounds": "Fundos de Chat", + "bg_chat_hint_1": "Planos de fundo de bate-papo gerados com o", + "bg_chat_hint_2": "a extensão aparecerá aqui.", + "Extensions": "Extensões", + "Notify on extension updates": "Notificar sobre atualizações de extensão", + "Manage extensions": "Gerenciar extensões", + "Import Extension From Git Repo": "Importar Extensão do Repositório Git", + "Install extension": "Instalar extensão", + "Extras API:": "API extras:", + "Auto-connect": "Auto-conectar", + "Extras API URL": "URL da API de extras", + "Extras API key (optional)": "Chave da API de extras (opcional)", + "Persona Management": "Gerenciamento de Personagens", + "How do I use this?": "Como eu uso isso?", + "Click for stats!": "Clique para estatísticas!", + "Usage Stats": "Estatísticas de uso", + "Backup your personas to a file": "Faça uma cópia de segurança de suas personas para um arquivo", + "Backup": "Cópia de Segurança", + "Restore your personas from a file": "Restaure suas personas de um arquivo", + "Restore": "Restaurar", + "Create a dummy persona": "Criar uma persona fictícia", + "Create": "Criar", + "Toggle grid view": "Alternar visualização de grade", + "No persona description": "[Sem descrição]", + "Name": "Nome", + "Enter your name": "Digite seu nome", + "Click to set a new User Name": "Clique para definir um novo nome de usuário", + "Click to lock your selected persona to the current chat. Click again to remove the lock.": "Clique para travar sua persona selecionada no chat atual. Clique novamente para remover o travamento.", + "Click to set user name for all messages": "Clique para definir o nome de usuário para todas as mensagens", + "Persona Description": "Descrição da Persona", + "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "Exemplo: [{{user}} é uma garota gata romena de 28 anos.]", + "Tokens persona description": "Descrição de tokens da persona", + "Position:": "Posição:", + "In Story String / Prompt Manager": "Na sequência de história / Gerenciador de prompt", + "Top of Author's Note": "Topo da nota do autor", + "Bottom of Author's Note": "Fundo da nota do autor", + "In-chat @ Depth": "No chat @ Depth", + "Depth:": "Profundidade:", + "Role:": "Papel:", + "System": "Sistema", + "User": "Do utilizador", + "Assistant": "Assistente", + "Show notifications on switching personas": "Mostrar notificações ao alternar personas", + "Character Management": "Gerenciamento de personagens", + "Locked = Character Management panel will stay open": "Trancado = O painel de gerenciamento de personagens permanecerá aberto", + "Select/Create Characters": "Selecionar/Criar Personagens", + "Favorite characters to add them to HotSwaps": "Favoritar personagens para adicioná-los aos HotSwaps", + "Token counts may be inaccurate and provided just for reference.": "As contagens de tokens podem ser imprecisas e fornecidas apenas para referência.", + "Total tokens": "Totais de fichas", + "Calculating...": "Calculando...", + "Tokens": "Tokens", + "Permanent tokens": "Tokens permanentes", + "Permanent": "Permanente", + "About Token 'Limits'": "Sobre os 'Limites' do Token", + "Toggle character info panel": "Alternar painel de informações do personagem", + "Name this character": "Nomeie este personagem", + "extension_token_counter": "Fichas:", + "Click to select a new avatar for this character": "Clique para selecionar um novo avatar para este personagem", + "Add to Favorites": "Adicionar aos favoritos", + "Advanced Definition": "Definição avançada", + "Character Lore": "Lore do personagem", + "Chat Lore": "História do bate-papo", + "Export and Download": "Exportar e baixar", + "Duplicate Character": "Duplicar personagem", + "Create Character": "Criar personagem", + "Delete Character": "Excluir personagem", + "More...": "Mais...", + "Link to World Info": "Link para informações do mundo", + "Import Card Lore": "Importar lore do cartão", + "Scenario Override": "Substituição de cenário", + "Convert to Persona": "Converter para Persona", + "Rename": "Renomear", + "Link to Source": "Link para a fonte", + "Replace / Update": "Substituir/Atualizar", + "Import Tags": "Importar tags", + "Search / Create Tags": "Pesquisar / Criar tags", + "View all tags": "Ver todas as tags", + "Creator's Notes": "Notas do criador", + "Show / Hide Description and First Message": "Mostrar / Ocultar Descrição e Primeira Mensagem", + "Character Description": "Descrição do personagem", + "Click to allow/forbid the use of external media for this character.": "Clique para permitir/proibir o uso de mídia externa para este personagem.", + "Ext. Media": "Mídia Externa", + "Describe your character's physical and mental traits here.": "Descreva os traços físicos e mentais do seu personagem aqui.", + "First message": "Primeira mensagem", + "Click to set additional greeting messages": "Clique para definir mensagens de saudação adicionais", + "Alt. Greetings": "Alt. Saudações", + "This will be the first message from the character that starts every chat.": "Esta será a primeira mensagem do personagem que inicia cada chat.", + "Group Controls": "Controles de Grupo", + "Chat Name (Optional)": "Nome do chat (opcional)", + "Click to select a new avatar for this group": "Clique para selecionar um novo avatar para este grupo", + "Group reply strategy": "Estratégia de resposta em grupo", + "Natural order": "Ordem natural", + "List order": "Ordem da lista", + "Group generation handling mode": "Modo de tratamento de geração de grupo", + "Swap character cards": "Trocar cartas de personagem", + "Join character cards (exclude muted)": "Junte-se a cartões de personagem (exclua silenciado)", + "Join character cards (include muted)": "Junte-se a cartões de personagem (inclua silenciado)", + "Inserted before each part of the joined fields.": "Inserido antes de cada parte dos campos unidos.", + "Join Prefix": "Prefixo de adesão", + "When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and with the name of the part (e.g.: description, personality, scenario, etc.)": "Quando 'Unir cartas de personagem' é selecionado, todos os respectivos campos dos personagens são unidos.\rIsto significa que na sequência da história, por exemplo, todas as descrições dos personagens serão unidas a um grande texto.\rSe quiser que esses campos sejam separados, você pode definir um prefixo ou sufixo aqui.\r\rEste valor suporta macros normais e também substituirá {{char}} pelo nome do char relevante e pelo nome da parte (por exemplo: descrição, personalidade, cenário, etc.)", + "Inserted after each part of the joined fields.": "Inserido após cada parte dos campos unidos.", + "Join Suffix": "Junte-se ao sufixo", + "Set a group chat scenario": "Definir um cenário de bate-papo em grupo", + "Click to allow/forbid the use of external media for this group.": "Clique para permitir/proibir o uso de mídia externa para este grupo.", + "Restore collage avatar": "Restaurar avatar de colagem", + "Allow self responses": "Permitir respostas próprias", + "Auto Mode": "Modo Automático", + "Auto Mode delay": "Atraso no modo automático", + "Hide Muted Member Sprites": "Ocultar Sprites de Membros Silenciados", + "Current Members": "Membros Atuais", + "Add Members": "Adicionar Membros", + "Create New Character": "Criar novo personagem", + "Import Character from File": "Importar personagem do arquivo", + "Import content from external URL": "Importar conteúdo de URL externa", + "Create New Chat Group": "Criar novo grupo de bate-papo", + "Characters sorting order": "Ordem de classificação dos personagens", + "A-Z": "A-Z", + "Z-A": "Z-A", + "Newest": "Mais recente", + "Oldest": "Mais antigo", + "Favorites": "Favoritos", + "Recent": "Recente", + "Most chats": "Maioria dos chats", + "Least chats": "Menos chats", + "Most tokens": "Mais tokens", + "Least tokens": "Menos tokens", + "Random": "Aleatório", + "Toggle character grid view": "Alternar visualização em grade de personagem", + "Bulk_edit_characters": "Editar personagens em massa", + "Bulk select all characters": "Selecione em massa todos os caracteres", + "Bulk delete characters": "Excluir personagens em massa", + "popup-button-save": "Salvar", + "popup-button-yes": "Sim", + "popup-button-no": "Não", + "popup-button-cancel": "Cancelar", + "popup-button-import": "Importar", + "Advanced Definitions": "Definições Avançadas", + "Prompt Overrides": "Substituições de prompt", + "(For Chat Completion and Instruct Mode)": "(Para conclusão de bate-papo e modo de instrução)", + "Insert {{original}} into either box to include the respective default prompt from system settings.": "Insira {{original}} em qualquer caixa para incluir o prompt padrão respectivo das configurações do sistema.", + "Main Prompt": "Prompt principal", + "Any contents here will replace the default Main Prompt used for this character. (v2 spec: system_prompt)": "Qualquer conteúdo aqui substituirá o prompt principal padrão usado para este personagem. (especificação v2: system_prompt)", + "Any contents here will replace the default Jailbreak Prompt used for this character. (v2 spec: post_history_instructions)": "Qualquer conteúdo aqui substituirá o prompt de jailbreak padrão usado para este personagem. (especificação v2: post_history_instructions)", + "Creator's Metadata (Not sent with the AI prompt)": "Metadados do criador (Não enviado com o prompt da IA)", + "Creator's Metadata": "Metadados do Criador", + "(Not sent with the AI Prompt)": "(Não enviado com o prompt AI)", + "Everything here is optional": "Tudo aqui é opcional", + "(Botmaker's name / Contact Info)": "(Nome do fabricante do bot / Informações de contato)", + "(If you want to track character versions)": "(Se você deseja rastrear versões do personagem)", + "(Describe the bot, give use tips, or list the chat models it has been tested on. This will be displayed in the character list.)": "(Descreva o bot, dê dicas de uso ou liste os modelos de chat nos quais ele foi testado. Isso será exibido na lista de personagens.)", + "Tags to Embed": "Tags para incorporar", + "(Write a comma-separated list of tags)": "(Escreva uma lista de tags separadas por vírgulas)", + "Personality summary": "Resumo da Personalidade", + "(A brief description of the personality)": "(Uma breve descrição da personalidade)", + "Scenario": "Cenário", + "(Circumstances and context of the interaction)": "(Circunstâncias e contexto da interação)", + "Character's Note": "Nota do personagem", + "(Text to be inserted in-chat @ designated depth and role)": "(Texto a ser inserido no chat na profundidade e função designadas)", + "@ Depth": "@ Profundidade", + "Role": "Papel", + "Talkativeness": "Loquacidade", + "How often the character speaks in group chats!": "Com que frequência o personagem fala em chats em grupo!", + "How often the character speaks in": "Com que frequência o personagem fala", + "group chats!": "chats em grupo!", + "Shy": "Tímido", + "Normal": "Normal", + "Chatty": "Conversador", + "Examples of dialogue": "Exemplos de diálogo", + "Important to set the character's writing style.": "Importante definir o estilo de escrita do personagem.", + "(Examples of chat dialog. Begin each example with START on a new line.)": "(Exemplos de diálogo de chat. Comece cada exemplo com START em uma nova linha.)", + "Save": "Salvar", + "Chat History": "Histórico de Chat", + "Import Chat": "Importar bate-papo", + "Copy to system backgrounds": "Copiar para planos de fundo do sistema", + "Rename background": "Renomear plano de fundo", + "Lock": "Trancar", + "Unlock": "Desbloquear", + "Delete background": "Excluir plano de fundo", + "Chat Scenario Override": "Substituição de cenário de bate-papo", + "Remove": "Remover", + "Type here...": "Digite aqui...", + "Chat Lorebook": "Lorebook de bate-papo para", + "Chat Lorebook for": "Lorebook de bate-papo para", + "chat_world_template_txt": "Uma informação mundial selecionada será vinculada a este chat. Ao gerar uma resposta de IA,\n ele será combinado com as entradas dos livros de história global e de personagens.", + "Select a World Info file for": "Selecionar um arquivo de informações do mundo para", + "Primary Lorebook": "Livro de lore primário", + "A selected World Info will be bound to this character as its own Lorebook.": "Um World Info selecionado será vinculado a este personagem como seu próprio Livro de Lore.", + "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "Ao gerar uma resposta da IA, ela será combinada com as entradas de um seletor global de Informações do Mundo.", + "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "Exportar um personagem também exportaria o arquivo de Livro de Lore selecionado incorporado nos dados JSON.", + "Additional Lorebooks": "Livros de lore adicionais", + "Associate one or more auxillary Lorebooks with this character.": "Associar um ou mais Livros de Lore auxiliares a este personagem.", + "NOTE: These choices are optional and won't be preserved on character export!": "NOTA: Essas escolhas são opcionais e não serão preservadas na exportação do personagem!", + "Rename chat file": "Renomear arquivo de bate-papo", + "Export JSONL chat file": "Exportar arquivo de bate-papo JSONL", + "Download chat as plain text document": "Baixar bate-papo como documento de texto simples", + "Delete chat file": "Excluir arquivo de bate-papo", + "Use tag as folder": "Marcar como pasta", + "Delete tag": "Excluir tag", + "Entry Title/Memo": "Título da Entrada/Memo", + "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized❌ Disabled": "Status de entrada WI:\r🔵 Constante\r🟢 Normais\r🔗 Vetorizado\r❌ Desativado", + "WI_Entry_Status_Constant": "Constante", + "WI_Entry_Status_Normal": "Normal", + "WI_Entry_Status_Vectorized": "Vetorizado", + "WI_Entry_Status_Disabled": "Desabilitado", + "T_Position": "↑Char: antes das definições de caractere\n↓Char: após as definições de caractere\n↑AN: antes das notas do autor\n↓AN: após as notas do autor\n@D: em profundidade", + "Before Char Defs": "Antes das definições de caractere", + "After Char Defs": "Após as definições de caractere", + "Before EM": "↑ EM", + "After EM": "↓EM", + "Before AN": "Antes do AN", + "After AN": "Após o AN", + "at Depth System": "@D⚙️", + "at Depth User": "@D 👤", + "at Depth AI": "@D 🤖", + "Depth": "Profundidade", + "Order:": "Ordem:", + "Order": "Ordem:", + "Trigger %:": "Acionar %:", + "Probability": "Probabilidade", + "Duplicate world info entry": "Entrada de informações mundiais duplicada", + "Delete world info entry": "Excluir entrada de informações mundiais", + "Comma separated (required)": "Separado por vírgula (obrigatório)", + "Primary Keywords": "Palavras-chave primárias", + "Keywords or Regexes": "Palavras-chave ou Regexes", + "Comma separated list": "Lista separada por vírgulas", + "Switch to plaintext mode": "Mudar para o modo de texto simples", + "Logic": "Lógica", + "AND ANY": "E QUALQUER", + "AND ALL": "E TODOS", + "NOT ALL": "NENHUM DE TODOS", + "NOT ANY": "NENHUM DE QUALQUER", + "(ignored if empty)": "(ignorado se estiver vazio)", + "Optional Filter": "Filtro opcional", + "Keywords or Regexes (ignored if empty)": "Palavras-chave ou Regexes (ignorados se vazios)", + "Comma separated list (ignored if empty)": "Lista separada por vírgulas (ignorada se estiver vazia)", + "Use global setting": "Usar configuração global", + "Case-Sensitive": "Diferencia maiúsculas de minúsculas", + "Yes": "Sim", + "No": "Não", + "Can be used to automatically activate Quick Replies": "Pode ser usado para ativar automaticamente as Respostas Rápidas", + "Automation ID": "ID de automação", + "( None )": "( Nenhum )", + "Content": "Conteúdo", + "Exclude from recursion": "Excluir da recursão", + "Prevent further recursion (this entry will not activate others)": "Impedir mais recursões (esta entrada não ativará outras)", + "Delay until recursion (this entry can only be activated on recursive checking)": "Atraso até a recursão (esta entrada só pode ser ativada na verificação recursiva)", + "What this keyword should mean to the AI, sent verbatim": "O que essa palavra-chave deve significar para a IA, enviada literalmente", + "Filter to Character(s)": "Filtrar para Personagem(s)", + "Character Exclusion": "Exclusão de personagem", + "-- Characters not found --": "-- Personagens não encontrados --", + "Inclusion Group": "Grupo de inclusão", + "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "Os Grupos de Inclusão garantem que apenas uma entrada de um grupo seja ativada por vez, se várias forem acionadas.\rSuporta vários grupos separados por vírgula.\r\rDocumentação: World Info - Grupo de Inclusão", + "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "Priorizar esta entrada: quando marcada, esta entrada é priorizada entre todas as seleções.\rSe vários forem priorizados, aquele com a “Ordem” mais alta será escolhido.", + "Only one entry with the same label will be activated": "Apenas uma entrada com o mesmo rótulo será ativada", + "A relative likelihood of entry activation within the group": "Uma probabilidade relativa de ativação de entrada dentro do grupo", + "Group Weight": "Peso do grupo", + "Selective": "Seletivo", + "Use Probability": "Usar Probabilidade", + "Add Memo": "Adicionar memorando", + "Text or token ids": "Texto ou [IDs de token]", + "close": "fechar", + "prompt_manager_edit": "Editar", + "prompt_manager_name": "Nome", + "A name for this prompt.": "Um nome para este prompt.", + "To whom this message will be attributed.": "A quem esta mensagem será atribuída.", + "AI Assistant": "Assistente de IA", + "prompt_manager_position": "Posição", + "Injection position. Next to other prompts (relative) or in-chat (absolute).": "Posição de injeção. Ao lado de outras solicitações (relativas) ou no chat (absolutas).", + "prompt_manager_relative": "Relativo", + "prompt_manager_depth": "Profundidade", + "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "Profundidade de injeção. 0 = após a última mensagem, 1 = antes da última mensagem, etc.", + "Prompt": "Prompt", + "The prompt to be sent.": "O prompt a ser enviado.", + "This prompt cannot be overridden by character cards, even if overrides are preferred.": "Este prompt não pode ser substituído por cartas de personagem, mesmo que as substituições sejam preferidas.", + "prompt_manager_forbid_overrides": "Proibir substituições", + "reset": "reiniciar", + "save": "salvar", + "This message is invisible for the AI": "Esta mensagem é invisível para a IA", + "Message Actions": "Ações de mensagens", + "Translate message": "Traduzir mensagem", + "Generate Image": "Gerar imagem", + "Narrate": "Narrar", + "Exclude message from prompts": "Excluir mensagem de prompts", + "Include message in prompts": "Incluir mensagem em prompts", + "Embed file or image": "Incorporar arquivo ou imagem", + "Create checkpoint": "Criar ponto de verificação", + "Create Branch": "Criar ramo", + "Copy": "Copiar", + "Open checkpoint chat": "Abrir bate-papo do ponto de verificação", + "Edit": "Editar", + "Confirm": "Confirmar", + "Copy this message": "Copiar esta mensagem", + "Delete this message": "Excluir esta mensagem", + "Move message up": "Mover mensagem para cima", + "Move message down": "Mover mensagem para baixo", + "Enlarge": "Aumentar", + "Welcome to SillyTavern!": "Bem-vindo ao SillyTavern!", + "welcome_message_part_1": "Leia o", + "welcome_message_part_2": "Documentação Oficial", + "welcome_message_part_3": null, + "welcome_message_part_4": "Tipo", + "welcome_message_part_5": "no chat para comandos e macros.", + "welcome_message_part_6": "Junte-se a", + "Discord server": "Servidor Discord", + "welcome_message_part_7": "para informações e anúncios.", + "SillyTavern is aimed at advanced users.": "SillyTavern é voltado para usuários avançados.", + "If you're new to this, enable the simplified UI mode below.": "Se você é novo nisso, habilite o modo de UI simplificado abaixo.", + "Change it later in the 'User Settings' panel.": "Altere-o posteriormente no painel ‘Configurações do usuário’.", + "Enable simple UI mode": "Ative o modo UI simples", + "Looking for AI characters?": "Procurando por personagens de IA?", + "onboarding_import": "Importar", + "from supported sources or view": "de fontes suportadas ou visualização", + "Sample characters": "Personagens de amostra", + "Your Persona": "Sua Persona", + "Before you get started, you must select a persona name.": "Antes de começar, você deve selecionar um nome de persona.", + "welcome_message_part_8": "Isso pode ser alterado a qualquer momento através do", + "welcome_message_part_9": "ícone.", + "Persona Name:": "Nome da Pessoa:", + "Temporarily disable automatic replies from this character": "Desativar temporariamente respostas automáticas deste personagem", + "Enable automatic replies from this character": "Ativar respostas automáticas deste personagem", + "Trigger a message from this character": "Disparar uma mensagem deste personagem", + "Move up": "Mover para cima", + "Move down": "Mover para baixo", + "View character card": "Ver cartão de personagem", + "Remove from group": "Remover do grupo", + "Add to group": "Adicionar ao grupo", + "Alternate Greetings": "Saudações alternativas", + "Alternate_Greetings_desc": "Eles serão exibidos como swipes na primeira mensagem ao iniciar um novo chat.\nOs membros do grupo podem selecionar um deles para iniciar a conversa.", + "Alternate Greetings Hint": "Clique no botão para começar!", + "(This will be the first message from the character that starts every chat)": "(Esta será a primeira mensagem do personagem que inicia cada chat)", + "Forbid Media Override explanation": "Capacidade do personagem/grupo atual de usar mídia externa em chats.", + "Forbid Media Override subtitle": "Mídia: imagens, vídeos, áudio. Externo: não hospedado no servidor local.", + "Always forbidden": "Sempre proibido", + "Always allowed": "Sempre permitido", + "View contents": "Ver conteúdo", + "Remove the file": "Remova o arquivo", + "Unique to this chat": "Exclusivo para este chat", + "Checkpoints inherit the Note from their parent, and can be changed individually after that.": "Os pontos de verificação herdam a nota de seu pai e podem ser alterados individualmente depois disso.", + "Include in World Info Scanning": "Incluir na varredura de informações mundiais", + "Before Main Prompt / Story String": "Antes do prompt principal/string da história", + "After Main Prompt / Story String": "Após o prompt principal/sequência de história", + "as": "como", + "Insertion Frequency": "Frequência de Inserção", + "(0 = Disable, 1 = Always)": "(0 = Desativar, 1 = Sempre)", + "User inputs until next insertion:": "Entradas do usuário até a próxima inserção:", + "Character Author's Note (Private)": "Nota do autor do personagem (privado)", + "Won't be shared with the character card on export.": "Não será compartilhado com o cartão de personagem na exportação.", + "Will be automatically added as the author's note for this character. Will be used in groups, but can't be modified when a group chat is open.": "Será adicionado automaticamente como nota do autor para este personagem. Será usado em grupos, mas\n não pode ser modificado quando um bate-papo em grupo está aberto.", + "Use character author's note": "Use a nota do autor do personagem", + "Replace Author's Note": "Substituir nota do autor", + "Default Author's Note": "Nota do autor padrão", + "Will be automatically added as the Author's Note for all new chats.": "Será adicionado automaticamente como Nota do Autor para todos os novos chats.", + "Chat CFG": "Bate-papo CFG", + "1 = disabled": "1 = desativado", + "write short replies, write replies using past tense": "escreva respostas curtas, escreva respostas usando o pretérito", + "Positive Prompt": "Alerta Positivo", + "Use character CFG scales": "Use escalas CFG de caracteres", + "Character CFG": "Personagem CFG", + "Will be automatically added as the CFG for this character.": "Será adicionado automaticamente como CFG para este personagem.", + "Global CFG": "CFG global", + "Will be used as the default CFG options for every chat unless overridden.": "Serão usadas como opções CFG padrão para todos os chats, a menos que sejam substituídas.", + "CFG Prompt Cascading": "Cascata de prompt CFG", + "Combine positive/negative prompts from other boxes.": "Combine prompts positivos/negativos de outras caixas.", + "For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string.": "Por exemplo, marcar as caixas de bate-papo, global e de caracteres combina todos os prompts negativos em uma string separada por vírgula.", + "Always Include": "Sempre incluir", + "Chat Negatives": "Negativos de bate-papo", + "Character Negatives": "Negativos de caracteres", + "Global Negatives": "Negativos Globais", + "Custom Separator:": "Separador personalizado:", + "Insertion Depth:": "Profundidade de inserção:", + "Token Probabilities": "Probabilidades de token", + "Select a token to see alternatives considered by the AI.": "Selecione um token para ver as alternativas consideradas pela IA.", + "Not connected to API!": "Não conectado à API!", + "Type a message, or /? for help": "Digite uma mensagem ou /? para ajuda", + "Continue script execution": "Continuar a execução do script", + "Pause script execution": "Pausar a execução do script", + "Abort script execution": "Abortar a execução do script", + "Abort request": "Cancelar solicitação", + "Continue the last message": "Continuar a última mensagem", + "Send a message": "Enviar uma mensagem", + "Close chat": "Fechar chat", + "Toggle Panels": "Alternar painéis", + "Back to parent chat": "Voltar para o chat anterior", + "Save checkpoint": "Salvar ponto de verificação", + "Convert to group": "Converter em grupo", + "Start new chat": "Iniciar novo chat", + "Manage chat files": "Gerenciar arquivos de chat", + "Delete messages": "Excluir mensagens", + "Regenerate": "Regenerar", + "Ask AI to write your message for you": "Peça à IA para escrever sua mensagem para você", + "Impersonate": "Personificar", + "Continue": "Continuar", + "Bind user name to that avatar": "Associar nome de usuário a esse avatar", + "Change persona image": "Alterar imagem da persona", + "Select this as default persona for the new chats.": "Selecionar isso como persona padrão para os novos chats.", + "Delete persona": "Excluir persona", + "These characters are the winners of character design contests and have outstandable quality.": "Esses personagens são vencedores de concursos de design de personagens e possuem qualidade notável.", + "Contest Winners": "Vencedores do concurso", + "These characters are the finalists of character design contests and have remarkable quality.": "Esses personagens são finalistas de concursos de design de personagens e possuem qualidade notável.", + "Featured Characters": "Personagens em destaque", + "Attach a File": "Anexar um arquivo", + "Open Data Bank": "Banco de dados aberto", + "Enter a URL or the ID of a Fandom wiki page to scrape:": "Insira um URL ou o ID de uma página wiki do Fandom para extrair:", + "Examples:": "Exemplos:", + "Example:": "Exemplo:", + "Single file": "Único arquivo", + "All articles will be concatenated into a single file.": "Todos os artigos serão concatenados em um único arquivo.", + "File per article": "Arquivo por artigo", + "Each article will be saved as a separate file.": "Não recomendado. Cada artigo será salvo como um arquivo separado.", + "Data Bank": "Banco de dados", + "These files will be available for extensions that support attachments (e.g. Vector Storage).": "Esses arquivos estarão disponíveis para extensões que suportam anexos (por exemplo, Vector Storage).", + "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.": "Tipos de arquivos suportados: Texto Simples, PDF, Markdown, HTML, EPUB.", + "Drag and drop files here to upload.": "Arraste e solte os arquivos aqui para fazer upload.", + "Date (Newest First)": "Data (mais recente primeiro)", + "Date (Oldest First)": "Data (mais antigo primeiro)", + "Name (A-Z)": "Nome (A-Z)", + "Name (Z-A)": "Nome (Z-A)", + "Size (Smallest First)": "Tamanho (menor primeiro)", + "Size (Largest First)": "Tamanho (maior primeiro)", + "Bulk Edit": "Edição em massa", + "Select All": "Selecionar tudo", + "Select None": "Selecione nenhum", + "Global Attachments": "Anexos Globais", + "These files are available for all characters in all chats.": "Esses arquivos estão disponíveis para todos os personagens em todos os chats.", + "Character Attachments": "Anexos de personagens", + "These files are available the current character in all chats they are in.": "Esses arquivos estão disponíveis no personagem atual em todos os chats em que eles participam.", + "Saved locally. Not exported.": "Salvo localmente. Não exportado.", + "Chat Attachments": "Anexos de bate-papo", + "These files are available to all characters in the current chat.": "Esses arquivos estão disponíveis para todos os personagens do chat atual.", + "Enter a base URL of the MediaWiki to scrape.": "Insira um URL base do MediaWiki para extrair.", + "Don't include the page name!": "Não inclua o nome da página!", + "Enter web URLs to scrape (one per line):": "Insira URLs da web para extrair (um por linha):", + "Enter a video URL to download its transcript.": "Insira o URL ou ID do vídeo para baixar sua transcrição.", + "Expression API": "Local\nExtras\nLLM", + "ext_sum_with": "Resuma com:", + "ext_sum_main_api": "API principal", + "ext_sum_current_summary": "Resumo atual:", + "ext_sum_restore_previous": "Restaurar anterior", + "ext_sum_memory_placeholder": "O resumo será gerado aqui...", + "Trigger a summary update right now.": "Resuma agora", + "ext_sum_force_text": "Resuma agora", + "Disable automatic summary updates. While paused, the summary remains as-is. You can still force an update by pressing the Summarize now button (which is only available with the Main API).": "Desative as atualizações automáticas de resumo. Durante a pausa, o resumo permanece como está. Você ainda pode forçar uma atualização pressionando o botão Resumir agora (que está disponível apenas na API principal).", + "ext_sum_pause": "Pausa", + "Omit World Info and Author's Note from text to be summarized. Only has an effect when using the Main API. The Extras API always omits WI/AN.": "Omitir Informações Mundiais e Nota do Autor do texto a ser resumido. Só tem efeito ao usar a API principal. A API Extras sempre omite WI/AN.", + "ext_sum_no_wi_an": "Sem WI/AN", + "ext_sum_settings_tip": "Edite o prompt de resumo, posição de inserção, etc.", + "ext_sum_settings": "Configurações de resumo", + "ext_sum_prompt_builder": "Construtor de prompt", + "ext_sum_prompt_builder_1_desc": "A extensão criará seu próprio prompt usando mensagens que ainda não foram resumidas. Bloqueia o chat até que o resumo seja gerado.", + "ext_sum_prompt_builder_1": "Cru, bloqueando", + "ext_sum_prompt_builder_2_desc": "A extensão construirá seu próprio prompt usando mensagens que ainda não foram resumidas. Não bloqueia o chat enquanto o resumo está sendo gerado. Nem todos os backends suportam este modo.", + "ext_sum_prompt_builder_2": "Bruto, sem bloqueio", + "ext_sum_prompt_builder_3_desc": "A extensão usará o construtor de prompt principal regular e adicionará a solicitação de resumo a ele como a última mensagem do sistema.", + "ext_sum_prompt_builder_3": "Clássico, bloqueio", + "Summary Prompt": "Solicitação de resumo", + "ext_sum_restore_default_prompt_tip": "Restaurar prompt padrão", + "ext_sum_prompt_placeholder": "Este prompt será enviado ao AI para solicitar a geração do resumo. {{words}} será resolvido para o parâmetro 'Número de palavras'.", + "ext_sum_target_length_1": "Comprimento do resumo do alvo", + "ext_sum_target_length_2": null, + "ext_sum_target_length_3": "palavras)", + "ext_sum_api_response_length_1": "Comprimento da resposta da API", + "ext_sum_api_response_length_2": null, + "ext_sum_api_response_length_3": "fichas)", + "ext_sum_0_default": "0 = padrão", + "ext_sum_raw_max_msg": "[Raw] Máximo de mensagens por solicitação", + "ext_sum_0_unlimited": "0 = ilimitado", + "Update frequency": "Frequência de atualização", + "ext_sum_update_every_messages_1": "Atualizar a cada", + "ext_sum_update_every_messages_2": "mensagens", + "ext_sum_0_disable": "0 = desabilitar", + "ext_sum_auto_adjust_desc": "Tente ajustar automaticamente o intervalo com base nas métricas do chat.", + "ext_sum_update_every_words_1": "Atualizar a cada", + "ext_sum_update_every_words_2": "palavras", + "ext_sum_both_sliders": "Se ambos os controles deslizantes forem diferentes de zero, ambos acionarão atualizações de resumo em seus respectivos intervalos.", + "ext_sum_injection_template": "Modelo de injeção", + "ext_sum_memory_template_placeholder": "{{summary}} resolverá o conteúdo do resumo atual.", + "ext_sum_injection_position": "Posição de injeção", + "How many messages before the current end of the chat.": "Quantas mensagens antes do final atual do chat.", + "ext_regex_title": "Regex", + "ext_regex_new_global_script": "+Global", + "ext_regex_new_scoped_script": "+ Escopo", + "ext_regex_import_script": "Importar", + "ext_regex_global_scripts": "Scripts Globais", + "ext_regex_global_scripts_desc": "Disponível para todos os personagens. Salvo nas configurações locais.", + "ext_regex_scoped_scripts": "Scripts com escopo", + "ext_regex_scoped_scripts_desc": "Disponível apenas para este personagem. Salvo nos dados do cartão.", + "Regex Editor": "Editor Regex", + "Test Mode": "Modo de teste", + "ext_regex_desc": "Regex é uma ferramenta para encontrar/substituir strings usando expressões regulares. Se quiser saber mais, clique no ? ao lado do título.", + "Input": "Entrada", + "ext_regex_test_input_placeholder": "Digite aqui...", + "Output": "Saída", + "ext_regex_output_placeholder": "Vazio", + "Script Name": "Nome do roteiro", + "Find Regex": "Encontre Regex", + "Replace With": "Substituir com", + "ext_regex_replace_string_placeholder": "Use {{match}} para incluir o texto correspondente do Find Regex ou $1, $2, etc. para grupos de captura.", + "Trim Out": "Aparar", + "ext_regex_trim_placeholder": "Corta globalmente quaisquer peças indesejadas de uma correspondência de regex antes da substituição. Separe cada elemento com um enter.", + "ext_regex_affects": "Afeta", + "ext_regex_user_input": "Entrada do usuário", + "ext_regex_ai_output": "Saída de IA", + "Slash Commands": "Comandos de barra", + "ext_regex_min_depth_desc": "Quando aplicado a prompts ou exibição, afeta apenas mensagens com pelo menos N níveis de profundidade. 0 = última mensagem, 1 = penúltima mensagem, etc. Conta apenas entradas WI @Depth e mensagens utilizáveis, ou seja, não ocultas ou do sistema.", + "Min Depth": "Profundidade mínima", + "ext_regex_min_depth_placeholder": "Ilimitado", + "ext_regex_max_depth_desc": "Quando aplicado a prompts ou exibição, afeta apenas mensagens com profundidade não superior a N. 0 = última mensagem, 1 = penúltima mensagem, etc. Conta apenas entradas WI @Depth e mensagens utilizáveis, ou seja, não ocultas ou do sistema.", + "ext_regex_other_options": "Outras opções", + "Only Format Display": "Somente formato de exibição", + "ext_regex_only_format_prompt_desc": "O histórico de bate-papo não será alterado, apenas o prompt conforme a solicitação é enviada (na geração).", + "Only Format Prompt (?)": "Apenas prompt de formato", + "Run On Edit": "Executar na edição", + "ext_regex_substitute_regex_desc": "Substitua {{macros}} em Find Regex antes de executá-lo", + "Substitute Regex": "Substituir Regex", + "ext_regex_import_target": "Importar para:", + "ext_regex_disable_script": "Desativar script", + "ext_regex_enable_script": "Habilitar script", + "ext_regex_edit_script": "Editar roteiro", + "ext_regex_move_to_global": "Mude para scripts globais", + "ext_regex_move_to_scoped": "Mover para scripts com escopo definido", + "ext_regex_export_script": "Exportar script", + "ext_regex_delete_script": "Excluir roteiro", + "Trigger Stable Diffusion": "Disparar difusão estável", + "sd_Yourself": "Você mesmo", + "sd_Your_Face": "Seu rosto", + "sd_Me": "Meu", + "sd_The_Whole_Story": "A história toda", + "sd_The_Last_Message": "A última mensagem", + "sd_Raw_Last_Message": "Última mensagem bruta", + "sd_Background": "Fundo", + "Image Generation": "Geração de imagem", + "sd_refine_mode": "Permitir editar prompts manualmente antes de enviá-los para a API de geração", + "sd_refine_mode_txt": "Edite os prompts antes da geração", + "sd_interactive_mode": "Gere imagens automaticamente ao enviar mensagens como 'mande-me uma foto de gato'.", + "sd_interactive_mode_txt": "Modo interativo", + "sd_multimodal_captioning": "Use legendas multimodais para gerar prompts para retratos de usuários e personagens com base em seus avatares.", + "sd_multimodal_captioning_txt": "Use legendas multimodais para retratos", + "sd_expand": "Estenda prompts automaticamente usando modelo de geração de texto", + "sd_expand_txt": "Solicitações de aprimoramento automático", + "sd_snap": "Solicitações de geração de snap com uma proporção de aspecto forçada (retratos, planos de fundo) para a resolução conhecida mais próxima, enquanto tenta preservar as contagens absolutas de pixels (recomendado para SDXL).", + "sd_snap_txt": "Tire resoluções ajustadas automaticamente", + "Source": "Fonte", + "sd_auto_url": "Exemplo: {{auto_url}}", + "Authentication (optional)": "Autenticação (opcional)", + "Example: username:password": "Exemplo: nome de usuário:senha", + "Important:": "Importante:", + "sd_auto_auth_warning_1": "execute SD Web UI com o", + "sd_auto_auth_warning_2": "bandeira! O servidor deve estar acessível a partir da máquina host SillyTavern.", + "sd_drawthings_url": "Exemplo: {{drawthings_url}}", + "sd_drawthings_auth_txt": "execute o aplicativo DrawThings com a opção HTTP API habilitada na IU! O servidor deve estar acessível a partir da máquina host SillyTavern.", + "sd_vlad_url": "Exemplo: {{vlad_url}}", + "The server must be accessible from the SillyTavern host machine.": "O servidor deve estar acessível a partir da máquina host SillyTavern.", + "Hint: Save an API key in AI Horde API settings to use it here.": "Dica: salve uma chave de API nas configurações da API AI Horde para usá-la aqui.", + "Allow NSFW images from Horde": "Permitir imagens NSFW da Horda", + "Sanitize prompts (recommended)": "Solicitações de higienização (recomendado)", + "Automatically adjust generation parameters to ensure free image generations.": "Ajuste automaticamente os parâmetros de geração para garantir gerações de imagens livres.", + "Avoid spending Anlas": "Evite gastar Anlas", + "Opus tier": "(Nível Opus)", + "View my Anlas": "Ver meus Anlas", + "These settings only apply to DALL-E 3": "Essas configurações se aplicam somente ao DALL-E 3", + "Image Style": "Estilo de imagem", + "Image Quality": "Qualidade da imagem", + "Standard": "Padrão", + "HD": "alta definição", + "sd_comfy_url": "Exemplo: {{comfy_url}}", + "Open workflow editor": "Abra o editor de fluxo de trabalho", + "Create new workflow": "Criar novo fluxo de trabalho", + "Delete workflow": "Excluir fluxo de trabalho", + "Enhance": "Melhorar", + "Refine": "Refinar", + "Decrisper": "Descrisper", + "Sampling steps": "Etapas de amostragem ()", + "Width": "Largura ()", + "Height": "Altura ()", + "Resolution": "Resolução", + "Model": "Modelo", + "Sampling method": "Método de amostragem", + "Karras (not all samplers supported)": "Karras (nem todos os samplers são suportados)", + "SMEA versions of samplers are modified to perform better at high resolution.": "As versões SMEA dos amostradores são modificadas para funcionar melhor em alta resolução.", + "SMEA": "SMEA", + "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "Variantes DYN de amostradores SMEA geralmente levam a resultados mais variados, mas podem falhar em resoluções muito altas.", + "DYN": "DIN", + "Scheduler": "Agendador", + "Restore Faces": "Restaurar rostos", + "Hires. Fix": "Contrata. Consertar", + "Upscaler": "Aprimorador", + "Upscale by": "Sofisticado por", + "Denoising strength": "Força de remoção de ruído", + "Hires steps (2nd pass)": "Contrata etapas (2ª passagem)", + "Preset for prompt prefix and negative prompt": "Predefinição para prefixo de prompt e prompt negativo", + "Style": "Estilo", + "Save style": "Salvar estilo", + "Delete style": "Excluir estilo", + "Common prompt prefix": "Prefixo de prompt comum", + "sd_prompt_prefix_placeholder": "Use {prompt} para especificar onde o prompt gerado será inserido", + "Negative common prompt prefix": "Prefixo de prompt comum negativo", + "Character-specific prompt prefix": "Prefixo de prompt específico de caractere", + "Won't be used in groups.": "Não será usado em grupos.", + "sd_character_prompt_placeholder": "Quaisquer características que descrevam o personagem selecionado no momento. Será adicionado após um prefixo de prompt comum.\nExemplo: mulher, olhos verdes, cabelo castanho, camisa rosa", + "Character-specific negative prompt prefix": "Prefixo de prompt negativo específico do caractere", + "sd_character_negative_prompt_placeholder": "Quaisquer características que não deveriam aparecer para o personagem selecionado. Será adicionado após um prefixo de prompt comum negativo.\nExemplo: joias, sapatos, óculos", + "Shareable": "Compartilhável", + "Image Prompt Templates": "Modelos de prompt de imagem", + "Vectors Model Warning": "É recomendado limpar os vetores ao alterar o modelo no meio do chat. Caso contrário, levará a resultados abaixo da média.", + "Translate files into English before processing": "Traduza os arquivos para o inglês antes de processá-los", + "Manager Users": "Gerenciar usuários", + "New User": "Novo usuário", + "Status:": "Status:", + "Created:": "Criada:", + "Display Name:": "Nome de exibição:", + "User Handle:": "Identificador do usuário:", + "Password:": "Senha:", + "Confirm Password:": "Confirme sua senha:", + "This will create a new subfolder...": "Isso criará uma nova subpasta no diretório /data/ com o identificador do usuário como nome da pasta.", + "Current Password:": "Senha atual:", + "New Password:": "Nova Senha:", + "Confirm New Password:": "Confirme a nova senha:", + "Debug Warning": "As funções nesta categoria são apenas para usuários avançados. Não clique em nada se não tiver certeza das consequências.", + "Execute": "Executar", + "Are you sure you want to delete this user?": "Tem certeza de que deseja excluir este usuário?", + "Deleting:": "Excluindo:", + "Also wipe user data.": "Limpe também os dados do usuário.", + "Warning:": "Aviso:", + "This action is irreversible.": "Esta ação é irreversível.", + "Type the user's handle below to confirm:": "Digite o identificador do usuário abaixo para confirmar:", + "Import Characters": "Importar caracteres", + "Enter the URL of the content to import": "Insira o URL do conteúdo a ser importado", + "Supported sources:": "Fontes suportadas:", + "char_import_1": "Personagem Chub (link direto ou ID)", + "char_import_example": "Exemplo:", + "char_import_2": "Chub Lorebook (link direto ou ID)", + "char_import_3": "Personagem JanitorAI (Link Direto ou UUID)", + "char_import_4": "Caractere Pygmalion.chat (Link Direto ou UUID)", + "char_import_5": "Personagem AICharacterCards.com (link direto ou ID)", + "char_import_6": "Link PNG direto (consulte", + "char_import_7": "para hosts permitidos)", + "char_import_8": "Personagem RisuRealm (link direto)", + "Supports importing multiple characters.": "Suporta importação de vários caracteres.", + "Write each URL or ID into a new line.": "Escreva cada URL ou ID em uma nova linha.", + "Export for character": "Exportar para personagem", + "Export prompts for this character, including their order.": "Exportar prompts para este personagem, incluindo sua ordem.", + "Export all": "Exportar tudo", + "Export all your prompts to a file": "Exporte todos os seus prompts para um arquivo", + "Insert prompt": "Inserir prompt", + "Delete prompt": "Excluir prompt", + "Import a prompt list": "Importar uma lista de prompts", + "Export this prompt list": "Exportar esta lista de prompts", + "Reset current character": "Redefinir personagem atual", + "New prompt": "Novo prompt", + "Prompts": "Prompts", + "Total Tokens:": "Total de Tokens:", + "prompt_manager_tokens": "Fichas", + "Are you sure you want to reset your settings to factory defaults?": "Tem certeza de que deseja redefinir as configurações para os padrões de fábrica?", + "Don't forget to save a snapshot of your settings before proceeding.": "Não se esqueça de salvar um instantâneo de suas configurações antes de continuar.", + "Settings Snapshots": "Instantâneos de configurações", + "Record a snapshot of your current settings.": "Grave um instantâneo de suas configurações atuais.", + "Make a Snapshot": "Faça um instantâneo", + "Restore this snapshot": "Restaurar este instantâneo", + "Hi,": "Oi,", + "To enable multi-account features, restart the SillyTavern server with": "Para habilitar recursos de múltiplas contas, reinicie o servidor SillyTavern com", + "set to true in the config.yaml file.": "definido como verdadeiro no arquivo config.yaml.", + "Account Info": "Informações da Conta", + "To change your user avatar, use the buttons below or select a default persona in the Persona Management menu.": "Para alterar seu avatar de usuário, use os botões abaixo ou selecione uma persona padrão no menu Gerenciamento de Personas.", + "Set your custom avatar.": "Defina seu avatar personalizado.", + "Remove your custom avatar.": "Remova seu avatar personalizado.", + "Handle:": "Lidar:", + "This account is password protected.": "Esta conta é protegida por senha.", + "This account is not password protected.": "Esta conta não é protegida por senha.", + "Account Actions": "Ações da conta", + "Change Password": "Alterar a senha", + "Manage your settings snapshots.": "Gerencie seus instantâneos de configurações.", + "Download a complete backup of your user data.": "Baixe um backup completo dos dados do seu usuário.", + "Download Backup": "Baixar cópia de segurança", + "Danger Zone": "Zona de perigo", + "Reset your settings to factory defaults.": "Redefina suas configurações para os padrões de fábrica.", + "Reset Settings": "Redefinir as configurações", + "Wipe all user data and reset your account to factory settings.": "Limpe todos os dados do usuário e redefina sua conta para as configurações de fábrica.", + "Reset Everything": "Redefinir tudo", + "Reset Code:": "Reiniciar código:", + "Want to update?": "Quer atualizar?", + "How to start chatting?": "Como começar a conversar?", + "Click _space": "Clique", + "and select a": "e selecione um", + "Chat API": "API de Chat", + "and pick a character.": "e escolha um personagem.", + "You can browse a list of bundled characters in the": "Você pode navegar por uma lista de personagens agrupados no", + "Download Extensions & Assets": "Baixar extensões e ativos", + "menu within": "menu dentro", + "Confused or lost?": "Confuso ou perdido?", + "click these icons!": "clique nesses ícones!", + "in the chat bar": "na barra de chat", + "SillyTavern Documentation Site": "Site de Documentação do SillyTavern", + "Extras Installation Guide": "Guia de Instalação de Extras", + "Still have questions?": "Ainda tem perguntas?", + "Join the SillyTavern Discord": "Junte-se ao Discord do SillyTavern", + "Post a GitHub issue": "Publicar um problema no GitHub", + "Contact the developers": "Contatar os desenvolvedores" +} diff --git a/jiuguan2025cc/public/locales/ru-ru.json b/jiuguan2025cc/public/locales/ru-ru.json new file mode 100644 index 0000000000000000000000000000000000000000..4efd0d03e6e9a1efa1809b31a7422e05931849ee --- /dev/null +++ b/jiuguan2025cc/public/locales/ru-ru.json @@ -0,0 +1,2207 @@ +{ + "clickslidertips": "Кликайте по цифрам под ползунками, чтобы менять их вручную.", + "kobldpresets": "Пресеты для Kobold", + "guikoboldaisettings": "Настройки из интерфейса KoboldAI", + "openaipresets": "Пресеты для OpenAI", + "response legth(tokens)": "Ответ (в токенах)", + "context size(tokens)": "Контекст (в токенах)", + "unlocked": "Неограниченный", + "rep.pen": "Штраф за повтор", + "rep.pen range": "Окно для штрафов за повтор", + "Temperature controls the randomness in token selection": "Температура контролирует процесс выбора токена:\n- при низкой температуре (<1.0) предпочтение отдаётся наиболее вероятным токенам, текст получается предсказуемым.\n- при высокой температуре (>1.0) повышаются шансы у токенов с низкой вероятностью, текст получается более креативным.\nУстановите значение 1.0, чтобы вероятности не менялись.", + "Top_K_desc": "Top K задает жёсткое ограничение на количество рассматриваемых токенов.\nЕсли Top-K равен 20, это означает, что будут сохранены только 20 наиболее вероятных токенов (распределение их вероятностей в расчёт не берётся)\nУстановите значение 0, чтобы отключить.", + "Top_P_desc": "Top P (он же nucleus sampling) складывает все верхние токены, пока их суммарные вероятности не достигнут целевого процента.\nТо есть, если 2 верхних токена составляют 25%, а Top-P равен 0.50, учитываются только эти 2 верхних токена.\nУстановите значение 1.0, чтобы отключить.", + "Typical_P_desc": "Сэмплер Typical P определяет приоритет токенов на основе их отклонения от средней энтропии набора.\nОстаются токены, чья кумулятивная вероятность близка к заданному порогу (например, 0,5), выделяя те, которые имеют среднее информационное содержание.\nУстановите значение 1.0, чтобы отключить.", + "Min_P_desc": "Min P устанавливает базовую минимальную вероятность. Она масштабируется в зависимости от вероятности верхнего токена.\nЕсли вероятность верхнего токена составляет 80%, а Min P - 0.1, будут рассматриваться только токены с вероятностью выше 8%.\nУстановите значение 0, чтобы отключить.", + "Top_A_desc": "Top A устанавливает порог для отбора токенов на основе квадрата наибольшей вероятности токена.\nЕсли значение Top A равно 0.2, а вероятность верхнего токена равна 50%, то токены с вероятностью ниже 5% (0.2 * 0.5^2) будут исключены.\nУстановите значение 0, чтобы отключить.", + "Tail_Free_Sampling_desc": "Tail-Free Sampling (TFS) ищет хвост маловероятных токнов в распределении,\n анализируя скорость изменения вероятностей токенов с помощью производных. Он сохраняет токены до порога (например, 0.3), основанного на нормированной второй производной.\nЧем ближе к 0, тем больше отброшенных токенов. Установите значение 1.0, чтобы отключить.", + "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "Epsilon cutoff устанавливает уровень вероятности, ниже которого токены исключаются из выборки.\nВ единицах 1e-4; разумное значение - 3.\nУстановите 0, чтобы отключить.", + "Scale Temperature dynamically per token, based on the variation of probabilities": "Динамическое масштабирование температуры для каждого токена, основанное на изменении вероятностей.", + "Minimum Temp": "Мин. температура", + "Maximum Temp": "Макс. температура", + "Exponent": "Экспонента", + "Mirostat Mode": "Режим", + "Mirostat Tau": "Tau", + "Mirostat Eta": "Eta", + "Variability parameter for Mirostat outputs": "Параметр изменчивости для выходных данных Mirostat.", + "Learning rate of Mirostat": "Скорость обучения Mirostat.", + "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "Сила условия регуляризации контрастивного поиска. Установите значение 0, чтобы отключить CS.", + "Temperature Last": "Температура последней", + "LLaMA / Mistral / Yi models only": "Только для моделей LLaMA / Mistral / Yi. Перед этим обязательно выберите подходящий токенизатор.\nПоследовательности, которых не должно быть на выходе.\nОдна на строку. Текст или [идентификаторы токенов].\nМногие токены имеют пробел впереди. Используйте счетчик токенов, если не уверены.", + "Example: some text [42, 69, 1337]": "Пример:\nкакой-то текст\n[42, 69, 1337]", + "Classifier Free Guidance. More helpful tip coming soon": "Classifier Free Guidance. Чуть позже опишем более подробно", + "Scale": "Scale", + "GBNF Grammar": "Грамматика GBNF", + "Usage Stats": "Статистика исп.", + "Click for stats!": "Нажмите для получения статистики!", + "Backup": "Бэкап", + "Backup your personas to a file": "Создать бэкап (резервную копию) персоны в виде файла", + "Restore": "Восстановить", + "Restore your personas from a file": "Восстановление персон из файла", + "Type in the desired custom grammar": "Введите нужную пользовательскую грамматику", + "Encoder Rep. Pen.": "Штраф за повтор для кодировщика", + "Smoothing Factor": "Коэффициент сглаживания", + "No Repeat Ngram Size": "Размер no_repeat_ngram", + "Min Length": "Мин. длина", + "Alternative server URL (leave empty to use the default value).": "URL альтернативного сервера (оставьте пустым для стандартного значения)", + "Remove your real OAI API Key from the API panel BEFORE typing anything into this box": "Удалите свой личный OAI API Key из панели API, и ТОЛЬКО ПОСЛЕ ЭТОГО вводите что-то сюда", + "We cannot provide support for problems encountered while using an unofficial OpenAI proxy": "Мы не сможем предоставить помощь с проблемами, с которыми вы столкнетесь при использовании неофициальных прокси для OpenAI", + "Context Size (tokens)": "Размер контекста (в токенах)", + "Max Response Length (tokens)": "Макс. длина ответа (в токенах)", + "Temperature": "Температура", + "Frequency Penalty": "Штраф за частоту", + "Presence Penalty": "Штраф за присутствие", + "Top A": "Top А", + "Tail Free Sampling": "Tail Free Sampling", + "Rep. Pen. Slope": "Rep. Pen. Slope", + "Top K": "Top K", + "Top P": "Top P", + "Do Sample": "Включить сэмплинг", + "Add BOS Token": "Добавлять BOS-токен", + "Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative": "Добавлять BOS-токен в начале промпта. Если выключить, ответы могут стать более креативными.", + "Ban EOS Token": "Запретить EOS-токен", + "Ban the eos_token. This forces the model to never end the generation prematurely": "Запрет EOS-токена не позволит модели завершить генерацию преждевременно", + "Skip Special Tokens": "Пропускать спец. токены", + "Beam search": "Поиск Beam", + "Number of Beams": "Количество Beam", + "Length Penalty": "Штраф за длину", + "Early Stopping": "Преждевременная остановка", + "Contrastive search": "Контрастный поиск", + "Penalty Alpha": "Penalty Alpha", + "Seed": "Зерно", + "Epsilon Cutoff": "Epsilon Cutoff", + "Eta Cutoff": "Eta Cutoff", + "Negative Prompt": "Отрицательный промпт", + "Mirostat (mode=1 is only for llama.cpp)": "Mirostat (режим=1 предназначен только для llama.cpp)", + "Add text here that would make the AI generate things you don't want in your outputs.": "Добавьте сюда текст, который заставит ИИ генерировать то, что вы не хотите видеть в его текстах", + "Phrase Repetition Penalty": "Штраф за повтор фразы", + "Preamble": "Преамбула", + "Use style tags to modify the writing style of the output.": "Используйте теги стиля, чтобы изменить стиль написания выходного текста.", + "Banned Tokens": "Запрещённые токены", + "Sequences you don't want to appear in the output. One per line.": "Строки, которых не должно быть в выходном тексте. По одной на строчку.", + "AI Module": "Модуль ИИ", + "Changes the style of the generated text.": "Изменяет стиль создаваемого текста.", + "Used if CFG Scale is unset globally, per chat or character": "Используется, если CFG Scale не установлен глобально, для каждого чата или персонажа.", + "Streaming": "Стриминг текста", + "Dynamic Temperature": "Динамическая температура", + "Restore current preset": "Восстановить текущий пресет", + "Neutralize Samplers": "Нейтрализовать сэмплеры", + "Text Completion presets": "Пресеты для Text Completion", + "Documentation on sampling parameters": "Документация по параметрам сэмплеров", + "Set all samplers to their neutral/disabled state.": "Установить все сэмплеры в нейтральное/отключенное состояние.", + "Only enable this if your model supports context sizes greater than 8192 tokens": "Включайте эту опцию, только если ваша модель поддерживает размер контекста более 8192 токенов.\nУвеличивайте только если вы знаете, что делаете.", + "Wrap in Quotes": "Заключать в кавычки", + "Wrap entire user message in quotes before sending.": "Перед отправкой заключать всё сообщение пользователя в кавычки.", + "Leave off if you use quotes manually for speech.": "Оставьте выключенным, если вручную выставляете кавычки для прямой речи.", + "Impersonation prompt": "Промпт для перевоплощения", + "Prompt that is used for Impersonation function": "Промпт, применяемый при генерации действий от лица пользователя", + "Logit Bias": "Смещение логитов", + "Helps to ban or reenforce the usage of certain words": "Запрещает или поощряет использование определенных слов", + "View / Edit bias preset": "Просмотр / Редактирование пресета смещения", + "Add bias entry": "Добавить правило смещения", + "Connect": "Подключиться", + "Test Message": "Тестовое сообщение", + "KoboldAI": "KoboldAI", + "API url": "URL-адрес API", + "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (Режим обёртки API OpenAI)", + "Register a Horde account for faster queue times": "Заведите учетную запись Horde для ускорения генерации", + "Adjust context size to worker capabilities": "Подстраивать размер контекста под возможности рабочих машин", + "Adjust response length to worker capabilities": "Подстраивать длину ответа под возможности рабочих машин", + "API key": "API-ключ", + "Tabby API key": "Tabby API-ключ", + "Get it here:": "Получить здесь:", + "Register": "Зарегистрироваться", + "TogetherAI Model": "Модель TogetherAI", + "Example: 127.0.0.1:5001": "Пример: http://127.0.0.1:5001", + "ggerganov/llama.cpp": "ggerganov/llama.cpp (сервер вывода)", + "Example: 127.0.0.1:8080": "Пример: http://127.0.0.1:8080", + "Example: 127.0.0.1:11434": "Пример: http://127.0.0.1:11434", + "Ollama Model": "Модель Ollama", + "Download": "Скачать", + "TogetherAI API Key": "TogetherAI API-ключ", + "-- Connect to the API --": "-- Подключитесь к API --", + "View my Kudos": "Посмотреть мой рейтинг(Kudos)", + "Enter": "Введите", + "to use anonymous mode.": "чтобы использовать анонимный режим.", + "Models": "Модели", + "Not connected...": "Нет подключения...", + "Novel API key": "API-ключ для NovelAI", + "Follow": "Следуйте", + "these directions": "данным инструкциям", + "Enter it in the box below": "Введите его в окошко ниже", + "Novel AI Model": "Модель NovelAI", + "Make sure you run it with": "Обязательно запускайте его с флагом", + "flag": "", + "API key (optional)": "Ключ API (необязательно)", + "Server url": "URL-адрес сервера", + "Custom model (optional)": "Пользовательская модель (необязательно)", + "Bypass API status check": "Обход проверки статуса API", + "Example: 127.0.0.1:5000": "Пример: http://127.0.0.1:5000", + "Bypass status check": "Обход проверки статуса", + "Mancer API key": "Ключ от Mancer API", + "to get your OpenAI API key.": "для получения ключа от API OpenAI", + "Window AI Model": "Модель Window AI", + "OpenAI Model": "Модель OpenAI", + "Get your key from": "Получите ключ в", + "Anthropic's developer console": "консоли разработчика Anthropic", + "Claude Model": "Модель Claude", + "Scale API Key": "Ключ от Scale API", + "Alt Method": "Альтернативный метод", + "AI21 API Key": "Ключ от API AI21", + "AI21 Model": "Модель AI21", + "View API Usage Metrics": "Посмотреть статистику использования API", + "Show External models (provided by API)": "Показать \"сторонние\" модели (предоставленные API)", + "Allow fallback routes": "Разрешить резервные маршруты", + "Allow fallback routes Description": "Автоматически выбирает альтернативную модель, если выбранная модель не может удовлетворить ваш запрос.", + "OpenRouter API Key": "Ключ от OpenRouter API", + "OpenRouter Model": "Модель OpenRouter", + "View Remaining Credits": "Посмотреть оставшиеся кредиты", + "Click Authorize below or get the key from": "Нажмите «Авторизоваться» ниже или получите ключ от", + "Auto-connect to Last Server": "Автоматическое подключение к последнему серверу", + "View hidden API keys": "Посмотреть скрытые API-ключи", + "Advanced Formatting": "Расширенное форматирование", + "Context Template": "Шаблон контекста", + "Replace Macro in Stop Strings": "Заменять макросы в пользовательских стоп-строках", + "Story String": "Строка истории", + "Example Separator": "Разделитель примеров сообщений", + "Chat Start": "Начало чата", + "Activation Regex": "Regex для активации", + "Instruct Mode": "Режим Instruct", + "Wrap Sequences with Newline": "Отделять строки символом новой строки", + "Include Names": "Добавлять имена", + "Force for Groups and Personas": "Также для групп и персон", + "System Prompt": "Системный промпт", + "Instruct Sequences": "Строки для Instruct-режима", + "Stop Sequence": "Стоп-строка", + "Context Formatting": "Форматирование контекста", + "(Saved to Context Template)": "(Сохраняется в шаблоне контекста)", + "Tokenizer": "Токенайзер", + "Token Padding": "Кол-во добавочных токенов", + "Save preset as": "Сохранить пресет как...", + "Always add character's name to prompt": "Всегда добавлять имя персонажа в промпт", + "Use as Stop Strings": "Использовать в качестве стоп-строк", + "Bind to Context": "Привязка к контексту", + "Generate only one line per request": "Генерировать одну строку на запрос", + "Misc. Settings": "Доп. настройки", + "Auto-Continue": "Авто-продолжение", + "Collapse Consecutive Newlines": "Сворачивать неск. новых строк в одну", + "Allow for Chat Completion APIs": "Разрешить для Chat Completion API", + "Target length (tokens)": "Целевая длина (в токенах)", + "World Info": "Информация о мире", + "Scan Depth": "Глубина сканирования", + "Case-Sensitive": "С учетом регистра", + "Match Whole Words": "Только полное совпадение", + "Use global setting": "Использовать глобальную настройку", + "Yes": "Да", + "No": "Нет", + "Context %": "Процент контекста", + "Budget Cap": "Лимит бюджета", + "(0 = disabled)": "(0 = отключено)", + "None": "Отсутствует", + "User Settings": "Настройки пользователя", + "UI Language": "Язык интерфейса", + "Avatar Style:": "Аватарки", + "Circle": "Круглые", + "Rectangle": "Прямоугольные", + "Square": "Квадратные", + "Default": "По умолчанию", + "Bubbles": "Пузыри", + "No Blur Effect": "Отключить размытие", + "No Text Shadows": "Отключить тень текста", + "Waifu Mode": "Рeжим Вайфу", + "Message Timer": "Таймер сообщений", + "Model Icon": "Значки моделей", + "Advanced Character Search": "Расширенный поиск по персонажам", + "Allow {{char}}: in bot messages": "Показывать {{char}}: в ответах", + "Allow {{user}}: in bot messages": "Показать {{user}}: в ответах", + "Show tags in responses": "Показывать <теги> в ответах", + "Lorebook Import Dialog": "Показывать окно импорта лорбука", + "MUI Preset": "Пресет MUI:", + "If set in the advanced character definitions, this field will be displayed in the characters list.": "Если это поле задано в расширенных параметрах персонажа, оно будет отображаться в списке персонажей.", + "Relaxed API URLS": "Смягчённые адреса API", + "Custom CSS": "Пользовательский CSS", + "Mancer Model": "Модель Mancer", + "API Type": "Тип API", + "Aphrodite API key": "Ключ от API Aphrodite", + "Relax message trim in Groups": "Мягкая обрезка сообщений в группах", + "Characters Hotswap": "HotSwap (смена персонажей на лету)", + "Request token probabilities": "Запрашивать вероятность токена", + "Movable UI Panels": "Подвижные панели UI", + "Main Text": "Основной текст", + "Italics Text": "Курсив", + "Quote Text": "Текст в кавычках", + "Shadow Color": "Цвет теней", + "Font Scale": "Размер текста", + "Blur Strength": "Сила размытия", + "Text Shadow Width": "Размер теней текста", + "Swipes": "Свайпы", + "Miscellaneous": "Разное", + "Background Sound Only": "Только фоновый звук", + "Auto-load Last Chat": "Автозагрузка последнего чата", + "Auto-save Message Edits": "Автоматически сохранять отредактированные сообщения", + "Auto-fix Markdown": "Автоисправление разметки", + "Auto-scroll Chat": "Автоматическая прокрутка чата", + "Send on Enter": "Отправка на Enter", + "Debug Menu": "Меню отладки", + "Restore User Input": "Восстанавливать введённый текст", + "Character Handling": "Обработка персонажа", + "Example Messages Behavior": "Примеры сообщений:", + "Gradual push-out": "Постепенное выталкивание", + "Chat/Message Handling": "Обработка чата и сообщений", + "Always include examples": "Всегда применять примеры", + "Never include examples": "Никогда не применять примеры", + "Forbid External Media": "Запрет внешних медиа", + "System Backgrounds": "Системные фоны", + "Name": "Имя", + "Auto-connect": "Подключаться автоматически", + "First message": "Первое сообщение", + "Group Controls": "Управление группой", + "Group reply strategy": "Персонажи отвечают...", + "Natural order": "По алфавиту", + "List order": "По списку", + "Allow self responses": "Разрешить ответ себе", + "Auto Mode": "Авто-режим", + "Add Members": "Добавить участников", + "Current Members": "Текущие участники", + "Delete": "Удалить", + "Cancel": "Отменить", + "Advanced Definitions": "Расширенное описание", + "Personality summary": "Резюме по личности", + "Scenario": "Сценарий", + "Talkativeness": "Разговорчивость", + "group chats!": "групповых чатах!", + "Shy": "Застенчивый", + "Normal": "Обычный", + "Chatty": "Разговорчивый", + "Examples of dialogue": "Примеры диалога", + "Save": "Сохранить", + "Chat History": "История чатов", + "Content": "Содержание", + "Selective": "Выборочно", + "Disable": "Отключено", + "Back to parent chat": "Вернуться в основной чат", + "Convert to group": "Сделать групповым", + "Start new chat": "Начать новый чат", + "Delete messages": "Удалить сообщения", + "Impersonate": "Перевоплощение", + "Regenerate": "Повторная генерация", + "Message Sound": "Звук сообщения", + "Author's Note": "Заметки автора", + "Replace empty message": "Заменять пустые сообщения", + "Send this text instead of nothing when the text box is empty.": "Этот текст будет отправлен в случае отсутствия текста на отправку.", + "Unrestricted maximum value for the context slider": "Убрать потолок для ползунка контекста. Включайте только если точно знаете, что делаете", + "Chat Completion Source": "Источник для Chat Completion", + "Avoid sending sensitive information to the Horde.": "Избегайте отправки личной информации Horde", + "Review the Privacy statement": "Ознакомиться с заявлением о конфиденциальности", + "Trusted workers only": "Только доверенные рабочие машины", + "For privacy reasons, your API key will be hidden after you reload the page.": "Из соображений безопасности ваш API-ключ будет скрыт после перезагрузки страницы.", + "-- Horde models not loaded --": "--Модель Horde не загружена--", + "Example: http://127.0.0.1:5000/api ": "Пример: http://127.0.0.1:5000/api", + "No connection...": "Нет соединения...", + "Get your NovelAI API Key": "Получите свой API-ключ для NovelAI", + "AI Horde": "AI Horde", + "NovelAI": "NovelAI", + "OpenAI API key": "Ключ для API OpenAI", + "Trim spaces": "Обрезать пробелы", + "Trim Incomplete Sentences": "Удалять неоконченные предложения", + "Include Newline": "Добавлять новую строку", + "Non-markdown strings": "Строки без разметки", + "Replace Macro in Sequences": "Заменить макросы в строках", + "Presets": "Пресеты", + "Start Reply With": "Начинать ответ с", + "Show reply prefix in chat": "Показывать префикс ответов в чате", + "Worlds/Lorebooks": "Миры и лорбуки", + "Sorted Evenly": "Равномерная сортировка", + "Active World(s) for all chats": "Активные миры для всех чатов", + "-- World Info not found --": "-- Информация о мире не найдена --", + "--- Pick to Edit ---": "--- Выберите для редактирования ---", + "or": "или", + "New": "Новый", + "Priority": "Приоритет", + "Custom": "Пользовательский", + "Title A-Z": "Название от A до Z", + "Title Z-A": "Название от Z до A", + "Tokens ↗": "Токены ↗", + "Tokens ↘": "Токены ↘", + "Depth ↗": "Глубина ↗", + "Depth ↘": "Глубина ↘", + "Order ↗": "Порядок ↗", + "Order ↘": "Порядок ↘", + "UID ↗": "UID ↗", + "UID ↘": "UID ↘", + "Trigger% ↗": "Триггер% ↗", + "Trigger% ↘": "Триггер% ↘", + "Depth:": "Глубина:", + "Character Lore First": "Сначала лор персонажа", + "Global Lore First": "Сначала глобальный лор", + "Recursive Scan": "Рекурсивное сканирование", + "Case Sensitive": "Учитывать регистр", + "Alert On Overflow": "Оповещение о переполнении", + "Use Probability": "Использовать вероятность", + "Exclude from recursion": "Исключить из рекурсии", + "Entry Title/Memo": "Название или заметка о записи", + "Position:": "Положение:", + "T_Position": "↑Char: Перед определениями Персонажа\n↓Char: После определений Персонажа\n↑AN: Перед Пометок автора\n↓AN: После Пометок автора\n@D: На глубине", + "Before Char Defs": "↑Перс.", + "After Char Defs": "↓Перс.", + "Before AN": "↑АЗ", + "After AN": "↓АЗ", + "Order": "Очерёдность:", + "Update a theme file": "Обновить файл темы", + "Save as a new theme": "Сохранить как новую тему", + "Minimum number of blacklisted words detected to trigger an auto-swipe": "Минимальное количество обнаруженных запрещённых слов, при котором срабатывает авто-свайп.", + "User Message Blur Tint": "Ваши сообщения", + "AI Message Blur Tint": "Сообщения ИИ", + "Chat Backgrounds": "Фоны чата", + "Chat Background": "Фон чата", + "UI Background": "Фон UI", + "Mad Lab Mode": "Режим безумца", + "Show Message Token Count": "Счетчик токенов сообщения", + "Compact Input Area (Mobile)": "Компактная зона ввода", + "Zen Sliders": "Дзен слайдеры", + "UI Border": "Границы UI", + "Chat Style:": "Стиль чата", + "Chat Timestamps": "Метки времени в чате", + "Tags as Folders": "Теги как папки", + "Streaming FPS": "FPS для стриминга", + "Gestures": "Жесты", + "Message IDs": "ID сообщений", + "Prefer Character Card Prompt": "Приоритет промпту из карточки персонажа", + "Prefer Character Card Jailbreak": "Приоритет джейлбрейку из карточки персонажа", + "Press Send to continue": "Кнопка отправки продолжает сообщение", + "Quick 'Continue' button": "Быстрое продолжение", + "Log prompts to console": "Выводить промпты в консоль", + "Never resize avatars": "Не менять размер аватарок", + "Show avatar filenames": "Показывать названия файлов аватарок", + "Import Card Tags": "Импортировать теги карточки", + "Confirm message deletion": "Подтверждение удаления сообщений", + "Spoiler Free Mode": "Режим без спойлеров", + "Auto-swipe": "Автоматические свайпы", + "Minimum generated message length": "Минимальная длина сгенерированных сообщений", + "Blacklisted words": "Запрещенные слова", + "Blacklisted word count to swipe": "Количество запрещенных слов для свайпа", + "Reload Chat": "Перезагрузить чат", + "Search Settings": "Поиск по настройкам", + "Disabled": "Отключено", + "Automatic (PC)": "Автоматическое (ПК)", + "Enabled": "Включено", + "Simple": "Простой", + "Advanced": "Расширенный", + "Disables animations and transitions": "Отключение анимаций и переходов.", + "removes blur from window backgrounds": "Убрать размытие с фона окон, чтобы ускорить рендеринг.", + "Remove text shadow effect": "Удаление эффекта тени от текста.", + "Reduce chat height, and put a static sprite behind the chat window": "Уменьшить высоту чата и поместить статичный спрайт за окном чата.", + "Always show the full list of the Message Actions context items for chat messages, instead of hiding them behind '...'": "Всегда показывать полный список действий с сообщением, а не прятать их за '...'.", + "Alternative UI for numeric sampling parameters with fewer steps": "Альтернативный пользовательский интерфейс для числовых параметров выборки с меньшим количеством шагов.", + "Entirely unrestrict all numeric sampling parameters": "Снять ограничения со всех числовых сэмплеров.", + "Time the AI's message generation, and show the duration in the chat log": "Время генерации сообщений ИИ и его показ в журнале чата.", + "Show a timestamp for each message in the chat log": "Показывать временную метку для каждого сообщения в журнале чата.", + "Show an icon for the API that generated the message": "Показать значок API, сгенерировавшего сообщение.", + "Show sequential message numbers in the chat log": "Показывать порядковые номера сообщений в журнале чата.", + "Show the number of tokens in each message in the chat log": "Показать количество токенов в каждом сообщении в журнале чата.", + "Single-row message input area. Mobile only, no effect on PC": "Однорядная область ввода сообщений. Только для мобильных устройств, на ПК не работает.", + "In the Character Management panel, show quick selection buttons for favorited characters": "На панели управления персонажами будут отображены кнопки быстрого выбора для избранных персонажей.", + "Show tagged character folders in the character list": "Отобразить теговые папки с персонажами в списке персонажей.", + "Play a sound when a message generation finishes": "Воспроизведение звука при завершении генерации сообщения.", + "Only play a sound when ST's browser tab is unfocused": "Воспроизводить звук только тогда, когда вкладка браузера ST не выбрана.", + "Reduce the formatting requirements on API URLs": "Снижение требований к форматированию URL-адресов API.", + "Ask to import the World Info/Lorebook for every new character with embedded lorebook. If unchecked, a brief message will be shown instead": "Спрашивать разрешение на импорт лорбука для всех персонажей со встроенным лорбуком. При выключенной опции вместо этого будет показываться короткое сообщение", + "Restore unsaved user input on page refresh": "Восстановление несохраненного пользовательского запроса при обновлении страницы.", + "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "Позволяет перемещать некоторые элементы интерфейса путем их перетаскивания. Только для ПК, на телефонах не работает.", + "MovingUI preset. Predefined/saved draggable positions": "Пресет для MovingUI. Предопределенные/сохраненные позиции для перетаскивания.", + "Save movingUI changes to a new file": "Сохранение изменений MovingUI в новый файл.", + "Apply a custom CSS style to all of the ST GUI": "Применять пользовательский CSS ко всему интерфейсу Таверны.", + "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "Искать персонажей по всем полям данных, а не только по имени.", + "If checked and the character card contains a prompt override (System Prompt), use that instead": "При включении этой опции, системный промпт будет заменяться кастомным промптом из карточки (при его наличии).", + "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "При включении этой опции, пользовательский джейлбрейк будет заменяться кастомным джейлбрейком из карточки (при его наличии).", + "Show actual file names on the disk, in the characters list display only": "Отображение названий файлов персонажей на диске, только в списке персонажей.", + "Prompt to import embedded card tags on character import. Otherwise embedded tags are ignored": "Запрашивать разрешения на импорт встроенных тегов карт при импорте персонажей. В противном случае встроенные теги игнорируются.", + "Hide character definitions from the editor panel behind a spoiler button": "Спрятать определения персонажей из панели редактора за кнопку спойлера.", + "Show a button in the input area to ask the AI to continue (extend) its last message": "Показывать на форме ответа кнопку, по нажатии на которую ИИ продолжит своё предыдущее сообщение.", + "Show arrow buttons on the last in-chat message to generate alternative AI responses. Both PC and mobile": "Показывать кнопки со стрелками на последнем сообщении в чате, чтобы генерировать альтернативные ответы ИИ. Как для ПК, так и для мобильных устройств.", + "Allow using swiping gestures on the last in-chat message to trigger swipe generation. Mobile only, no effect on PC": "Позволяет использовать жесты смахивания на последнем сообщении в чате, чтобы вызвать альтернативную генерацию. Только для мобильных устройств, на ПК не работает.", + "Save edits to messages without confirmation as you type": "Сохранять правки в сообщениях без подтверждения по мере ввода текста.", + "Skip encoding and characters in message text, allowing a subset of HTML markup as well as Markdown": "Не кодировать символы < и > в тексте сообщения, что позволяет использовать подмножество HTML-разметки, а также Markdown.", + "Allow AI messages in groups to contain lines spoken by other group members": "Разрешить ИИ в группах генерировать строчки за других участников группы в своих сообщениях.", + "Requests logprobs from the API for the Token Probabilities feature": "Запросить логпробы из API для функции Token Probabilities.", + "Automatically reject and re-generate AI message based on configurable criteria": "Автоматическое отклонение и повторная генерация сообщений AI на основе настраиваемых критериев.", + "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Включить авто-свайп. Настройки в этом разделе действуют только при включенном авто-свайпе.", + "If the generated message is shorter than these many characters, trigger an auto-swipe": "Если сгенерированное сообщение короче этого значения, срабатывает авто-свайп.", + "Reload and redraw the currently open chat": "Перезагрузить и перерисовать открытый в данный момент чат.", + "Auto-Expand Message Actions": "Развернуть действия", + "Persona Management": "Управление персоной", + "Persona Description": "Описание персоны", + "Your Persona": "Ваша персона", + "Show notifications on switching personas": "Показывать уведомления при смене персоны", + "In Story String / Prompt Manager": "В строке истории / Менеджере промптов", + "Top of Author's Note": "Сверху от заметок автора", + "Bottom of Author's Note": "Снизу от заметок автора", + "How do I use this?": "Как пользоваться?", + "More...": "Ещё...", + "Link to World Info": "Ссылка на информацию о мире", + "Import Card Lore": "Импортировать лор карточки", + "Scenario Override": "Перезапись сценария", + "Rename": "Переименовать", + "Character Description": "Описание персонажа", + "Creator's Notes": "Заметки создателя", + "A-Z": "A-Z", + "Z-A": "Z-A", + "Newest": "Сначала новые", + "Oldest": "Сначала старые", + "Favorites": "Избранные", + "Recent": "Последние", + "Most chats": "Больше всего чатов", + "Least chats": "Меньше всего чатов", + "Prompt Overrides": "Индивидуальные промпты", + "Insert {{original}} into either box to include the respective default prompt from system settings.": "Введите {{original}} в любое поле, чтобы вставить соответствующий промпт из системных настроек", + "Main Prompt": "Основной промпт", + "Jailbreak": "Джейлбрейк", + "Everything here is optional": "Все поля необязательные", + "Created by": "Автор", + "Character Version": "Версия персонажа", + "Tags to Embed": "Встраиваемые теги", + "Important to set the character's writing style.": "Серьёзно влияет на стиль письма персонажа.", + "Samplers Order": "Порядок сэмплеров", + "Samplers will be applied in a top-down order. Use with caution.": "Сэмплеры будут применяться в порядке от верхнего к нижнему. Используйте с осторожностью.", + "Repetition Penalty": "Штраф за повторы", + "Rep. Pen. Range.": "Диапазон поиска повторов", + "Rep. Pen. Freq.": "Частота штрафа за повторы", + "Rep. Pen. Presence": "Наличие штрафа за повторы", + "separate with commas w/o space between": "разделять запятыми без пробела", + "Document": "Документ", + "Continue": "Продолжить", + "CFG Scale": "CFG Scale", + "AI reply prefix": "Префикс для ответа ИИ", + "Custom Stopping Strings": "Стоп-строки", + "JSON serialized array of strings": "Список строк в формате JSON", + "words you dont want generated separated by comma ','": "слова, которые вы не хотите генерировать, через запятую ','", + "Enter your name": "Введите свое имя", + "Name this character": "Назовите этого персонажа", + "Search / Create Tags": "Искать / Создать тэги", + "Describe your character's physical and mental traits here.": "Опишите ментальные и физические черты персонажа", + "This will be the first message from the character that starts every chat.": "Это будет первое сообщение от персонажа при начале нового чата", + "Chat Name (Optional)": "Название чата (необязательно)", + "Search...": "Поиск...", + "Any contents here will replace the default Main Prompt used for this character. (v2 spec: system_prompt)": "Все содержимое этого поля будет заменять стандартный промпт", + "Any contents here will replace the default Jailbreak Prompt used for this character. (v2 spec: post_history_instructions)": "Все содержимое этого поля будет заменять стандартный джейлбрейк", + "(Botmaker's name / Contact Info)": "(Имя автора, контакты)", + "(If you want to track character versions)": "Если вы хотите отслеживать версии персонажа", + "(Describe the bot, give use tips, or list the chat models it has been tested on. This will be displayed in the character list.)": "(Описание персонажа, советы по использованию, список моделей, на которых он тестировался. Информация будет отображаться в списке персонажей)", + "(Write a comma-separated list of tags)": "(Список тегов через запятую)", + "(A brief description of the personality)": "(Краткое описание личности)", + "(Circumstances and context of the interaction)": "(Обстоятельства и контекст этого диалога)", + "(Examples of chat dialog. Begin each example with START on a new line.)": "(Примеры диалога. Начинайте каждый пример с START или новой строкой.)", + "Type here...": "Пишите здесь...", + "Comma separated (required)": "Через запятую (обязательное поле)", + "What this keyword should mean to the AI, sent verbatim": "Что это ключевое слово должно означать для ИИ, отправляется дословно", + "Filter to Character(s)": "Фильтр по персонажу(ам)", + "Character Exclusion": "Исключить персонажей", + "Inclusion Group": "Группа записей", + "Only one entry with the same label will be activated": "Будет активна только одна запись с одинаковой меткой", + "-- Characters not found --": "-- Персонажей не найдено --", + "(This will be the first message from the character that starts every chat)": "(Это будет первое сообщение от персонажа, когда вы начинаете новый чат)", + "AI Response Configuration": "Настройка ответа ИИ", + "AI Configuration panel will stay open": "Панель настройки ИИ останется открытой", + "Update current preset": "Обновить текущий пресет", + "Import preset": "Импортировать пресет", + "Export preset": "Экспортировать пресет", + "Delete the preset": "Удалить пресет", + "Auto-select this preset for Instruct Mode": "Автоматический выбор этого пресета для режима Instruct.", + "Auto-select this preset on API connection": "Автоматический выбор этого пресета при подключении к API.", + "Wrap user messages in quotes before sending": "Перед отправкой заключать ответ пользователя в кавычки", + "Restore default prompt": "Восстановить станндартный промпт", + "New preset": "Новый пресет", + "Delete preset": "Удалить пресет", + "API Connections": "Соединения с API", + "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "Может помочь с плохими ответами ставя в очередь только подтвержденных работников. Может замедлить время ответа.", + "Clear your API key": "Стереть ключ от API", + "Refresh models": "Обновить модели", + "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Получите свой OpenRouter API токен используя OAuth. У вас будет открыта вкладка openrouter.ai", + "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "Проверка работоспособности вашего соединения с API путём отправки короткого тестового сообщения. Внимание: оно будет отправлено от вашего имени.", + "Edit": "Редактировать", + "Locked = World Editor will stay open": "Закреплено = Редактор мира останется открытым", + "Entries can activate other entries by mentioning their keywords": "Записи могут активировать другие записи, если в них содержатся ключевые слова", + "Lookup for the entry keys in the context will respect the case": "Большая буква имеет значение при активации ключевого слова", + "If the entry key consists of only one word, it would not be matched as part of other words": "Если ключевое слово состоит только из одного слова, оно не будет активироваться как часть других слов", + "Open all Entries": "Открыть все записи", + "Close all Entries": "Закрыть все записи", + "Create": "Создать", + "Import World Info": "Импортировать мир", + "Export World Info": "Экспортировать мир", + "Delete World Info": "Удалить мир", + "Duplicate World Info": "Дублировать мир", + "Rename World Info": "Переименовать мир", + "Refresh": "Обновить", + "Primary Keywords": "Основные ключевые слова", + "Logic": "Логика", + "AND ANY": "И ЛЮБОЙ", + "AND ALL": "И ВСЕ", + "NOT ALL": "НЕ ВСЕ", + "NOT ANY": "НЕ ЛЮБОЙ", + "Optional Filter": "Дополнительный фильтр", + "New Entry": "Новая запись", + "Fill empty Memo/Titles with Keywords": "Заполнить пустые названия ключевыми словами", + "AI Response Formatting": "Формат ответа ИИ", + "Change Background Image": "Изменить фон", + "Extensions": "Расширения", + "Click to set a new User Name": "Нажмите, чтобы задать новое имя пользователя.", + "Click to lock your selected persona to the current chat. Click again to remove the lock.": "Нажмите, чтобы закрепить выбранную персону для текущего чата. Нажмите еще раз, чтобы открепить.", + "Click to set user name for all messages": "Нажмите, чтобы задать имя пользователя для всех сообщений.", + "Create a dummy persona": "Создать пустую персону", + "Character Management": "Управление персонажами", + "Locked = Character Management panel will stay open": "Закреплено = Панель управление персонажами останется открытой", + "Select/Create Characters": "Выбрать/Создать персонажа", + "Token counts may be inaccurate and provided just for reference.": "Счетчик токенов может быть неточным, используйте как ориентир", + "Click to select a new avatar for this character": "Нажмите чтобы выбрать новый аватар для этого персонажа", + "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "Пример:\n [{{user}} is a 28-year-old Romanian cat girl.]", + "Toggle grid view": "Переключить вид сетки", + "Add to Favorites": "Добавить в Избранное", + "Advanced Definition": "Расширенное описание", + "Character Lore": "Лор персонажа", + "Export and Download": "Экспортировать и скачать", + "Duplicate Character": "Клонировать персонажа", + "Create Character": "Создать персонажа", + "Delete Character": "Удалить персонажа", + "View all tags": "Показать все тэги", + "Click to set additional greeting messages": "Нажмите чтобы создать дополнительное вступительное сообщение", + "Show / Hide Description and First Message": "Показать / убрать описание и первое сообщение", + "Click to select a new avatar for this group": "Нажмите чтобы выбрать новый аватар для этой группы", + "Set a group chat scenario": "Задать сценарий для группового чата", + "Restore collage avatar": "Восстановить аватар-коллаж", + "Create New Character": "Создать нового персонажа", + "Import Character from File": "Импортировать персонажа из файла", + "Import content from external URL": "Импортировать содержимое из внешнего URL", + "Create New Chat Group": "Создать новый групповой чат", + "Characters sorting order": "Порядок сортировки персонажей", + "Remove": "Убрать", + "Select a World Info file for": "Выбрать файл с миром для", + "Primary Lorebook": "Основной лорбук", + "A selected World Info will be bound to this character as its own Lorebook.": "Информация о мире будет привязана к персонажу как его собственный лорбук.", + "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "Когда ИИ генерирует ответ, он будет совмещён с записями из глобально выбранного мира.", + "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "При экспорте персонажа вместе с ним также выгрузится выбранный лорбук в виде JSON.", + "Additional Lorebooks": "Вспомогательные лорбуки", + "Associate one or more auxillary Lorebooks with this character.": "Привязать к этому персонажу один или больше вспомогательных лорбуков", + "NOTE: These choices are optional and won't be preserved on character export!": "ВНИМАНИЕ: эти выборы необязательные и не будут сохранены при экспорте персонажа!", + "Rename chat file": "Переименовать чат", + "Export JSONL chat file": "Экспортировать чат в формате JSONL", + "Download chat as plain text document": "Скачать чат в формате .txt", + "Delete chat file": "Удалить файл этого чата", + "Delete tag": "Удалить тэг", + "Translate message": "Перевести сообщение", + "Generate Image": "Создать изображение", + "Narrate": "Повествовать", + "Prompt": "Промпт", + "Copy": "Скопировать", + "Confirm": "Подтвердить", + "Copy this message": "Продублировать сообщение", + "Delete this message": "Удалить сообщение", + "Move message up": "Переместить сообщение вверх", + "Move message down": "Переместить сообщение вниз", + "Enlarge": "Увеличить", + "Temporarily disable automatic replies from this character": "Временно отключить автоматические сообщения от этого персонажа", + "Enable automatic replies from this character": "Включить автоматическую отправку сообщения этого персонажа", + "Trigger a message from this character": "Запросить сообщение от этого персонажа", + "Move up": "Переместить вверх", + "Move down": "Переместить вниз", + "View character card": "Посмотреть карточку персонажа", + "Remove from group": "Убрать из группы", + "Add to group": "Добавить в группу", + "Add": "Добавить", + "Abort request": "Прекратить генерацию", + "Send a message": "Отправить сообщение", + "Ask AI to write your message for you": "Попросить ИИ написать сообщение за вас", + "Continue the last message": "Продолжить текущее сообщение", + "Bind user name to that avatar": "Закрепить имя за этим аватаром", + "Select this as default persona for the new chats.": "Выбирать эту персону по умолчанию для всех новых чатов.", + "Change persona image": "Сменить аватар персоны", + "Delete persona": "Удалить персону", + "Reduced Motion": "Сокращение анимаций", + "Auto-select": "Авто-выбор", + "Automatically select a background based on the chat context": "Автоматический выбор фона в зависимости от контекста чата", + "Filter": "Фильтр", + "Exclude message from prompts": "Исключить сообщение из промпта", + "Include message in prompts": "Включить сообщение в промпт", + "Create checkpoint": "Создать чекпоинт", + "Create Branch": "Создать ветку", + "Embed file or image": "Вставить файл или изображение", + "UI Theme": "Тема UI", + "This message is invisible for the AI": "Это сообщение невидимо для ИИ", + "Sampler Priority": "Приоритет сэмплеров", + "Ooba only. Determines the order of samplers.": "Только oobabooga. Определяет порядок сэмплеров.", + "Load default order": "Загрузить стандартный порядок", + "Max Tokens Second": "Макс. кол-во токенов в секунду", + "CFG": "CFG", + "Extras API key (optional)": "Ключ от Extras API (необязательно)", + "Notify on extension updates": "Уведомлять об обновлениях расширений", + "Toggle character grid view": "Изменить вид грида персонажей", + "Bulk delete characters": "Массовое удаление персонажей", + "Favorite characters to add them to HotSwaps": "Чтобы включить персонажа в HotSwaps, добавьте его в Избранное", + "Underlined Text": "Подчёркнутый", + "Token Probabilities": "Вероятности токенов", + "Close chat": "Закрыть чат", + "Manage chat files": "Все чаты", + "Import Extension From Git Repo": "Импортировать расширение из Git-репозитория.", + "Install extension": "Установить расширение", + "Manage extensions": "Управление расширениями", + "Tokens persona description": "Токенов", + "Most tokens": "Больше всего токенов", + "Least tokens": "Меньше всего токенов", + "Random": "Случайно", + "Skip Example Dialogues Formatting": "Пропустить форматирование примеров диалогов", + "Import a theme file": "Импортировать файл темы", + "Export a theme file": "Экспортировать файл темы", + "Unlocked Context Size": "Неограниченный размер контекста", + "Display the response bit by bit as it is generated.": "Выводить текст последовательно по мере его генерации.", + "When this is off, responses will be displayed all at once when they are complete.": "Если параметр выключен, ответы будут отображаться сразу целиком, и только после полного завершения генерации.", + "Quick Prompts Edit": "Быстрое редактирование промптов", + "Enable OpenAI completion streaming": "Включить стриминг OpenAI", + "Main": "Основной", + "Utility Prompts": "Служебные промпты", + "Continue prefill": "Префилл для продолжения", + "Continue sends the last message as assistant role instead of system message with instruction.": "Продолжение отправляет последнее сообщение в роли ассистента, вместо системного сообщения с инструкцией.", + "Squash system messages": "Склеивать сообщения системы", + "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Объединяет последовательные системные сообщения в одно (за исключением примеров диалогов). У некоторых моделей может улучшить логичность ответов.", + "Send inline images": "Отправлять inline-картинки", + "Assistant Prefill": "Префилл для ассистента", + "Start Claude's answer with...": "Начать ответ Клода с...", + "Use system prompt (Claude 2.1+ only)": "Использовать системный промпт (только Claude 2.1+)", + "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "Отправлять системный промпт для поддерживаемых моделей. Если отключено, в начало промпта добавляется сообщение пользователя.", + "Prompts": "Промпты", + "Total Tokens:": "Всего токенов:", + "Insert prompt": "Вставить промпт", + "Delete prompt": "Удалить промпт", + "Import a prompt list": "Импортировать список промптов", + "Export this prompt list": "Экспортировать этот список промптов", + "Reset current character": "Сбросить текущего персонажа", + "New prompt": "Новый промпт", + "Tokens": "токенов", + "Want to update?": "Хотите обновиться?", + "How to start chatting?": "Как начать общение?", + "and select a": " и выберите ", + "Chat API": "API чата", + "in the chat bar": " в поле чата", + "Confused or lost?": "Не можете в чём-то разобраться?", + "click these icons!": "нажмите на эти значки!", + "SillyTavern Documentation Site": "Сайт документации SillyTavern", + "Extras Installation Guide": "Руководство по установке Extras", + "Still have questions?": "Остались вопросы?", + "Join the SillyTavern Discord": "Заходите на сервер SillyTavern в Discord", + "Post a GitHub issue": "Опубликуйте GitHub issue", + "Contact the developers": "Свяжитесь с разработчиками", + "Nucleus Sampling": "Nucleus Sampling", + "Typical P": "Typical P", + "Top K Sampling": "Top K", + "Top A Sampling": "Top A", + "Off": "Выключено", + "Very light": "Очень легкий", + "Light": "Легкий", + "Medium": "Средний", + "Aggressive": "Агрессивный", + "Very aggressive": "Очень агрессивный", + "Eta_Cutoff_desc": "Eta cutoff - основной параметр специальной техники сэмплинга под названием Eta Sampling. В единицах 1e-4; разумное значение - 3. Установите в 0, чтобы отключить. См. статью Truncation Sampling as Language Model Desmoothing от Хьюитт и др. (2022) для получения подробной информации.", + "Learn how to contribute your idle GPU cycles to the Horde": "Узнайте, как внести свой вклад в свои свободные GPU-циклы в орду", + "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "Используйте соответствующий токенизатор для моделей Google через их API. Медленная обработка подсказок, но предлагает намного более точный подсчет токенов.", + "Load koboldcpp order": "Загрузить порядок из koboldcpp", + "Use Google Tokenizer": "Использовать токенизатор Google", + "koboldcpp API key (optional)": "Ключ от API koboldcpp (необязательно)", + "Reverse Proxy": "Прокси", + "Use Proxy password field instead. This input will be ignored.": "Используйте поле \"Пароль от прокси\". Значение в этом окошке игнорируется", + "Proxy Password": "Пароль от прокси", + "Will be used as a password for the proxy instead of API key.": "Будет использован в качестве пароля от прокси вместо ключа от API", + "Proxy Presets": "Пресеты для прокси", + "Saved addresses and passwords.": "Сохранённые адреса и пароли.", + "Save Proxy": "Сохранить прокси", + "Delete Proxy": "Удалить прокси", + "Proxy Name": "Название прокси", + "This will show up as your saved preset.": "Будет отображено в вашем списке пресетов.", + "Proxy Server URL": "Адрес прокси-сервера", + "MistralAI Model": "Модель MistralAI", + "MistralAI API Key": "Ключ от API MistralAI", + "Google AI Studio API Key": "Ключ от API Google AI Studio", + "Google Model": "Модель Google", + "Cohere API Key": "Ключ от API Cohere", + "Cohere Model": "Модель Cohere", + "Model Order": "Сортировка моделей OpenRouter", + "Alphabetically": "По алфавиту", + "Price": "По цене (наиболее низкая)", + "Context Size": "По размеру контекста", + "Group by vendors": "Сгруппировать по владельцу", + "Group by vendors Description": "Модели от OpenAI попадут в одну группу, от Anthropic - в другую, и т.д. Можно комбинировать с сортировкой.", + "Allow Jailbreak": "Разрешить джейлбрейк", + "System Prompt Wrapping": "Обрамление для системного промпта", + "System Prompt Prefix": "Префикс системного промпта", + "System Prompt Suffix": "Постфикс системного промпта", + "Chat Messages Wrapping": "Обрамление для сообщений в чате", + "User Prefix": "Префикс сообщения пользователя", + "User Suffix": "Постфикс сообщения пользователя", + "Assistant Prefix": "Префикс сообщения ассистента", + "Assistant Suffix": "Постфикс сообщения ассистента", + "System Prefix": "Префикс сообщения системы", + "System Suffix": "Постфикс сообщения системы", + "System same as User": "Для системы то же самое, что и для пользователя", + "Misc. Sequences": "Прочие строки", + "First Assistant Prefix": "Первый префикс ассистента", + "Last Assistant Prefix": "Последний префикс ассистента", + "System Instruction Prefix": "Префикс системной инструкции", + "User Filler Message": "Принудительное сообщение пользователя", + "Permanent": "перманентных", + "Alt. Greetings": "Др. варианты", + "Smooth Streaming": "Плавный стриминг", + "Save checkpoint": "Сохранить чекпоинт", + "Min Activations": "Мин. число активаций", + "Scan chronologically until reached min entries or token budget.": "Сканировать в хронологической последовательности, пока не будет достигнуто мин. число вхождений или не израсходуется бюджет токенов.", + "Max Depth": "Макс. глубина", + "(0 = unlimited, use budget)": "(0 = безграничная, использовать бюджет)", + "Ext. Media": "Внешн. медиа", + "Multiple swipes per generation": "Несколько свайпов на генерацию", + "Set to get deterministic results. Use -1 for random seed.": "Используется для получения предсказуемого результата. Введите -1 для случайного зерна", + "Most tokens have a leading space.": "У большинства токенов в начале пробел.", + "Text or token ids": "Текст или [идентификаторы токенов]", + "World Info Format Template": "Шаблон оформления информации о мире", + "Wraps activated World Info entries before inserting into the prompt.": "Дополняет информацию об активном на данный момент мире перед её отправкой в промпт.", + "Doesn't work? Try adding": "Не работает? Попробуйте добавить в конце", + "at the end!": "!", + "Authorize": "Авторизоваться", + "No persona description": "[Нет описания]", + "Not connected to API!": "Нет соединения с API!", + "Type a message, or /? for help": "Введите сообщение, или /? для получения справки", + "Welcome to SillyTavern!": "Добро пожаловать в SillyTavern!", + "Won't be shared with the character card on export.": "Не попадут в карточку персонажа при экспорте.", + "Persona Name:": "Имя персоны:", + "User first message": "Первое сообщение пользователя", + "extension_token_counter": "Токенов:", + "Character's Note": "Заметка о персонаже", + "(Text to be inserted in-chat @ designated depth and role)": "Этот текст будет вставлен в чат на заданную глубину и с определённой ролью", + "@ Depth": "Глубина", + "Role": "Роль", + "System": "Система", + "User": "Пользователь", + "Assistant": "Ассистент", + "How often the character speaks in": "Как часто персонаж говорит в", + "Creator's Metadata": "Метаданные", + "(Not sent with the AI Prompt)": "(не отправляются ИИ)", + "New Chat": "Новый чат", + "Import Chat": "Импорт чата", + "Chat Lore": "Лор чата", + "Chat Lorebook for": "Лорбук для чата", + "Missing key": "❌ Ключа нет", + "Key saved": "✔️ Ключ сохранён", + "Use the appropriate tokenizer for Jurassic models, which is more efficient than GPT's.": "Использовать токенайзер для моделей Jurassic, эффективнее GPT-токенайзера", + "Experimental feature. May not work for all backends.": "Экспериментальная возможность, на некоторых бэкендах может не работать.", + "Avatar Hover Magnification": "Зум аватарки по наведению", + "Enable magnification for zoomed avatar display.": "Добавляет возможность приближать увеличенную версию аватарки.", + "Unique to this chat": "Только для текущего чата", + "Checkpoints inherit the Note from their parent, and can be changed individually after that.": "Чекпоинты наследуют заметки от родительского чата, но впоследствие их всегда можно изменить.", + "Include in World Info Scanning": "Учитывать при сканировании Информации о мире", + "Before Main Prompt / Story String": "Перед основным промптом / строкой истории", + "After Main Prompt / Story String": "После основного промпта / строки истории", + "In-chat @ Depth": "Встав. на глуб.", + "as": "роль:", + "Insertion Frequency": "Частота вставки", + "(0 = Disable, 1 = Always)": "(0 = никогда, 1 = всегда)", + "User inputs until next insertion:": "Ваших сообщений до след. вставки:", + "Character Author's Note (Private)": "Заметки автора персонажа (личные)", + "Will be automatically added as the author's note for this character. Will be used in groups, but can't be modified when a group chat is open.": "Автоматически применятся к этому персонажу в качестве заметок автора. Будут использоваться в группах, но при активном групповом чате к редактированию недоступны.", + "Use character author's note": "Использовать заметки автора персонажа", + "Replace Author's Note": "Вместо заметок автора", + "Default Author's Note": "Стандартные заметки автора", + "Will be automatically added as the Author's Note for all new chats.": "Будут автоматически добавляться во все новые чаты в качестве Заметок автора", + "1 = disabled": "1 = откл.", + "write short replies, write replies using past tense": "пиши короткие ответы, пиши в настоящем времени", + "Positive Prompt": "Положительный промпт", + "Character CFG": "CFG для персонажа", + "Will be automatically added as the CFG for this character.": "Автоматически применится к персонажу как его CFG.", + "Global CFG": "Глобальный CFG", + "Will be used as the default CFG options for every chat unless overridden.": "Будет применяться как стандартный CFG для всех чатов, если не указаны индивидуальные настройки.", + "CFG Prompt Cascading": "Совмещение CFG-промптов", + "Combine positive/negative prompts from other boxes.": "Комбинировать различные положительные и негативные промпты.", + "For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string.": "К примеру, если отметить галочки с чатом, персонажем и глобальной настройкой, то все эти негативы соберутся в одну строку, разделённую запятыми.", + "Always Include": "Всегда применять", + "Chat Negatives": "Негативы от чата", + "Character Negatives": "Негативы от персонажа", + "Global Negatives": "Глобальные негативы", + "Custom Separator:": "Кастомный разделитель:", + "Insertion Depth:": "Глубина вставки:", + "Chat CFG": "CFG для чата", + "bg_chat_hint_1": "Здесь будут появляться фоны, сгенерированные расширением", + "bg_chat_hint_2": ".", + "Prevent further recursion (this entry will not activate others)": "Пресечь дальнейшую рекурсию (эта запись не будет активировать другие)", + "Alert if your world info is greater than the allocated budget.": "Оповещать, если ваш мир выходит за выделенный бюджет.", + "Convert to Persona": "Преобразовать в персону", + "Link to Source": "Ссылка на источник", + "Replace / Update": "Заменить / Обновить", + "Smoothing Curve": "Кривая сглаживания", + "Message Actions": "Действия с сообщением", + "SillyTavern is aimed at advanced users.": "SillyTavern рассчитана на продвинутых пользователей.", + "If you're new to this, enable the simplified UI mode below.": "Если вы новичок, советуем включить упрощённый UI.", + "Enable simple UI mode": "Включить упрощённый UI", + "welcome_message_part_1": "Ознакомьтесь с", + "welcome_message_part_2": "официальной документацией", + "welcome_message_part_3": ".", + "welcome_message_part_4": "Введите", + "welcome_message_part_5": "в чате, чтобы получить справку по командам и макросам.", + "welcome_message_part_6": "Заходите на наш", + "Discord server": "Discord-сервер,", + "welcome_message_part_7": "там публикуется много разной полезной информации, в том числе анонсы.", + "Before you get started, you must select a persona name.": "Для начала вам следует выбрать имя своей персоны.", + "welcome_message_part_8": "Его можно будет изменить в любое время через иконку", + "welcome_message_part_9": ".", + "Ignore EOS Token": "Игнорировать EOS-токен", + "Ignore the EOS Token even if it generates.": "Игнорировать EOS-токен, даже если он сгенерировался.", + "Hide Muted Member Sprites": "Скрыть спрайты заглушенных участников", + "Group generation handling mode": "Генерировать ответы путём...", + "Swap character cards": "Подмены карточки персонажа", + "Join character cards (exclude muted)": "Совмещения карточек (кроме заглушенных)", + "Join character cards (include muted)": "Совмещения карточек (включая заглушенных)", + "Click to allow/forbid the use of external media for this group.": "Нажмите, чтобы разрешить/запретить использование внешних медиа в этой группе.", + "Scenario Format Template": "Шаблон оформления сценария", + "scenario_format_template_part_1": "Используйте", + "scenario_format_template_part_2": "чтобы указать, куда именно вставляется основное содержимое.", + "Personality Format Template": "Шаблон оформления характера", + "Group Nudge Prompt Template": "Шаблон промпта-подсказки для групп", + "Sent at the end of the group chat history to force reply from a specific character.": "Добавляется в конец истории сообщений в групповом чате, чтобы запросить ответ от конкретного персонажа.", + "Set at the beginning of the chat history to indicate that a new chat is about to start.": "Добавляется в начале истории сообщений в качестве указания на то, что дальше начнётся новый чат.", + "New Group Chat": "Новый групповой чат", + "Set at the beginning of the chat history to indicate that a new group chat is about to start.": "Добавляется в начале истории сообщений в качестве указания на то, что дальше начнётся новый групповой чат.", + "New Example Chat": "Новый образец чата", + "Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.": "Добавляется в начале примеров диалогов в качестве указания на то, что дальше начнётся новый чат-пример.", + "Continue nudge": "Подсказка для продолжения", + "Set at the end of the chat history when the continue button is pressed.": "Добавляется в конец истории чата, когда отправлен запрос на продолжение текущего сообщения.", + "Continue Postfix": "Постфикс для продолжения", + "Space": "Пробел", + "Newline": "Новая строка", + "Double Newline": "Две новые строки", + "The next chunk of the continued message will be appended using this as a separator.": "Используется в качестве разделителя между уже имеющимся сообщением и его новым отрывком, при генерации продолжения", + "Regex Editor": "Редактор рег. выражений", + "ext_regex_import_script": "Импорт скрипта", + "ext_regex_desc": "Regex - это инструмент, позволяющий находить и изменять строки, используя регулярные выражения. Для более подробной информации нажмите ? рядом с заголовком.", + "Input": "Поле ввода", + "ext_regex_test_input_placeholder": "Введите текст...", + "Output": "Результат", + "ext_regex_output_placeholder": "Пусто", + "Script Name": "Название скрипта", + "Find Regex": "Рег. выражение для поиска", + "Replace With": "Замена", + "ext_regex_replace_string_placeholder": "Чтобы вставить всё вхождение рег. выражения, используйте {{match}}. Чтобы вставить группу символов, используйте $1, $2 и т.д.", + "Trim Out": "Усечение", + "ext_regex_trim_placeholder": "Удалить перед обработкой ненужные части текста. Каждый элемент с новой строки.", + "Slash Commands": "Слэш-команды", + "Min Depth": "Мин. глубина", + "ext_regex_min_depth_desc": "При форматировании затрагивать только те сообщения, которые находятся как минимум на глубине N. 0 = последнее сообщение, 1 = предпоследнее и т.д. Учитываются только видимые сообщения, т.е. не скрытые и не системные.", + "ext_regex_max_depth_desc": "При форматировании затрагивать только те сообщения, которые находятся на глубине не более N. 0 = последнее сообщение, 1 = предпоследнее и т.д. Учитываются только видимые сообщения, т.е. не скрытые и не системные.", + "ext_regex_min_depth_placeholder": "Неогранич.", + "ext_regex_other_options": "Другие опции", + "Only Format Display": "Только визуально", + "ext_regex_only_format_prompt_desc": "История чата не изменится, замена будет осуществляться только в промпте (при генерации)", + "Only Format Prompt (?)": "Только промпт", + "Run On Edit": "Выполнять при редактировании", + "Substitute Regex": "Заменить в рег. выражении", + "ext_regex_substitute_regex_desc": "Перед выполнением заменять {{макросы}} в рег. выражении", + "Test Mode": "Протестировать", + "ext_regex_affects": "Затрагивает", + "ext_regex_user_input": "Ваши сообщения", + "ext_regex_ai_output": "Ответы ИИ", + "ext_regex_disable_script": "Выключить этот скрипт", + "ext_regex_enable_script": "Включить скрипт", + "ext_regex_edit_script": "Редактировать", + "ext_regex_export_script": "Экспортировать", + "ext_regex_delete_script": "Удалить", + "ext_sum_with": "Для пересказа использовать:", + "ext_sum_main_api": "Основное API", + "ext_sum_current_summary": "Текущий пересказ:", + "ext_sum_restore_previous": "Восстановить предыдущий", + "ext_sum_memory_placeholder": "Сгенерированный пересказ будет здесь...", + "ext_sum_force_text": "Пересказать сейчас", + "Disable automatic summary updates. While paused, the summary remains as-is. You can still force an update by pressing the Summarize now button (which is only available with the Main API).": "Отключить авто-обновление пересказа. Пересказ всё время будет фиксированным. Однако останется возможность принудительно обновить пересказ через кнопку \"Пересказать сейчас\" (доступно только через Основное API)", + "ext_sum_pause": "Приостановить", + "Omit World Info and Author's Note from text to be summarized. Only has an effect when using the Main API. The Extras API always omits WI/AN.": "Исключать из пересказа Информацию о мире и Заметки автора. Работает только для Основного API. Extras API всегда их исключает.", + "ext_sum_no_wi_an": "Без мира и заметок", + "ext_sum_settings_tip": "Изменить промпт пересказа, место для инжекта и т.д.", + "ext_sum_settings": "Настройки пересказа", + "ext_sum_prompt_builder": "Алгоритм формирования промпта", + "ext_sum_prompt_builder_1_desc": "Расширение само составит промпт с учётом непересказанных сообщений. Во время генерации чат недоступен.", + "ext_sum_prompt_builder_1": "Прямой, блокирующий", + "ext_sum_prompt_builder_2_desc": "Расширение само составит промпт с учётом непересказанных сообщений. Во время генерации чат доступен. Может не поддерживаться некоторыми бэкендами.", + "ext_sum_prompt_builder_2": "Прямой, неблокирующий", + "ext_sum_prompt_builder_3_desc": "Расширение будет использовать стандартные основные настройки промпта, и добавит свой промпт в качестве последнего системного сообщения.", + "ext_sum_prompt_builder_3": "Классический, блокирующий", + "Summary Prompt": "Промпт для пересказа", + "ext_sum_restore_default_prompt_tip": "Восстановить стандартный промпт", + "ext_sum_prompt_placeholder": "Этот промпт будет отправлен ИИ при запросе на генерацию пересказа. Макрос {{words}} будет заменён на значение параметра \"Количество слов\".", + "ext_sum_target_length_1": "Целевая длина пересказа (слов):", + "ext_sum_target_length_2": "", + "ext_sum_target_length_3": "", + "ext_sum_api_response_length_1": "Длина ответа от API (токенов):", + "ext_sum_api_response_length_2": "", + "ext_sum_api_response_length_3": " ", + "ext_sum_0_default": "по умолчанию = 0", + "ext_sum_raw_max_msg": "[Прямое форматирование] Макс. сообщений в запросе", + "ext_sum_0_unlimited": "неограничено = 0", + "Update frequency": "Частота обновления", + "ext_sum_update_every_messages_1": "Интервал обновления (кол-во сообщений):", + "ext_sum_update_every_messages_2": "", + "ext_sum_update_every_words_1": "Интервал обновления (кол-во слов):", + "ext_sum_update_every_words_2": "", + "ext_sum_0_disable": "для отключения поставьте 0", + "ext_sum_auto_adjust_desc": "Попытаться автоматически рассчитать значение интервала, исходя из статистики чата", + "ext_sum_both_sliders": "Если оба ползунка отличны от нуля, то оба будут триггерить генерацию пересказа с соответствующей периодичностью.", + "ext_sum_injection_template": "Шаблон для инжекта", + "ext_sum_memory_template_placeholder": "Макрос {{summary}} будет заменён на содержимое пересказа", + "ext_sum_injection_position": "Куда инжектить", + "How many messages before the current end of the chat.": "Сколько сообщений от конца чата.", + "Change it later in the 'User Settings' panel.": "Его можно будет выключить в меню \"Настройки пользователя\"", + "Looking for AI characters?": "Ищете ИИ-персонажей?", + "onboarding_import": "Импортируйте", + "from supported sources or view": "из источника или посмотрите", + "Sample characters": "Стандартных персонажей", + "popup-button-save": "Сохранить", + "popup-button-yes": "Да", + "popup-button-no": "Нет", + "popup-button-cancel": "Отмена", + "popup-button-import": "Импортировать", + "Enter the URL of the content to import": "Введите URL-адрес импортируемого контента", + "Supported sources:": "Поддерживаются следующие источники:", + "char_import_example": "Пример:", + "char_import_1": "Персонаж с Chub (прямая ссылка или ID)", + "char_import_2": "Лорбук с Chub (прямая ссылка или ID)", + "char_import_3": "Персонаж с JanitorAI (прямая ссылка или UUID)", + "char_import_4": "Персонаж с Pygmalion.chat (прямая ссылка или UUID)", + "char_import_5": "Персонаж с AICharacterCards.com (прямая ссылка или ID)", + "char_import_6": "Прямая ссылка на PNG-файл (чтобы узнать список разрешённых хостов, загляните в", + "char_import_7": ")", + "Grammar String": "Грамматика", + "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF или EBNF, зависит от бэкенда. Если вы это используете, то, скорее всего, сами знаете, какой именно.", + "Account": "Аккаунт", + "Hi,": "Привет,", + "To enable multi-account features, restart the SillyTavern server with": "Чтобы активировать систему аккаунтов, перезапустите SillyTavern, выставив", + "set to true in the config.yaml file.": "в файле config.yaml в положение true.", + "Account Info": "Об аккаунте", + "Handle:": "Хэндл:", + "Role:": "Роль:", + "Created:": "Создан:", + "Password:": "Пароль:", + "This account is password protected.": "Аккаунт защищён паролем.", + "This account is not password protected.": "Аккаунт не защищён паролем.", + "Account Actions": "Действия", + "Settings Snapshots": "Снимки настроек", + "Manage your settings snapshots.": "Управление снимками настроек.", + "Download Backup": "Скачать бэкап", + "Download a complete backup of your user data.": "Скачать полный бэкап данных пользователя.", + "Danger Zone": "Опасно", + "Reset Settings": "Сбросить настройки", + "Reset your settings to factory defaults.": "Сбросить настройки до заводских.", + "Reset Everything": "Сбросить всё", + "Wipe all user data and reset your account to factory settings.": "Стереть все данные пользователя и сбросить аккаунт до заводских настроек.", + "Set your custom avatar.": "Установить аватарку", + "Remove your custom avatar.": "Сбросить аватарку", + "Make a Snapshot": "Сделать снимок", + "never_resize_avatars_tooltip": "Не менять размер картинок у импортируемых персонажей. При отключении все картинки будут приводиться к размеру 512х768", + "Char List Subheader": "Доп. заголовок в списке персонажей", + "# Messages to Load": "Сколько сообщений загружать", + "(0 = All)": "(0 = все)", + "Theme Colors": "Цвета темы", + "Specify colors for your theme.": "Настройте собственные цвета для вашей темы.", + "Update speed of streamed text.": "Скорость обновления текста при стриминге.", + "The number of chat history messages to load before pagination.": "Кол-во сообщений чата, загружаемых перед пагинацией.", + "Chat Width": "Ширина чата", + "Width of the main chat window in % of screen width": "Ширина окна с чатом, в % от ширины экрана", + "Blur strength on UI panels.": "Сила размытия на панелях UI.", + "Font size": "Размер шрифта", + "Strength of the text shadows": "Размер теней, отбрасываемых текстом", + "prompt_manager_edit": "Редактирование", + "prompt_manager_tokens": "Токенов", + "prompt_manager_name": "Имя", + "A name for this prompt.": "Имя данного промпта.", + "To whom this message will be attributed.": "От чьего лица будет отправляться сообщение.", + "AI Assistant": "ИИ-ассистент", + "prompt_manager_position": "Точка инжекта", + "Injection position. Next to other prompts (relative) or in-chat (absolute).": "Как рассчитывать позицию для инжекта. Она может располагаться по отношению к другим промптам (относительная) либо по отношению к чату (абсолютная).", + "prompt_manager_relative": "Относительная", + "prompt_manager_depth": "Глубина", + "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "Глубина вставки. 0 = после последнего сообщения, 1 = перед последним сообщением, и т.д.", + "The prompt to be sent.": "Отправляемый ИИ промпт.", + "prompt_manager_forbid_overrides": "Запретить перезапись", + "This prompt cannot be overridden by character cards, even if overrides are preferred.": "Карточка персонажа не сможет перезаписать этот промпт, даже если настройки отдают приоритет именно ей.", + "image_inlining_hint_1": "Отправлять картинки как часть промпта, если позволяет модель (такой функционал поддерживают GPT-4V, Claude 3 или Llava 13B). Чтобы добавить в чат изображение, используйте на нужном сообщении действие", + "image_inlining_hint_2": ". Также это можно сделать через меню", + "image_inlining_hint_3": ".", + "Contest Winners": "Победители конкурса", + "Rename background": "Переименовать фон", + "Lock": "Закрепить", + "Unlock": "Открепить", + "Delete background": "Удалить фон", + "Export all": "Экспортировать всё", + "Export all your prompts to a file": "Экспортировать все промпты в виде файла", + "Don't add character names.": "Не добавлять имя персонажа", + "Add character names to completion objects.": "Добавлять имя персонажа как часть Completion object", + "Message Content": "Внутри сообщения", + "Prepend character names to message contents.": "Предварять сообщения именем персонажа.", + "Character Names Behavior": "Вставка имени персонажа", + "and pick a character.": "и выберите персонажа.", + "Record a snapshot of your current settings.": "Сделать снимок текущих настроек.", + "Restore this snapshot": "Откатиться к этому снимку", + "To change your user avatar, use the buttons below or select a default persona in the Persona Management menu.": "Чтобы сменить аватарку, используйте кнопки ниже, либо выберите персону по умолчанию в меню управления персоной.", + "These characters are the winners of character design contests and have outstandable quality.": "Персонажи наивысшего качества, одержавшие победу в конкурсе персонажей.", + "Featured Characters": "Рекомендуемые персонажи", + "These characters are the finalists of character design contests and have remarkable quality.": "Персонажи отличного качества, финалисты конкурса персонажей.", + "Inline Image Quality": "Качество inline-изображений", + "openai_inline_image_quality_auto": "Автоопределение", + "openai_inline_image_quality_low": "Низкое", + "openai_inline_image_quality_high": "Высокое", + "Assistant Impersonation Prefill": "Префилл для ассистента при перевоплощении", + "Hide Chat Avatars": "Не показывать аватарки в чате", + "Hide avatars in chat messages.": "Скрыть аватарки сбоку от сообщений в чате", + "Flat": "Стандартный", + "Toggle character info panel": "Показать / скрыть инфо-панель", + "(For Chat Completion and Instruct Mode)": "(для Chat Completion и режима Instruct)", + "help_1": "Приветствуем! Выберите тему, которая вас интересует:", + "help_2": "Слэш-команды", + "help_or": "также", + "help_3": "Разметка", + "help_4": "Горячие клавиши", + "help_5": "{{Макросы}}", + "help_6": "Не нашли ответа на свой вопрос? Загляните в", + "help_7": "официальную документацию SillyTavern", + "help_8": ", там система описана гораздо более подробно!", + "help_format_1": "Команды для разметки текста:", + "help_format_2": "*текст*", + "help_format_3": "добавляет ", + "help_format_4": "курсив", + "help_format_5": "**текст**", + "help_format_6": "делает текст ", + "help_format_7": "полужирным", + "help_format_8": "***текст***", + "help_format_9": "добавляет ", + "help_format_10": "полужирный курсив", + "help_format_11": "__текст__", + "help_format_12": "добавляет ", + "help_format_13": "подчёркивание", + "help_format_14": "~~текст~~", + "help_format_15": "делает текст ", + "help_format_16": "зачёркнутым", + "help_format_17": "[текст](url)", + "help_format_18": "добавляет в текст ", + "help_format_19": "ссылку", + "help_format_20": "![текст](url)", + "help_format_21": "добавляет в текст картинку", + "help_format_22": "```текст```", + "help_format_23": "оформляет текст как кусок кода (символ новой строки также допустим)", + "help_format_like_this": "вот так", + "help_format_24": "`текст`", + "help_format_25": "отображает кусок кода ", + "help_format_26": "внутри строки", + "help_format_27": "> текст", + "help_format_28": "отображает текст как цитату (обратите внимание на пробел после >)", + "help_format_29": "# текст", + "help_format_30": "создаёт крупный заголовок (обратите внимание на пробел)", + "help_format_32": "## текст", + "help_format_33": "создаёт средний заголовок (обратите внимание на пробел)", + "help_format_35": "### текст", + "help_format_36": "создаёт малый заголовок (обратите внимание на пробел)", + "help_format_38": "$$ текст $$", + "help_format_39": "отрендерить в виде формулы LaTeX (если включено в настройках)", + "help_format_40": "$ текст $", + "help_format_41": "отрендерить в виде формулы AsciiMath (если включено в настройках)", + "help_hotkeys_1": "Стрелка вверх", + "help_hotkeys_2": "Редактировать последнее сообщение в чате", + "help_hotkeys_3": "Ctrl+Стрелка вверх", + "help_hotkeys_4": "Редактировать ВАШЕ последнее сообщение в чате", + "help_hotkeys_5": "Стрелка влево", + "help_hotkeys_6": "Свайп влево", + "help_hotkeys_7": "Стрелка вправо", + "help_hotkeys_8": "Свайп вправо (ОБРАТИТЕ ВНИМАНИЕ: если в окошке ввода что-то есть, клавиши для свайпов не работают)", + "help_hotkeys_10": "(при фокусе на окошке ввода)", + "help_hotkeys_10_1": "Отправить сообщение", + "help_hotkeys_12": "Повторно сгенерировать последний ответ ИИ", + "help_hotkeys_14": "Продолжить последний ответ ИИ", + "help_hotkeys_16": "Остановить генерацию ответа, скрыть UI-панель, отменить редактирование сообщения", + "help_hotkeys_17": "Ctrl+Shift+Вверх", + "help_hotkeys_18": "Прокрутить до линии контекста", + "help_hotkeys_19": "Ctrl+Shift+Вниз", + "help_hotkeys_20": "Прокрутить вниз до конца", + "help_hotkeys_0": "Горячие клавиши", + "You can browse a list of bundled characters in the": "Комплектных персонажей можно найти в меню", + "Download Extensions & Assets": "Загрузить расширения и ресурсы", + "menu within": "в меню", + "Assets URL": "URL с описанием ресурсов", + "Custom (OpenAI-compatible)": "Кастомный (совместимый с OpenAI)", + "Custom Endpoint (Base URL)": "Кастомный эндпоинт (базовый URL)", + "Example: http://localhost:1234/v1": "Пример: http://localhost:1234/v1", + "Custom API Key": "Ключ от кастомного API", + "(Optional)": "(необязательно)", + "Enter a Model ID": "Введите идентификатор модели", + "Example: gpt-4o": "Пример: gpt-4o", + "Available Models": "Доступные модели", + "Prompt Post-Processing": "Постобработка промпта", + "Applies additional processing to the prompt before sending it to the API.": "Позволяет обработать промпт перед отправкой в API.", + "prompt_post_processing_none": "Отсутствует", + "Additional Parameters": "Доп. параметры", + "Include Body Parameters": "Добавить параметры в тело", + "custom_include_body_desc": "Эти параметры будут добавлены в тело запроса к API Chat Completion (YAML-объект)\n\nПример:\n- top_k: 20\n- repetition_penalty: 1.1", + "Exclude Body Parameters": "Исключить параметры из тела", + "custom_exclude_body_desc": "Эти параметры будут исключены из тела запроса к API Chat Completion (YAML-массив)\n\nПример:\n- frequency_penalty\n- presence_penalty", + "Include Request Headers": "Добавить заголовки запроса", + "custom_include_headers_desc": "Дополнительные заголовки, добавляемые к запросу в API Chat Completion (YAML-объект)\n\nПример:\n- CustomHeader: custom-value\n- AnotherHeader: custom-value", + "Groq API Key": "Ключ от API Groq", + "Groq Model": "Модель Groq", + "Perplexity API Key": "Ключ от API Perplexity", + "Perplexity Model": "Модель Perplexity", + "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "Создаёт эффект приближения, когда вы наводитесь мышкой на изображение, отображаемое по клику на аватарку в чате.", + "STscript Settings": "Настройки STscript", + "Sets default flags for the STscript parser.": "Задаёт стандартные значения флагов для парсера STscript.", + "Parser Flags": "Флаги парсера", + "ext_regex_new_global_script": "+ Глобальный", + "ext_regex_new_scoped_script": "+ Локальный", + "ext_regex_new_global_script_desc": "Создать глобальный regex-скрипт", + "ext_regex_new_scoped_script_desc": "Создать локальный regex-скрипт", + "ext_regex_global_scripts": "Глобальные скрипты", + "ext_regex_global_scripts_desc": "Распространяются на всех персонажей. Сохраняются как часть настроек.", + "ext_regex_scoped_scripts": "Локальные скрипты", + "ext_regex_scoped_scripts_desc": "Распространяются только на этого персонажа. Сохраняются в его карточку.", + "ext_regex_allow_scoped": "Включить локальные скрипты", + "ext_regex_disallow_scoped": "Отключить локальные скрипты", + "ext_regex_move_to_global": "Сделать глобальным", + "openai_logit_bias_no_items": "Правил нет", + "Enable function calling": "Включить функции", + "enable_functions_desc_1": "Включает возможность ", + "enable_functions_desc_2": "вызова функций", + "enable_functions_desc_3": "Используется расширениями для добавления нового функционала.", + "MAD LAB MODE ON": "ВКЛЮЧЕН РЕЖИМ БЕЗУМЦА", + "api_no_connection": "Нет соединения...", + "Sampler Select": "Выбор сэмплеров", + "Customize displayed samplers or add custom samplers.": "Выберите, какие сэмплеры хотите здесь отображать, или добавьте собственные сэмплеры", + "ext_translate_auto_mode": "Автоперевод", + "ext_translate_mode_none": "Откл.", + "ext_translate_mode_responses": "Переводить ответы ИИ", + "ext_translate_mode_inputs": "Переводить ваши сообщения", + "ext_translate_mode_both": "Переводить всё", + "ext_translate_mode_provider": "Переводчик", + "ext_translate_target_lang": "На какой язык переводить", + "ext_translate_clear": "Очистить переводы", + "ext_translate_btn_chat": "Перевести чат", + "ext_translate_btn_input": "Перевести моё сообщение", + "ext_translate_delete_confirm_1": "Вы уверены?", + "ext_translate_delete_confirm_2": "Будет удалён текст всех имеющихся в этом чате переводов. Отменить это действие невозможно.", + "Favorite": "Избранное", + "Tag": "Тег", + "Duplicate": "Duplicate", + "Persona": "Персона", + "novelaipresets": "Пресеты NovelAI", + "No Module": "No Module", + "Instruct": "Instruct", + "Prose Augmenter": "Prose Augmenter", + "Text Adventure": "Text Adventure", + "Streaming_desc": "Выводить текст последовательно по мере его генерации.\rЕсли параметр выключен, ответы будут отображаться сразу целиком, и только после полного завершения генерации.", + "Max prompt cost:": "Max prompt cost:", + "TFS": "TFS", + "Count Penalty": "Count Penalty", + "Min P": "Min P", + "NSFW": "NSFW", + "Restore default format": "Restore default format", + "Restore new chat prompt": "Restore new chat prompt", + "Restore new group chat prompt": "Restore default prompt", + "Mirostat": "Mirostat", + "Mode": "Режим", + "Mirostat_Mode_desc": "0 = отключить полностью. 1 = включить Mirostat 1.0. 2 = включить Mirostat 2.0.", + "Tau": "Tau", + "Mirostat_Tau_desc": "Controls variability of Mirostat outputs", + "Eta": "Eta", + "Mirostat_Eta_desc": "Controls learning rate of Mirostat", + "Ban_EOS_Token_desc": "Запретить токен конца последовательности (EOS) (актуально для KoboldCpp, но KoboldAI может запрещать ещё и другие токены).\rПодходит для написания историй, но не рекомендуется для режимов Chat и Instruct.", + "Mirostat LR": "Mirostat LR", + "rep.pen decay": "Rep Pen Decay", + "Skew": "Skew", + "Smooth Sampling": "Smooth Sampling", + "Smooth_Sampling_desc": "Allows you to use quadratic/cubic transformations to adjust the distribution. Lower Smoothing Factor values will be more creative, usually between 0.2-0.3 is the sweetspot (assuming the curve = 1). Higher Smoothing Curve values will make the curve steeper, which will punish low probability choices more aggressively. 1.0 curve is equivalent to only using Smoothing Factor.", + "DRY_Repetition_Penalty_desc": "DRY penalizes tokens that would extend the end of the input into a sequence that has previously occurred in the input. Set multiplier to 0 to disable.", + "DRY Repetition Penalty": "DRY Repetition Penalty", + "DRY_Multiplier_desc": "Set to value > 0 to enable DRY. Controls the magnitude of the penalty for the shortest penalized sequences.", + "Multiplier": "Multiplier", + "DRY_Base_desc": "Controls how fast the penalty grows with increasing sequence length.", + "Base": "Base", + "DRY_Allowed_Length_desc": "Longest sequence that can be repeated without being penalized.", + "Allowed Length": "Allowed Length", + "Penalty Range": "Penalty Range", + "DRY_Sequence_Breakers_desc": "Tokens across which sequence matching is not continued. Specified as a comma-separated list of quoted strings.", + "Sequence Breakers": "Sequence Breakers", + "JSON-serialized array of strings.": "Список строк в формате JSON.", + "Mirostat_desc": "Mirostat - своего рода термометр, измеряющий перплексию для выводимого текста.\nMirostat подгоняет перплексию генерируемого текста к перплексии входного текста, что позволяет избежать повторов.\n(когда по мере генерации текста авторегрессионным инференсом, перплексия всё больше приближается к нулю)\n а также ловушки перплексии (когда перплексия начинает уходить в сторону)\nБолее подробное описание в статье Mirostat: A Neural Text Decoding Algorithm that Directly Controls Perplexity by Basu et al. (2020).\nРежим выбирает версию Mirostat. 0=отключить, 1=Mirostat 1.0 (только llama.cpp), 2=Mirostat 2.0.", + "Helpful tip coming soon.": "Подсказку скоро добавим.", + "Temperature_Last_desc": "Использовать Temperature сэмплер в последнюю очередь. Это почти всегда разумно.\nПри включении: сначала выборка набора правдоподобных токенов, затем применение Temperature для корректировки их относительных вероятностей (технически, логитов).\nПри отключении: сначала применение Temperature для корректировки относительных вероятностей ВСЕХ токенов, затем выборка правдоподобных токенов из этого.\nОтключение Temperature Last увеличивает вероятности в хвосте распределения, что увеличивает шансы получить несогласованный ответ.", + "Speculative Ngram": "Speculative Ngram", + "Use a different speculative decoding method without a draft model": "Use a different speculative decoding method without a draft model.\rUsing a draft model is preferred. Speculative ngram is not as effective.", + "Spaces Between Special Tokens": "Spaces Between Special Tokens", + "JSON Schema": "JSON Schema", + "Type in the desired JSON schema": "Type in the desired JSON schema", + "Top P & Min P": "Top P & Min P", + "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.", + "Helps the model to associate messages with characters.": "Помогает модели связывать сообщения с персонажами.", + "character_names_default": "Except for groups and past personas. Otherwise, make sure you provide names in the prompt.", + "Completion": "Completion Object", + "character_names_completion": "Только латинские буквы, цифры и знак подчёркивания. Работает не для всех бэкендов, в частности для Claude, MistralAI, Google.", + "Use AI21 Tokenizer": "Использовать токенайзер AI21", + "Use system prompt": "Использовать системный промпт", + "(Gemini 1.5 Pro/Flash only)": "(только Gemini 1.5 Pro/Flash)", + "Merges_all_system_messages_desc_1": "Объединяет все системные сообщения до первого не-системного, и отсылает их в поле", + "Merges_all_system_messages_desc_2": ".", + "Restore User first message": "Restore User first message", + "Human message": "Сообщение, инструкция и т.п. от лица человека.\nПри пустом поле ничего не отправляется, тогда требуется самостоятельно отправить промт от лица пользователя.", + "Text Completion": "Text Completion", + "Chat Completion": "Chat Completion", + "Default (completions compatible)": "Default [OpenAI /completions compatible: oobabooga, LM Studio, etc.]", + "Model Providers": "Model Providers", + "InfermaticAI API Key": "Ключ от API InfermaticAI", + "InfermaticAI Model": "Модель InfermaticAI", + "DreamGen API key": "Ключ от API DreamGen", + "DreamGen Model": "Модель DreamGen", + "vllm-project/vllm": "vllm-project/vllm (режим враппера OpenAI API)", + "vLLM API key": "Ключ от API vLLM", + "Example: 127.0.0.1:8000": "Example: http://127.0.0.1:8000", + "vLLM Model": "Модель vLLM", + "Aphrodite Model": "Модель Aphrodite", + "Peek a password": "Посмотреть пароль", + "Clear your cookie": "Clear your cookie", + "Add Chat Start and Example Separator to a list of stopping strings.": "Использовать Начало чата и Разделитель примеров сообщений в качестве стоп-строк.", + "context_allow_jailbreak": "Если в карточке есть джейлбрейк И ПРИ ЭТОМ включена опция \"Приоритет джейлбрейку из карточки персонажа\", то этот джейлбрейк добавляется в конец промпта.\nНЕ РЕКОМЕНДУЕТСЯ ДЛЯ МОДЕЛЕЙ TEXT COMPLETION, МОЖЕТ ПОРТИТЬ ВЫХОДНОЙ ТЕКСТ.", + "Context Order": "Context Order", + "Summary": "Summary", + "Example Dialogues": "Примеры диалогов", + "Hint": "Hint:", + "In-Chat Position not affected": "Summary and Author's Note orders are only affected when they don't have an In-Chat position set.", + "instruct_bind_to_context": "If enabled, Context templates will be automatically selected based on selected Instruct template name or by preference.", + "Inserted before a System prompt.": "Вставляется перед системным промптом.", + "Inserted after a System prompt.": "Вставляется после системного промпта.", + "Inserted before a User message and as a last prompt line when impersonating.": "Inserted before a User message and as a last prompt line when impersonating.", + "Inserted after a User message.": "Вставляется после сообщения пользователя.", + "Inserted before an Assistant message and as a last prompt line when generating an AI reply.": "Вставляется перед сообщением ассистента и в качестве последней строки промпта во время генерации ответа ИИ.", + "Inserted after an Assistant message.": "Вставляется после сообщения ассистента.", + "Inserted before a System (added by slash commands or extensions) message.": "Inserted before a System (added by slash commands or extensions) message.", + "Inserted after a System message.": "Вставляется после сообщения системы.", + "If enabled, System Sequences will be the same as User Sequences.": "Для сообщений системы будет использоваться то же обрамление, что и для пользователя.", + "Inserted before the first Assistant's message.": "Вставляется перед первым сообщением ассистента.", + "instruct_last_output_sequence": "Вставляется перед последним сообщением ассистента либо в качестве последней строки промпта во время генерации ответа ИИ (если роль не системная / нейтральная).", + "Will be inserted as a last prompt line when using system/neutral generation.": "Will be inserted as a last prompt line when using system/neutral generation.", + "If a stop sequence is generated, everything past it will be removed from the output (inclusive).": "Если ИИ генерирует стоп-строку, то всё после неё будет вырезано из ответа (включая и саму стоп-строку).", + "Will be inserted at the start of the chat history if it doesn't start with a User message.": "Вставляется в начале истории чата, если она начинается не с сообщения пользователя.", + "Global World Info/Lorebook activation settings": "Настройки активации глобального лорбука / Информации о мире", + "Click to expand": "Щёлкните, чтобы развернуть", + "Insertion Strategy": "Как инжектить", + "Only the entries with the most number of key matches will be selected for Inclusion Group filtering": "Only the entries with the most number of key matches will be selected for Inclusion Group filtering", + "Use Group Scoring": "Use Group Scoring", + "Search": "Search", + "Admin Panel": "Admin Panel", + "Logout": "Logout", + "Delete a theme": "Delete a theme", + "Tags_as_Folders_desc": "Recent change: Tags must be marked as folders in the Tag Management menu to appear as such. Click here to bring it up.", + "Slow": "Slow", + "Fast": "Fast", + "Reset MovingUI panel sizes/locations.": "Reset MovingUI panel sizes/locations.", + "Expand the editor": "Expand the editor", + "Disallow embedded media from other domains in chat messages": "Disallow embedded media from other domains in chat messages.", + "AutoComplete Settings": "AutoComplete Settings", + "Automatically hide details": "Automatically hide details", + "Determines how entries are found for autocomplete.": "Determines how entries are found for autocomplete.", + "Autocomplete Matching": "Matching", + "Starts with": "Starts with", + "Includes": "Includes", + "Fuzzy": "Fuzzy", + "Sets the style of the autocomplete.": "Sets the style of the autocomplete.", + "Autocomplete Style": "Style", + "Follow Theme": "Follow Theme", + "Dark": "Dark", + "Sets the font size of the autocomplete.": "Sets the font size of the autocomplete.", + "Sets the width of the autocomplete.": "Sets the width of the autocomplete.", + "Autocomplete Width": "Width", + "chat input box": "chat input box", + "entire chat width": "entire chat width", + "full window width": "full window width", + "Switch to stricter escaping, allowing all delimiting characters to be escaped with a backslash, and backslashes to be escaped as well.": "Switch to stricter escaping, allowing all delimiting characters to be escaped with a backslash, and backslashes to be escaped as well.", + "STRICT_ESCAPING": "STRICT_ESCAPING", + "Replace all {{getvar::}} and {{getglobalvar::}} macros with scoped variables to avoid double macro substitution.": "Replace all {{getvar::}} and {{getglobalvar::}} macros with scoped variables to avoid double macro substitution.", + "REPLACE_GETVAR": "REPLACE_GETVAR", + "Extras API:": "Extras API:", + "Extras API URL": "Extras API URL", + "Total tokens": "Total tokens", + "Calculating...": "Calculating...", + "Permanent tokens": "Permanent tokens", + "About Token 'Limits'": "About Token 'Limits'", + "Import Tags": "Импортировать теги", + "Click to allow/forbid the use of external media for this character.": "Нажмите, чтобы разрешить/запретить использование внешних медиа для этого персонажа.", + "Inserted before each part of the joined fields.": "Inserted before each part of the joined fields.", + "Join Prefix": "Join Prefix", + "When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and with the name of the part (e.g.: description, personality, scenario, etc.)": "When 'Join character cards' is selected, all respective fields of the characters are being joined together.\rThis means that in the story string for example all character descriptions will be joined to one big text.\rIf you want those fields to be separated, you can define a prefix or suffix here.\r\rThis value supports normal macros and will also replace {{char}} with the relevant char's name and with the name of the part (e.g.: description, personality, scenario, etc.)", + "Inserted after each part of the joined fields.": "Inserted after each part of the joined fields.", + "Join Suffix": "Join Suffix", + "Auto Mode delay": "Auto Mode delay", + "Bulk_edit_characters": "Bulk edit characters\r\rClick to toggle characters\rShift + Click to select/deselect a range of characters\rRight-click for actions", + "Bulk select all characters": "Bulk select all characters", + "Copy to system backgrounds": "Copy to system backgrounds", + "Chat Scenario Override": "Chat Scenario Override", + "Chat Lorebook": "Chat Lorebook for", + "chat_world_template_txt": "A selected World Info will be bound to this chat. When generating an AI reply,\n it will be combined with the entries from global and character lorebooks.", + "Use tag as folder": "Tag as folder", + "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized": "Статус записи:\n 🔵 Постоянная\n 🟢 Обычная\n 🔗 Векторизованная", + "WI_Entry_Status_Constant": "Постоянная", + "WI_Entry_Status_Normal": "Обычная", + "WI_Entry_Status_Vectorized": "Векторизованная", + "WI_Entry_Status_Disabled": "Отключена", + "Before EM": "↑EM", + "After EM": "↓EM", + "at Depth System": "@D ⚙️", + "at Depth User": "@D 👤", + "at Depth AI": "@D 🤖", + "Depth": "Глубина", + "Trigger %:": "Trigger %:", + "Probability": "Вероятность", + "Duplicate world info entry": "Дублировать запись", + "Delete world info entry": "Удалить запись", + "Keywords or Regexes": "Ключевые слова или регулярки", + "Comma separated list": "Comma separated list", + "Switch to plaintext mode": "Switch to plaintext mode", + "(ignored if empty)": "(пустое поле игнорируется)", + "Keywords or Regexes (ignored if empty)": "Ключевые слова или регулярки (пустое поле игнорируется)", + "Comma separated list (ignored if empty)": "Список через запятую (пустой игнорируется)", + "Can be used to automatically activate Quick Replies": "Can be used to automatically activate Quick Replies", + "Automation ID": "Automation ID", + "( None )": "( None )", + "Add Memo": "Add Memo", + "reset": "reset", + "save": "save", + "Open checkpoint chat": "Открыть чат из чекпоинта", + "Alternate Greetings": "Варианты первого сообщения", + "Alternate_Greetings_desc": "Будут отображаться в виде свайпов для первого сообщения нового чата.\n Участники групповых чатов могут выбирать одно из них при начале беседы.", + "alternate_greetings_hint_1": "Чтобы начать, нажмите на кнопку", + "alternate_greetings_hint_2": ".", + "Forbid Media Override explanation": "Ability of the current character/group to use external media in chats.", + "Forbid Media Override subtitle": "Media: images, videos, audio. External: not hosted on the local server.", + "Always forbidden": "Always forbidden", + "Always allowed": "Always allowed", + "View contents": "View contents", + "Remove the file": "Remove the file", + "Use character CFG scales": "Use character CFG scales", + "Select a token to see alternatives considered by the AI.": "Select a token to see alternatives considered by the AI.", + "Continue script execution": "Continue script execution", + "Pause script execution": "Pause script execution", + "Abort script execution": "Abort script execution", + "Toggle Panels": "Toggle Panels", + "Attach a File": "Attach a File", + "Open Data Bank": "Open Data Bank", + "Enter a URL or the ID of a Fandom wiki page to scrape:": "Enter a URL or the ID of a Fandom wiki page to scrape:", + "Examples:": "Examples:", + "Example:": "Example:", + "Single file": "Single file", + "All articles will be concatenated into a single file.": "All articles will be concatenated into a single file.", + "File per article": "File per article", + "Each article will be saved as a separate file.": "Not recommended. Each article will be saved as a separate file.", + "Data Bank": "Data Bank", + "These files will be available for extensions that support attachments (e.g. Vector Storage).": "These files will be available for extensions that support attachments (e.g. Vector Storage).", + "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.": "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.", + "Drag and drop files here to upload.": "Drag and drop files here to upload.", + "Date (Newest First)": "Date (Newest First)", + "Date (Oldest First)": "Date (Oldest First)", + "Name (A-Z)": "Name (A-Z)", + "Name (Z-A)": "Name (Z-A)", + "Size (Smallest First)": "Size (Smallest First)", + "Size (Largest First)": "Size (Largest First)", + "Bulk Edit": "Bulk Edit", + "Select All": "Select All", + "Select None": "Select None", + "Enable": "Enable", + "Global Attachments": "Global Attachments", + "These files are available for all characters in all chats.": "These files are available for all characters in all chats.", + "Character Attachments": "Character Attachments", + "These files are available for the current character in all chats they are in.": "These files are available for the current character in all chats they are in.", + "Saved locally. Not exported.": "Saved locally. Not exported.", + "Chat Attachments": "Chat Attachments", + "These files are available for all characters in the current chat.": "These files are available for all characters in the current chat.", + "Enter a base URL of the MediaWiki to scrape.": "Enter a base URL of the MediaWiki to scrape.", + "Don't include the page name!": "Don't include the page name!", + "Enter web URLs to scrape (one per line):": "Enter web URLs to scrape (one per line):", + "Enter a video URL to download its transcript.": "Enter a video URL or ID to download its transcript.", + "Expression API": "Local\nExtras\nLLM", + "Trigger a summary update right now.": "Сгенерировать пересказ прямо сейчас.", + "ext_regex_title": "Regex", + "ext_regex_import_target": "Импортировать в:", + "ext_regex_move_to_scoped": "Сделать локальным", + "Trigger Stable Diffusion": "Trigger Stable Diffusion", + "sd_Yourself": "Yourself", + "sd_Your_Face": "Your Face", + "sd_Me": "Me", + "sd_The_Whole_Story": "The Whole Story", + "sd_The_Last_Message": "The Last Message", + "sd_Raw_Last_Message": "Raw Last Message", + "sd_Background": "Background", + "Image Generation": "Image Generation", + "sd_refine_mode": "Allow to edit prompts manually before sending them to generation API", + "sd_refine_mode_txt": "Edit prompts before generation", + "sd_interactive_mode": "Automatically generate images when sending messages like 'send me a picture of cat'.", + "sd_interactive_mode_txt": "Interactive mode", + "sd_multimodal_captioning": "Use multimodal captioning to generate prompts for user and character portraits based on their avatars.", + "sd_multimodal_captioning_txt": "Use multimodal captioning for portraits", + "sd_expand": "Automatically extend prompts using text generation model", + "sd_expand_txt": "Auto-enhance prompts", + "sd_snap": "Snap generation requests with a forced aspect ratio (portraits, backgrounds) to the nearest known resolution, while trying to preserve the absolute pixel counts (recommended for SDXL).", + "sd_snap_txt": "Snap auto-adjusted resolutions", + "Source": "Source", + "sd_auto_url": "Example: {{auto_url}}", + "Authentication (optional)": "Authentication (optional)", + "Example: username:password": "Example: username:password", + "Important:": "Important:", + "sd_auto_auth_warning_1": "run SD Web UI with the", + "sd_auto_auth_warning_2": "flag! The server must be accessible from the SillyTavern host machine.", + "sd_drawthings_url": "Example: {{drawthings_url}}", + "sd_drawthings_auth_txt": "run DrawThings app with HTTP API switch enabled in the UI! The server must be accessible from the SillyTavern host machine.", + "sd_vlad_url": "Example: {{vlad_url}}", + "The server must be accessible from the SillyTavern host machine.": "The server must be accessible from the SillyTavern host machine.", + "Hint: Save an API key in AI Horde API settings to use it here.": "Hint: Save an API key in AI Horde API settings to use it here.", + "Allow NSFW images from Horde": "Разрешить NSFW-картинки в Horde", + "Sanitize prompts (recommended)": "Sanitize prompts (recommended)", + "Automatically adjust generation parameters to ensure free image generations.": "Automatically adjust generation parameters to ensure free image generations.", + "Avoid spending Anlas": "Avoid spending Anlas", + "Opus tier": "(Opus tier)", + "View my Anlas": "View my Anlas", + "These settings only apply to DALL-E 3": "These settings only apply to DALL-E 3", + "Image Style": "Image Style", + "Image Quality": "Image Quality", + "Standard": "Standard", + "HD": "HD", + "sd_comfy_url": "Example: {{comfy_url}}", + "Open workflow editor": "Open workflow editor", + "Create new workflow": "Create new workflow", + "Delete workflow": "Delete workflow", + "Enhance": "Enhance", + "Refine": "Refine", + "Decrisper": "Decrisper", + "Sampling steps": "Sampling steps ()", + "Width": "Width ()", + "Height": "Height ()", + "Resolution": "Resolution", + "Model": "Model", + "Sampling method": "Sampling method", + "Karras (not all samplers supported)": "Karras (not all samplers supported)", + "SMEA versions of samplers are modified to perform better at high resolution.": "SMEA versions of samplers are modified to perform better at high resolution.", + "SMEA": "SMEA", + "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.", + "DYN": "DYN", + "Scheduler": "Scheduler", + "Restore Faces": "Restore Faces", + "Hires. Fix": "Hires. Fix", + "Upscaler": "Upscaler", + "Upscale by": "Upscale by", + "Denoising strength": "Denoising strength", + "Hires steps (2nd pass)": "Hires steps (2nd pass)", + "Preset for prompt prefix and negative prompt": "Preset for prompt prefix and negative prompt", + "Style": "Style", + "Save style": "Save style", + "Delete style": "Delete style", + "Common prompt prefix": "Common prompt prefix", + "sd_prompt_prefix_placeholder": "Use {prompt} to specify where the generated prompt will be inserted", + "Negative common prompt prefix": "Negative common prompt prefix", + "Character-specific prompt prefix": "Character-specific prompt prefix", + "Won't be used in groups.": "Won't be used in groups.", + "sd_character_prompt_placeholder": "Any characteristics that describe the currently selected character. Will be added after a common prompt prefix.\nExample: female, green eyes, brown hair, pink shirt", + "Character-specific negative prompt prefix": "Character-specific negative prompt prefix", + "sd_character_negative_prompt_placeholder": "Any characteristics that should not appear for the selected character. Will be added after a negative common prompt prefix.\nExample: jewellery, shoes, glasses", + "Shareable": "Shareable", + "Image Prompt Templates": "Image Prompt Templates", + "ext_translate_title": "Chat Translation", + "Vectors Model Warning": "It is recommended to purge vectors when changing the model mid-chat. Otherwise, it will lead to sub-par results.", + "Translate files into English before processing": "Translate files into English before processing", + "Manager Users": "Manage Users", + "New User": "New User", + "Status:": "Status:", + "Display Name:": "Отображаемое имя:", + "User Handle:": "Хэндл пользователя:", + "Confirm Password:": "Подтвердждение пароля:", + "This will create a new subfolder...": "В папке /data/ будет создана новая подпапка, названная согласно хэндлу пользователя.", + "Current Password:": "Текущий пароль:", + "New Password:": "Новый пароль:", + "Confirm New Password:": "Подтвердите новый пароль:", + "Debug Warning": "Functions in this category are for advanced users only. Don't click anything if you're not sure about the consequences.", + "Execute": "Execute", + "Are you sure you want to delete this user?": "Вы точно хотите удалить этого пользователя?", + "Deleting:": "Удаляется:", + "Also wipe user data.": "Также стереть данные пользователя.", + "Warning:": "Предупреждение:", + "This action is irreversible.": "Данное действие невозможно отменить.", + "Type the user's handle below to confirm:": "Для подтверждения введите хэндл пользователя:", + "help_hotkeys_9": "Enter", + "help_hotkeys_11": "Ctrl+Enter", + "help_hotkeys_13": "Alt+Enter", + "help_hotkeys_15": "Escape", + "Import Characters": "Импорт персонажей", + "char_import_8": "Персонаж с RisuRealm (прямая ссылка)", + "Supports importing multiple characters.": "Можно импортировать несколько персонажей за раз.", + "Write each URL or ID into a new line.": "Запишите URL-адреса / идентификаторы на отдельных строчках.", + "System-wide Replacement Macros (in order of evaluation):": "System-wide Replacement Macros (in order of evaluation):", + "help_macros_1": "only for slash command batching. Replaced with the returned result of the previous command.", + "help_macros_2": "just inserts a newline.", + "help_macros_3": "trims newlines surrounding this macro.", + "help_macros_4": "no operation, just an empty string.", + "help_macros_5": "global prompts defined in API settings. Only valid in Advanced Definitions prompt overrides.", + "help_macros_6": "the user input", + "help_macros_7": "the Character's Main Prompt override", + "help_macros_8": "the Character's Jailbreak Prompt override", + "help_macros_9": "the Character's Description", + "help_macros_10": "the Character's Personality", + "help_macros_11": "the Character's Scenario", + "help_macros_12": "your current Persona Description", + "help_macros_13": "the Character's Dialogue Examples", + "help_macros_14": "unformatted Dialogue Examples", + "help_macros_15": "your current Persona username", + "help_macros_16": "the Character's name", + "help_macros_17": "the Character's version number", + "help_macros_18": "a comma-separated list of group member names or the character name in solo chats. Alias: {{charIfNotGroup}}", + "help_macros_19": "a text generation model name for the currently selected API.", + "help_macros_20": "the text of the latest chat message.", + "help_macros_21": "index # of the latest chat message. Useful for slash command batching.", + "help_macros_22": "the ID of the first message included in the context. Requires generation to be ran at least once in the current session.", + "help_macros_23": "the 1-based ID of the current swipe in the last chat message. Empty string if the last message is user or prompt-hidden.", + "help_macros_24": "the number of swipes in the last chat message. Empty string if the last message is user or prompt-hidden.", + "help_macros_25": "you can leave a note here, and the macro will be replaced with blank content. Not visible for the AI.", + "help_macros_26": "the current time", + "help_macros_27": "the current date", + "help_macros_28": "the current weekday", + "help_macros_29": "the current ISO time (24-hour clock)", + "help_macros_30": "the current ISO date (YYYY-MM-DD)", + "help_macros_31": "the current date/time in the specified format, e. g. for German date/time:", + "help_macros_32": "the current time in the specified UTC time zone offset, e.g. UTC-4 or UTC+2", + "help_macros_33": "the time difference between time1 and time2. Accepts time and date macros. (Ex: {{timeDiff::{{isodate}} {{time}}::2024/5/11 12:30:00}})", + "help_macros_34": "the time since the last user message was sent", + "help_macros_35": "sets a behavioral bias for the AI until the next user input. Quotes around the text are important.", + "help_macros_36": "rolls a dice. (ex:", + "help_macros_37": "returns a random item from the list. (ex:", + "help_macros_38": "alternative syntax for random that allows to use commas in the list items.", + "help_macros_39": "picks a random item from the list. Works the same as {{random}}, with the same possible syntax options, but the pick will stay consistent for this chat once picked and won't be re-rolled on consecutive messages and prompt processing.", + "help_macros_40": "dynamically add text in the quotes to banned words sequences, if Text Generation WebUI backend used. Do nothing for others backends. Can be used anywhere (Character description, WI, AN, etc.) Quotes around the text are important.", + "Instruct Mode and Context Template Macros:": "Instruct Mode and Context Template Macros:", + "(enabled in the Advanced Formatting settings)": "(enabled in the Advanced Formatting settings)", + "help_macros_41": "max allowed prompt length in tokens = (context size - response length)", + "help_macros_42": "context template example dialogues separator", + "help_macros_43": "context template chat start line", + "help_macros_44": "main system prompt (either character prompt override if chosen, or instructSystemPrompt)", + "help_macros_45": "instruct system prompt", + "help_macros_46": "instruct system prompt prefix sequence", + "help_macros_47": "instruct system prompt suffix sequence", + "help_macros_48": "instruct user prefix sequence", + "help_macros_49": "instruct user suffix sequence", + "help_macros_50": "instruct assistant prefix sequence", + "help_macros_51": "instruct assistant suffix sequence", + "help_macros_52": "instruct assistant first output sequence", + "help_macros_53": "instruct assistant last output sequence", + "help_macros_54": "instruct system message prefix sequence", + "help_macros_55": "instruct system message suffix sequence", + "help_macros_56": "instruct system instruction prefix", + "help_macros_57": "instruct first user message filler", + "help_macros_58": "instruct stop sequence", + "Chat variables Macros:": "Chat variables Macros:", + "Local variables = unique to the current chat": "Local variables = unique to the current chat", + "Global variables = works in any chat for any character": "Global variables = works in any chat for any character", + "Scoped variables = works in STscript": "Scoped variables = works in STscript", + "help_macros_59": "replaced with the value of the local variable \"name\"", + "help_macros_60": "replaced with empty string, sets the local variable \"name\" to \"value\"", + "help_macros_61": "replaced with empty strings, adds a numeric value of \"increment\" to the local variable \"name\"", + "help_macros_62": "replaced with the result of the increment of value of the variable \"name\" by 1", + "help_macros_63": "replaced with the result of the decrement of value of the variable \"name\" by 1", + "help_macros_64": "replaced with the value of the global variable \"name\"", + "help_macros_65": "replaced with empty string, sets the global variable \"name\" to \"value\"", + "help_macros_66": "replaced with empty string, adds a numeric value of \"increment\" to the global variable \"name\"", + "help_macros_67": "replaced with the result of the increment of value of the global variable \"name\" by 1", + "help_macros_68": "replaced with the result of the decrement of value of the global variable \"name\" by 1", + "help_macros_69": "replaced with the value of the scoped variable \"name\"", + "help_macros_70": "replaced with the value of item at index (for arrays / lists or objects / dictionaries) of the scoped variable \"name\"", + "Export for character": "Export for character", + "Export prompts for this character, including their order.": "Export prompts for this character, including their order.", + "Are you sure you want to reset your settings to factory defaults?": "Вы точно хотите сбросить настройки до заводских?", + "Don't forget to save a snapshot of your settings before proceeding.": "Настоятельно советуем перед этим сохранить снимок текущих настроек.", + "Change Password": "Сменить пароль", + "Reset Code:": "Reset Code:", + "Click _space": "Нажмите ", + "Alternate Greeting #": "Вариант #", + "Defines on importing cards which action should be chosen for importing its listed tags. 'Ask' will always display the dialog.": "Выберите, какие действия следует предпринять по отношению к тегам импортируемой карточки. При выборе опции \"Спрашивать\" вы будете решать это индивидуально для каждой карточки.", + "Ask": "Спрашивать", + "tag_import_all": "Все", + "tag_import_existing": "Только существующие", + "tag_import_none": "Не импортировать", + "Using a proxy that you're not running yourself is a risk to your data privacy.": "Помните, что используя чужую прокси, вы подвергаете риску конфиденциальность своих данных.", + "ANY support requests will be REFUSED if you are using a proxy.": "НЕ РАССЧИТЫВАЙТЕ на нашу поддержку, если используете прокси.", + "Do not proceed if you do not agree to this!": "Не продолжайте, если не согласны с этими условиями!", + "Injection position. Relative (to other prompts in prompt manager) or In-chat @ Depth.": "Как рассчитывать позицию, на которую вставляется данный промпт. Относительно других промтов в менеджере, либо на опред. глубину в чате.", + "prompt_manager_in_chat": "На глубине в чате", + "01.AI API Key": "Ключ от API 01.AI", + "01.AI Model": "Модель 01.AI", + "Load a custom asset list or select": "Загрузите набор внешних ресурсов или выберите", + "Install Extension": "Установить расширение", + "to install 3rd party extensions.": ", чтобы установить стороннее расширение.", + "Load an asset list": "Загрузить набор ресурсов", + "load_asset_list_desc": "Загрузить набор ресурсов и/или расширений из определённого списка.\n\nДефолтный URL содержит описание набора стандартных ресурсов, идущих в комплекте.\nЕсли хотите скачать ресурсы из стороннего набора, вставьте в это поле свой URL.\n\nЧтобы установить одиночное расширение от стороннего разработчика, воспользуйтесь кнопкой \"Установить расширение\" в левом верхнем углу.", + "Show group chat queue": "Показывать очерёдность в групповых чатах", + "In group chat, highlight the character(s) that are currently queued to generate responses and the order in which they will respond.": "Подсвечивать персонажей, которые скоро будут генерировать ответ в групповом чате, а также порядок, в котором они будут это делать", + "Sequence Breakers": "Брейкеры для строк", + "DRY_Sequence_Breakers_desc": "Токены, которые прерывают сопоставление/поиск строк. Вводятся через запятую, каждый брейкер в отдельных кавычках.", + "ext_regex_user_input_desc": "Сообщения, отправленные пользователем", + "ext_regex_ai_output_desc": "Сообщения, полученные от API", + "ext_regex_sts_desc": "Сообщения, отправленные с помощью команд STscript", + "ext_regex_wi_desc": "Содержимое лорбуков и миров. Для работы требует включения флажка \"Только промпт\"!", + "ext_regex_only_format_display_desc": "История чата не изменится, замена будет осуществляться только в отображаемом сообщении (в UI)", + "Prefer Character Card Instructions": "Приоритет инструкциям из карточек", + "If checked and the character card contains a Post-History Instructions override, use that instead": "Если в карточке персонажа имеется собственная инструкция после истории, в промпт попадёт именно она", + "Auto-select Input Text": "Автовыделение вводимого текста", + "Enable auto-select of input text in some text fields when clicking/selecting them. Applies to popup input textboxes, and possible other custom input fields.": "Автоматически выделять вводимый текст в некоторых текстовых полях при клике/выборе. Работает для вспл. окон и различных кастомных полей ввода.", + "Reset MovingUI panel sizes/locations.": "Сбросить расположение и размеры панелей MovingUI.", + "mui_reset": "Сброс", + "Quick 'Impersonate' button": "Быстрое перевоплощение", + "Show a button in the input area to ask the AI to impersonate your character for a single message": "Показать в поле ввода кнопку, по нажатии на которую ИИ сгенерирует одно сообщение от лица вашего персонажа.", + "Separators as Stop Strings": "Разделители как стоп-строки", + "Names as Stop Strings": "Имена как стоп-строки", + "Add Character and User names to a list of stopping strings.": "Добавлять имена персонажа и пользователя в список стоп-строк.", + "Allow Post-History Instructions": "Разрешить инструкции после истории", + "context_allow_post_history_instructions": "Добавлять в конец промпта инструкции после истории. Работает только при наличии таких инструкций в карточке И при включенной опции ''Приоритет инструкциям из карточек''.\nНЕ РЕКОМЕНДУЕТСЯ ДЛЯ МОДЕЛЕЙ TEXT COMPLETION, МОЖЕТ ПОРТИТЬ ВЫХОДНОЙ ТЕКСТ.", + "First User Prefix": "Первый префикс пользователя", + "Inserted before the first User's message.": "Вставляется перед первым сообщением пользователя.", + "Last User Prefix": "Последний префикс пользователя", + "instruct_last_input_sequence": "Вставляется перед последним сообщением пользователя.", + "Inserted before a User message and as a last prompt line when impersonating.": "Вставляется перед сообщением пользователя в качестве последней строки промпта при перевоплощении.", + "Inserted before a System (added by slash commands or extensions) message.": "Вставляется перед сообщением системы (может быть добавлено слэш-командой или расширением).", + "Load Asset List": "Загрузить список ресурсов", + "Never add character names.": "Не вставлять имя персонажа.", + "Don't add character names unless necessary.": "Вставлять имя персонажа только когда это необходимо.", + "character_names_none": "Не добавлять имена персонажей в качестве префикса. Может повредить качеству ответов в групповых чатах, используйте с осторожностью.", + "Auxiliary": "Вспомогательный", + "Post-History Instructions": "Инструкции после истории", + "Current persona updated": "Текущая персона изменена", + "Your messages will now be sent as ${0}": "Ваши сообщения будут отправляться от лица ${0}", + "Copied!": "Скопировано!", + "Are you sure you want to delete this message?": "Вы точно хотите удалить это сообщение?", + "Delete Message": "Удалить сообщение", + "Delete Swipe": "Удалить свайп", + "Could not get a reply from API. Check your connection settings / API key and try again.": "Не удалось получить ответ от API. Проверьте настройки соединения и API-ключ и повторите попытку.", + "Connecting To Proxy": "Подключиться к прокси", + "Are you sure you want to connect to the following proxy URL?": "Вы точно хотите соединиться с прокси по этому адресу?", + "API connection successful!": "Соединение с API установлено!", + "Proxy Saved": "Прокси сохранена", + "Proxy Deleted": "Прокси удалена", + "Could not find proxy with name '${0}'": "Не удалось найти прокси с названием '${0}'", + "Proxy preset '${0}' not found in proxies array.": "Пресет с названием '${0}' не найден в списке прокси.", + "Please wait for the previous request to complete.": "Пожалуйста, дождитесь окончания обработки предыдущего запроса.", + "Start new chat?": "Начать новый чат?", + "If necessary, you can later restore this chat file from the /backups folder": "При необходимости этот чат можно будет восстановить из папки /backups", + "Also delete the current chat file": "Также удалить текущий чат", + "chat_rename_1": "Введите новое имя чата:", + "chat_rename_2": "!!Не используйте имя уже существующего файла, это приведёт к ошибке!!", + "chat_rename_3": "Будут разрушены связи между чатами-чекпоинтами.", + "chat_rename_4": "Расширение '.jsonl' дописывать не нужно.", + "If you're connected to an API, try asking me something!": "Есть соединение с API? Напишите мне что-нибудь!", + "Connection Profile": "Профиль соединения", + "View connection profile details": "Посмотреть параметры профиля соединения", + "Create a new connection profile": "Создать новый профиль соединения", + "Update a connection profile": "Обновить профиль соединения", + "Rename a connection profile": "Переименовать профиль соединения", + "Reload a connection profile": "Перезагрузить профиль соединения", + "Delete a connection profile": "Удалить профиль соединения", + "No profile selected": "Профиль не выбран", + "Creating a Connection Profile": "Создать профиль соединения", + "Settings Preset": "Пресет настроек", + "Model": "Модель", + "Proxy Preset": "Пресет для прокси", + "Enter a name:": "Введите название:", + "Are you sure you want to delete the selected profile?": "Вы точно хотите удалить выбранный профиль?", + "instruct_enabled": "Вкл/выкл Instruct-режим", + "Instruct Template": "Шаблон Instruct-режима", + "instruct_template_activation_regex_desc": "Автоматически активировать этот шаблон в момент подключения к API или выбора модели, если название модели соответствует этому рег. выражению.", + "instruct_bind_to_context": "При включении этой опции Шаблон контекста будет выбираться, исходя из выбранного в текущий момент Шаблона Instruct-режима, либо по вашему желанию.", + "Master Import": "Глоб. импорт", + "Import Advanced Formatting settings": "Импорт настроек Расширенного форматирования\nТакже принимает файлы старого формата с Шаблонами контекста и Шаблонами Instruct-режима.", + "Master Export": "Глоб. экспорт", + "Export Advanced Formatting settings": "Экспорт настроек Расширенного форматирования", + "Select your current System Prompt": "Выберите текущий системный промпт", + "Prompt Content": "Текст промпта", + "Update current prompt": "Сохранить промпт", + "Save prompt as": "Сохранить как...", + "Import template": "Импорт шаблона", + "Export template": "Экспорт шаблона", + "Restore current prompt": "Восстановить промпт", + "comma delimited,no spaces between": "через запятую,без пробелов в промежутках", + "User Message Sequences": "Строки для сообщений пользователя", + "Assistant Message Sequences": "Строки для сообщений ассистента", + "System Message Sequences": "Строки для сообщений системы", + "System Prompt Sequences": "Строки для системного промпта", + "sysprompt_enabled": "Вкл/выкл системный промпт", + "Are you sure you want to delete this alternate greeting?": "Вы точно хотите удалить этот вариант?", + "Any contents here will replace the default Post-History Instructions used for this character. (v2 spec: post_history_instructions)": "Содержимое этого поля заменит стандартные Инструкции после истории, применяемые для этого персонажа. (v2 spec: post_history_instructions)", + "None (disabled)": "Нигде (откл.)", + "Markdown Hotkeys": "Горячие клавиши для разметки", + "markdown_hotkeys_desc": "Включить горячие клавиши для вставки символов разметки в некоторых полях ввода. См. '/help hotkeys'.", + "Save and Update": "Сохранить и обновить", + "Profile name:": "Название профиля:", + "API returned an error": "API вернуло ошибку", + "Failed to save preset": "Не удалось сохранить пресет", + "Preset name should be unique.": "Название пресета должно быть уникальным.", + "Invalid file": "Невалидный файл", + "No preset selected": "Пресет не выбран", + "Invalid logit bias preset file.": "Файл пресета невалиден.", + "Preset was not deleted from server": "Пресет не удалён с сервера", + "Preset deleted": "Пресет удалён", + "Delete the preset?": "Удалить пресет?", + "Preset updated": "Пресет сохранён", + "Entered reverse proxy address is not a valid URL": "Введённый адрес прокси невалиден", + "An error occurred while counting tokens: Token budget exceeded.": "Ошибка при подсчёте токенов: Превышен бюджет токенов", + "An error occurred while counting tokens: Invalid character name": "Ошибка при подсчёте токенов: Невалидное имя персонажа", + "Not enough free tokens for mandatory prompts. Raise your token Limit or disable custom prompts.": "Недостаточно токенов для всех выбранных промптов. Повысьте лимит токенов или отключите часть промптов.", + "The name of at least one character contained whitespaces or special characters. Please check your user and character name.": "В имени одного из персонажей содержится пробел или иной спецсимвол. Проверьте имена пользователя и персонажа.", + "An unknown error occurred while counting tokens. Further information may be available in console.": "Неизвестная ошибка при подсчёте токенов. Проверьте консоль, возможно, подробная информация есть там.", + "Encountered an error while processing your request.": "При обработке вашего запроса возникла ошибка.", + "Check you have credits available on your": "Убедитесь, что на вашем", + "OpenAI account quora_error": "аккаунте OpenAI", + "dot quota_error": "имеется достаточно кредитов.", + "If you have sufficient credits, please try again later.": "Если кредитов достаточно, то повторите попытку позднее.", + "Proxy preset '${0}' not found": "Пресет '${0}' не найден", + "Window.ai returned an error": "Window.ai вернул ошибку", + "Get it here:": "Загрузите здесь:", + "Extension is not installed": "Расширение не установлено", + "Update or remove your reverse proxy settings.": "Измените или удалите ваши настройки прокси.", + "An error occurred while importing prompts. More info available in console.": "В процессе импорта произошла ошибка. Подробную информацию см. в консоли.", + "Could not import prompts. Export failed validation.": "Не удалось импортировать промпты. Не пройдена валидация при экспорте.", + "Prompt import complete.": "Импорт завершён.", + "Are you sure you want to delete this prompt?": "Вы точно хотите удалить этот промпт?", + "Existing prompts with the same ID will be overridden. Do you want to proceed?": "Имеющиеся промпты с совпадающими идентификаторами будут перезаписаны. Продолжить?", + "This will reset the prompt order for this character. You will not lose any prompts.": "Будет сброшен порядок промптов для этого персонажа. Сами промпты вы не потеряете.", + "Note:": "Примечание:", + "this chat is temporary and will be deleted as soon as you leave it.": "это временный чат, он будет удалён, как только вы из него выйдете.", + "help_hotkeys_20": "Горячие клавиши для разметки", + "help_hotkeys_21": "Работают в окне ввода чата, а также в полях, отмеченных этим значком:", + "help_hotkeys_22": "**полужирный**", + "help_hotkeys_23": "*курсив*", + "help_hotkeys_24": "__подчёркивание__", + "help_hotkeys_25": "`inline-код`", + "help_hotkeys_26": "~~зачёркнутый~~", + "ext_regex_only_format_visual_desc": "Содержимое файла с историей чата останется нетронутым, изменения будут лишь визуальными (в UI).", + "Could not convert file": "Не удалось сконвертировать файл", + "Could not upload file": "Не удалось загрузить файл", + "Could not download file": "Не удалось скачать файл", + "File is too big. Maximum size is ${0}.": "Слишком большой файл. Максимальный размер: ${0}.", + "Binary files are not supported. Select a text file or image.": "Бинарные файлы не поддерживаются. Выберите текстовый файл или изображение.", + "No character or group selected": "Не выбрано ни одного персонажа или группы", + "Could not delete file": "Не удалось удалить файл", + "No attachments selected.": "Вложение не выбрано.", + "Data Bank": "Банк данных", + "No files were scraped.": "Скрапинг не выполнен.", + "Scraped ${0} files from ${1} to ${2}.": "Соскраплено из ${0} файлов из ${1} в ${2}.", + "Check browser console for details.": "Подробности см. в консоли браузера.", + "Scraping failed": "Ошибка скрапинга", + "External media has been blocked": "Внешние медиа отключены", + "Use the 'Ext. Media' button to allow it. Click on this message to dismiss.": "Разрешить можно с помощью кнопки 'Внешн. медиа'. Нажмите на это сообщение, чтобы его скрыть.", + "Couldn't get CSRF token. Please refresh the page.": "Не удалось получить CSRF токен. Попробуйте перезагрузить страницу.", + "Error": "Ошибка", + "API Error": "Ошибка API", + "Please wait until the chat is saved before switching characters.": "Пожалуйста, дождитесь сохранения чата, прежде чем переключать персонажа.", + "Your chat is still saving...": "Чат всё ещё сохраняется...", + "Character ${0} not found in the list": "Персонаж ${0} не найден в списке", + "Streaming is enabled, but the version of Kobold used does not support token streaming.": "Включён стриминг текста, но ваша версия Kobold не поддерживает стриминг токенов.", + "Verify that the server is running and accessible.": "Убедитесь, что сервер запущен и доступен по сети.", + "ST Server cannot be reached": "Не удалось соединиться с сервером ST", + "You must first select a character to duplicate!": "Вы не выбрали персонажа, которого хотите клонировать!", + "Character Duplicated": "Персонаж склонирован", + "No character name provided.": "Вы не ввели имя персонажа.", + "Rename Character": "Переименование", + "No character selected.": "Вы не выбрали персонажа.", + "New name:": "Новое имя:", + "Same character name provided, so name did not change.": "Введено то же самое имя, ничего не изменилось.", + "Character renamed and past chats updated!": "Персонаж переименован, а чаты обновлены!", + "Character renamed!": "Персонаж переименован!", + "Something went wrong. The page will be reloaded.": "Что-то пошло не так. Страница будет перезагружена.", + "Past chat could not be updated: ${0}": "Не удалось обновить чат ${0}", + "Trying to save group chat with regular saveChat function. Aborting to prevent corruption.": "Произошла попытка сохранения группового чата функцией saveChat. Откатываем изменения, чтобы предотвратить потерю данных.", + "Check the server connection and reload the page to prevent data loss.": "Проверьте связь с сервером и перезагрузите страницу, чтобы избежать потери данных.", + "Chat could not be saved": "Не удалось сохранить чат", + "Settings could not be loaded after multiple attempts. Please try again later.": "Не удалось загрузить настройки за несколько попыток. Попробуйте позднее.", + "Settings could not be saved": "Не удалось сохранить настройки", + "Could not load chat data. Try reloading the page.": "Не удалось загрузить чат. Попробуйте обновить страницу.", + "Invalid process (no 'type')": "Невалидный процесс (нет параметра 'type')", + "Character Deleted: ${0}": "Персонаж удалён: ${0}", + "Character Created: ${0}": "Персонаж создан: ${0}", + "Group Created": "Группа создана", + "Group Deleted": "Группа удалена", + "Character Imported: ${0}": "Персонаж импортирован: ${0}", + "Invalid swipe ID: ${0}": "Некорректный идентификатор свайпа: ${0}", + "No messages to delete swipes from.": "Сообщение, из которого требуется удалить свайп, не найдено.", + "Can't delete the last swipe.": "Невозможно удалить единственный свайп.", + "GUI Settings preset is not supported for Horde. Please select another preset.": "Для Horde не поддерживаются пресеты настроек GUI. Пожалуйста, выберите другой пресет.", + "Embedded lorebook will be removed from this character.": "Встроенный лорбук будет удалён из персонажа.", + "Name is required": "Введите имя", + "Cannot create characters while generating. Stop the request and try again.": "Во время генерации ответа создать персонажа невозможно. Остановите запрос и повторите попытку.", + "Creation aborted": "Процесс создания прерван", + "Failed to create character": "Не удалось создать персонажа", + "Something went wrong while saving the character, or the image file provided was in an invalid format. Double check that the image is not a webp.": "Что-то пошло не так в процессе сохранения персонажа, либо вы загрузили файл некорректного формата. Проверьте, что изображение точно не в формате webp.", + "Context template '${0}' not found": "Шаблон контекста '${0}' не найден", + "Instruct template '${0}' not found": "Шаблон Instruct-режима '${0}' не найден", + "Error: ${0} is not a valid API": "Ошибка: ${0} не является валидным API", + "API set to ${0}, trying to connect..": "Установлено API ${0}, пробуем подключиться...", + "Unsupported file type: ": "Неподдерживаемый тип файла: ", + "Cannot import characters while generating. Stop the request and try again.": "Во время генерации ответа импорт персонажа невозможен. Остановите запрос и повторите попытку.", + "Import aborted": "Процесс импорта прерван", + "The file is likely invalid or corrupted.": "Вероятно, файл невалиден или повреждён.", + "Could not import character": "Не удалось импортировать персонажа", + "Cannot run /impersonate command while the reply is being generated.": "Во время генерации ответа выполнить /impersonate невозможно.", + "Name must be provided as an argument to rename this chat.": "Для переименования чата необходимо предоставить новое имя в качестве аргумента.", + "No chat selected that can be renamed.": "Чат, который требуется переименовать, не найден.", + "Successfully renamed chat to: ${0}": "Чат успешно переименован в: ${0}", + "Character ${0} not found. Skipping deletion.": "Персонаж ${0} не найден. Удаление пропускается.", + "Failed to delete character": "При удалении персонажа произошло ошибка", + "Are you sure you want to duplicate this character?": "Вы точно хотите клонировать этого персонажа?", + "If you just want to start a new chat with the same character...": "Если вы хотите просто создать новый чат, воспользуйтесь кнопкой \"Начать новый чат\" в меню слева внизу.", + "THIS IS PERMANENT!": "ОТМЕНИТЬ БУДЕТ НЕВОЗМОЖНО!", + "Also delete the chat files": "Также удалить файлы чатов", + "Delete the character?": "Удалить персонажа?", + "Not a valid number": "Некорректное число", + "Author's Note depth updated": "Глубина заметок автора обновлена", + "Author's Note frequency updated": "Частота заметок автора обновлена", + "Not a valid position": "Некорректная позиция", + "Author's Note position updated": "Позиция заметок автора обновлена", + "Something went wrong. Could not save character's author's note.": "Что-то пошло не так. Не удалось сохранить заметки автора для этого персонажа.", + "Select a character before trying to use Author's Note": "Сначала необходимо выбрать персонажа", + "Author's Note text updated": "Текст заметок автора обновлён", + "Group Validation": "Валидация группы", + "Warning: Listed member ${0} does not exist as a character. It will be removed from the group.": "Предупреждение: персонаж ${0} не существует в виде карточки. Он будет удалён из группы.", + "Group Chat could not be saved": "Не удалось сохранить групповой чат", + "Deleted group member swiped. To get a reply, add them back to the group.": "Вы пытаетесь свайпнуть удалённого члена группы. Чтобы получить ответ, добавьте этого персонажа обратно в группу.", + "Currently no group selected.": "В данный момент не выбрано ни одной группы.", + "Not so fast! Wait for the characters to stop typing before deleting the group.": "Чуть помедленнее! Перед удалением группы дождитесь, пока персонаж закончит печатать.", + "Delete the group?": "Удалить группу?", + "This will also delete all your chats with that group. If you want to delete a single conversation, select a \"View past chats\" option in the lower left menu.": "Вместе с ней будут удалены и все её чаты. Если требуется удалить только один чат, воспользуйтесь кнопкой \"Все чаты\" в меню в левом нижнем углу.", + "Can't peek a character while group reply is being generated": "Невозможно открыть карточку персонажа во время генерации ответа", + "Threshold": "Порог", + "DRY Repetition Penalty": "DRY Штраф за повтор", + "Multiplier": "Множитель", + "DRY_Multiplier_desc": "Поставьте в положение > 0, чтобы включить DRY. Определяет величину штрафа для кратчайшей \"штрафуемой\" строки.", + "DRY_Repetition_Penalty_desc": "DRY налагает штраф на токены, генерация которых приведёт к появлению строки, которая уже была в тексте раньше. Установите множитель = 0, чтобы отключить.", + "Base": "Основание", + "DRY_Base_desc": "Определяет, насколько быстро возрастает штраф с увеличением длины строки.", + "Allowed Length": "Допустимая длина", + "DRY_Allowed_Length_desc": "Длина повторяющейся строки, при превышении которой DRY начинает налагать штраф.", + "Invalid data provided for master import": "Глоб. импорт не может быть выполнен по причине невалидности данных", + "Importing instruct template...": "Импортируем...", + "Instruct template detected": "Обнаружен шаблон Instruct-режима", + "Importing as context template...": "Импортируем...", + "Context template detected": "Обнаружен шаблон контекста", + "Importing as system prompt...": "Импортируем...", + "System prompt detected": "Обнаружен системный промпт", + "Importing as settings preset...": "Импортируем...", + "Text Completion settings detected": "Обнаружены настройки Text Completion", + "No valid sections found in imported data": "Не найдено ни одной валидной секции данных", + "No sections selected for import": "Не выбрано ни одной секции для импорта", + "Import": "Импортировать", + "Imported ${0} settings: ${1}": "Импортировано ${0} настроек: ${1}", + "Export": "Экспортировать", + "No sections selected for export": "Не выбрано ни одной секции для экспорта", + "Cannot update GUI preset": "Пресет для GUI обновить невозможно", + "Template updated": "Шаблон сохранён", + "Hint: Use a character/group name to bind preset to a specific chat.": "Совет: введите имя персонажа/группы, чтобы привязать пресет к определённым чатам.", + "Preset name:": "Название пресета:", + "Template name:": "Название шаблона:", + "Preset saved": "Пресет сохранён", + "Template saved": "Шаблон сохранён", + "Preset could not be saved": "Не удалось сохранить пресет", + "Preset could not be renamed": "Не удалось обновить пресет", + "Preset renamed": "Пресет переименован", + "Template renamed": "Шаблон переименован", + "Cannot delete GUI preset": "Пресет для GUI удалить невозможно", + "Failed to restore default preset": "Не удалось восстановить пресет по умолчанию", + "Failed to restore default template": "Не удалось восстановить шаблон по умолчанию", + "Rename preset": "Переименовать пресет", + "Rename template": "Переименовать шаблон", + "Enter a new name:": "Введите новое название:", + "Preset imported": "Пресет импортирован", + "Template imported": "Шаблон импортирован", + "Delete this preset?": "Удалить этот пресет?", + "Delete this template?": "Удалить этот шаблон?", + "This action is irreversible and your current settings will be overwritten.": "Отменить это действие невозможно. Ваши текущие настройки будут перезаписаны.", + "Preset deleted": "Пресет удалён", + "Template deleted": "Шаблон удалён", + "Template was not deleted from server": "Шаблон не удалён с сервера", + "Cannot restore GUI preset": "Пресет для Gui восстановить нельзя", + "Default preset cannot be restored": "Невозможно восстановить пресет по умолчанию", + "Default template cannot be restored": "Невозможно восстановить шаблон по умолчанию", + "Resetting a default preset will restore the default settings": "Сброс стандартного пресета восстановит настройки по умолчанию.", + "Resetting a default template will restore the default settings.": "Сброс стандартного шаблона восстановит настройки по умолчанию.", + "Are you sure?": "Вы уверены?", + "Default preset restored": "Стандартный пресет восстановлен", + "Default template restored": "Стандартный шаблон восстановлен", + "Resetting a custom preset will restore to the last saved state.": "Сброс пользовательского пресета откатит его к последнему сохранённому состоянию.", + "Resetting a custom template will restore to the last saved state.": "Сброс пользовательского шаблона откатит его к последнему сохранённому состоянию.", + "Preset restored": "Пресет восстановлен", + "Template restored": "Шаблон восстановлен", + "Update current template": "Сохранить шаблон", + "Rename current template": "Переименовать шаблон", + "Save template as": "Сохранить как...", + "Restore current template": "Восстановить шаблон", + "Delete the template": "Удалить шаблон", + "Rename current prompt": "Переименовать промпт", + "Select your current Context Template": "Выберите активный шаблон контекста", + "Select your current Instruct Template": "Выберите активный шаблон Instruct-режима", + "and connect to an": "и подключитесь к", + "You can add more": "Можете добавить больше", + "from other websites": "с других сайтов.", + "Go to the": "Заходите в", + "to install additional features.": ", чтобы установить разные дополнительные ресурсы.", + "or_welcome": "; также доступен", + "Claude API Key": "Ключ от API Claude", + "Block Entropy API Key": "Ключ от API Block Entropy", + "Select a Model": "Выберите модель", + "The content of this prompt is pulled from elsewhere and cannot be edited here.": "Эта часть промпта подтягивается откуда-то извне. Отредактировать её здесь невозможно.", + "save": "сохранить", + "reset": "сбросить", + "close": "закрыть", + "Your preset contains proxy and/or custom endpoint settings.": "Ваш пресет содержит настройки прокси и/или настройки кастомного эндпоинта.", + "Do you want to remove these fields before exporting?": "Желаете ли удалить эти поля перед экспортом?", + "Save": "Сохранить", + "Chat Lorebook": "Лорбук для чата", + "chat_world_template_txt": "Выбранный мир будет привязан к этому чату. Будет добавляться в промпт наряду с глобальным лорбуком и лором персонажа.", + "world_button_title": "Лор персонажа\n\nНажмите, чтобы загрузить\nShift + ЛКМ, чтобы открыть диалог привязки мира", + "No auxillary Lorebooks set. Click here to select.": "Вспомогательный лорбук не выбран. Нажмите, чтобы выбрать.", + "ext_regex_user_input_desc": "Отправленные вами сообщения.", + "ext_regex_ai_input_desc": "Полученные от API ответы.", + "ext_regex_slash_desc": "Сообщения, отправленные с помощью команд STscript.", + "ext_regex_wi_desc": "Содержимое лорбуков/информации о мире. Работает только со включенной галочкой \"Только промпт\"!", + "ext_regex_run_on_edit_desc": "Выполнять скрипт при редактировании принадлежащих обозначенной роли (ролям) сообщений.", + "Convert to group chat": "Сделать чат групповым", + "Are you sure you want to convert this chat to a group chat?": "Вы точно хотите сделать этот чат групповым?", + "This cannot be reverted.": "Отменить будет невозможно.", + "Enter a name for this persona:": "Введите имя для этой персоны:", + "Cancel if you're just uploading an avatar.": "Отмените, если просто загружаете аватарку.", + "Set the crop position of the avatar image": "Обозначьте зону, по которой будет обрезана аватарка", + "popup-button-crop": "Обрезать", + "Duplicate persona": "Клонировать персону", + "Are you sure you want to duplicate this persona?": "Вы точно хотите клонировать эту персону?", + "Enter a description for this persona:": "Введите описание для этой персоны:", + "You can always add or change it later.": "Его можно будет добавить или изменить в любое время.", + "You can now pick ${0} as a persona in the Persona Management menu.": "Теперь ${0} может быть выбран(а) в качестве персоны в меню \"Управление персоной\".", + "Persona Created": "Персона создана", + "Overwrite Existing Persona": "Перезаписать существующую персону", + "This character exists as a persona already. Do you want to overwrite it?": "Этот персонаж уже существует в виде персоны. Желаете перезаписать?", + "Persona Description Macros": "Макросы в описании персоны", + "This character has a description that uses {{char}} or {{user}} macros. Do you want to swap them in the persona description?": "В описании персонажа присутствуют макросы {{char}} и/или {{user}}. Желаете поменять их местами?", + "(If empty name is provided, this will unbind the name from this avatar)": "(если оставить пустым, то имя будет отвязано от этой аватарки)", + "To permanently set \"${0}\" as the selected persona, unlock and relock it using the \"Lock\" button. Otherwise, the selection resets upon reloading the chat.": "Чтобы перманентно привязать персону \"${0}\" к этому чату, открепите текущую персону и затем закрепите новую кнопкой \"Закрепить\". Иначе при следующем заходе персона будет сброшена.", + "This chat is locked to a different persona (${0}).": "К этому чату уже привязана другая персона (${0}).", + "User persona is now unlocked for this chat. Click the \"Lock\" again to revert.": "Персона откреплена. Нажмите \"Закрепить\", чтобы снова зафиксировать её в этом чате.", + "Persona unlocked": "Персона откреплена", + "Creating a new persona for currently selected user name and avatar...": "Создаём новую персону для этого имени и аватарки...", + "Persona not set for this avatar": "К этой аватарке не привязано ни одной персоны", + "User persona is locked to ${0} in this chat": "${0} установлен(а) в качестве фиксированной персоны в этом чате", + "You cannot delete the avatar you are currently using": "Невозможно удалить аватарку, которую вы используете прямо сейчас", + "Warning": "Внимание", + "Are you sure you want to delete this avatar?": "Вы точно хотите удалить эту аватарку?", + "All information associated with its linked persona will be lost.": "Вся информация о связанной с ней персоне будет утеряна.", + "The default persona was deleted. You will need to set a new default persona.": "Удалена персона по умолчанию. Вам будет необходимо выбрать новую вместо неё.", + "Default persona deleted": "Удалена персона по умолчанию", + "The locked persona was deleted. You will need to set a new persona for this chat.": "Удалена привязанная к чату персона. Вам будет необходимо выбрать новую фиксированную персону для этого чата.", + "Persona deleted": "Персона удалена", + "You must bind a name to this persona before you can set it as the default.": "Прежде чем установить эту персону в качестве персоны по умолчанию, ей необходимо задать имя.", + "Persona name not set": "У персоны отсутствует имя", + "Are you sure you want to remove the default persona?": "Вы точно хотите снять статус персоны по умолчанию?", + "This persona will no longer be used by default when you open a new chat.": "Эта персона больше не будет автоматически выбираться при старте нового чата", + "Default persona removed": "Персона по умолчанию снята", + "Are you sure you want to set \"${0}\" as the default persona?": "Вы точно хотите установить \"${0}\" в качестве персоны по умолчанию?", + "This name and avatar will be used for all new chats, as well as existing chats where the user persona is not locked.": "Это имя и аватарка будут автоматически выбираться при старте нового чата, а также в любом существующем чате, где нет фиксированной персоны.", + "This persona will be used by default when you open a new chat.": "Эта персона будет выбираться автоматически при старте нового чата.", + "Default persona set to ${0}": "${0} установлен(а) в качестве персоны по умолчанию", + "Invalid file selected": "Загружен невалидный файл", + "Invalid file format": "Некорректный формат файла", + "Personas restored with warnings. Check console for details.": "Персона восстановлена, но были сгенерированы варнинги. Подробности см. в консоли.", + "Personas restored successfully.": "Персона успешно восстановлена.", + "All user-sent messages in this chat will be attributed to ${0}.": "Все ваши сообщения в этом чате будут приписаны ${0}.", + "Forbid Media Override explanation": "Способность текущего персонажа/группы использовать в чате внешние медиа.", + "forbid_media_global_state_forbidden": "(запрещены)", + "forbid_media_global_state_allowed": "(разрешены)", + "Always forbidden": "Всегда запрещены", + "Always allowed": "Всегда разрешены", + "Forbid Media Override subtitle": "Под медиа подразумеваются картинки, видео, аудио. Под внешними - любые, не хостящиеся на локальном сервере.", + "Tag Management": "Управление тегами", + "Save your tags to a file": "Сохранить ваши теги в файл", + "Restore tags from a file": "Восстановить теги из файла", + "Create a new tag": "Создать новый тег", + "Drag handle to reorder. Click name to rename. Click color to change display.": "Перемещайте мышкой, чтобы менять порядок. Нажмите, чтобы переименовать. Нажмите на цвет, чтобы сменить его.", + "Click on the folder icon to use this tag as a folder.": "Нажмите на иконку папки, чтобы использовать тег как папку.", + "Use alphabetical sorting": "Сортировать по алфавиту", + "tags_sorting_desc": "Автоматически сортировать теги по алфавиту после создания или переименования одного из них.\nПри выключении новые теги будут просто добавляться в конец.\n\nЕсли вручную перетащить один из тегов на другое место, автосортировка отключится.", + "Imported tags:": "Импортируемые теги:", + "Importing Tags": "Импорт тегов", + "Couldn't import tags:": "Не удалось импортировать теги:", + "Allow fallback models": "Разрешить fallback-модели", + "Allow fallback providers": "Разрешить fallback-провайдеров", + "To use instruct formatting, switch to OpenRouter under Text Completion API.": "Переключитесь на OpenRouter в Text Completion API, чтобы использовать форматирование Instruct-режима.", + "Select providers. No selection = all providers.": "Выберите провайдера. Нет выбранного = выбраны все.", + "Model Providers": "Провайдеры моделей", + "Select a model": "Выберите модель", + "Search models...": "Искать по моделям...", + "[Currently loaded]": "[Загруженная сейчас]", + "Search providers...": "Искать по провайдерам...", + "Automatically chooses an alternative provider if chosen providers can't serve your request.": "Автоматически переключаться на другого провайдера, если текущий не может обслужить запрос.", + "Example: 127.0.0.1:8000": "Пример: 127.0.0.1:8000", + "Edit a connection profile": "Редактировать профиль соединения", + "System Prompt Name": "Название системного промпта", + "Use System Prompt": "Использовать системный промпт", + "Hint:": "Подсказка:", + "Click on the setting name to omit it from the profile.": "Нажмите на название настройки, чтобы исключить её из профиля", + "Included settings:": "Сохранённые параметры:", + "Server URL": "Адрес сервера", + "NanoGPT API Key": "Ключ от API NanoGPT", + "NanoGPT Model": "Модель NanoGPT", + "Use extension settings": "Использовать настройки из расширения", + "DeepSeek API Key": "Ключ от API DeepSeek", + "DeepSeek Model": "Модель DeepSeek", + "prompt_post_processing_merge": "Объединять идущие подряд сообщения с одной ролью", + "prompt_post_processing_semi": "Semi-strict (чередовать роли)", + "prompt_post_processing_strict": "Strict (чередовать роли, сначала пользователь)", + "Select Horde models": "Выбрать модель из Horde", + "Model ID (optional)": "Идентификатор модели (необязательно)", + "Derive context size from backend": "Использовать бэкенд для определения размера контекста", + "Rename current preset": "Переименовать пресет", + "No Worlds active. Click here to select.": "Нет активных миров. Нажмите, чтобы выбрать.", + "Title/Memo": "Название", + "Strategy": "Статус", + "Position": "Позиция", + "Trigger %": "% срабатывания", + "Use global": "Глоб. настройка", + "Whole Words": "Целые слова", + "Non-recursable (will not be activated by another)": "Не рекурсивная (не активируется другими)", + "Delay until recursion (can only be activated on recursive checking)": "Рекурсивная (активируется только рекурсией)", + "Toggle entry's active state.": "Вкл/выкл запись.", + "Prioritize": "Важная", + "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "Важная запись получает приоритет среди всех выбранных. Если важных записей несколько, выбирается та, у которой выше \"Очерёдность\".", + "Group Weight": "Вес в группе", + "A relative likelihood of entry activation within the group": "Относительная вероятность активации записи в рамках группы", + "Sticky": "Липучка", + "Sticky entries will stay active for N messages after being triggered.": "Запись-\"липучка\" останется активной в течение N сообщений после срабатывания.", + "Cooldown": "Кулдаун", + "Entries with a cooldown can't be activated N messages after being triggered.": "Запись с заданным кулдауном не активируется следующие N сообщений после срабатывания.", + "Delay": "Задержка", + "Entries with a delay can't be activated until there are N messages present in the chat.": "Запись с заданной задержкой может активироваться только после того, как в чате наберётся N сообщений.", + "Non-sticky": "Нет", + "No cooldown": "Нет", + "No delay": "Нет", + "Filter to Characters or Tags": "Фильтровать по персонажам или тегам", + "Switch to plaintext mode": "Вкл/выкл режим чистого текста", + "Exclude": "Режим исключения", + "Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry": "Инвертировать логику: для выбранных в фильтре персонажей/тегов данная запись активна НЕ БУДЕТ", + "Apply current sorting as Order": "Настроить Очерёдность в соответствии с текущей сортировкой", + "Create a new World Info": "Создать новый мир", + "Enter a name for the new file:": "Название нового файла:", + "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "Если сразу несколько записей из одной группы окажутся активированными, по факту сработает только одна. Одна запись может входить в несколько групп, отделяются запятыми. Раздел в документации: World Info - Inclusion Group", + "Valid World Info file name is required": "Требуется корректное имя для файла мира", + "World Info file has an invalid format": "Файл мира имеет неизвестный формат", + "World Info file has no entries": "В файле нет ни одной записи", + "Character not found.": "Персонаж не найден", + "Open a chat to get a name of the chat-bound lorebook": "Чтобы получить название привязанного к чату лорбука, требуется открыть чат.", + "File is not valid: ${0}": "Файл повреждён или имеет неизвестный формат: ${0}", + "The world with ${0} is invalid or corrupted.": "Мир ${0} повреждён или имеет неизвестный формат.", + "Deactivated all worlds": "Все миры отключены", + "No world found named: ${0}": "Не найдено мира с название ${0}", + "Activated world: ${0}": "Мир ${0} включён", + "Deactivated world: ${0}": "Мир ${0} отключён", + "World was not active: ${0}": "Мир ${0} не включён", + "The world '${0}' has been imported and linked to the character successfully.": "Мир ${0} успешно импортирован и привязан к персонажу.", + "World/Lorebook imported": "Мир/лорбук импортирован", + "Are you sure you want to import '${0}'?": "Вы точно хотите импортировать '${0}'?", + "It will overwrite the World/Lorebook with the same name.": "Существующий мир с таким же названием будет перезаписан.", + "Automatically 'continue' a response if the model stopped before reaching a certain amount of tokens.": "Автоматически \"продолжать\" ответ, если он оказался короче, чем целевая длина (в токенах).", + "None (not injected)": "Никуда", + "ext_sum_injection_position_none": "Пересказ не будет вставляться в промпт. Однако его по-прежнему можно будет вставить с помощью макроса {{summary}}", + "ext_sum_include_wi_scan": "Учитывать при сканировании лорбуком", + "ext_sum_include_wi_scan_desc": "Учитывать актуальный пересказ при сканировании промпта лорбуком.", + "ext_sum_force_tip": "Отправить запрос на создание пересказа прямо сейчас.", + "ext_sum_restore_tip": "Откатиться к предыдущему пересказу; используйте несколько раз, чтобы очистить историю пересказов для чата", + "Built-in Extensions:": "Комплектные расширения:", + "Installed Extensions:": "Установленные расширения:", + "Loading third-party extensions... Please wait...": "Загрузка сторонних расширений... Пожалуйста, подождите...", + "The page will be reloaded shortly...": "Страница будет перезагружена...", + "Extensions state changed": "Изменено состояние расширения", + "Error loading extensions. See browser console for details.": "Не удалось загрузить расширения. Подробности см. в консоли браузера.", + "You don't have permission to update global extensions.": "Отсутствуют права на обновление глобальных расширений.", + "Extension update failed": "Не удалось обновить расширение", + "Extension ${0} updated to ${1}": "Расширение ${0} обновлено до ${1}", + "Reload the page to apply updates": "Чтобы изменения вступили в силу, обновите страницу", + "You don't have permission to delete global extensions.": "Отсутствуют права на удаление глобальных расширений.", + "Are you sure you want to delete ${0}?": "Вы точно хотите удалить ${0}?", + "You don't have permission to move extensions.": "Отсутствуют права на перемещение расширений.", + "Are you sure you want to move ${0} to your local extensions? This will make it available only for you.": "Вы точно хотите сделать ${0} локальным расширением? После этого оно будет доступно только вам.", + "Are you sure you want to move ${0} to the global extensions? This will make it available for all users.": "Вы точно хотите сделать ${0} глобальным расширением? После этого оно будет доступно всем пользователям.", + "Extension ${0} moved.": "Расширение ${0} перемещено.", + "Extension ${0} deleted": "Расширение ${0} удалено.", + "Please wait...": "Пожалуйста, подождите...", + "Installing extension": "Идёт установка расширения", + "Extension installation failed": "Не удалось установить расширение", + "Extension '${0}' by ${1} (version ${2}) has been installed successfully!": "Расширение ${0} от автора ${1} (версия ${2}) успешно установлено!", + "Extension installation successful": "Расширение установлено", + "Extension updates available": "Доступных обновлений расширений", + "Auto-updating extensions. This may take several minutes.": "Запущено автоматическое обновление расширений. Это может занять несколько минут.", + "Install just for me": "Установить только мне", + "Install": "Установить", + "Install for all users": "Установить для всех пользователей", + "Modules provided by your Extras API:": "Модули из Extras API:", + "Not connected to the API!": "Нет соединения с API!", + "ext_type_system": "Это комплектное расширение. Его нельзя удалить, а обновляется оно вместе со всей системой.", + "Update all": "Обновить все", + "Close": "Закрыть", + "Optional modules:": "Необязательные модули:", + "Sort: Display Name": "Сортировать: по названию", + "Sort: Loading Order": "Сортировать: в порядке загрузки", + "Click to toggle": "Нажмите, чтобы включить или выключить", + "Loading Asset List": "Загрузить список ресурсов", + "Don't ask again for this URL": "Запомнить выбор для этого адреса", + "Are you sure you want to connect to the following url?": "Вы точно хотите подключиться к этому адресу?", + "All": "Всё", + "Characters": "Персонажи", + "Ambient sounds": "Звуковой эмбиент", + "Blip sounds": "Звуки уведомлений", + "Background music": "Фоновая музыка", + "Search": "Поиск", + "extension_install_1": "Чтобы загружать расширения из этого списка, у вас должен быть установлен ", + "extension_install_2": ".", + "extension_install_3": "Нажмите на иконку ", + "extension_install_4": ", чтобы перейти в репозиторий расширения и получить более подробную информацию о нём.", + "Extension repo/guide:": "Репозиторий расширения:", + "Preview in browser": "Предпросмотр", + "Adds a function tool": "Частично или полностью работает через вызов функций", + "Tool": "Функции", + "Move extension": "Переместить расширение", + "ext_type_local": "Это локальное расширение, доступно только вам", + "ext_type_global": "Это глобальное расширение, доступно всем пользователям", + "Move": "Переместить", + "Enter the Git URL of the extension to install": "Введите Git-адрес расширения", + "Please be aware that using external extensions can have unintended side effects and may pose security risks. Always make sure you trust the source before importing an extension. We are not responsible for any damage caused by third-party extensions.": "помните, что используя расширения от сторонних авторов, вы можете подвергать систему опасности. Устанавливайте расширения только от проверенных разработчиков. Мы не несём ответственности за любой ущерб, причинённый сторонними расширениями.", + "Disclaimer:": "Внимание:", + "Example:": "Пример:", + "context_derived": "Считывать из метаданных модели (по возможности)", + "instruct_derived": "Считывать из метаданных модели (по возможности)", + "Confirm token parsing with": "Чтобы убедиться в правильности выделения токенов, используйте", + "Reasoning Effort": "Рассуждения", + "Constrains effort on reasoning for reasoning models.": "Регулирует объём внутренних рассуждений модели (reasoning), для моделей которые поддерживают эту возможность.\nНа данный момент поддерживаются три значения: Подробные, Обычные, Поверхностные.\nПри менее подробном рассуждении ответ получается быстрее, а также экономятся токены, уходящие на рассуждения.", + "openai_reasoning_effort_low": "Поверхностные", + "openai_reasoning_effort_medium": "Обычные", + "openai_reasoning_effort_high": "Подробные", + "Persona Lore Alt+Click to open the lorebook": "Лорбук данной персоны\nAlt + ЛКМ чтобы открыть лорбук", + "Persona Lorebook for": "Лорбук для персоны", + "persona_world_template_txt": "Выбранная Информация о мире будет привязана к этой персоне. Информация будет добавляться в каждом промпте вместе с глобальным лорбуком и лорбуками персонажа и чата.", + "Global list": "Глобальный список", + "Preset-specific list": "Список для данного пресета", + "Banned tokens/strings are being sent in the request.": "Запрещённые токены и строки отсылаются в запросе.", + "Banned tokens/strings are NOT being sent in the request.": "Запрещённые токены и строки НЕ отсылаются в запросе.", + "Add a reasoning block": "Добавить блок рассуждений", + "Create a copy of this message?": "Продублировать это сообщение?", + "Max Recursion Steps": "Макс. глубина рекурсии", + "0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc": "0 = неограничено, 1 = сканировать единожды, 2 = сканировать единожды и сделать один повторный проход, и т.д.\n(неактивно при указанном мин. числе активаций)", + "(disabled when max recursion steps are used)": "(неактивно при указанной макс. глубине рекурсии)", + "Enter a valid API URL": "Введите корректный адрес API", + "No Ollama model selected.": "Не выбрана модель Ollama", + "Background Fitting": "Способ подгонки фона под разрешение", + "Chat Lore Alt+Click to open the lorebook": "Лорбук данного чата\nAlt + ЛКМ чтобы открыть лорбук", + "Token Counter": "Подсчитать токены", + "Type / paste in the box below to see the number of tokens in the text.": "Введите или вставьте текст в окошко ниже, чтобы подсчитать количество токенов в нём.", + "Selected tokenizer:": "Выбранный токенайзер:", + "Input:": "Входные данные:", + "Tokenized text:": "Токенизированный текст:", + "Token IDs:": "Идентификаторы токенов:", + "Tokens:": "Токенов:" +} diff --git a/jiuguan2025cc/public/locales/uk-ua.json b/jiuguan2025cc/public/locales/uk-ua.json new file mode 100644 index 0000000000000000000000000000000000000000..f595aa43595c60bbbbfce2fc5057e92b9147e294 --- /dev/null +++ b/jiuguan2025cc/public/locales/uk-ua.json @@ -0,0 +1,1443 @@ +{ + "Favorite": "улюблений", + "Tag": "Тег", + "Duplicate": "дублікат", + "Persona": "Персона", + "Delete": "Видалити", + "AI Response Configuration": "Конфігурація відповіді ШІ", + "AI Configuration panel will stay open": "Панель конфігурації ШІ залишиться відкритою", + "clickslidertips": "Натисніть, щоб ввести значення вручну.", + "MAD LAB MODE ON": "УВІМКНЕНО РЕЖИМ БОЖЕНОЇ ЛАБОРАТОРІЇ", + "Documentation on sampling parameters": "Документація щодо параметрів вибірки", + "kobldpresets": "Налаштування Kobold", + "guikoboldaisettings": "З інтерфейсу KoboldAI", + "Update current preset": "Оновити поточний шаблон", + "Save preset as": "Зберегти шаблон як", + "Import preset": "Імпортувати шаблон", + "Export preset": "Експортувати шаблон", + "Restore current preset": "Відновити поточні налаштування", + "Delete the preset": "Видалити шаблон", + "novelaipresets": "Налаштування NovelAI", + "Default": "За замовчуванням", + "openaipresets": "Налаштування OpenAI", + "Text Completion presets": "Налаштування Text Completion", + "AI Module": "Модуль ШІ", + "Changes the style of the generated text.": "Змінює стиль створеного тексту.", + "No Module": "Немає модуля", + "Instruct": "Інструктувати", + "Prose Augmenter": "Збільшувач прози", + "Text Adventure": "Текстові пригоди", + "response legth(tokens)": "Відповідь (токени)", + "Streaming": "Потокова передача", + "Streaming_desc": "Поступово відображати відповідь по мірі її створення", + "context size(tokens)": "Контекст (токени)", + "unlocked": "Розблоковано", + "Only enable this if your model supports context sizes greater than 8192 tokens": "Увімкніть це лише в разі підтримки моделлю розмірів контексту більше 8192 токенів", + "Max prompt cost:": "Максимальна оперативна вартість:", + "Display the response bit by bit as it is generated.": "Показувати відповідь по бітах по мірі її генерації.", + "When this is off, responses will be displayed all at once when they are complete.": "Коли це вимкнено, відповіді будуть відображатися разом, коли вони будуть завершені.", + "Temperature": "Температура", + "rep.pen": "Штраф за повтор", + "Rep. Pen. Range.": "Діапазон штрафу за повторення.", + "Rep. Pen. Slope": "Кутна нахилу штрафу за повтор", + "Rep. Pen. Freq.": "Частота штрафу за повторення.", + "Rep. Pen. Presence": "Наявність штрафу за повторення.", + "TFS": "TFS", + "Phrase Repetition Penalty": "Штраф за повтор фраз", + "Off": "Вимкнено", + "Very light": "Дуже легкий", + "Light": "Легкий", + "Medium": "Середній", + "Aggressive": "Агресивний", + "Very aggressive": "Дуже агресивний", + "Unlocked Context Size": "Розблокований розмір контексту", + "Unrestricted maximum value for the context slider": "Необмежене максимальне значення для повзунка контексту", + "Context Size (tokens)": "Розмір контексту (токени)", + "Max Response Length (tokens)": "Довжина відповіді (токени)", + "Multiple swipes per generation": "Кілька свайпів за покоління", + "Enable OpenAI completion streaming": "Увімкнути потокове завершення OpenAI", + "Frequency Penalty": "Штраф за частоту", + "Presence Penalty": "Штраф за наявність", + "Count Penalty": "Рахувати пенальті", + "Top K": "Топ K", + "Top P": "Топ P", + "Repetition Penalty": "Штраф за повторення", + "Min P": "Мін П", + "Top A": "Топ A", + "Quick Prompts Edit": "Швидке редагування підказок", + "Main": "Головний", + "NSFW": "NSFW", + "Jailbreak": "Джейлбрейк", + "Utility Prompts": "Допоміжні підказки", + "Impersonation prompt": "Запит на перевтілення", + "Restore default prompt": "Відновити типовий запит", + "Prompt that is used for Impersonation function": "Запит, який використовується для функції перевтілення", + "World Info Format Template": "Шаблон формату World Info", + "Restore default format": "Відновити стандартний формат", + "Wraps activated World Info entries before inserting into the prompt.": "Обтікає активовані записи World Info перед вставленням у підказку.", + "scenario_format_template_part_1": "використання", + "scenario_format_template_part_2": "щоб позначити місце, куди вставляється вміст.", + "Scenario Format Template": "Шаблон формату сценарію", + "Personality Format Template": "Шаблон формату особистості", + "Group Nudge Prompt Template": "Шаблон підказки Group Nudge", + "Sent at the end of the group chat history to force reply from a specific character.": "Надсилається в кінці історії групового чату, щоб примусово відповісти від певного персонажа.", + "New Chat": "Новий чат", + "Restore new chat prompt": "Відновити новий чат", + "Set at the beginning of the chat history to indicate that a new chat is about to start.": "Встановіть на початку історії чату, щоб вказати, що незабаром розпочнеться новий чат.", + "New Group Chat": "Новий груповий чат", + "Restore new group chat prompt": "Відновити запит за замовчуванням", + "Set at the beginning of the chat history to indicate that a new group chat is about to start.": "Установіть на початку історії чату, щоб вказати, що незабаром розпочнеться новий груповий чат.", + "New Example Chat": "Новий приклад чату", + "Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.": "Встановіть на початку прикладів діалогу, щоб вказати, що незабаром розпочнеться новий приклад чату.", + "Continue nudge": "Продовжуйте штовхати", + "Set at the end of the chat history when the continue button is pressed.": "Встановлюється в кінці історії чату, коли натискається кнопка продовження.", + "Replace empty message": "Замінити порожнє повідомлення", + "Send this text instead of nothing when the text box is empty.": "Надіслати цей текст замість порожнього, коли поле тексту порожнє.", + "Seed": "Зерно", + "Set to get deterministic results. Use -1 for random seed.": "Налаштувати для отримання детермінованих результатів. Використовуйте -1 для випадкового початкового числа.", + "Temperature controls the randomness in token selection": "Температура контролює випадковість у виборі токенів", + "Top_K_desc": "Top K встановлює максимальну кількість наймовірніших токенів, які можна обрати", + "Top_P_desc": "Top P (також відомий як відбір ядра)", + "Typical P": "Типове P", + "Typical_P_desc": "Типовий відбір P визначає пріоритет токенів на основі їх відхилення від середньої ентропії набору", + "Min_P_desc": "Min P встановлює базову мінімальну ймовірність", + "Top_A_desc": "Top A встановлює поріг для вибору токенів на основі квадрату найвищої ймовірності токена", + "Tail_Free_Sampling_desc": "Безхвостовий відбір (TFS)", + "rep.pen range": "Діапазон штрафу за повтор", + "Mirostat": "Міростат", + "Mode": "Режим", + "Mirostat_Mode_desc": "Значення 0 повністю вимикає Mirostat. 1 – для Mirostat 1.0, а 2 – для Mirostat 2.0", + "Tau": "Тау", + "Mirostat_Tau_desc": "Контролює змінність виходів Mirostat", + "Eta": "Ета", + "Mirostat_Eta_desc": "Контролює швидкість навчання Mirostat", + "Ban EOS Token": "Заборонити токен EOS", + "Ban_EOS_Token_desc": "Заборонити токен кінця послідовності (EOS) за допомогою KoboldCpp (і, можливо, також інші токени за допомогою KoboldAI).\rДобре підходить для написання історій, але не слід використовувати для режиму чату та інструктажу.", + "GBNF Grammar": "Синтаксис GBNF", + "Type in the desired custom grammar": "Введіть бажаний власний синтаксис", + "Samplers Order": "Порядок вибірки", + "Samplers will be applied in a top-down order. Use with caution.": "Вибірки будуть застосовані у порядку зверху донизу. Використовуйте з обережністю.", + "Tail Free Sampling": "Безхвостовий відбір", + "Load koboldcpp order": "Завантажити порядок koboldcpp", + "Preamble": "Преамбула", + "Use style tags to modify the writing style of the output.": "Використовуйте теги стилю для зміни стилю написання виводу.", + "Banned Tokens": "Заборонені токени", + "Sequences you don't want to appear in the output. One per line.": "Послідовності, які ви не хочете бачити у виводі. Одна на рядок.", + "Logit Bias": "Зміщення логітів", + "Add": "Додати", + "Helps to ban or reenforce the usage of certain words": "Допомагає забороняти або підсилювати використання певних слів", + "CFG Scale": "Масштаб CFG", + "Negative Prompt": "Негативна підказка", + "Add text here that would make the AI generate things you don't want in your outputs.": "Додайте сюди текст, який змусить штучний інтелект генерувати речі, які ви не хочете бачити у виводах.", + "Used if CFG Scale is unset globally, per chat or character": "Використовується, якщо масштаб CFG не встановлений глобально, на кожен чат або персонажа.", + "Mirostat Tau": "Тау Mirostat", + "Mirostat LR": "Міростат ЛР", + "Min Length": "Мінімальна довжина", + "Top K Sampling": "Вибірка топ K", + "Nucleus Sampling": "Вибірка ядра", + "Top A Sampling": "Вибірка топ A", + "CFG": "CFG", + "Neutralize Samplers": "Нейтралізувати вибірку", + "Set all samplers to their neutral/disabled state.": "Встановити всі семплери у їх нейтральний/вимкнений стан.", + "Sampler Select": "Вибір семплера", + "Customize displayed samplers or add custom samplers.": "Налаштуйте відображувані семплери або додайте власні семплери.", + "Epsilon Cutoff": "Відсіч епсилону", + "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "Епсилон встановлює нижню межу ймовірності, нижче якої токени виключаються з вибірки", + "Eta Cutoff": "Відсіч ети", + "Eta_Cutoff_desc": "Eta-відсічення - основний параметр спеціальної техніки вибірки Ета. У одиницях 1e-4; розумна величина - 3. Встановіть 0, щоб вимкнути. Див. статтю «Вибірка відсічення як модель мовного розподілення» Хевітта та ін. (2022) для деталей.", + "rep.pen decay": "Rep Pen Decay", + "Encoder Rep. Pen.": "Штраф за повтор кодера", + "No Repeat Ngram Size": "Розмір n-грам без повторень", + "Skew": "Перекіс", + "Max Tokens Second": "Максимальна кількість токенів / секунду", + "Smooth Sampling": "Плавна вибірка", + "Smooth_Sampling_desc": "Дозволяє використовувати квадратичні/кубічні перетворення для коригування розподілу. Нижчі значення коефіцієнта згладжування будуть більш креативними, зазвичай між 0,2-0,3 є найкращою точкою (припускаючи, що крива = 1). Вищі значення кривої згладжування зроблять криву крутішою, що агресивніше каратиме вибір із низькою ймовірністю. Крива 1.0 еквівалентна лише використанню коефіцієнта згладжування.", + "Smoothing Factor": "Коефіцієнт згладжування", + "Smoothing Curve": "Крива згладжування", + "DRY_Repetition_Penalty_desc": "DRY штрафує токени, які розширюють кінець вхідних даних у послідовність, яка раніше траплялася у вхідних даних. Встановіть множник на 0, щоб вимкнути.", + "DRY Repetition Penalty": "Штраф за СУХЕ повторення", + "DRY_Multiplier_desc": "Встановіть значення > 0, щоб увімкнути DRY. Контролює величину штрафу для найкоротших штрафних послідовностей.", + "Multiplier": "Множник", + "DRY_Base_desc": "Контролює швидкість збільшення штрафу зі збільшенням довжини послідовності.", + "Base": "База", + "DRY_Allowed_Length_desc": "Найдовша послідовність, яку можна повторити без покарання.", + "Allowed Length": "Дозволена довжина", + "Penalty Range": "Діапазон пенальті", + "DRY_Sequence_Breakers_desc": "Токени, збіг яких не триває. Задається як список рядків у лапках, розділених комами.", + "Sequence Breakers": "Порушники послідовності", + "JSON-serialized array of strings.": "JSON-серіалізований масив рядків.", + "Dynamic Temperature": "Динамічна температура", + "Scale Temperature dynamically per token, based on the variation of probabilities": "Шкала температури динамічно за кожний токен, на основі варіації ймовірностей", + "Minimum Temp": "Мінімальна температура", + "Maximum Temp": "Максимальна температура", + "Exponent": "Експонента", + "Mirostat (mode=1 is only for llama.cpp)": "Mirostat (режим=1 тільки для llama.cpp)", + "Mirostat_desc": "Mirostat - це термостат для заплутанності виводу", + "Mirostat Mode": "Режим Mirostat", + "Variability parameter for Mirostat outputs": "Параметр змінності для виходів Mirostat", + "Mirostat Eta": "Ета Mirostat", + "Learning rate of Mirostat": "Швидкість навчання Mirostat", + "Beam search": "Пучковий пошук", + "Helpful tip coming soon.": "Корисна порада незабаром.", + "Number of Beams": "Кількість пучків", + "Length Penalty": "Штраф за довжину", + "Early Stopping": "Раннє зупинення", + "Contrastive search": "Контрастний пошук", + "Penalty Alpha": "Коефіцієнт штрафу", + "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "Сила терміну регуляризації контрастного пошуку. Встановіть 0, щоб вимкнути контрастний пошук", + "Do Sample": "Робити відбір", + "Add BOS Token": "Додати токен BOS", + "Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative": "Додавати bos_token на початок запиту. Вимкнення цього може зробити відповіді більш креативними", + "Ban the eos_token. This forces the model to never end the generation prematurely": "Заборонити токен eos. Це змусить модель ніколи не завершувати генерацію передчасно", + "Ignore EOS Token": "Ігнорувати токен EOS", + "Ignore the EOS Token even if it generates.": "Ігноруйте токен EOS, навіть якщо він генерується.", + "Skip Special Tokens": "Пропустити спеціальні токени", + "Temperature Last": "Температура останньою", + "Temperature_Last_desc": "Використовувати вибірку по температурі останньою", + "Speculative Ngram": "Спекулятивний Ngram", + "Use a different speculative decoding method without a draft model": "Використовуйте інший спекулятивний метод декодування без чорнової моделі.\rБажано використовувати чорнову модель. Спекулятивна ngram не така ефективна.", + "Spaces Between Special Tokens": "Проміжки між спеціальними маркерами", + "LLaMA / Mistral / Yi models only": "Тільки моделі LLaMA / Mistral / Yi", + "Example: some text [42, 69, 1337]": "Приклад: деякий текст [42, 69, 1337]", + "Classifier Free Guidance. More helpful tip coming soon": "Вільні інструкції класифікатора. Більше корисних порад незабаром", + "Scale": "Масштаб", + "JSON Schema": "Схема JSON", + "Type in the desired JSON schema": "Введіть потрібну схему JSON", + "Grammar String": "Граматичний рядок", + "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF або EBNF, залежить від серверної частини, яка використовується. Якщо ви використовуєте це, ви повинні знати, який.", + "Top P & Min P": "Верхній P & Min P", + "Load default order": "Завантажити типовий порядок", + "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "лише llama.cpp. Визначає порядок пробовідбірників. Якщо режим Mirostat не 0, порядок вибірки ігнорується.", + "Sampler Priority": "Пріоритет вибірки", + "Ooba only. Determines the order of samplers.": "Лише Ooba. Визначає порядок вибірки.", + "Character Names Behavior": "Поведінка імен персонажів", + "Helps the model to associate messages with characters.": "Допомагає моделі пов’язувати повідомлення з символами.", + "None": "Немає", + "character_names_default": "За винятком груп і минулих персонажів. В іншому випадку переконайтеся, що ви вказали імена в підказці.", + "Don't add character names.": "Не додавайте імена персонажів.", + "Completion": "Об'єкт завершення", + "character_names_completion": "Застосовуються обмеження: лише латинські букви та цифри підкреслення. Працює не для всіх джерел, зокрема: Claude, MistralAI, Google.", + "Add character names to completion objects.": "Додайте імена персонажів до об’єктів завершення.", + "Message Content": "Вміст повідомлення", + "Prepend character names to message contents.": "Додайте імена символів до вмісту повідомлення.", + "Continue Postfix": "Продовжити Postfix", + "The next chunk of the continued message will be appended using this as a separator.": "Наступний фрагмент продовженого повідомлення буде додано з використанням цього як роздільника.", + "Space": "Простір", + "Newline": "Новий рядок", + "Double Newline": "Подвійний новий рядок", + "Wrap user messages in quotes before sending": "Перед відправленням обгортати повідомлення користувача в лапки", + "Wrap in Quotes": "Обертати у лапки", + "Wrap entire user message in quotes before sending.": "Перед відправкою повідомлення користувача обертати усе у лапки.", + "Leave off if you use quotes manually for speech.": "Не включайте, якщо ви вручну використовуєте лапки для мовлення.", + "Continue prefill": "Продовжувати автозаповнення", + "Continue sends the last message as assistant role instead of system message with instruction.": "Продовженням буде відправлена остання повідомлення як роль асистента, а не системне повідомлення з інструкцією.", + "Squash system messages": "Заповнювати системні повідомлення", + "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Об'єднує послідовні системні повідомлення в одне (крім прикладів діалогів). Може покращити співпрацю для деяких моделей.", + "Enable function calling": "Увімкнути виклик функцій", + "Send inline images": "Надсилати вбудовані зображення", + "image_inlining_hint_1": "Надсилає зображення у підказках, якщо модель це підтримує (наприклад, GPT-4V, Claude 3 або Llava 13B).\n Використовувати", + "image_inlining_hint_2": "дії з будь-яким повідомленням або", + "image_inlining_hint_3": "меню, щоб прикріпити файл зображення до чату.", + "Inline Image Quality": "Якість вбудованого зображення", + "openai_inline_image_quality_auto": "Авто", + "openai_inline_image_quality_low": "Низький", + "openai_inline_image_quality_high": "Високий", + "Use AI21 Tokenizer": "Використовуйте AI21 Tokenizer", + "Use the appropriate tokenizer for Jurassic models, which is more efficient than GPT's.": "Використовуйте відповідний токенізатор для моделей Jurassic, який ефективніший, ніж GPT.", + "Use Google Tokenizer": "Використовувати токенізатор Google", + "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "Використовуйте відповідний токенізатор для моделей Google через їх API. Повільніша обробка підказок, але пропонує набагато точніше підрахунку токенів.", + "Use system prompt": "Використовуйте системну підказку", + "(Gemini 1.5 Pro/Flash only)": "(тільки Gemini 1.5 Pro/Flash)", + "Merges_all_system_messages_desc_1": "Об’єднує всі системні повідомлення до першого повідомлення з несистемною роллю та надсилає їх у a", + "Merges_all_system_messages_desc_2": "поле.", + "Assistant Prefill": "Асистент автозаповнення", + "Start Claude's answer with...": "Почати відповідь Клода з...", + "Assistant Impersonation Prefill": "Попереднє заповнення уособлення помічника", + "Use system prompt (Claude 2.1+ only)": "Використовувати системний промпт (тільки Claude 2.1+)", + "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "Надсилати системний промпт для підтримуваних моделей. Якщо відключено, повідомлення користувача додається в початок промпта.", + "User first message": "Перше повідомлення користувача", + "Restore User first message": "Відновити перше повідомлення користувача", + "Human message": "Людське повідомлення, інструкція тощо.\nНе додає нічого, якщо пусте, тобто вимагає нового запиту з роллю «користувач».", + "New preset": "Новий шаблон", + "Delete preset": "Видалити шаблон", + "View / Edit bias preset": "Переглянути / Редагувати налаштування зміщення", + "Add bias entry": "Додати запис зміщення", + "Most tokens have a leading space.": "Більшість жетонів мають пробіл на початку.", + "API Connections": "З'єднання з API", + "Text Completion": "Завершення тексту", + "Chat Completion": "Завершення чату", + "NovelAI": "NovelAI", + "AI Horde": "AI Horde", + "KoboldAI": "KoboldAI", + "Avoid sending sensitive information to the Horde.": "Уникайте надсилання чутливої інформації в Horde.", + "Review the Privacy statement": "Перегляньте заяву про конфіденційність", + "Register a Horde account for faster queue times": "Зареєструйте обліковий запис Horde для швидшого часу очікування в черзі", + "Learn how to contribute your idle GPU cycles to the Horde": "Дізнайтеся, як сприяти внеском вашого неактивного циклу GPU до горди", + "Adjust context size to worker capabilities": "Налаштовувати розмір контексту відповідно до можливостей робітників", + "Adjust response length to worker capabilities": "Налаштовувати довжину відповіді відповідно до можливостей робітників", + "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "Може допомогти з поганими відповідями, ставлячи в чергу тільки схвалених робітників. Може сповільнити час відповіді.", + "Trusted workers only": "Лише довірені працівники", + "API key": "Ключ API", + "Get it here:": "Отримайте його тут:", + "Register": "Зареєструвати", + "View my Kudos": "Переглянути мої Kudos", + "Enter": "Увійти", + "to use anonymous mode.": "щоб використовувати анонімний режим.", + "Clear your API key": "Очистити свій ключ API", + "For privacy reasons, your API key will be hidden after you reload the page.": "З причин приватності ваш ключ API буде приховано після перезавантаження сторінки.", + "Models": "Моделі", + "Refresh models": "Оновити моделі", + "-- Horde models not loaded --": "-- Моделі Horde не завантажені --", + "Not connected...": "Не підключено...", + "API url": "URL-адреса API", + "Example: http://127.0.0.1:5000/api ": "Приклад: http://127.0.0.1:5000/api", + "Connect": "Підключитися", + "Cancel": "Скасувати", + "Novel API key": "Ключ API для NovelAI", + "Get your NovelAI API Key": "Отримайте свій ключ API NovelAI", + "Enter it in the box below": "Введіть його в поле нижче", + "Novel AI Model": "Модель NovelAI", + "No connection...": "Немає підключення...", + "API Type": "Тип API", + "Default (completions compatible)": "За замовчуванням [сумісні з OpenAI /доповненнями: oobabooga, LM Studio тощо]", + "TogetherAI API Key": "Ключ API для TogetherAI", + "TogetherAI Model": "Модель TogetherAI", + "-- Connect to the API --": "-- Підлючиться до API --", + "OpenRouter API Key": "Ключ API для OpenRouter", + "Click Authorize below or get the key from": "Клацніть 'Авторизувати' нижче або отримайте ключ з", + "View Remaining Credits": "Переглянути залишкові кредити", + "OpenRouter Model": "Модель OpenRouter", + "Model Providers": "Модельні постачальники", + "InfermaticAI API Key": "Ключ API InfermaticAI", + "InfermaticAI Model": "Модель InfermaticAI", + "DreamGen API key": "Ключ API DreamGen", + "DreamGen Model": "Модель DreamGen", + "Mancer API key": "Ключ API для Mancer", + "Mancer Model": "Модель Mancer", + "Make sure you run it with": "Переконайтеся, що ви запускаєте його з", + "flag": "прапорцем", + "API key (optional)": "Ключ API (необов'язково)", + "Server url": "URL-адреса сервера", + "Example: 127.0.0.1:5000": "Приклад: 127.0.0.1:5000", + "Custom model (optional)": "Власна модель (необов'язково)", + "vllm-project/vllm": "vllm-project/vllm (режим оболонки OpenAI API)", + "vLLM API key": "Ключ API vLLM", + "Example: 127.0.0.1:8000": "Приклад: http://127.0.0.1:8000", + "vLLM Model": "Модель vLLM", + "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (режим OpenAI API)", + "Aphrodite API key": "Ключ API для Aphrodite", + "Aphrodite Model": "Модель Афродіта", + "ggerganov/llama.cpp": "ggerganov/llama.cpp (сервер виведення)", + "Example: 127.0.0.1:8080": "Приклад: 127.0.0.1:8080", + "Example: 127.0.0.1:11434": "Приклад: 127.0.0.1:11434", + "Ollama Model": "Модель Ollama", + "Download": "Завантажити", + "Tabby API key": "Ключ API для Tabby", + "koboldcpp API key (optional)": "API-ключ koboldcpp (необов’язково)", + "Example: 127.0.0.1:5001": "Приклад: 127.0.0.1:5001", + "Authorize": "Авторизувати", + "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Отримайте свій токен API OpenRouter за допомогою OAuth. Вас буде перенаправлено на openrouter.ai", + "Bypass status check": "Обійти перевірку статусу", + "Chat Completion Source": "Джерело Chat Completion", + "Reverse Proxy": "Зворотний проксі", + "Proxy Presets": "Попередні налаштування проксі", + "Saved addresses and passwords.": "Збережені адреси та паролі.", + "Save Proxy": "Зберегти проксі", + "Delete Proxy": "Видалити проксі", + "Proxy Name": "Ім'я проксі", + "This will show up as your saved preset.": "Це відображатиметься як ваш збережений стиль.", + "Proxy Server URL": "URL проксі-сервера", + "Alternative server URL (leave empty to use the default value).": "URL-адрес альтернативного сервера (залиште порожнім, щоб використовувати значення за замовчуванням).", + "Remove your real OAI API Key from the API panel BEFORE typing anything into this box": "Видаліть свій справжній API ключ OAI з API-панелі ПЕРЕД тим, як щось вводити в це поле", + "We cannot provide support for problems encountered while using an unofficial OpenAI proxy": "Ми не можемо надати підтримку для проблем, які виникають при використанні неофіційного проксі OpenAI", + "Doesn't work? Try adding": "не працює? Спробуйте додати", + "at the end!": "в кінці!", + "Proxy Password": "Пароль проксі", + "Will be used as a password for the proxy instead of API key.": "Використовуватиметься як пароль для проксі замість ключа API.", + "Peek a password": "Подивіться пароль", + "OpenAI API key": "Ключ API для OpenAI", + "View API Usage Metrics": "Переглянути метрики використання API", + "Follow": "Дотримуйтесь", + "these directions": "цих інструкцій", + "to get your OpenAI API key.": "щоб отримати свій ключ API для OpenAI.", + "Use Proxy password field instead. This input will be ignored.": "Натомість використовуйте поле «Пароль проксі». Це введення буде проігноровано.", + "OpenAI Model": "Модель OpenAI", + "Bypass API status check": "Обійти перевірку статусу API", + "Show External models (provided by API)": "Показати зовнішні моделі (надані API)", + "Get your key from": "Отримайте свій ключ з", + "Anthropic's developer console": "консолі розробника Anthropic", + "Claude Model": "Модель Claude", + "Window AI Model": "Модель Window AI", + "Model Order": "Сортування моделі OpenRouter", + "Alphabetically": "За алфавітом", + "Price": "Ціна (найдешевша)", + "Context Size": "Розмір контексту", + "Group by vendors": "Групувати за постачальниками", + "Group by vendors Description": "Помістіть моделі OpenAI в одну групу, моделі Anthropic в іншу групу тощо. Можна поєднати з сортуванням.", + "Allow fallback routes": "Дозволити резервні маршрути", + "Allow fallback routes Description": "Автоматично вибирає альтернативну модель, якщо вибрана модель не може задовольнити ваш запит.", + "Scale API Key": "Ключ API для Scale", + "Clear your cookie": "Очистіть файл cookie", + "Alt Method": "Альтернативний метод", + "AI21 API Key": "Ключ API для AI21", + "AI21 Model": "Модель AI21", + "Google AI Studio API Key": "Ключ API Google AI Studio", + "Google Model": "Модель Google", + "MistralAI API Key": "Ключ API MistralAI", + "MistralAI Model": "Модель MistralAI", + "Groq API Key": "Ключ API Groq", + "Groq Model": "Модель Groq", + "Perplexity API Key": "Ключ API Perplexity", + "Perplexity Model": "Модель здивування", + "Cohere API Key": "Ключ API Cohere", + "Cohere Model": "Модель Cohere", + "Custom Endpoint (Base URL)": "Спеціальна кінцева точка (базова URL-адреса)", + "Custom API Key": "Спеціальний ключ API", + "Available Models": "Доступні моделі", + "Prompt Post-Processing": "Швидка постобробка", + "Applies additional processing to the prompt before sending it to the API.": "Застосовує додаткову обробку запиту перед надсиланням його в API.", + "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "Підтверджує ваше підключення до API, надсилаючи коротке тестове повідомлення. Пам'ятайте, що ви будете платити за це!", + "Test Message": "Тестове повідомлення", + "Auto-connect to Last Server": "Автоматичне підключення до останнього сервера", + "Missing key": "❌ Відсутній ключ", + "Key saved": "✔️ Ключ збережено", + "View hidden API keys": "Переглянути приховані ключі API", + "AI Response Formatting": "Форматування відповіді ШІ", + "Advanced Formatting": "Розширене форматування", + "Context Template": "Шаблон контексту", + "Auto-select this preset for Instruct Mode": "Автоматично вибрати цей шаблон для режиму інструкцій", + "Story String": "Рядок історії", + "Example Separator": "Роздільник прикладів", + "Chat Start": "Початок чату", + "Add Chat Start and Example Separator to a list of stopping strings.": "Додайте початок чату та роздільник прикладів до списку рядків зупинки.", + "Use as Stop Strings": "Використовувати як рядки зупинки", + "context_allow_jailbreak": "Включає втечу з в’язниці в кінці підказки, якщо визначено в картці символів ТА «Переважати символ. Втечу з в'язниці'' увімкнено.\nЦЕ НЕ РЕКОМЕНДУЄТЬСЯ ДЛЯ МОДЕЛЕЙ ЗАВЕРШЕННЯ ТЕКСТУ, МОЖЕ ПРИЗВЕСТИ ДО ПОГАНОГО РЕЗУЛЬТАТУ.", + "Allow Jailbreak": "Дозволити втечу з в'язниці", + "Context Order": "Порядок контексту", + "Summary": "Резюме", + "Author's Note": "Примітка автора", + "Example Dialogues": "Приклади діалогів", + "Hint": "Підказка:", + "In-Chat Position not affected": "Порядки резюме та примітки автора діють лише тоді, коли для них не встановлено позицію в чаті.", + "Instruct Mode": "Режим інструкцій", + "Enabled": "Увімкнено", + "instruct_bind_to_context": "Якщо ввімкнено, шаблони контексту вибиратимуться автоматично на основі назви вибраного шаблону вказівок або за бажанням.", + "Bind to Context": "Прив'язати до контексту", + "Presets": "Налаштування", + "Auto-select this preset on API connection": "Автоматично вибрати цей шаблон при підключенні до API", + "Activation Regex": "Регулярний вираз активації", + "Wrap Sequences with Newline": "Починати послідовності з нового рядка", + "Replace Macro in Sequences": "Заміняти макроси в послідовностях", + "Skip Example Dialogues Formatting": "Пропустити форматування прикладів діалогів", + "Include Names": "Включити імена", + "Force for Groups and Personas": "Примусово для груп і персон", + "System Prompt": "Системне запитання", + "Instruct Mode Sequences": "Послідовності режиму інструкцій", + "System Prompt Wrapping": "Обгортка системних підказок", + "Inserted before a System prompt.": "Вставляється перед системним запитом.", + "System Prompt Prefix": "Префікс системної підказки", + "Inserted after a System prompt.": "Вставляється після системного запиту.", + "System Prompt Suffix": "Суфікс системної підказки", + "Chat Messages Wrapping": "Обгортка повідомлень чату", + "Inserted before a User message and as a last prompt line when impersonating.": "Вставляється перед повідомленням користувача та як останній рядок підказки під час уособлення.", + "User Message Prefix": "Префікс повідомлення користувача", + "Inserted after a User message.": "Вставляється після повідомлення користувача.", + "User Message Suffix": "Суфікс повідомлення користувача", + "Inserted before an Assistant message and as a last prompt line when generating an AI reply.": "Вставляється перед повідомленням Асистента та як останній рядок підказки під час створення відповіді ШІ.", + "Assistant Message Prefix": "Префікс повідомлення помічника", + "Inserted after an Assistant message.": "Вставляється після повідомлення Асистента.", + "Assistant Message Suffix": "Суфікс повідомлення помічника", + "Inserted before a System (added by slash commands or extensions) message.": "Вставляється перед системним повідомленням (додається за допомогою скісної риски або розширень).", + "System Message Prefix": "Префікс системного повідомлення", + "Inserted after a System message.": "Вставляється після системного повідомлення.", + "System Message Suffix": "Суфікс системного повідомлення", + "If enabled, System Sequences will be the same as User Sequences.": "Якщо ввімкнено, системні послідовності будуть такими самими, як і послідовності користувача.", + "System same as User": "Система така ж, як Користувач", + "Misc. Sequences": "Різне Послідовності", + "Inserted before the first Assistant's message.": "Вставляється перед першим повідомленням Помічника.", + "First Assistant Prefix": "Префікс першого помічника", + "instruct_last_output_sequence": "Вставляється перед останнім повідомленням Помічника або як останній рядок підказки під час створення відповіді ШІ (за винятком нейтральної/системної ролі).", + "Last Assistant Prefix": "Префікс останнього помічника", + "Will be inserted as a last prompt line when using system/neutral generation.": "Буде вставлено як останній рядок підказки під час використання системної/нейтральної генерації.", + "System Instruction Prefix": "Префікс системної інструкції", + "If a stop sequence is generated, everything past it will be removed from the output (inclusive).": "Якщо згенеровано стоп-послідовність, усе, що минуло, буде видалено з виводу (включно).", + "Stop Sequence": "Послідовність зупинки", + "Will be inserted at the start of the chat history if it doesn't start with a User message.": "Буде вставлено на початку історії чату, якщо вона не починається з повідомлення користувача.", + "User Filler Message": "Повідомлення користувача", + "Context Formatting": "Форматування контексту", + "(Saved to Context Template)": "(Зберігаються в шаблоні контексту)", + "Always add character's name to prompt": "Завжди додавати ім'я персонажа до запиту", + "Generate only one line per request": "Генерувати лише один рядок за запит", + "Trim Incomplete Sentences": "Обрізати неповні речення", + "Include Newline": "Включити новий рядок", + "Misc. Settings": "Різні налаштування", + "Collapse Consecutive Newlines": "Згортати послідовні нові рядки", + "Trim spaces": "Обрізати пробіли", + "Tokenizer": "Токенізатор", + "Token Padding": "Набивка токенів", + "Start Reply With": "Почати відповідь з", + "AI reply prefix": "Префікс відповіді ШІ", + "Show reply prefix in chat": "Показати префікс відповіді в чаті", + "Non-markdown strings": "Рядки без Markdown", + "separate with commas w/o space between": "розділяйте комами без пропусків між ними", + "Custom Stopping Strings": "Власні рядки зупинки", + "JSON serialized array of strings": "JSON-серіалізований масив рядків", + "Replace Macro in Stop Strings": "Замінювати макроси у власних рядках зупинки", + "Auto-Continue": "Автоматичне продовження", + "Allow for Chat Completion APIs": "Дозволити для Chat Completion API", + "Target length (tokens)": "Цільова довжина (токени)", + "World Info": "Інформація про світ", + "Locked = World Editor will stay open": "Заблоковано = Редактор світу залишиться відкритим", + "Worlds/Lorebooks": "Світи / Книги знань", + "Active World(s) for all chats": "Активні світи для всіх чатів", + "-- World Info not found --": "-- Світи не знайдені --", + "Global World Info/Lorebook activation settings": "Налаштування активації Global World Info/Lorebook", + "Click to expand": "Натисніть, щоб розгорнути", + "Scan Depth": "Глибина сканування", + "Context %": "Контекст %", + "Budget Cap": "Ліміт бюджету", + "(0 = disabled)": "(0 = вимкнено)", + "Scan chronologically until reached min entries or token budget.": "Скануйте в хронологічному порядку, поки не буде досягнуто мінімальних записів або бюджету маркерів.", + "Min Activations": "Мінімальна кількість активацій", + "Max Depth": "Максимальна глибина", + "(0 = unlimited, use budget)": "(0 = без обмежень, використовуйте бюджет)", + "Insertion Strategy": "Стратегія вставки", + "Sorted Evenly": "Рівномірно впорядковані", + "Character Lore First": "Інформація персонажу першою", + "Global Lore First": "Глобальна інформація першою", + "Entries can activate other entries by mentioning their keywords": "Записи можуть активувати інші записи, згадуючи їх ключові слова", + "Recursive Scan": "Рекурсивне сканування", + "Lookup for the entry keys in the context will respect the case": "Пошук ключів запису в контексті буде дотримуватися регістру", + "Case Sensitive": "Чутливість до регістру", + "If the entry key consists of only one word, it would not be matched as part of other words": "Якщо ключ запису складається лише з одного слова, він не буде співпадати як частина інших слів", + "Match Whole Words": "Відповідність цілим словам", + "Only the entries with the most number of key matches will be selected for Inclusion Group filtering": "Для фільтрації групи включення буде вибрано лише записи з найбільшою кількістю збігів ключів", + "Use Group Scoring": "Використовуйте групову оцінку", + "Alert if your world info is greater than the allocated budget.": "Сповіщайте, якщо інформація про ваш світ перевищує виділений бюджет.", + "Alert On Overflow": "Сповіщення при переповненні", + "New": "Новий", + "or": "або", + "--- Pick to Edit ---": "--- Редагувати ---", + "Rename World Info": "Перейменувати інформацію про світ", + "Open all Entries": "Відкрити всі записи", + "Close all Entries": "Закрити всі записи", + "New Entry": "Новий запис", + "Fill empty Memo/Titles with Keywords": "Заповнити порожні заголовки ключовими словами", + "Import World Info": "Імпортувати інформацію про світ", + "Export World Info": "Експортувати інформацію про світ", + "Duplicate World Info": "Дублювати інформацію про світ", + "Delete World Info": "Видалити інформацію про світ", + "Search...": "Пошук...", + "Search": "Пошук", + "Priority": "Пріоритет", + "Custom": "Користувацький", + "Title A-Z": "Заголовок від А до Я", + "Title Z-A": "Заголовок від Я до А", + "Tokens ↗": "Токени ↗", + "Tokens ↘": "Токени ↘", + "Depth ↗": "Глибина ↗", + "Depth ↘": "Глибина ↘", + "Order ↗": "Порядок ↗", + "Order ↘": "Порядок ↘", + "UID ↗": "UID ↗", + "UID ↘": "UID ↘", + "Trigger% ↗": "Тригер% ↗", + "Trigger% ↘": "Тригер% ↘", + "Refresh": "Оновити", + "User Settings": "Налаштування користувача", + "Simple": "Простий", + "Advanced": "Розширений", + "UI Language": "Мова", + "Account": "Обліковий запис", + "Admin Panel": "Панель адміністратора", + "Logout": "Вийти", + "Search Settings": "Пошук налаштувань", + "UI Theme": "Тема інтерфейсу", + "Import a theme file": "Імпортувати файл теми", + "Export a theme file": "Експортувати файл теми", + "Delete a theme": "Видалити тему", + "Update a theme file": "Оновити файл теми", + "Save as a new theme": "Зберегти як нову тему", + "Avatar Style:": "Стиль аватара", + "Circle": "Коло", + "Square": "Квадрат", + "Rectangle": "Прямокутник", + "Chat Style:": "Стиль чату:", + "Flat": "Плоский\nБульбашки\nдокумент", + "Bubbles": "Бульбашки", + "Document": "Документ", + "Specify colors for your theme.": "Визначте кольори для вашої теми.", + "Theme Colors": "Кольори теми", + "Main Text": "Головний текст", + "Italics Text": "Курсивний текст", + "Underlined Text": "Підкреслений текст", + "Quote Text": "Текст в лапках", + "Shadow Color": "Колір тіні", + "Chat Background": "Фон чату", + "UI Background": "Фон інтерфейсу", + "UI Border": "Межі інтерфейсу", + "User Message Blur Tint": "Колір повідомлення користувача", + "AI Message Blur Tint": "Колір повідомлення ШІ", + "Chat Width": "Ширина чату", + "Width of the main chat window in % of screen width": "Ширина головного вікна чату у % ширини екрана", + "Font Scale": "Масштаб шрифту", + "Font size": "Розмір шрифту", + "Blur Strength": "Сила розмиття", + "Blur strength on UI panels.": "Сила розмиття на панелях інтерфейсу.", + "Text Shadow Width": "Ширина тіні тексту", + "Strength of the text shadows": "Інтенсивність тіні тексту", + "Disables animations and transitions": "Вимикає анімації та переходи", + "Reduced Motion": "Зменшена рухомість", + "removes blur from window backgrounds": "видаляє розмиття з фонів вікон для прискорення відображення", + "No Blur Effect": "Без ефекту розмиття", + "Remove text shadow effect": "Видалити тінь тексту", + "No Text Shadows": "Без тіней тексту", + "Reduce chat height, and put a static sprite behind the chat window": "Зменшити висоту чату та розмістити статичний спрайт за вікном чату", + "Waifu Mode": "Режим візуальної новели", + "Always show the full list of the Message Actions context items for chat messages, instead of hiding them behind '...'": "Завжди показувати повний список контекстних дій для повідомлень чату, а не приховувати їх за '...' ", + "Auto-Expand Message Actions": "Автоматично розгортати дії повідомлень", + "Alternative UI for numeric sampling parameters with fewer steps": "Альтернативний інтерфейс для числових параметрів вибірки з меншою кількістю кроків", + "Zen Sliders": "Слайдери зен", + "Entirely unrestrict all numeric sampling parameters": "Повністю скасовує обмеження всіх числових параметрів вибірки", + "Mad Lab Mode": "Режим лабораторії", + "Time the AI's message generation, and show the duration in the chat log": "Вимірювати час генерації повідомлення ШІ та показувати тривалість у журналі чату", + "Message Timer": "Таймер повідомлень", + "Show a timestamp for each message in the chat log": "Показувати відмітку часу для кожного повідомлення у журналі чату", + "Chat Timestamps": "Відмітки часу в чаті", + "Show an icon for the API that generated the message": "Показувати значок для API, який згенерував повідомлення", + "Model Icon": "Іконка моделі", + "Show sequential message numbers in the chat log": "Показувати послідовні номери повідомлень у журналі чату", + "Message IDs": "Ідентифікатори повідомлень", + "Hide avatars in chat messages.": "Приховати аватари в повідомленнях чату.", + "Hide Chat Avatars": "Приховати аватари чату", + "Show the number of tokens in each message in the chat log": "Показувати кількість токенів у кожному повідомленні у журналі чату", + "Show Message Token Count": "Кількість токенів у повідомленні", + "Single-row message input area. Mobile only, no effect on PC": "Область введення повідомлення з одним рядком. Тільки для мобільних пристроїв, не впливає на ПК", + "Compact Input Area (Mobile)": "Компактна область введення", + "In the Character Management panel, show quick selection buttons for favorited characters": "У панелі Управління персонажами показувати кнопки швидкого вибору для улюблених персонажів", + "Characters Hotswap": "Швидка заміна персонажів", + "Enable magnification for zoomed avatar display.": "Увімкніть збільшення для збільшеного відображення аватара.", + "Avatar Hover Magnification": "Збільшення аватара при наведенні", + "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "Вмикає ефект збільшення під час наведення курсора, коли ви відображаєте збільшений аватар після натискання зображення аватара в чаті.", + "Show tagged character folders in the character list": "Показувати папки персонажів з тегами у списку персонажів", + "Tags as Folders": "Теги як теки", + "Tags_as_Folders_desc": "Останні зміни: теги мають бути позначені як папки в меню керування тегами, щоб вони відображалися як такі. Натисніть тут, щоб відкрити його.", + "Character Handling": "Обробка персонажа", + "If set in the advanced character definitions, this field will be displayed in the characters list.": "Якщо встановлено у розширених визначеннях персонажа, це поле буде відображено в списку персонажів.", + "Char List Subheader": "Підзаголовок списку символів", + "Character Version": "Версія персонажа", + "Created by": "Ім'я автора", + "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "Використовувати нечітку відповідность та шукати персонажів у списку за всіма полями даних, а не лише за рядком імені", + "Advanced Character Search": "Розширений пошук персонажа", + "If checked and the character card contains a prompt override (System Prompt), use that instead": "Якщо відмічено і картка персонажа містить заміну запиту (Системний запит), використовувати її замість цього", + "Prefer Character Card Prompt": "Перевага запиту персонажа", + "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Якщо відмічено і картка персонажа містить заміну джейлбрейку (Інструкцію), використовуйте її замість цього", + "Prefer Character Card Jailbreak": "Перевага джейлбрейку персонажа", + "never_resize_avatars_tooltip": "Уникайте обрізання та зміни розміру імпортованих зображень символів. Коли вимкнено, обрізати/змінити розмір до 512x768.", + "Never resize avatars": "Ніколи не змінювати розмір аватарів", + "Show actual file names on the disk, in the characters list display only": "Показувати фактичні назви файлів на диску, тільки у відображенні списку персонажів", + "Show avatar filenames": "Показувати імена файлів аватарів", + "Prompt to import embedded card tags on character import. Otherwise embedded tags are ignored": "Запитувати імпортувати вбудовані теги картки при імпорті персонажа. В іншому випадку вбудовані теги ігноруються", + "Import Card Tags": "Імпортувати теги з картки", + "Hide character definitions from the editor panel behind a spoiler button": "Ховати визначення персонажів з панелі редактора за кнопкою спойлера", + "Spoiler Free Mode": "Режим без спойлерів", + "Miscellaneous": "Різне", + "Reload and redraw the currently open chat": "Перезавантажте та перетворіть на новий поточний чат", + "Reload Chat": "Перезавантажити чат", + "Debug Menu": "Меню налагодження", + "Smooth Streaming": "Плавне потокове передавання", + "Experimental feature. May not work for all backends.": "Експериментальна функція. Може працювати не для всіх серверних програм.", + "Slow": "Повільно", + "Fast": "швидко", + "Play a sound when a message generation finishes": "Відтворювати звук, коли завершується генерація повідомлення", + "Message Sound": "Звук повідомлення", + "Only play a sound when ST's browser tab is unfocused": "Відтворювати звук лише тоді, коли вкладка браузера ST неактивна", + "Background Sound Only": "Тільки фоновий звук", + "Reduce the formatting requirements on API URLs": "Зменшити вимоги до форматування URL-адрес API", + "Relaxed API URLS": "Послаблення URL-адреси API", + "Ask to import the World Info/Lorebook for every new character with embedded lorebook. If unchecked, a brief message will be shown instead": "Запитувати імпортувати інформацію про світ/книгу знань для кожного нового персонажа з вбудованою книгою. Якщо не відзначено, замість цього буде показано коротке повідомлення", + "Lorebook Import Dialog": "Діалог імпорту книги знань", + "Restore unsaved user input on page refresh": "Відновлювати незбережений введений користувачем текст при оновленні сторінки", + "Restore User Input": "Відновлення введення користувача", + "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "Дозволяти переміщення деяких елементів інтерфейсу користувача, перетягуючи їх. Тільки для ПК, не впливає на мобільні пристрої", + "Movable UI Panels": "Рухомі панелі", + "MovingUI preset. Predefined/saved draggable positions": "Налаштування рухомого інтерфейсу. Передбачені/збережені позиції елементів, які можна перетягувати", + "MUI Preset": "Попереднє встановлення MUI:", + "Save movingUI changes to a new file": "Зберегти зміни в рухомому інтерфейсі у новий файл", + "Reset MovingUI panel sizes/locations.": "Скинути розміри/розташування панелі MovingUI.", + "Apply a custom CSS style to all of the ST GUI": "Застосовувати власний стиль CSS до всього графічного інтерфейсу ST", + "Custom CSS": "Власний CSS", + "Expand the editor": "Розгорніть редактор", + "Chat/Message Handling": "Обробка чату/повідомлень", + "# Messages to Load": "# Повідомлення Завантажити", + "The number of chat history messages to load before pagination.": "Кількість повідомлень історії чату, які потрібно завантажити перед розбиттям на сторінки.", + "(0 = All)": "(0 = усі)", + "Streaming FPS": "Потоких оновлень на секунду", + "Update speed of streamed text.": "Швидкість оновлення потокового тексту.", + "Example Messages Behavior": "Поведінка прикладів повідомлень", + "Gradual push-out": "Поступова заміна", + "Always include examples": "Завжди включати приклади", + "Never include examples": "Ніколи не включати приклади", + "Send on Enter": "Відправити при натисканні Enter", + "Disabled": "Вимкнено", + "Automatic (PC)": "Автоматично (ПК)", + "Press Send to continue": "Натисніть 'Відправити', щоб продовжити", + "Show a button in the input area to ask the AI to continue (extend) its last message": "Показувати кнопку у області введення для запиту у ШІ про продовження (розширення) його останнього повідомлення", + "Quick 'Continue' button": "Швидка кнопка 'Продовжити'", + "Show arrow buttons on the last in-chat message to generate alternative AI responses. Both PC and mobile": "Показувати кнопки стрілок на останньому повідомленні в чаті, щоб згенерувати альтернативні відповіді ШІ. Як на ПК, так і на мобільних пристроях", + "Swipes": "Змахи", + "Allow using swiping gestures on the last in-chat message to trigger swipe generation. Mobile only, no effect on PC": "Дозвольте використовувати жести перетягування на останньому повідомленні в чаті для запуску генерації змахів. Тільки для мобільних пристроїв, не впливає на ПК", + "Gestures": "Жести", + "Auto-load Last Chat": "Автоматичне завантаження останнього чату", + "Auto-scroll Chat": "Автоматична прокрутка чату", + "Save edits to messages without confirmation as you type": "Зберігати внесені зміни до повідомлень без підтвердження під час набору", + "Auto-save Message Edits": "Автоматичне збереження редагувань повідомлень", + "Confirm message deletion": "Підтвердити видалення повідомлення", + "Auto-fix Markdown": "Автоматичне виправлення Markdown", + "Disallow embedded media from other domains in chat messages": "Заборонити вбудовані мультимедійні дані з інших доменів у повідомленнях чату.", + "Forbid External Media": "Заборонити зовнішні медіа", + "Allow {{char}}: in bot messages": "Дозволити {{char}}: у повідомленнях бота", + "Allow {{user}}: in bot messages": "Дозволити {{user}}: у повідомленнях бота", + "Skip encoding and characters in message text, allowing a subset of HTML markup as well as Markdown": "Пропускати кодування символів < та > у тексті повідомлення, дозволяючи підмножину розмітки HTML, а також Markdown", + "Show tags in responses": "Показати <теги> в відповідях", + "Allow AI messages in groups to contain lines spoken by other group members": "Дозволяти повідомленням ШІ у групах містити рядки, сказані іншими учасниками групи", + "Relax message trim in Groups": "Послаблення обрізання повідомлень у групах", + "Log prompts to console": "Записуйте запити у консоль", + "Requests logprobs from the API for the Token Probabilities feature": "Запитувати імовірності з API для функції ймовірностей токенів", + "Request token probabilities": "Запитувати ймовірності токенів", + "Automatically reject and re-generate AI message based on configurable criteria": "Автоматично відхиляти та знову генерувати повідомлення ШІ на основі налаштованих критеріїв", + "Auto-swipe": "Автоматичний змах", + "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Вмикає функцію автоматичного змаху. Налаштування в цьому розділі діють лише тоді, коли увімкнено автоматичний змах", + "Minimum generated message length": "Мінімальна довжина згенерованого повідомлення", + "If the generated message is shorter than these many characters, trigger an auto-swipe": "Якщо згенероване повідомлення коротше за це, викликайте автоматичний змаху", + "Blacklisted words": "Список заборонених слів", + "words you dont want generated separated by comma ','": "слова, які ви не хочете генерувати, розділені комою ','", + "Blacklisted word count to swipe": "Кількість заборонених слів для змаху", + "Minimum number of blacklisted words detected to trigger an auto-swipe": "Мінімальна кількість заборонених слів, виявлених для запуску автоматичного змаху.", + "AutoComplete Settings": "Налаштування автозаповнення", + "Automatically hide details": "Автоматично приховувати деталі", + "Determines how entries are found for autocomplete.": "Визначає спосіб пошуку записів для автозаповнення.", + "Autocomplete Matching": "Зіставлення", + "Starts with": "Починається з", + "Includes": "Включає в себе", + "Fuzzy": "нечіткий", + "Sets the style of the autocomplete.": "Встановлює стиль автозаповнення.", + "Autocomplete Style": "Стиль", + "Follow Theme": "Слідкуйте за темою", + "Dark": "Темний", + "Sets the font size of the autocomplete.": "Встановлює розмір шрифту автозаповнення.", + "Sets the width of the autocomplete.": "Встановлює ширину автозаповнення.", + "Autocomplete Width": "Ширина", + "chat input box": "поле введення чату", + "entire chat width": "вся ширина чату", + "full window width": "повна ширина вікна", + "STscript Settings": "Налаштування STscript", + "Sets default flags for the STscript parser.": "Встановлює позначки за замовчуванням для аналізатора STscript.", + "Parser Flags": "Прапори аналізатора", + "Switch to stricter escaping, allowing all delimiting characters to be escaped with a backslash, and backslashes to be escaped as well.": "Перейдіть на суворіше екранування, дозволяючи екранувати всі розмежувальні символи зворотною похилою рискою, а також зворотні похилі риски.", + "STRICT_ESCAPING": "STRICT_ESCAPING", + "Replace all {{getvar::}} and {{getglobalvar::}} macros with scoped variables to avoid double macro substitution.": "Замініть усі макроси {{getvar::}} і {{getglobalvar::}} на змінні з областю видимості, щоб уникнути подвійної підстановки макросів.", + "REPLACE_GETVAR": "REPLACE_GETVAR", + "Change Background Image": "Змінити фонове зображення", + "Filter": "Фільтр", + "Automatically select a background based on the chat context": "Автоматичний вибір фону на основі контексту чату", + "Auto-select": "Автовибір", + "System Backgrounds": "Системні фони", + "Chat Backgrounds": "Фони чату", + "bg_chat_hint_1": "Фонове зображення чату, створене за допомогою", + "bg_chat_hint_2": "тут з’явиться розширення.", + "Extensions": "Розширення", + "Notify on extension updates": "Повідомити про оновлення розширень", + "Manage extensions": "Керувати розширеннями", + "Import Extension From Git Repo": "Імпортувати розширення з репозиторію Git", + "Install extension": "Встановити розширення", + "Extras API:": "Додатковий API:", + "Auto-connect": "Автоматичне підключення", + "Extras API URL": "Додаткова URL-адреса API", + "Extras API key (optional)": "Додатковий ключ API (необов'язково)", + "Persona Management": "Управління персонами", + "How do I use this?": "Як це використовувати?", + "Click for stats!": "Клацніть для статистики!", + "Usage Stats": "Статистика використання", + "Backup your personas to a file": "Зробіть резервну копію своїх персон у файл", + "Backup": "Резервне копіювання", + "Restore your personas from a file": "Відновіть свої персони з файлу", + "Restore": "Відновлення", + "Create a dummy persona": "Створити порожню персону", + "Create": "Створити", + "Toggle grid view": "Перемкнути вид сітки", + "No persona description": "[Без опису]", + "Name": "Ім'я", + "Enter your name": "Введіть своє ім'я", + "Click to set a new User Name": "Клацніть, щоб встановити нове ім'я користувача", + "Click to lock your selected persona to the current chat. Click again to remove the lock.": "Клацніть, щоб заблокувати обрану персону в поточному чаті. Клацніть ще раз, щоб видалити блокування.", + "Click to set user name for all messages": "Клацніть, щоб встановити ім'я користувача для всіх повідомлень", + "Persona Description": "Опис персони", + "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "Приклад: [{{user}} - 28-річна румунська дівчина-кішка].", + "Tokens persona description": "Опис персонажа", + "Position:": "Позиція:", + "In Story String / Prompt Manager": "У рядку історії / Менеджері запитів", + "Top of Author's Note": "На вершині примітки автора", + "Bottom of Author's Note": "Унизу примітки автора", + "In-chat @ Depth": "In-chat @ Depth", + "Depth:": "Глибина:", + "Role:": "роль:", + "System": "система", + "User": "Користувач", + "Assistant": "помічник", + "Show notifications on switching personas": "Показувати сповіщення при зміні персон", + "Character Management": "Управління персонажем", + "Locked = Character Management panel will stay open": "Заблоковано = Панель управління персонажем залишиться відкритою", + "Select/Create Characters": "Вибрати/створити персонажів", + "Favorite characters to add them to HotSwaps": "Оберіть улюблених персонажів, щоб додати їх до HotSwaps", + "Token counts may be inaccurate and provided just for reference.": "Лічильники токенів можуть бути неточними і надаються тільки для довідки.", + "Total tokens": "Всього жетонів", + "Calculating...": "Розрахунок...", + "Tokens": "Токени", + "Permanent tokens": "Постійні жетони", + "Permanent": "Постійний", + "About Token 'Limits'": "Про «Обмеження» токенів", + "Toggle character info panel": "Перемкнути панель інформації про персонажа", + "Name this character": "Дайте цьому персонажу ім'я", + "extension_token_counter": "Жетони:", + "Click to select a new avatar for this character": "Клацніть, щоб вибрати новий аватар для цього персонажа", + "Add to Favorites": "Додати до обраного", + "Advanced Definition": "Розширені визначення", + "Character Lore": "Книга знань персонажа", + "Chat Lore": "Історія чату", + "Export and Download": "Експорт і завантаження", + "Duplicate Character": "Дублювати персонажа", + "Create Character": "Створити персонажа", + "Delete Character": "Видалити персонажа", + "More...": "Більше...", + "Link to World Info": "Зв'язати з інформацією про світ", + "Import Card Lore": "Імпортувати книгу знань з картки", + "Scenario Override": "Перевизначити сценарій", + "Convert to Persona": "Перетворити в Persona", + "Rename": "Перейменувати", + "Link to Source": "Посилання на джерело", + "Replace / Update": "Замінити / Оновити", + "Import Tags": "Імпорт тегів", + "Search / Create Tags": "Пошук / Створення тегів", + "View all tags": "Переглянути всі теги", + "Creator's Notes": "Нотатки творця", + "Show / Hide Description and First Message": "Показати / приховати опис і перше повідомлення", + "Character Description": "Опис персонажа", + "Click to allow/forbid the use of external media for this character.": "Натисніть, щоб дозволити/заборонити використання зовнішнього носія для цього персонажа.", + "Ext. Media": "доп. ЗМІ", + "Describe your character's physical and mental traits here.": "Опишіть фізичні та психічні риси вашого персонажа тут.", + "First message": "Перше повідомлення", + "Click to set additional greeting messages": "Клацніть, щоб встановити додаткові привітальні повідомлення", + "Alt. Greetings": "Альт. вітаю", + "This will be the first message from the character that starts every chat.": "Це буде перше повідомлення від персонажа, яке починає кожен чат.", + "Group Controls": "Керування групою", + "Chat Name (Optional)": "Назва чату (необов'язково)", + "Click to select a new avatar for this group": "Клацніть, щоб вибрати новий аватар для цієї групи", + "Group reply strategy": "Стратегія відповіді у групі", + "Natural order": "Звичайний порядок", + "List order": "Порядок списку", + "Group generation handling mode": "Режим обробки групового формування", + "Swap character cards": "Поміняйтеся картками персонажів", + "Join character cards (exclude muted)": "Приєднатися до карток персонажів (за винятком тихих)", + "Join character cards (include muted)": "Приєднатися до карток персонажів (включно з приглушеними)", + "Inserted before each part of the joined fields.": "Вставляється перед кожною частиною об’єднаних полів.", + "Join Prefix": "Префікс приєднання", + "When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and with the name of the part (e.g.: description, personality, scenario, etc.)": "Якщо вибрано «Об’єднати картки персонажів», усі відповідні поля персонажів об’єднуються.\rЦе означає, що, наприклад, у рядку історії всі описи персонажів будуть об’єднані в один великий текст.\rЯкщо ви хочете, щоб ці поля були розділені, ви можете визначити тут префікс або суфікс.\r\rЦе значення підтримує звичайні макроси, а також замінює {{char}} на ім’я відповідного символу, а — на назву частини (наприклад, опис, особистість, сценарій тощо).", + "Inserted after each part of the joined fields.": "Вставляється після кожної частини об’єднаних полів.", + "Join Suffix": "Суфікс приєднання", + "Set a group chat scenario": "Встановити сценарій групового чату", + "Click to allow/forbid the use of external media for this group.": "Натисніть, щоб дозволити/заборонити використання зовнішніх носіїв для цієї групи.", + "Restore collage avatar": "Відновити аватар колажу", + "Allow self responses": "Дозволити відповіді самому собі", + "Auto Mode": "Автоматичний режим", + "Auto Mode delay": "Затримка автоматичного режиму", + "Hide Muted Member Sprites": "Приховати вимкнені спрайти учасників", + "Current Members": "Поточні учасники", + "Add Members": "Додати учасників", + "Create New Character": "Створити нового персонажа", + "Import Character from File": "Імпортувати персонажа з файлу", + "Import content from external URL": "Імпортувати вміст з зовнішнього URL", + "Create New Chat Group": "Створити нову групу чату", + "Characters sorting order": "Порядок сортування персонажів", + "A-Z": "А-Я", + "Z-A": "Я-А", + "Newest": "Найновіші", + "Oldest": "Найстаріші", + "Favorites": "Вибрані", + "Recent": "Останні", + "Most chats": "Більше чатів", + "Least chats": "Менше чатів", + "Most tokens": "Найбільше токенів", + "Least tokens": "Найменше токенів", + "Random": "Випадковий", + "Toggle character grid view": "Перемкнути вид сітки персонажів", + "Bulk_edit_characters": "Масове редагування персонажів", + "Bulk select all characters": "Масове виділення всіх символів", + "Bulk delete characters": "Масове видалення персонажів", + "popup-button-save": "зберегти", + "popup-button-yes": "Так", + "popup-button-no": "Немає", + "popup-button-cancel": "Скасувати", + "popup-button-import": "Імпорт", + "Advanced Definitions": "Розширені визначення", + "Prompt Overrides": "Перевизначення підказок", + "(For Chat Completion and Instruct Mode)": "(Для завершення чату та режиму інструктажу)", + "Insert {{original}} into either box to include the respective default prompt from system settings.": "Вставте {{original}} в будь-яке поле, щоб включити відповідний запит з налаштувань системи.", + "Main Prompt": "Головний запит", + "Any contents here will replace the default Main Prompt used for this character. (v2 spec: system_prompt)": "Будь-який вміст тут замінить типову головний запит, використовуваний для цього персонажа. (v2 специфікація: system_prompt)", + "Any contents here will replace the default Jailbreak Prompt used for this character. (v2 spec: post_history_instructions)": "Будь-який вміст тут замінить запит для джейлбрейку, використовуваний для цього персонажа. (v2 специфікація: post_history_instructions)", + "Creator's Metadata (Not sent with the AI prompt)": "Метадані творця (не надсилаються до ШІ)", + "Creator's Metadata": "Метадані творця", + "(Not sent with the AI Prompt)": "(Не надсилається разом із запитом AI)", + "Everything here is optional": "Все тут є необов'язковим", + "(Botmaker's name / Contact Info)": "(Ім'я розробника бота / Контактна інформація)", + "(If you want to track character versions)": "(Якщо ви хочете відстежувати версії персонажа)", + "(Describe the bot, give use tips, or list the chat models it has been tested on. This will be displayed in the character list.)": "(Опишіть бота, дайте поради щодо використання або перерахуйте моделі чату, на яких він був протестований. Це буде відображатися у списку персонажів.)", + "Tags to Embed": "Теги для вбудовування", + "(Write a comma-separated list of tags)": "(Напишіть список тегів, розділених комами)", + "Personality summary": "Опис особистості", + "(A brief description of the personality)": "(Короткий опис особистості)", + "Scenario": "Сценарій", + "(Circumstances and context of the interaction)": "(Обставини та контекст взаємодії)", + "Character's Note": "Примітка персонажа", + "(Text to be inserted in-chat @ designated depth and role)": "(Текст, який потрібно вставити в чат @ визначена глибина та роль)", + "@ Depth": "@ Глибина", + "Role": "Роль", + "Talkativeness": "Балакучість", + "How often the character speaks in group chats!": "Як часто персонаж розмовляє в групових чатах!", + "How often the character speaks in": "Як часто персонаж говорить", + "group chats!": "групових чатах!", + "Shy": "Сором'язливий", + "Normal": "Нормальний", + "Chatty": "Балакучий", + "Examples of dialogue": "Приклади діалогу", + "Important to set the character's writing style.": "Важливо щоб встановити стиль письма персонажа.", + "(Examples of chat dialog. Begin each example with START on a new line.)": "(Приклади діалогу в чаті. Почніть кожний приклад зі на новому рядку.)", + "Save": "Зберегти", + "Chat History": "Історія чату", + "Import Chat": "Імпорт чату", + "Copy to system backgrounds": "Скопіювати в системні фони", + "Rename background": "Перейменувати фон", + "Lock": "Замок", + "Unlock": "Розблокувати", + "Delete background": "Видалити фон", + "Chat Scenario Override": "Перевизначення сценарію чату", + "Remove": "Видалити", + "Type here...": "Введіть тут...", + "Chat Lorebook": "Чат Lorebook для", + "Chat Lorebook for": "Чат Lorebook для", + "chat_world_template_txt": "Вибрану світову інформацію буде прив’язано до цього чату. Під час генерації відповіді AI,\n він буде поєднаний із записами з глобальних книг і книг персонажів.", + "Select a World Info file for": "Виберіть файл інформації про світ для", + "Primary Lorebook": "Основний збірник легенд", + "A selected World Info will be bound to this character as its own Lorebook.": "Вибрана інформація про світ буде пов'язана з цим персонажем як власна книга знань.", + "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "Під час генерації відповіді ШІ, вона буде поєднана з записами із глобального селектора інформації про світ.", + "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "Експорт персонажа також експортуватиме вибраний файл збірника легенд, вбудований у дані JSON.", + "Additional Lorebooks": "Додаткові книги знань", + "Associate one or more auxillary Lorebooks with this character.": "Асоціюйте одну або кілька допоміжних книг знань з цим персонажем.", + "NOTE: These choices are optional and won't be preserved on character export!": "ПРИМІТКА: Ці вибори є необов'язковими і не будуть збережені при експорті персонажа!", + "Rename chat file": "Перейменувати файл чату", + "Export JSONL chat file": "Експортувати файл чату у форматі JSONL", + "Download chat as plain text document": "Завантажити чат як документ у форматі простого тексту", + "Delete chat file": "Видалити файл чату", + "Use tag as folder": "Позначити як папку", + "Delete tag": "Видалити тег", + "Entry Title/Memo": "Заголовок запису", + "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized❌ Disabled": "Статус вступу до WI:\r🔵 Постійно\r🟢 Нормально\r🔗 Векторизовано\r❌ Вимкнено", + "WI_Entry_Status_Constant": "Постійний", + "WI_Entry_Status_Normal": "нормальний", + "WI_Entry_Status_Vectorized": "Векторизований", + "WI_Entry_Status_Disabled": "Вимкнено", + "T_Position": "↑Символ: перед визначеннями персонажу\n↓Символ: після визначень персонажу\n↑AN: перед авторськими примітками\n↓AN: після авторських приміток\n@D: на глибині", + "Before Char Defs": "↑Визначення персонажу", + "After Char Defs": "↓Визначення персонажу", + "Before EM": "↑EM", + "After EM": "↓EM", + "Before AN": "↑AN", + "After AN": "↓AN", + "at Depth System": "@D ⚙️", + "at Depth User": "@D 👤", + "at Depth AI": "@D 🤖", + "Depth": "Глибина", + "Order:": "Порядок:", + "Order": "Порядок:", + "Trigger %:": "Тригер %:", + "Probability": "Ймовірність", + "Duplicate world info entry": "Подвійний запис інформації про світ", + "Delete world info entry": "Видалити запис інформації про світ", + "Comma separated (required)": "Розділення комами (обов'язково)", + "Primary Keywords": "Основні ключові слова", + "Keywords or Regexes": "Ключові слова або регулярні вирази", + "Comma separated list": "Список, розділений комами", + "Switch to plaintext mode": "Перейти в режим відкритого тексту", + "Logic": "Логіка", + "AND ANY": "І БУДЬ-ЯКІ", + "AND ALL": "І ВСІ", + "NOT ALL": "НЕ ВСІ", + "NOT ANY": "НЕ БУДЬ-ЯКІ", + "(ignored if empty)": "(ігнорується, якщо порожній)", + "Optional Filter": "Додатковий фільтр", + "Keywords or Regexes (ignored if empty)": "Ключові слова або регулярні вирази (ігноруються, якщо пусті)", + "Comma separated list (ignored if empty)": "Список, розділений комами (ігнорується, якщо порожній)", + "Use global setting": "Використовувати глобальні налаштування", + "Case-Sensitive": "З урахуванням регістру", + "Yes": "Так", + "No": "Ні", + "Can be used to automatically activate Quick Replies": "Можна використовувати для автоматичної активації швидких відповідей", + "Automation ID": "Ідентифікатор автоматизації", + "( None )": "( Жодного )", + "Content": "Зміст", + "Exclude from recursion": "Виключити з рекурсії", + "Prevent further recursion (this entry will not activate others)": "Запобігти подальшій рекурсії (цей запис не активує інші)", + "Delay until recursion (this entry can only be activated on recursive checking)": "Затримка до рекурсії (цей запис можна активувати лише під час рекурсивної перевірки)", + "What this keyword should mean to the AI, sent verbatim": "Що це ключове слово повинно означати для ШІ, надсилається дослівно", + "Filter to Character(s)": "Фільтр для персонажів", + "Character Exclusion": "Виключення персонажів", + "-- Characters not found --": "-- Персонажі не знайдені --", + "Inclusion Group": "Група включення", + "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "Групи включення гарантують, що одночасно активується лише один запис із групи, якщо їх активовано декілька.\rПідтримує кілька груп, розділених комами.\r\rДокументація: World Info - Inclusion Group", + "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "Пріоритезувати цей запис: якщо позначено, цей запис має пріоритет серед усіх вибраних.\rЯкщо кілька пріоритетів, вибирається той, який має найвищий «порядок».", + "Only one entry with the same label will be activated": "Буде активовано лише один запис з однією міткою", + "A relative likelihood of entry activation within the group": "Відносна ймовірність активації входу в групу", + "Group Weight": "Вага групи", + "Selective": "Вибірковий", + "Use Probability": "Використовувати ймовірність", + "Add Memo": "Додати нагадування", + "Text or token ids": "Текст або [ідентифікатори маркерів]", + "close": "закрити", + "prompt_manager_edit": "Редагувати", + "prompt_manager_name": "Ім'я", + "A name for this prompt.": "Назва цього підказки.", + "To whom this message will be attributed.": "Кому буде віднесено це повідомлення.", + "AI Assistant": "ШІ помічник", + "prompt_manager_position": "Позиція", + "Injection position. Next to other prompts (relative) or in-chat (absolute).": "Позиція ін'єкції. Поруч з іншими підказками (відносні) або в чаті (абсолютні).", + "prompt_manager_relative": "Відносна", + "prompt_manager_depth": "Глибина", + "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "Глибина ін'єкції. 0 = після останнього повідомлення, 1 = перед останнім повідомленням тощо.", + "Prompt": "Запит", + "The prompt to be sent.": "Підказка для надсилання.", + "This prompt cannot be overridden by character cards, even if overrides are preferred.": "Це підказка не може бути перевизначено картками символів, навіть якщо перевизначення є кращим.", + "prompt_manager_forbid_overrides": "Заборонити перевизначення", + "reset": "скинути", + "save": "зберегти", + "This message is invisible for the AI": "Це повідомлення невидиме для ШІ", + "Message Actions": "Дії з повідомленнями", + "Translate message": "Перекласти повідомлення", + "Generate Image": "Створити зображення", + "Narrate": "Розповідати", + "Exclude message from prompts": "Виключити повідомлення з підказок", + "Include message in prompts": "Включити повідомлення в підказки", + "Embed file or image": "Вбудувати файл або зображення", + "Create checkpoint": "Створити контрольну точку", + "Create Branch": "Створити гілку", + "Copy": "Копіювати", + "Open checkpoint chat": "Відкрити чат КПП", + "Edit": "Редагувати", + "Confirm": "Підтвердити", + "Copy this message": "Скопіювати це повідомлення", + "Delete this message": "Видалити це повідомлення", + "Move message up": "Перемістити повідомлення вгору", + "Move message down": "Перемістити повідомлення вниз", + "Enlarge": "Збільшити", + "Welcome to SillyTavern!": "Ласкаво просимо до SillyTavern!", + "welcome_message_part_1": "Читати", + "welcome_message_part_2": "Офіційна документація", + "welcome_message_part_3": null, + "welcome_message_part_4": "Тип", + "welcome_message_part_5": "у чаті для команд і макросів.", + "welcome_message_part_6": "Приєднуйтесь до", + "Discord server": "Сервер Discord", + "welcome_message_part_7": "для інформації та оголошень.", + "SillyTavern is aimed at advanced users.": "SillyTavern орієнтована на досвідчених користувачів.", + "If you're new to this, enable the simplified UI mode below.": "Якщо ви новачок у цьому, увімкніть спрощений режим інтерфейсу користувача нижче.", + "Change it later in the 'User Settings' panel.": "Змініть це пізніше на панелі «Налаштування користувача».", + "Enable simple UI mode": "Увімкніть простий режим інтерфейсу користувача", + "Looking for AI characters?": "Шукаєте персонажів зі штучним інтелектом?", + "onboarding_import": "Імпорт", + "from supported sources or view": "із підтримуваних джерел або перегляду", + "Sample characters": "Зразок символів", + "Your Persona": "Ваша персона", + "Before you get started, you must select a persona name.": "Перш ніж почати, ви повинні вибрати ім'я особи.", + "welcome_message_part_8": "Це можна будь-коли змінити за допомогою", + "welcome_message_part_9": "значок.", + "Persona Name:": "Ім'я особи:", + "Temporarily disable automatic replies from this character": "Тимчасово вимкнути автоматичні відповіді від цього персонажа", + "Enable automatic replies from this character": "Увімкнути автоматичні відповіді від цього персонажа", + "Trigger a message from this character": "Викликати повідомлення від цього персонажа", + "Move up": "Перемістити вгору", + "Move down": "Перемістити вниз", + "View character card": "Переглянути картку персонажа", + "Remove from group": "Вилучити з групи", + "Add to group": "Додати до групи", + "Alternate Greetings": "Альтернативні привітання", + "Alternate_Greetings_desc": "Вони відображатимуться як гортання по першому повідомленню під час початку нового чату.\n Учасники групи можуть вибрати одного з них, щоб розпочати розмову.", + "Alternate Greetings Hint": "Натисніть кнопку, щоб почати!", + "(This will be the first message from the character that starts every chat)": "(Це буде перше повідомлення від персонажа, яке починає кожен чат)", + "Forbid Media Override explanation": "Можливість поточного персонажа/групи використовувати зовнішні носії в чатах.", + "Forbid Media Override subtitle": "Медіа: зображення, відео, аудіо. Зовнішній: не розміщений на локальному сервері.", + "Always forbidden": "Завжди заборонено", + "Always allowed": "Завжди дозволено", + "View contents": "Переглянути вміст", + "Remove the file": "Видаліть файл", + "Unique to this chat": "Унікальний для цього чату", + "Checkpoints inherit the Note from their parent, and can be changed individually after that.": "Контрольні точки успадковують Примітку від свого батька і можуть бути змінені окремо після цього.", + "Include in World Info Scanning": "Включити в World Info Scanning", + "Before Main Prompt / Story String": "Перед головною підказкою / рядком історії", + "After Main Prompt / Story String": "Після основного підказки / рядка історії", + "as": "як", + "Insertion Frequency": "Частота введення", + "(0 = Disable, 1 = Always)": "(0 = вимкнено, 1 = завжди)", + "User inputs until next insertion:": "Введення користувача до наступного вставлення:", + "Character Author's Note (Private)": "Примітка автора персонажа (приватна)", + "Won't be shared with the character card on export.": "Не буде надано спільний доступ до картки персонажа під час експорту.", + "Will be automatically added as the author's note for this character. Will be used in groups, but can't be modified when a group chat is open.": "Буде автоматично додано як примітку автора для цього персонажа. Буде використовуватися в групах, але\n не можна змінити, коли відкрито груповий чат.", + "Use character author's note": "Використовуйте примітку автора персонажа", + "Replace Author's Note": "Замінити примітку автора", + "Default Author's Note": "Примітка автора за замовчуванням", + "Will be automatically added as the Author's Note for all new chats.": "Буде автоматично додано як примітку автора для всіх нових чатів.", + "Chat CFG": "Чат CFG", + "1 = disabled": "1 = вимкнено", + "write short replies, write replies using past tense": "писати короткі відповіді, писати відповіді, використовуючи минулий час", + "Positive Prompt": "Позитивна підказка", + "Use character CFG scales": "Використовуйте шкали CFG символів", + "Character CFG": "CFG символів", + "Will be automatically added as the CFG for this character.": "Буде автоматично додано як CFG для цього персонажа.", + "Global CFG": "Глобальна CFG", + "Will be used as the default CFG options for every chat unless overridden.": "Використовуватиметься як параметри CFG за замовчуванням для кожного чату, якщо не буде замінено.", + "CFG Prompt Cascading": "CFG Prompt Cascading", + "Combine positive/negative prompts from other boxes.": "Поєднайте позитивні/негативні підказки з інших ящиків.", + "For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string.": "Наприклад, відмічаючи поля чату, глобального та символьного, усі негативні підказки об’єднуються в рядок, розділений комами.", + "Always Include": "Завжди включати", + "Chat Negatives": "Негативи чату", + "Character Negatives": "Негативні символи", + "Global Negatives": "Глобальні негативи", + "Custom Separator:": "Спеціальний роздільник:", + "Insertion Depth:": "Глибина вставки:", + "Token Probabilities": "Ймовірності токенів", + "Select a token to see alternatives considered by the AI.": "Виберіть маркер, щоб побачити альтернативи, розглянуті ШІ.", + "Not connected to API!": "Не підключено до API!", + "Type a message, or /? for help": "Введіть повідомлення або /? для допомоги", + "Continue script execution": "Продовжити виконання сценарію", + "Pause script execution": "Призупинити виконання сценарію", + "Abort script execution": "Перервати виконання сценарію", + "Abort request": "Скасувати запит", + "Continue the last message": "Продовжити останнє повідомлення", + "Send a message": "Надіслати повідомлення", + "Close chat": "Закрити чат", + "Toggle Panels": "Перемикати панелі", + "Back to parent chat": "Повернутися до головного чату", + "Save checkpoint": "Зберегти КПП", + "Convert to group": "Перетворити на групу", + "Start new chat": "Розпочати новий чат", + "Manage chat files": "Керувати файлами чату", + "Delete messages": "Видалити повідомлення", + "Regenerate": "Регенерувати", + "Ask AI to write your message for you": "Попросити ШІ написати ваше повідомлення за вас", + "Impersonate": "Перевтілення", + "Continue": "Продовжити", + "Bind user name to that avatar": "Прив'язати ім'я користувача до цього аватара", + "Change persona image": "Змінити зображення особистості", + "Select this as default persona for the new chats.": "Виберіть це як типову персону для нових чатів.", + "Delete persona": "Видалити персону", + "These characters are the winners of character design contests and have outstandable quality.": "Ці персонажі є переможцями конкурсів дизайну персонажів і мають надзвичайну якість.", + "Contest Winners": "Переможці конкурсу", + "These characters are the finalists of character design contests and have remarkable quality.": "Ці персонажі є фіналістами конкурсів дизайну персонажів і мають надзвичайну якість.", + "Featured Characters": "Вибрані персонажі", + "Attach a File": "Прикріпити файл", + "Open Data Bank": "Відкритий банк даних", + "Enter a URL or the ID of a Fandom wiki page to scrape:": "Введіть URL-адресу або ідентифікатор вікі-сторінки Fandom, яку потрібно отримати:", + "Examples:": "приклади:", + "Example:": "приклад:", + "Single file": "Один файл", + "All articles will be concatenated into a single file.": "Усі статті будуть об’єднані в один файл.", + "File per article": "Файл на статтю", + "Each article will be saved as a separate file.": "Не рекомендовано. Кожна стаття буде збережена як окремий файл.", + "Data Bank": "Банк даних", + "These files will be available for extensions that support attachments (e.g. Vector Storage).": "Ці файли будуть доступні для розширень, які підтримують вкладення (наприклад, Vector Storage).", + "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.": "Підтримувані типи файлів: звичайний текст, PDF, Markdown, HTML, EPUB.", + "Drag and drop files here to upload.": "Перетягніть файли сюди, щоб завантажити.", + "Date (Newest First)": "Дата (Спочатку найновіші)", + "Date (Oldest First)": "Дата (спочатку найдавніші)", + "Name (A-Z)": "Ім'я (А-Я)", + "Name (Z-A)": "Ім'я (Я-А)", + "Size (Smallest First)": "Розмір (спочатку найменший)", + "Size (Largest First)": "Розмір (спочатку найбільший)", + "Bulk Edit": "Масове редагування", + "Select All": "Вибрати все", + "Select None": "Виберіть Немає", + "Global Attachments": "Глобальні вкладення", + "These files are available for all characters in all chats.": "Ці файли доступні для всіх персонажів у всіх чатах.", + "Character Attachments": "Вкладення символів", + "These files are available the current character in all chats they are in.": "Ці файли доступні поточному персонажу в усіх чатах, у яких він перебуває.", + "Saved locally. Not exported.": "Збережено локально. Не експортовано.", + "Chat Attachments": "Вкладення чату", + "These files are available to all characters in the current chat.": "Ці файли доступні для всіх персонажів поточного чату.", + "Enter a base URL of the MediaWiki to scrape.": "Введіть базову URL-адресу MediaWiki, яку потрібно отримати.", + "Don't include the page name!": "Не вказуйте назву сторінки!", + "Enter web URLs to scrape (one per line):": "Введіть URL-адреси веб-сторінок для сканування (по одній на рядок):", + "Enter a video URL to download its transcript.": "Введіть URL-адресу або ідентифікатор відео, щоб завантажити його текст.", + "Expression API": "Місцевий\nДодатково\nмагістр права", + "ext_sum_with": "Підсумуйте за допомогою:", + "ext_sum_main_api": "Основний API", + "ext_sum_current_summary": "Поточне резюме:", + "ext_sum_restore_previous": "Відновити попередній", + "ext_sum_memory_placeholder": "Зведення буде створено тут...", + "Trigger a summary update right now.": "Підведіть підсумки зараз", + "ext_sum_force_text": "Підведіть підсумки зараз", + "Disable automatic summary updates. While paused, the summary remains as-is. You can still force an update by pressing the Summarize now button (which is only available with the Main API).": "Вимкніть автоматичне оновлення підсумків. Під час паузи підсумок залишається таким, як є. Ви все ще можете примусово оновити, натиснувши кнопку «Підсумувати зараз» (яка доступна лише в основному API).", + "ext_sum_pause": "Пауза", + "Omit World Info and Author's Note from text to be summarized. Only has an effect when using the Main API. The Extras API always omits WI/AN.": "Пропустіть інформацію про світ і примітку автора з тексту, який потрібно підсумувати. Діє лише під час використання основного API. Extras API завжди пропускає WI/AN.", + "ext_sum_no_wi_an": "Немає WI/AN", + "ext_sum_settings_tip": "Редагувати підказку підсумовування, позицію вставки тощо.", + "ext_sum_settings": "Підсумкові налаштування", + "ext_sum_prompt_builder": "Оперативний забудовник", + "ext_sum_prompt_builder_1_desc": "Розширення створить власну підказку, використовуючи повідомлення, які ще не були підсумовані. Блокує чат, доки не буде згенеровано підсумок.", + "ext_sum_prompt_builder_1": "Сирий, блокуючий", + "ext_sum_prompt_builder_2_desc": "Розширення створить власну підказку, використовуючи повідомлення, які ще не були підсумовані. Не блокує чат під час генерації зведення. Не всі серверні модулі підтримують цей режим.", + "ext_sum_prompt_builder_2": "Необроблений, неблокуючий", + "ext_sum_prompt_builder_3_desc": "Розширення використовуватиме звичайний конструктор головних підказок і додасть до нього підсумковий запит як останнє системне повідомлення.", + "ext_sum_prompt_builder_3": "Класичний, блокуючий", + "Summary Prompt": "Резюме", + "ext_sum_restore_default_prompt_tip": "Відновити запит за замовчуванням", + "ext_sum_prompt_placeholder": "Це підказка буде надіслано ШІ для запиту створення підсумку. {{words}} перетворює на параметр «Кількість слів».", + "ext_sum_target_length_1": "Цільова довжина резюме", + "ext_sum_target_length_2": null, + "ext_sum_target_length_3": "слова)", + "ext_sum_api_response_length_1": "Довжина відповіді API", + "ext_sum_api_response_length_2": null, + "ext_sum_api_response_length_3": "жетони)", + "ext_sum_0_default": "0 = за замовчуванням", + "ext_sum_raw_max_msg": "[Raw] Максимальна кількість повідомлень на запит", + "ext_sum_0_unlimited": "0 = необмежений", + "Update frequency": "Частота оновлення", + "ext_sum_update_every_messages_1": "Оновлювати кожен", + "ext_sum_update_every_messages_2": "повідомлення", + "ext_sum_0_disable": "0 = вимкнено", + "ext_sum_auto_adjust_desc": "Спробуйте автоматично налаштувати інтервал на основі показників чату.", + "ext_sum_update_every_words_1": "Оновлювати кожен", + "ext_sum_update_every_words_2": "слова", + "ext_sum_both_sliders": "Якщо обидва повзунки відрізняються від нуля, обидва запускатимуть підсумкові оновлення через відповідні інтервали.", + "ext_sum_injection_template": "Шаблон ін'єкції", + "ext_sum_memory_template_placeholder": "{{summary}} перейде до поточного вмісту резюме.", + "ext_sum_injection_position": "Позиція ін'єкції", + "How many messages before the current end of the chat.": "Скільки повідомлень до поточного завершення чату.", + "ext_regex_title": "Регулярний вираз", + "ext_regex_new_global_script": "+ Глобальний", + "ext_regex_new_scoped_script": "+ Огляд", + "ext_regex_import_script": "Імпорт", + "ext_regex_global_scripts": "Глобальні сценарії", + "ext_regex_global_scripts_desc": "Доступно для всіх персонажів. Збережено в локальних налаштуваннях.", + "ext_regex_scoped_scripts": "Охоплені сценарії", + "ext_regex_scoped_scripts_desc": "Доступно лише для цього персонажа. Збережено в даних картки.", + "Regex Editor": "Редактор регулярних виразів", + "Test Mode": "Тестовий режим", + "ext_regex_desc": "Regex — це інструмент для пошуку/заміни рядків за допомогою регулярних виразів. Якщо ви хочете дізнатися більше, натисніть на ? поруч із заголовком.", + "Input": "Введення", + "ext_regex_test_input_placeholder": "Друкуйте тут...", + "Output": "Вихід", + "ext_regex_output_placeholder": "Порожній", + "Script Name": "Назва сценарію", + "Find Regex": "Знайдіть Regex", + "Replace With": "Замінити", + "ext_regex_replace_string_placeholder": "Використовуйте {{match}}, щоб включити відповідний текст із Find Regex або $1, $2 тощо для груп захоплення.", + "Trim Out": "Обрізати", + "ext_regex_trim_placeholder": "Глобально видаляє будь-які небажані частини зі збігу регулярного виразу перед заміною. Відокремте кожен елемент за допомогою enter.", + "ext_regex_affects": "Впливає", + "ext_regex_user_input": "Введення користувача", + "ext_regex_ai_output": "Вихід AI", + "Slash Commands": "Слеш команди", + "ext_regex_min_depth_desc": "Якщо застосувати до підказок або відображення, впливати лише на повідомлення, що містять принаймні N рівнів. 0 = останнє повідомлення, 1 = передостаннє повідомлення тощо. Враховуються лише записи WI @Depth і придатні для використання повідомлення, тобто не приховані чи системні.", + "Min Depth": "Мінімальна глибина", + "ext_regex_min_depth_placeholder": "Необмежений", + "ext_regex_max_depth_desc": "Якщо застосувати до підказок або відображення, впливати лише на повідомлення не більше N рівнів. 0 = останнє повідомлення, 1 = передостаннє повідомлення тощо. Враховуються лише записи WI @Depth і придатні для використання повідомлення, тобто не приховані чи системні.", + "ext_regex_other_options": "Інші параметри", + "Only Format Display": "Лише форматувати дисплей", + "ext_regex_only_format_prompt_desc": "Історія чату не зміниться, лише підказка під час надсилання запиту (під час створення).", + "Only Format Prompt (?)": "Лише запит на форматування", + "Run On Edit": "Запустіть на редагуванні", + "ext_regex_substitute_regex_desc": "Замініть {{макроси}} у Find Regex перед його запуском", + "Substitute Regex": "Замініть Regex", + "ext_regex_import_target": "Імпорт до:", + "ext_regex_disable_script": "Вимкнути скрипт", + "ext_regex_enable_script": "Увімкнути сценарій", + "ext_regex_edit_script": "Редагувати сценарій", + "ext_regex_move_to_global": "Перейти до глобальних сценаріїв", + "ext_regex_move_to_scoped": "Перейти до сценаріїв із обмеженою областю", + "ext_regex_export_script": "Скрипт експорту", + "ext_regex_delete_script": "Видалити сценарій", + "Trigger Stable Diffusion": "Тригер стабільної дифузії", + "sd_Yourself": "себе", + "sd_Your_Face": "Твоє обличчя", + "sd_Me": "я", + "sd_The_Whole_Story": "Вся історія", + "sd_The_Last_Message": "Останнє повідомлення", + "sd_Raw_Last_Message": "Необроблене останнє повідомлення", + "sd_Background": "Фон", + "Image Generation": "Генерація зображень", + "sd_refine_mode": "Дозвольте редагувати підказки вручну, перш ніж надсилати їх до API генерації", + "sd_refine_mode_txt": "Редагувати підказки перед створенням", + "sd_interactive_mode": "Автоматично створювати зображення під час надсилання повідомлень на зразок \"надішліть мені фотографію кота\".", + "sd_interactive_mode_txt": "Інтерактивний режим", + "sd_multimodal_captioning": "Використовуйте мультимодальні субтитри, щоб створювати підказки для портретів користувачів і персонажів на основі їхніх аватарів.", + "sd_multimodal_captioning_txt": "Використовуйте мультимодальні субтитри для портретів", + "sd_expand": "Автоматично розширюйте підказки за допомогою моделі генерації тексту", + "sd_expand_txt": "Підказки автоматичного покращення", + "sd_snap": "Запити на створення прив’язки з примусовим співвідношенням сторін (портрети, фон) до найближчої відомої роздільної здатності, намагаючись зберегти абсолютну кількість пікселів (рекомендовано для SDXL).", + "sd_snap_txt": "Зніміть роздільну здатність із автоматичним налаштуванням", + "Source": "Джерело", + "sd_auto_url": "Приклад: {{auto_url}}", + "Authentication (optional)": "Автентифікація (необов'язково)", + "Example: username:password": "Приклад: ім'я користувача: пароль", + "Important:": "Важливо:", + "sd_auto_auth_warning_1": "запустіть SD Web UI за допомогою", + "sd_auto_auth_warning_2": "прапор! Сервер має бути доступним із хост-машини SillyTavern.", + "sd_drawthings_url": "Приклад: {{drawthings_url}}", + "sd_drawthings_auth_txt": "запустіть програму DrawThings із увімкненим перемикачем HTTP API в інтерфейсі користувача! Сервер має бути доступним із хост-машини SillyTavern.", + "sd_vlad_url": "Приклад: {{vlad_url}}", + "The server must be accessible from the SillyTavern host machine.": "Сервер має бути доступним із хост-машини SillyTavern.", + "Hint: Save an API key in AI Horde API settings to use it here.": "Підказка: збережіть ключ API в налаштуваннях AI Horde API, щоб використовувати його тут.", + "Allow NSFW images from Horde": "Дозволити зображення NSFW від Horde", + "Sanitize prompts (recommended)": "Очистити підказки (рекомендовано)", + "Automatically adjust generation parameters to ensure free image generations.": "Автоматично налаштовуйте параметри генерації, щоб забезпечити вільне створення зображень.", + "Avoid spending Anlas": "Уникайте витрат Anlas", + "Opus tier": "(рівень Opus)", + "View my Anlas": "Переглянути мій Anlas", + "These settings only apply to DALL-E 3": "Ці налаштування застосовуються лише до DALL-E 3", + "Image Style": "Стиль зображення", + "Image Quality": "Якість зображення", + "Standard": "Стандартний", + "HD": "HD", + "sd_comfy_url": "Приклад: {{comfy_url}}", + "Open workflow editor": "Відкрийте редактор робочих процесів", + "Create new workflow": "Створіть новий робочий процес", + "Delete workflow": "Видалити робочий процес", + "Enhance": "Поліпшення", + "Refine": "Уточніть", + "Decrisper": "Декриспер", + "Sampling steps": "Етапи вибірки ()", + "Width": "Ширина ()", + "Height": "Висота ()", + "Resolution": "резолюція", + "Model": "Модель", + "Sampling method": "Метод відбору проб", + "Karras (not all samplers supported)": "Karras (підтримуються не всі семплери)", + "SMEA versions of samplers are modified to perform better at high resolution.": "Версії семплерів SMEA модифіковано для кращої роботи при високій роздільній здатності.", + "SMEA": "SMEA", + "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "Варіанти DYN семплерів SMEA часто дають більш різноманітний вихід, але можуть вийти з ладу при дуже високій роздільній здатності.", + "DYN": "DYN", + "Scheduler": "Планувальник", + "Restore Faces": "Відновити обличчя", + "Hires. Fix": "Наймає. Виправити", + "Upscaler": "Upscaler", + "Upscale by": "Висококласний за", + "Denoising strength": "Сила шумозаглушення", + "Hires steps (2nd pass)": "Наймає кроки (2-й прохід)", + "Preset for prompt prefix and negative prompt": "Попереднє налаштування для префікса підказки та негативного підказки", + "Style": "Стиль", + "Save style": "Зберегти стиль", + "Delete style": "Видалити стиль", + "Common prompt prefix": "Загальний префікс підказки", + "sd_prompt_prefix_placeholder": "Використовуйте {prompt}, щоб указати, куди буде вставлено згенерований запит", + "Negative common prompt prefix": "Негативний загальний префікс запиту", + "Character-specific prompt prefix": "Префікс підказки для певного символу", + "Won't be used in groups.": "Не буде використовуватися в групах.", + "sd_character_prompt_placeholder": "Будь-які характеристики, які описують поточного обраного персонажа. Буде додано після загального префікса запиту.\nПриклад: жінка, зелені очі, каштанове волосся, рожева сорочка", + "Character-specific negative prompt prefix": "Специфічний негативний префікс підказки", + "sd_character_negative_prompt_placeholder": "Будь-які характеристики, які не повинні з’являтися для вибраного персонажа. Буде додано після негативного загального префікса запиту.\nПриклад: прикраси, взуття, окуляри", + "Shareable": "Можна поділитися", + "Image Prompt Templates": "Шаблони підказок із зображеннями", + "Vectors Model Warning": "Рекомендується очистити вектори під час зміни моделі в середині чату. Інакше це призведе до негативних результатів.", + "Translate files into English before processing": "Перекладіть файли англійською мовою перед обробкою", + "Manager Users": "Керувати користувачами", + "New User": "Новий користувач", + "Status:": "Статус:", + "Created:": "Створено:", + "Display Name:": "Відображуване ім'я:", + "User Handle:": "Ідентифікатор користувача:", + "Password:": "Пароль:", + "Confirm Password:": "Підтвердьте пароль:", + "This will create a new subfolder...": "Це створить нову вкладену папку в каталозі /data/ з ідентифікатором користувача як ім’я папки.", + "Current Password:": "Поточний пароль:", + "New Password:": "Новий пароль:", + "Confirm New Password:": "Підтвердити новий пароль:", + "Debug Warning": "Функції цієї категорії призначені лише для досвідчених користувачів. Не натискайте нічого, якщо ви не впевнені в наслідках.", + "Execute": "Виконати", + "Are you sure you want to delete this user?": "Ви впевнені, що хочете видалити цього користувача?", + "Deleting:": "Видалення:", + "Also wipe user data.": "Також стерти дані користувача.", + "Warning:": "УВАГА:", + "This action is irreversible.": "Ця дія незворотна.", + "Type the user's handle below to confirm:": "Введіть дескриптор користувача нижче, щоб підтвердити:", + "Import Characters": "Імпорт символів", + "Enter the URL of the content to import": "Введіть URL-адресу вмісту для імпорту", + "Supported sources:": "Підтримувані джерела:", + "char_import_1": "Головний персонаж (пряме посилання або ідентифікатор)", + "char_import_example": "приклад:", + "char_import_2": "Chub Lorebook (пряме посилання або ID)", + "char_import_3": "Символ JanitorAI (пряме посилання або UUID)", + "char_import_4": "Символ Pygmalion.chat (пряме посилання або UUID)", + "char_import_5": "Символ AICharacterCards.com (пряме посилання або ідентифікатор)", + "char_import_6": "Пряме посилання на PNG (див", + "char_import_7": "для дозволених хостів)", + "char_import_8": "Персонаж RisuRealm (пряме посилання)", + "Supports importing multiple characters.": "Підтримується імпорт кількох символів.", + "Write each URL or ID into a new line.": "Напишіть кожну URL-адресу або ідентифікатор у новому рядку.", + "Export for character": "Експорт для персонажа", + "Export prompts for this character, including their order.": "Експортуйте підказки для цього персонажа, включаючи їх порядок.", + "Export all": "Експортувати все", + "Export all your prompts to a file": "Експортуйте всі підказки у файл", + "Insert prompt": "Вставити підказку", + "Delete prompt": "Видалити підказку", + "Import a prompt list": "Імпортувати список підказок", + "Export this prompt list": "Експортувати цей список підказок", + "Reset current character": "Скинути поточного персонажа", + "New prompt": "Нова підказка", + "Prompts": "Підказки", + "Total Tokens:": "Загальна кількість токенів:", + "prompt_manager_tokens": "Жетони", + "Are you sure you want to reset your settings to factory defaults?": "Ви впевнені, що бажаєте скинути налаштування до заводських?", + "Don't forget to save a snapshot of your settings before proceeding.": "Перш ніж продовжити, не забудьте зберегти знімок ваших налаштувань.", + "Settings Snapshots": "Налаштування Знімки", + "Record a snapshot of your current settings.": "Запишіть знімок поточних налаштувань.", + "Make a Snapshot": "Зробіть знімок", + "Restore this snapshot": "Відновити цей знімок", + "Hi,": "Привіт,", + "To enable multi-account features, restart the SillyTavern server with": "Щоб увімкнути функції кількох облікових записів, перезапустіть сервер SillyTavern за допомогою", + "set to true in the config.yaml file.": "встановити значення true у файлі config.yaml.", + "Account Info": "Інформація про обліковий запис", + "To change your user avatar, use the buttons below or select a default persona in the Persona Management menu.": "Щоб змінити свій аватар користувача, скористайтеся кнопками нижче або виберіть персонаж за замовчуванням у меню «Керування особами».", + "Set your custom avatar.": "Встановіть свій власний аватар.", + "Remove your custom avatar.": "Видаліть свій власний аватар.", + "Handle:": "Ручка:", + "This account is password protected.": "Цей обліковий запис захищено паролем.", + "This account is not password protected.": "Цей обліковий запис не захищено паролем.", + "Account Actions": "Дії облікового запису", + "Change Password": "Змінити пароль", + "Manage your settings snapshots.": "Керуйте своїми знімками налаштувань.", + "Download a complete backup of your user data.": "Завантажте повну резервну копію ваших даних користувача.", + "Download Backup": "Завантажте резервну копію", + "Danger Zone": "НЕБЕЗПЕЧНА ЗОНА", + "Reset your settings to factory defaults.": "Скиньте налаштування до заводських.", + "Reset Settings": "Скинути налаштування", + "Wipe all user data and reset your account to factory settings.": "Видаліть усі дані користувача та скиньте обліковий запис до заводських налаштувань.", + "Reset Everything": "Скинути все", + "Reset Code:": "Скинути код:", + "Want to update?": "Хочете оновити?", + "How to start chatting?": "Як почати спілкування?", + "Click _space": "Натисніть", + "and select a": "і виберіть", + "Chat API": "API чату", + "and pick a character.": "і виберіть персонажа.", + "You can browse a list of bundled characters in the": "Ви можете переглянути список об’єднаних символів у", + "Download Extensions & Assets": "Завантажити розширення та ресурси", + "menu within": "меню всередині", + "Confused or lost?": "Збентежені чи загублені?", + "click these icons!": "клацніть на ці іконки!", + "in the chat bar": "в рядку чату", + "SillyTavern Documentation Site": "Сайт документації SillyTavern", + "Extras Installation Guide": "Посібник з встановлення додаткових компонентів", + "Still have questions?": "Все ще є питання?", + "Join the SillyTavern Discord": "Приєднуйтесь до SillyTavern Discord", + "Post a GitHub issue": "Опублікуйте проблему на GitHub", + "Contact the developers": "Зв'яжіться з розробниками" +} diff --git a/jiuguan2025cc/public/locales/vi-vn.json b/jiuguan2025cc/public/locales/vi-vn.json new file mode 100644 index 0000000000000000000000000000000000000000..09441d68ab5caba42535bb3ac080160a1fd3f8e3 --- /dev/null +++ b/jiuguan2025cc/public/locales/vi-vn.json @@ -0,0 +1,1443 @@ +{ + "Favorite": "Yêu thích", + "Tag": "Từ khóa", + "Duplicate": "Nhân đôi", + "Persona": "Nhân cách", + "Delete": "Xóa", + "AI Response Configuration": "Setting Phản hồi của AI", + "AI Configuration panel will stay open": "Bảng Setting AI sẽ luôn được mở", + "clickslidertips": "Nhấp vào thanh trượt để nhập giá trị bằng tay.", + "MAD LAB MODE ON": "CHẾ ĐỘ PHÒNG THÍ NGHIỆM ĐIÊN RỒ ĐANG BẬT", + "Documentation on sampling parameters": "Tài liệu về các tham số lấy mẫu", + "kobldpresets": "Cài đặt trước Kobold", + "guikoboldaisettings": "Cài đặt giao diện KoboldAI", + "Update current preset": "Cập nhật thiết lập hiện tại", + "Save preset as": "Lưu cài đặt trước dưới dạng", + "Import preset": "Nhập preset", + "Export preset": "Xuất preset", + "Restore current preset": "Khôi phục cài đặt hiện tại", + "Delete the preset": "Xóa preset", + "novelaipresets": "NovelAI presets", + "Default": "Mặc định", + "openaipresets": "OpenAI presets", + "Text Completion presets": "Preset cho Text Completion", + "AI Module": "Mô-đun AI", + "Changes the style of the generated text.": "Thay đổi kiểu của văn bản được tạo.", + "No Module": "Không có mô-đun", + "Instruct": "Instruct", + "Prose Augmenter": "Gia tố văn xuôi", + "Text Adventure": "Phiêu lưu văn bản", + "response legth(tokens)": "Độ dài của văn phản hồi (trong các token)", + "Streaming": "Phát trực tiếp", + "Streaming_desc": "Hiển thị văn phản hồi kí tự từng chút một khi nó được tạo.", + "context size(tokens)": "Kích cỡ Context (token)", + "unlocked": "Đã mở", + "Only enable this if your model supports context sizes greater than 4096 tokens": "Chỉ bật tính năng này nếu AI model của bạn hỗ trợ Context size lớn hơn 4096 token.", + "Max prompt cost:": "Chi phí cho prompt tối đa:", + "Display the response bit by bit as it is generated.": "Hiển thị phản hồi từ từ khi nó được tạo ra.", + "When this is off, responses will be displayed all at once when they are complete.": "Khi tắt tính năng này, các phản hồi sẽ được hiển thị cùng lúc khi chúng hoàn thành.", + "Temperature": "Nhiệt Độ (Temperature)", + "rep.pen": "rep.pen", + "Rep. Pen. Range.": "Rep. Pen. Range.", + "Rep. Pen. Slope": "Rep. Pen. Slope", + "Rep. Pen. Freq.": "Rep. Pen. Freq.", + "Rep. Pen. Presence": "Rep. Pen. Presence", + "TFS": "TFS", + "Phrase Repetition Penalty": "Phrase Repetition Penalty", + "Off": "Tắt", + "Very light": "Rất nhẹ", + "Light": "Nhẹ", + "Medium": "Trung bình", + "Aggressive": "Quyết đoán", + "Very aggressive": "Rất quyết đoán", + "Unlocked Context Size": "Kích thước context đã mở khóa", + "Unrestricted maximum value for the context slider": "Giá trị tối đa không giới hạn cho thanh trượt context", + "Context Size (tokens)": "Kích thước context (token)", + "Max Response Length (tokens)": "Độ dài phản hồi tối đa (token)", + "Multiple swipes per generation": "Vuốt nhiều lần trong một lần tạo", + "Enable OpenAI completion streaming": "Bật streaming của OpenAI", + "Frequency Penalty": "Frequency Penalty", + "Presence Penalty": "Presence Penalty", + "Count Penalty": "Count Penalty", + "Top K": "Top K", + "Top P": "Top P", + "Repetition Penalty": "Repetition Penalty", + "Min P": "Min P", + "Top A": "Top A", + "Quick Prompts Edit": "Chỉnh sửa nhanh prompt", + "Main": "Chính", + "NSFW": "NSFW", + "Jailbreak": "Bẻ khóa (Jailbreak)", + "Utility Prompts": "Tiện ích cho prompt", + "Impersonation prompt": "Giả danh văn thoại", + "Restore default prompt": "Khôi phục lại prompt mặc định", + "Prompt that is used for Impersonation function": "Prompt được sử dụng cho tính năng Giả danh", + "World Info Format Template": "Mẫu định dạng cho World Info", + "Restore default format": "Khôi phục định dạng mặc định", + "Wraps activated World Info entries before inserting into the prompt.": "Bao bọc các mục World Info đã kích hoạt trước khi chèn vào Prompt.", + "scenario_format_template_part_1": "Sử dụng", + "scenario_format_template_part_2": "để đánh dấu nơi chèn nội dung.", + "Scenario Format Template": "Mẫu định dạng kịch bản", + "Personality Format Template": "Mẫu cho định dạng Nhân cách", + "Group Nudge Prompt Template": "Mẫu cho Prompt của Nhóm", + "Sent at the end of the group chat history to force reply from a specific character.": "Được chèn vào cuối lịch sử trò chuyện nhóm để buộc một nhân vật cụ thể phải trả đáp.", + "New Chat": "Cuộc trò truyện mới", + "Restore new chat prompt": "Khôi phục Prompt cho trò chuyện mới", + "Set at the beginning of the chat history to indicate that a new chat is about to start.": "Được đặt ở đầu lịch sử trò chuyện để cho biết một cuộc trò chuyện mới sắp bắt đầu.", + "New Group Chat": "Trò chuyện nhóm mới", + "Restore new group chat prompt": "Khôi phục Prompt mặc định", + "Set at the beginning of the chat history to indicate that a new group chat is about to start.": "Đặt ở đầu lịch sử trò chuyện để cho biết cuộc trò chuyện nhóm mới sắp bắt đầu.", + "New Example Chat": "Mẫu trò chuyện mới", + "Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.": "Đặt ở đầu Ví dụ hội thoại để cho biết rằng một cuộc trò chuyện mẫu mới sắp bắt đầu.", + "Continue nudge": "Tiếp tục thúc giục", + "Set at the end of the chat history when the continue button is pressed.": "Đặt ở cuối lịch sử trò chuyện khi nhấn nút tiếp tục.", + "Replace empty message": "Thay thế văn bản trống", + "Send this text instead of nothing when the text box is empty.": "Gửi văn bản này thay vì không gì khi ô văn bản đang bị trống.", + "Seed": "Hạt giống (Seed)", + "Set to get deterministic results. Use -1 for random seed.": "Đặt để có được kết quả xác định. Sử dụng -1 cho hạt giống (seed) ngẫu nhiên.", + "Temperature controls the randomness in token selection": "Nhiệt độ (Temp) điều chỉnh sự ngẫu nhiên trong việc chọn token:\n- Nhiệt độ thấp (<1.0) dẫn đến văn bản dự đoán hơn, với ưu tiên cho các token có xác suất cao.\n- Nhiệt độ cao (>1.0) tăng tính sáng tạo và đa dạng của đầu ra, với nhiều cơ hội cho các token có xác suất thấp hơn.\nThiết lập giá trị 1.0 cho xác suất gốc.", + "Top_K_desc": "Top K đặt một giá trị tối đa cho số lượng token hàng đầu có thể được chọn từ đó.", + "Top_P_desc": "Top P (còn được gọi là mẫu hạt nhân) kết hợp tất cả các token hàng đầu cần thiết để đạt được một phần trăm nhất định.\nNói cách khác, nếu các token hàng đầu 2 đại diện cho 25%, và Top-P bằng 0.50, chỉ có hai token hàng đầu này được xem xét.\nThiết lập giá trị 1.0 để vô hiệu hóa.", + "Typical P": "Typical P", + "Typical_P_desc": "Mẫu P điển hình ưu tiên các token dựa trên sự sai lệch của chúng so với năng lượng cân bằng trung bình của tập hợp.\nCác token có xác suất tích lũy gần với ngưỡng được chỉ định (ví dụ: 0.5) được giữ lại, phân biệt chúng khỏi những token có thông tin trung bình.\nThiết lập giá trị 1.0 để vô hiệu hóa.", + "Min_P_desc": "Min P đặt một xác suất tối thiểu cơ bản. Nó được tinh chỉnh dựa trên xác suất token hàng đầu.\nNếu xác suất của token hàng đầu là 80%, và Min P là 0.1, chỉ có token với xác suất cao hơn 8% được xem xét.\nThiết lập giá trị 0 để vô hiệu hóa.", + "Top_A_desc": "Top A đặt một ngưỡng cho việc chọn token dựa trên bình phương của xác suất token cao nhất.\nNếu Top A là 0.2, và xác suất của token hàng đầu là 50%, các token có xác suất dưới 5% sẽ bị loại bỏ (0.2 * 0.5^2).\nThiết lập giá trị 0 để vô hiệu hóa.", + "Tail_Free_Sampling_desc": "Mẫu không đuôi (TFS) tìm kiếm đuôi của token với xác suất nhỏ trong phân phối,\n thông qua phân tích tốc độ thay đổi xác suất token bằng cách sử dụng đạo hàm. Các token được giữ lại đến ngưỡng (ví dụ: 0.3), dựa trên đạo hàm hai lần thống nhất.\nMỗi khi tiến về 0, số lượng token bị loại bỏ tăng lên. Thiết lập giá trị 1.0 để vô hiệu hóa.", + "rep.pen range": "Phạm vi trừ phạt tái phát", + "Mirostat": "Mirostat", + "Mode": "Mode", + "Mirostat_Mode_desc": "Giá trị 0 sẽ vô hiệu hóa hoàn toàn Mirostat. 1 dành cho Mirostat 1.0 và 2 dành cho Mirostat 2.0", + "Tau": "Tau", + "Mirostat_Tau_desc": "Kiểm soát sự thay đổi của đầu ra Mirostat", + "Eta": "eta", + "Mirostat_Eta_desc": "Kiểm soát tốc độ học tập của Mirostat", + "Ban EOS Token": "Cấm EOS Token", + "Ban_EOS_Token_desc": "Cấm mã thông báo Cuối chuỗi (EOS) với KoboldCpp (và có thể cả các mã thông báo khác có KoboldAI).\rTốt cho việc viết truyện, nhưng không nên dùng cho chế độ trò chuyện và hướng dẫn.", + "GBNF Grammar": "GBNF Grammar", + "Type in the desired custom grammar": "Nhập vào cú pháp tùy chỉnh mong muốn", + "Samplers Order": "Thứ tự Bộ lấy mẫu", + "Samplers will be applied in a top-down order. Use with caution.": "Các bộ lấy mẫu sẽ được áp dụng theo thứ tự từ trên xuống. Sử dụng cẩn thận.", + "Tail Free Sampling": "Mẫu Không đuôi", + "Load koboldcpp order": "Tải đơn hàng koboldcpp", + "Preamble": "Preamble", + "Use style tags to modify the writing style of the output.": "Sử dụng tags để sửa đổi kiểu viết của đầu ra.", + "Banned Tokens": "Các token Bị ban", + "Sequences you don't want to appear in the output. One per line.": "Các chuỗi bạn không muốn xuất hiện trong kết quả. Một dòng mỗi chuỗi.", + "Logit Bias": "Logit Bias", + "Add": "Thêm", + "Helps to ban or reenforce the usage of certain words": "Giúp cấm hoặc củng cố việc sử dụng một số từ", + "CFG Scale": "Tỷ lệ CFG", + "Negative Prompt": "Câu hỏi tiêu cực", + "Add text here that would make the AI generate things you don't want in your outputs.": "Thêm văn bản ở đây sẽ khiến trí tuệ nhân tạo tạo ra những điều bạn không muốn trong đầu ra của mình.", + "Used if CFG Scale is unset globally, per chat or character": "Sử dụng nếu CFG Scale không được thiết lập toàn cầu, mỗi cuộc trò chuyện hoặc mỗi ký tự.", + "Mirostat Tau": "Mirostat Tau", + "Mirostat LR": "Mirostat LR", + "Min Length": "Min Length", + "Top K Sampling": "Mẫu Top K", + "Nucleus Sampling": "Mẫu hạt nhân", + "Top A Sampling": "Mẫu Top A", + "CFG": "CFG", + "Neutralize Samplers": "Làm trung lập các mẫu", + "Set all samplers to their neutral/disabled state.": "Đặt tất cả các mẫu vào trạng thái trung lập/tắt.", + "Sampler Select": "Chọn mẫu", + "Customize displayed samplers or add custom samplers.": "Tùy chỉnh các bộ lấy mẫu được hiển thị hoặc thêm các bộ lấy mẫu tùy chỉnh.", + "Epsilon Cutoff": "Cắt Epsilon", + "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "Cắt ngắn Epsilon đặt một ngưỡng xác suất dưới đó các token sẽ không được lựa chọn để mẫu.\nTrong đơn vị 1e-4; giá trị thích hợp là 3.\nThiết lập 0 để vô hiệu hóa.", + "Eta Cutoff": "Cắt Eta", + "Eta_Cutoff_desc": "Ngưỡng Eta là tham số chính của kỹ thuật Mẫu Eta đặc biệt. Trong đơn vị của 1e-4; một giá trị hợp lý là 3. Đặt thành 0 để tắt. Xem bài báo Truncation Sampling as Language Model Desmoothing của Hewitt và cộng sự (2022) để biết chi tiết.", + "rep.pen decay": "Đại diện bút phân rã", + "Encoder Rep. Pen.": "Bút phạt mã hóa", + "No Repeat Ngram Size": "Kích thước Ngram không lặp lại", + "Skew": "Nghiêng", + "Max Tokens Second": "Số lượng Mã thông báo Tối đa / Giây", + "Smooth Sampling": "Lấy mẫu mượt mà", + "Smooth_Sampling_desc": "Cho phép bạn sử dụng các phép biến đổi bậc hai/khối để điều chỉnh phân bố. Giá trị Hệ số làm mịn thấp hơn sẽ sáng tạo hơn, thường nằm trong khoảng 0,2-0,3 là điểm ngọt (giả sử đường cong = 1). Giá trị Đường cong làm mịn cao hơn sẽ làm cho đường cong dốc hơn, điều này sẽ trừng phạt mạnh mẽ hơn các lựa chọn có xác suất thấp. Đường cong 1.0 tương đương với việc chỉ sử dụng Smoothing Factor.", + "Smoothing Factor": "Hệ số làm mịn", + "Smoothing Curve": "Làm mịn đường cong", + "DRY_Repetition_Penalty_desc": "DRY phạt các mã thông báo sẽ kéo dài phần cuối của đầu vào thành một chuỗi đã xảy ra trước đó trong đầu vào. Đặt hệ số nhân thành 0 để tắt.", + "DRY Repetition Penalty": "Hình phạt lặp lại DRY", + "DRY_Multiplier_desc": "Đặt thành giá trị > 0 để bật DRY. Kiểm soát mức độ hình phạt đối với các chuỗi hình phạt ngắn nhất.", + "Multiplier": "Số nhân", + "DRY_Base_desc": "Kiểm soát tốc độ tăng của hình phạt khi tăng độ dài chuỗi.", + "Base": "Base", + "DRY_Allowed_Length_desc": "Trình tự dài nhất có thể được lặp lại mà không bị phạt.", + "Allowed Length": "Allowed Length", + "Penalty Range": "Penalty Range", + "DRY_Sequence_Breakers_desc": "Các mã thông báo mà việc khớp trình tự không được tiếp tục. Được chỉ định dưới dạng danh sách các chuỗi được trích dẫn được phân tách bằng dấu phẩy.", + "Sequence Breakers": "Bộ ngắt trình tự", + "JSON-serialized array of strings.": "Mảng chuỗi được tuần tự hóa JSON.", + "Dynamic Temperature": "Dynamic Temperature", + "Scale Temperature dynamically per token, based on the variation of probabilities": "Nhiệt độ tỷ lệ động cho mỗi token, dựa trên sự biến đổi của xác suất.", + "Minimum Temp": "Nhiệt độ Tối thiểu", + "Maximum Temp": "Nhiệt độ Tối đa", + "Exponent": "Exponent", + "Mirostat (mode=1 is only for llama.cpp)": "Mirostat (chế độ=1 chỉ dành cho llama.cpp)", + "Mirostat_desc": "Mirostat là một bộ điều chỉnh nhiệt cho sự phức tạp của đầu ra.", + "Mirostat Mode": "Chế độ Mirostat", + "Variability parameter for Mirostat outputs": "Tham số biến đổi cho đầu ra của Mirostat.", + "Mirostat Eta": "Mirostat Eta", + "Learning rate of Mirostat": "Learning rate of Mirostat.", + "Beam search": "Beam search", + "Helpful tip coming soon.": "Lời khuyên hữu ích sắp ra mắt.", + "Number of Beams": "Số Lượng Beam", + "Length Penalty": "Length Penalty", + "Early Stopping": "Dừng Sớm", + "Contrastive search": "Contrastive search", + "Penalty Alpha": "Penalty Alpha", + "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "Độ mạnh của thuật ngữ điều chỉnh Tìm kiếm Trái ngược. Đặt thành 0 để vô hiệu hóa CS.", + "Do Sample": "Lấy Sample", + "Add BOS Token": "Thêm BOS Token", + "Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative": "Thêm bos_token vào đầu câu hỏi. Vô hiệu hóa điều này có thể làm cho các câu trả lời sáng tạo hơn", + "Ban the eos_token. This forces the model to never end the generation prematurely": "Cấm eos_token. Điều này buộc mô hình không bao giờ kết thúc quá trình sinh ra trước khi cần thiết", + "Ignore EOS Token": "Bỏ qua mã thông báo EOS", + "Ignore the EOS Token even if it generates.": "Bỏ qua EOS Token ngay cả khi nó được tạo ra.", + "Skip Special Tokens": "Bỏ qua Các Token Đặc biệt", + "Temperature Last": "Temperature Last", + "Temperature_Last_desc": "Sử dụng bộ lấy Temperature cuối cùng. Thường là hợp lý.\nKhi bật: Một nhóm các token tiềm năng được chọn trước tiên, sau đó nhiệt độ được áp dụng để hiệu chỉnh xác suất tương đối của chúng (kỹ thuật, logits).\nKhi vô hiệu hóa: Nhiệt độ được áp dụng trước tiên để hiệu chỉnh xác suất tương đối của từng token, sau đó một nhóm các token tiềm năng được chọn từ đó.\nVô hiệu hóa nhiệt độ cuối cùng.", + "Speculative Ngram": "Speculative Ngram", + "Use a different speculative decoding method without a draft model": "Sử dụng phương pháp giải mã suy đoán khác mà không cần mô hình phác thảo.\rƯu tiên sử dụng mô hình dự thảo. Ngram đầu cơ không hiệu quả bằng.", + "Spaces Between Special Tokens": "Khoảng cách giữa các mã thông báo đặc biệt", + "LLaMA / Mistral / Yi models only": "Chỉ áp dụng cho các mô hình LLaMA / Mistral / Yi. Hãy chắc chắn chọn bộ phân tích đúng trước.\nChuỗi phải không xuất hiện trong kết quả.\nMỗi dòng chỉ một chuỗi. Văn bản hoặc [nhận diện của token].\nNhiều token bắt đầu bằng dấu cách. Sử dụng bộ đếm token nếu bạn không chắc chắn.", + "Example: some text [42, 69, 1337]": "Ví dụ:\nmột số văn bản\n[42, 69, 1337]", + "Classifier Free Guidance. More helpful tip coming soon": "Hướng dẫn không cần Bộ phân loại. Mẹo hữu ích hơn sẽ được cập nhật sớm.", + "Scale": "Tỷ lệ", + "JSON Schema": "JSON Schema", + "Type in the desired JSON schema": "Nhập JSON schema mong muốn", + "Grammar String": "Chuỗi ngữ pháp", + "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF hoặc EBNF, tùy thuộc vào backend đang sử dụng. Nếu bạn đang sử dụng cái này, bạn nên biết cái nào.", + "Top P & Min P": "Top P & Min P", + "Load default order": "Tải thứ tự mặc định", + "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "chỉ llama.cpp. Xác định thứ tự lấy mẫu. Nếu chế độ Mirostat khác 0, thứ tự lấy mẫu sẽ bị bỏ qua.", + "Sampler Priority": "Ưu tiên sampler", + "Ooba only. Determines the order of samplers.": "Chỉ Ooba. Xác định thứ tự của samplers.", + "Character Names Behavior": "Cài đặt tên nhân vật", + "Helps the model to associate messages with characters.": "Giúp mô hình liên kết tin nhắn với các ký tự.", + "None": "Không", + "character_names_default": "Ngoại trừ các nhóm và cá tính trong quá khứ. Nếu không, hãy đảm bảo bạn cung cấp tên trong Prompt.", + "Don't add character names.": "Không thêm tên nhân vật.", + "Completion": "Hoàn thành", + "character_names_completion": "Áp dụng hạn chế: chỉ chữ và số Latinh và dấu gạch dưới. Không hoạt động với tất cả các nguồn, đặc biệt là: Claude, MistralAI, Google.", + "Add character names to completion objects.": "Thêm tên nhân vật vào completion objects.", + "Message Content": "Nội dung tin nhắn", + "Prepend character names to message contents.": "Thêm tên ký tự vào nội dung tin nhắn.", + "Continue Postfix": "Tiếp tục Prefix", + "The next chunk of the continued message will be appended using this as a separator.": "Đoạn tiếp theo của tin nhắn tiếp theo sẽ được thêm vào bằng cách sử dụng đoạn này làm dấu phân cách.", + "Space": "Không gian", + "Newline": "Dòng mới", + "Double Newline": "Dòng mới kép", + "Wrap user messages in quotes before sending": "Cho tin nhắn của người dùng trong dấu ngoặc kép trước khi gửi", + "Wrap in Quotes": "Cho vào trong dấu ngoặc", + "Wrap entire user message in quotes before sending.": "Cho toàn bộ tin nhắn của người dùng trong dấu ngoặc kép trước khi gửi", + "Leave off if you use quotes manually for speech.": "Bỏ qua nếu bạn sử dụng dấu ngoặc kép cho lời nói.", + "Continue prefill": "Tiếp tục Prefill", + "Continue sends the last message as assistant role instead of system message with instruction.": "Tiếp tục gửi tin nhắn cuối cùng dưới dạng Assistant thay vì Prompt hệ thống với Instruction.", + "Squash system messages": "Nén tin nhắn văn bản hệ thống", + "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Kết hợp các tin nhắn hệ thống liên tiếp thành một (loại bỏ các đoạn hội thoại mẫu). Có thể cải thiện tính nhất quán cho một số model.", + "Enable function calling": "Sử dụng tính năng gọi hàm (function calling)", + "Send inline images": "Gửi hình ảnh nội bộ", + "image_inlining_hint_1": "Gửi hình ảnh theo Prompt nếu kiểu máy hỗ trợ (ví dụ: GPT-4V, Claude 3 hoặc Llava 13B).\n Sử dụng", + "image_inlining_hint_2": "hành động đối với bất kỳ tin nhắn nào hoặc", + "image_inlining_hint_3": "menu để đính kèm tệp hình ảnh vào cuộc trò chuyện.", + "Inline Image Quality": "Chất lượng hình ảnh nội tuyến", + "openai_inline_image_quality_auto": "Tự động", + "openai_inline_image_quality_low": "Thấp", + "openai_inline_image_quality_high": "Cao", + "Use AI21 Tokenizer": "Sử bộ Tokenizer (bộ tách từ) của AI21", + "Use the appropriate tokenizer for Jurassic models, which is more efficient than GPT's.": "Sử dụng bộ tách từ thích hợp cho các Model của Jurassic, hiệu quả hơn GPT.", + "Use Google Tokenizer": "Sử Tokenizer của Google", + "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "Sử dụng bộ tách từ phù hợp cho các model của Google thông qua API. Xử lý prompt chậm hơn, nhưng đếm token chính xác hơn.", + "Use system prompt": "Sử dụng Prompt hệ thống", + "(Gemini 1.5 Pro/Flash only)": "(Chỉ cho Gemini 1.5 Pro/Flash)", + "Merges_all_system_messages_desc_1": "Hợp nhất tất cả các tin nhắn văn bản hệ thống cho đến tin nhắn đầu tiên có vai trò không thuộc hệ thống và gửi chúng theo cách", + "Merges_all_system_messages_desc_2": "cánh đồng.", + "Assistant Prefill": "Prefill trợ lý", + "Start Claude's answer with...": "Claude trả lời bắt đầu bằng...", + "Assistant Impersonation Prefill": "Prefill cho mạo danh trợ lý", + "Use system prompt (Claude 2.1+ only)": "Sử dụng prompt hệ thống (Chỉ áp dụng từ Claude 2.1+)", + "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "Gửi yêu cầu hệ thống cho các model được hỗ trợ. Nếu bị vô hiệu hóa, tin nhắn của người dùng sẽ được thêm vào đầu yêu cầu.", + "User first message": "Tin nhắn đầu tiên của người dùng", + "Restore User first message": "Khôi phục tin nhắn đầu tiên của người dùng", + "Human message": "Prompt, hướng dẫn của human, v.v.\nKhông thêm gì khi trống, tức là yêu cầu Prompt mới với vai trò 'người dùng'.", + "New preset": "Preset mới", + "Delete preset": "Xóa preset", + "View / Edit bias preset": "Xem / Chỉnh sửa cài đặt thiên vị", + "Add bias entry": "Thêm mục thiên vị", + "Most tokens have a leading space.": "Hầu hết các token đều có khoảng trống ở đầu.", + "API Connections": "Kết nối API", + "Text Completion": "Text Completion", + "Chat Completion": "Chat Completion", + "NovelAI": "NovelAI", + "AI Horde": "AI Horde", + "KoboldAI": "KoboldAI", + "Avoid sending sensitive information to the Horde.": "Tránh gửi thông tin nhạy cảm cho Horde.", + "Review the Privacy statement": "Xem lại Chính sách bảo mật", + "Register a Horde account for faster queue times": "Đăng ký tài khoản Horde để có thời gian xếp hàng ngắn hơn", + "Learn how to contribute your idle GPU cycles to the Horde": "Tìm hiểu cách đóng góp công sức GPU của bạn cho Horde", + "Adjust context size to worker capabilities": "Điều chỉnh kích thước context cho phù hợp với khả năng của công nhân", + "Adjust response length to worker capabilities": "Điều chỉnh độ dài phản hồi cho phù hợp với khả năng của công nhân", + "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "Có thể giúp đỡ với các phản hồi không tốt bằng cách xếp hàng chỉ các nhân viên được phê duyệt. Có thể làm chậm lại thời gian phản hồi.", + "Trusted workers only": "Chỉ các nhân viên được tin cậy", + "API key": "Key API", + "Get it here:": "Nhận nó tại đây:", + "Register": "Đăng ký", + "View my Kudos": "Xem Kudos của tui", + "Enter": "Nhập", + "to use anonymous mode.": "để sử dụng chế độ ẩn danh.", + "Clear your API key": "Xóa key API của tui", + "For privacy reasons, your API key will be hidden after you reload the page.": "Vì lý do bảo mật, khóa API của bạn sẽ bị ẩn sau khi bạn tải lại trang.", + "Models": "Model", + "Refresh models": "Làm mới model", + "-- Horde models not loaded --": "-- Các mô hình Horde không được tải --", + "Not connected...": "Không kết nối...", + "API url": "URL API", + "Example: http://127.0.0.1:5000/api ": "Ví dụ: http://127.0.0.1:5000/api", + "Connect": "Kết nối", + "Cancel": "Hủy bỏ", + "Novel API key": "Key API NovelAI", + "Get your NovelAI API Key": "Nhận khóa API NovelAI của bạn", + "Enter it in the box below": "Nhập nó vào ô dưới đây", + "Novel AI Model": "Model Novel AI", + "No connection...": "Không có kết nối...", + "API Type": "Loại API", + "Default (completions compatible)": "Mặc định [OpenAI/tương thích hoàn thành: oobabooga, LM Studio, v.v.]", + "TogetherAI API Key": "Key API TogetherAI", + "TogetherAI Model": "Model TogetherAI", + "-- Connect to the API --": "-- Kết nối với API --", + "OpenRouter API Key": "Key API của OpenRouter", + "Click Authorize below or get the key from": "Nhấp vào Tác động dưới đây hoặc lấy Key từ", + "View Remaining Credits": "Xem số dư còn lại", + "OpenRouter Model": "Model OpenRouter", + "Model Providers": "Nhà cung cấp model", + "InfermaticAI API Key": "Key API InfermaticAI", + "InfermaticAI Model": "Model InfermaticAI", + "DreamGen API key": "Key API DreamGen", + "DreamGen Model": "Model DreamGen", + "Mancer API key": "Key API của Mancer", + "Mancer Model": "Model Mancer", + "Make sure you run it with": "Đảm bảo bạn chạy nó với nó", + "flag": "cờ", + "API key (optional)": "Key API (tùy chọn)", + "Server url": "URL máy chủ", + "Example: 127.0.0.1:5000": "Ví dụ: 127.0.0.1:5000", + "Custom model (optional)": "Model tùy chỉnh (tùy chọn)", + "vllm-project/vllm": "vllm-project/vllm (Chế độ trình bao bọc API OpenAI)", + "vLLM API key": "Key API vLLM", + "Example: 127.0.0.1:8000": "Ví dụ: http://127.0.0.1:8000", + "vLLM Model": "Model vLLM", + "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (Chế độ đóng gói cho Giao diện lập trình ứng dụng OpenAI)", + "Aphrodite API key": "Key API Aphrodite", + "Aphrodite Model": "Moddel cho Aphrodite", + "ggerganov/llama.cpp": "ggerganov/llama.cpp", + "Example: 127.0.0.1:8080": "Ví dụ: 127.0.0.1:8080", + "Example: 127.0.0.1:11434": "Ví dụ: 127.0.0.1:11434", + "Ollama Model": "Model Ollama", + "Download": "Tải xuống", + "Tabby API key": "Key API Tabby", + "koboldcpp API key (optional)": "Key API koboldcpp (tùy chọn)", + "Example: 127.0.0.1:5001": "Ví dụ: 127.0.0.1:5001", + "Cho phép": "Ủy quyền", + "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Nhận mã thông báo API OpenRouter của bạn bằng cách sử dụng luồng OAuth. Bạn sẽ được chuyển hướng đến openrouter.ai", + "Bypass status check": "Bỏ qua check trạng thái", + "Chat Completion Source": "Nguồn cho Chat Completion", + "Reverse Proxy": "Proxy", + "Proxy Presets": "Preset proxy", + "Saved addresses and passwords.": "Link và mật khẩu đã lưu.", + "Save Proxy": "Lưu proxy", + "Delete Proxy": "Xóa proxy", + "Proxy Name": "Tên của Proxy", + "This will show up as your saved preset.": "Điều này sẽ hiển thị dưới dạng cài đặt trước đã lưu của bạn.", + "Proxy Server URL": "Link URL proxy", + "Alternative server URL (leave empty to use the default value).": "URL máy chủ thay thế (để trống để sử dụng giá trị mặc định).", + "Remove your real OAI API Key from the API panel BEFORE typing anything into this box": "Xóa Key API OAI thực của bạn khỏi bảng API TRƯỚC khi nhập bất kỳ điều gì vào hộp này", + "We cannot provide support for problems encountered while using an unofficial OpenAI proxy": "Chúng tôi không thể cung cấp hỗ trợ cho các vấn đề gặp phải khi sử dụng proxy OpenAI không chính thức", + "Doesn't work? Try adding": "Không hoạt động? Hãy thử thêm", + "at the end!": " ở cuối cùng!", + "Proxy Password": "Mật khẩu cho proxy", + "Will be used as a password for the proxy instead of API key.": "Sẽ được sử dụng làm mật khẩu cho proxy thay vì key API.", + "Peek a password": "Xem mật khẩu", + "OpenAI API key": "OpenAI API key", + "View API Usage Metrics": "Xem stats xài API", + "Follow": "Theo dõi", + "these directions": "những hướng dẫn này", + "to get your OpenAI API key.": "để lấy Key API của OpenAI.", + "Use Proxy password field instead. This input will be ignored.": "Dùng ô \"Mật khẩu proxy\" đi. Ô này không dùng được đâu.", + "OpenAI Model": "Model OpenAI", + "Bypass API status check": "Bỏ qua kiểm tra trạng thái API", + "Show External models (provided by API)": "Hiện các model ngoài vào (do API cung cấp)", + "Get your key from": "Lấy Key của bạn từ", + "Anthropic's developer console": "developer console của Anthropic", + "Claude Model": "Model Claude", + "Window AI Model": "Model Window AI", + "Model Order": "Sắp xếp model OpenRouter", + "Alphabetically": "Theo thứ tự bảng chữ cái", + "Price": "Giá (rẻ nhất)", + "Context Size": "Kích thước bối cảnh", + "Group by vendors": "Nhóm theo nhà cung cấp", + "Group by vendors Description": "Xếp các mô hình OpenAI vào một nhóm, các mô hình Anthropic vào một nhóm khác, v.v. Có thể kết hợp với việc sắp xếp.", + "Allow fallback routes": "Cho phép các tuyến đường phụ", + "Allow fallback routes Description": "Bot thay thế tự động nếu mô hình được chọn không thể đáp ứng yêu cầu của bạn.", + "Scale API Key": "Scale API Key", + "Clear your cookie": "Xóa cookie", + "Alt Method": "Phương pháp thay thế", + "AI21 API Key": "AI21 API Key", + "AI21 Model": "Model của AI21", + "Google AI Studio API Key": "Google AI Studio API Key", + "Google Model": "Model của Google", + "MistralAI API Key": "MistralAI API Key", + "MistralAI Model": "Model của MistralAI", + "Groq API Key": "Groq API Key", + "Groq Model": "Model của Groq", + "Perplexity API Key": "Perplexity API Key", + "Perplexity Model": "Model của Perplexity", + "Cohere API Key": "Cohere API Key", + "Cohere Model": "Model của Cohere", + "Custom Endpoint (Base URL)": "Đường link custom (Base URL)", + "Custom API Key": "Key API tùy chỉnh", + "Available Models": "Các Model hiện có", + "Prompt Post-Processing": "Xử lý hậu kỳ Prompt", + "Applies additional processing to the prompt before sending it to the API.": "Áp dụng xử lý bổ sung cho Prompt trước khi gửi nó tới API.", + "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "Xác minh kết nối API của bạn bằng cách gửi một tin nhắn kiểm tra ngắn. Hãy nhớ rằng bạn sẽ được ghi nhận về điều đó!", + "Test Message": "Test tin nhắn", + "Auto-connect to Last Server": "Tự động kết nối với link trước đó", + "Missing key": "❌ Thiếu Key", + "Key saved": "✔️ Đã lưu Key", + "View hidden API keys": "Xem các Key API ẩn", + "AI Response Formatting": "Định dạng Phản hồi của AI", + "Advanced Formatting": "Định dạng Nâng cao", + "Context Template": "Mẫu context", + "Auto-select this preset for Instruct Mode": "Tự động chọn thiết lập này cho Chế độ Hướng dẫn", + "Story String": "Chuỗi Truyện", + "Example Separator": "Ngăn cách Mẫu", + "Chat Start": "Bắt đầu Chat", + "Add Chat Start and Example Separator to a list of stopping strings.": "Thêm Bắt đầu trò chuyện và Dấu phân cách ví dụ vào danh sách các chuỗi dừng.", + "Use as Stop Strings": "Sử dụng như chuỗi dừng", + "context_allow_jailbreak": "Bao gồm Bẻ khóa ở cuối Prompt, nếu được xác định trong thẻ ký tự VÀ ''Thích Char. Bẻ khóa'' được bật.\nĐIỀU NÀY KHÔNG ĐƯỢC KHUYẾN NGHỊ CHO CÁC MÔ HÌNH HOÀN THÀNH VĂN BẢN, CÓ THỂ DẪN ĐẾN ĐẦU RA XẤU.", + "Allow Jailbreak": "Cho phép bẻ khóa", + "Context Order": "Thứ tự bối cảnh", + "Summary": "Bản tóm tắt", + "Author's Note": "Ghi chú của tác giả", + "Example Dialogues": "Đối thoại mẫu", + "Hint": "Gợi ý:", + "In-Chat Position not affected": "Thứ tự Tóm tắt và Ghi chú của tác giả chỉ bị ảnh hưởng khi chúng không được đặt vị trí Trong trò chuyện.", + "Instruct Mode": "Chế độ Hướng dẫn", + "Enabled": "Đã bật", + "instruct_bind_to_context": "Nếu được bật, các mẫu context sẽ được tự động chọn dựa trên tên mẫu hướng dẫn đã chọn hoặc theo sở thích.", + "Bind to Context": "Buộc vào Context", + "Presets": "Cài đặt Preset", + "Auto-select this preset on API connection": "Tự động chọn thiết lập này khi kết nối API", + "Activation Regex": "Kích hoạt Regex", + "Wrap Sequences with Newline": "Bao gói Các chuỗi với Dòng mới", + "Replace Macro in Sequences": "Thay thế Macro trong chuỗi", + "Skip Example Dialogues Formatting": "Bỏ qua Định dạng Đoạn hội thoại Mẫu", + "Include Names": "Bao gồm Tên", + "Force for Groups and Personas": "Ép buộc cho Nhóm và Nhân vật", + "System Prompt": "Prompt của hệ thống", + "Instruct Mode Sequences": "Các chuỗi chế độ hướng dẫn", + "System Prompt Wrapping": "Gói Prompt hệ thống", + "Inserted before a System prompt.": "Được chèn trước Prompt Hệ thống.", + "System Prompt Prefix": "Tiếp đầu ngữ cho Prompt hệ thống", + "Inserted after a System prompt.": "Được chèn sau Prompt của Hệ thống.", + "System Prompt Suffix": "Hậu tố nhắc nhở hệ thống", + "Chat Messages Wrapping": "Gói tin nhắn trò chuyện", + "Inserted before a User message and as a last prompt line when impersonating.": "Được chèn trước thông báo Người dùng và làm dòng nhắc nhở cuối cùng khi mạo danh.", + "User Message Prefix": "Tiền tố tin nhắn người dùng", + "Inserted after a User message.": "Được chèn sau tin nhắn của Người dùng.", + "User Message Suffix": "Hậu tố tin nhắn của người dùng", + "Inserted before an Assistant message and as a last prompt line when generating an AI reply.": "Được chèn trước tin nhắn Trợ lý và làm dòng nhắc nhở cuối cùng khi tạo câu trả lời AI.", + "Assistant Message Prefix": "Tiền tố tin nhắn trợ lý", + "Inserted after an Assistant message.": "Được chèn sau tin nhắn của Trợ lý.", + "Assistant Message Suffix": "Hậu tố tin nhắn trợ lý", + "Inserted before a System (added by slash commands or extensions) message.": "Được chèn trước thông báo Hệ thống (được thêm bằng lệnh gạch chéo hoặc phần mở rộng).", + "System Message Prefix": "Tiền tố tin nhắn hệ thống", + "Inserted after a System message.": "Được chèn sau thông báo Hệ thống.", + "System Message Suffix": "Hậu tố tin nhắn hệ thống", + "If enabled, System Sequences will be the same as User Sequences.": "Nếu được bật, Trình tự hệ thống sẽ giống như Trình tự của người dùng.", + "System same as User": "Hệ thống giống như Người dùng", + "Misc. Sequences": "Linh tinh. trình tự", + "Inserted before the first Assistant's message.": "Được chèn trước tin nhắn của Trợ lý đầu tiên.", + "First Assistant Prefix": "Tiền tố trợ lý đầu tiên", + "instruct_last_output_sequence": "Được chèn trước tin nhắn cuối cùng của Trợ lý hoặc dưới dạng dòng nhắc nhở cuối cùng khi tạo phản hồi AI (ngoại trừ vai trò trung lập/hệ thống).", + "Last Assistant Prefix": "Tiền tố trợ lý cuối cùng", + "Will be inserted as a last prompt line when using system/neutral generation.": "Sẽ được chèn dưới dạng dòng nhắc cuối cùng khi sử dụng hệ thống/thế hệ trung lập.", + "System Instruction Prefix": "Tiền tố hướng dẫn hệ thống", + "If a stop sequence is generated, everything past it will be removed from the output (inclusive).": "Nếu một chuỗi dừng được tạo ra, mọi thứ trước đó sẽ bị xóa khỏi đầu ra (bao gồm).", + "Stop Sequence": "Chuỗi Dừng", + "Will be inserted at the start of the chat history if it doesn't start with a User message.": "Sẽ được chèn vào đầu lịch sử trò chuyện nếu nó không bắt đầu bằng tin nhắn Người dùng.", + "User Filler Message": "Thông báo điền của người dùng", + "Context Formatting": "Định dạng context", + "(Saved to Context Template)": "(Đã lưu trong Mẫu context)", + "Always add character's name to prompt": "Luôn thêm tên nhân vật vào điều khiển", + "Generate only one line per request": "Chỉ tạo một dòng cho mỗi yêu cầu", + "Trim Incomplete Sentences": "Cắt các câu không hoàn chỉnh", + "Include Newline": "Bao gồm dòng mới", + "Misc. Settings": "Các cài đặt khác", + "Collapse Consecutive Newlines": "Thu gọn các dòng mới liên tiếp", + "Trim spaces": "Cắt khoảng trắng", + "Tokenizer": "Công cụ tách từ", + "Token Padding": "Đệm Token", + "Start Reply With": "Bắt đầu Phản hồi Bằng", + "AI reply prefix": "Tiền tố trả lời AI", + "Show reply prefix in chat": "Hiển thị tiền tố phản hồi trong chat", + "Non-markdown strings": "Chuỗi không Markdown", + "separate with commas w/o space between": "phân tách bằng dấu phẩy không có khoảng trắng giữa", + "Custom Stopping Strings": "Chuỗi dừng tùy chỉnh", + "JSON serialized array of strings": "Mảng chuỗi được tuần tự hóa JSON", + "Replace Macro in Stop Strings": "Thay thế Macro trong Chuỗi Dừng Tùy chỉnh", + "Auto-Continue": "Tự động Tiếp tục", + "Allow for Chat Completion APIs": "Cho phép các API hoàn thành Trò chuyện", + "Target length (tokens)": "Độ dài mục tiêu (token)", + "World Info": "World Info", + "Locked = World Editor will stay open": "Được khóa = Trình chỉnh sửa Thế giới sẽ được mở", + "Worlds/Lorebooks": "Thế giới", + "Active World(s) for all chats": "Thế giới Hoạt động cho tất cả các cuộc trò chuyện", + "-- World Info not found --": "-- Không tìm thấy World Info --", + "Global World Info/Lorebook activation settings": "Cài đặt kích hoạt Thông tin thế giới World Info/Lorebook", + "Click to expand": "Bấm để mở rộng", + "Scan Depth": "Độ sâu quét", + "Context %": "Bối cảnh %", + "Budget Cap": "Ngân sách tối đa", + "(0 = disabled)": "(0 = vô hiệu hóa)", + "Scan chronologically until reached min entries or token budget.": "Quét theo trình tự thời gian cho đến khi đạt được mục nhập hoặc ngân sách mã thông báo tối thiểu.", + "Min Activations": "Kích hoạt tối thiểu", + "Max Depth": "Độ sâu tối đa", + "(0 = unlimited, use budget)": "(0 = không giới hạn, sử dụng ngân sách)", + "Insertion Strategy": "Chiến lược chèn", + "Sorted Evenly": "Sắp xếp đều", + "Character Lore First": "Sử liệu nhân vật đầu tiên", + "Global Lore First": "Sử liệu toàn cầu đầu tiên", + "Entries can activate other entries by mentioning their keywords": "Các mục có thể kích hoạt các mục khác bằng cách đề cập đến từ khóa của họ", + "Recursive Scan": "Quét đệ quy", + "Lookup for the entry keys in the context will respect the case": "Tìm kiếm các khóa mục trong context sẽ tôn trọng trường hợp", + "Case Sensitive": "Phân biệt chữ hoa chữ thường", + "If the entry key consists of only one word, it would not be matched as part of other words": "Nếu khóa mục bao gồm chỉ một từ, nó sẽ không được kết hợp như một phần của các từ khác", + "Match Whole Words": "Khớp toàn bộ từ", + "Only the entries with the most number of key matches will be selected for Inclusion Group filtering": "Chỉ những mục có số lượng kết quả khớp chính nhiều nhất mới được chọn để lọc Nhóm Bao gồm", + "Use Group Scoring": "Sử dụng tính điểm nhóm", + "Alert if your world info is greater than the allocated budget.": "Cảnh báo nếu thông tin thế giới của bạn vượt quá ngân sách được phân bổ.", + "Alert On Overflow": "Cảnh báo khi tràn", + "New": "Mới", + "or": "hoặc", + "--- Pick to Edit ---": "--- Chọn để Chỉnh sửa ---", + "Rename World Info": "Đổi tên World Info", + "Open all Entries": "Mở tất cả các Mục", + "Close all Entries": "Đóng tất cả các Mục", + "New Entry": "Mục mới", + "Fill empty Memo/Titles with Keywords": "Điền vào Memo/Tiêu đề trống với từ khóa", + "Import World Info": "Nhập World Info", + "Export World Info": "Xuất World Info", + "Duplicate World Info": "Nhân đôi World Info", + "Delete World Info": "Xóa World Info", + "Search...": "Tìm kiếm...", + "Search": "Tìm kiếm", + "Priority": "Ưu tiên", + "Custom": "Tùy chỉnh", + "Title A-Z": "Tiêu đề A-Z", + "Title Z-A": "Tiêu đề Z-A", + "Tokens ↗": "Token ↗", + "Tokens ↘": "Token ↘", + "Depth ↗": "Độ sâu ↗", + "Depth ↘": "Độ sâu ↘", + "Order ↗": "Thứ tự ↗", + "Order ↘": "Thứ tự ↘", + "UID ↗": "UID ↗", + "UID ↘": "UID ↘", + "Trigger% ↗": "Kích hoạt% ↗", + "Trigger% ↘": "Kích hoạt% ↘", + "Refresh": "Làm mới", + "User Settings": "Cài đặt người dùng", + "Simple": "Đơn giản", + "Advanced": "Nâng cao", + "UI Language": "ngôn ngữ", + "Account": "Tài khoản", + "Admin Panel": "bảng quản trị", + "Logout": "Đăng xuất", + "Search Settings": "Cài đặt Tìm kiếm", + "UI Theme": "Chủ đề Giao diện Người dùng", + "Import a theme file": "Nhập một tệp chủ đề", + "Export a theme file": "Xuất một tệp chủ đề", + "Delete a theme": "Xóa một chủ đề", + "Update a theme file": "Cập nhật một tập tin chủ đề", + "Save as a new theme": "Lưu dưới dạng chủ đề mới", + "Avatar Style:": "Kiểu hình đại diện", + "Circle": "Hình tròn", + "Square": "Hình vuông", + "Rectangle": "Hình chữ nhật", + "Chat Style:": "Kiểu Chat:", + "Flat": "Phẳng\nbong bóng\nTài liệu", + "Bubbles": "Bong bóng", + "Document": "Tài liệu", + "Specify colors for your theme.": "Chỉ định màu sắc cho chủ đề của bạn.", + "Theme Colors": "Màu chủ đề", + "Main Text": "Văn bản chính", + "Italics Text": "Văn bản nghiêng", + "Underlined Text": "Văn bản Gạch chân", + "Quote Text": "Văn bản Trích dẫn", + "Shadow Color": "Màu bóng", + "Chat Background": "Hình nền Chat", + "UI Background": "Hình nền UI", + "UI Border": "Viền UI", + "User Message Blur Tint": "Màu sắc làm mờ Tin nhắn của Người dùng", + "AI Message Blur Tint": "Màu sắc làm mờ Tin nhắn của Trí tuệ Nhân tạo", + "Chat Width": "Chiều rộng chat", + "Width of the main chat window in % of screen width": "Chiều rộng của cửa sổ trò chuyện chính tính bằng % chiều rộng màn hình", + "Font Scale": "Tỷ lệ Font", + "Font size": "Cỡ chữ", + "Blur Strength": "Mực độ mạnh mờ", + "Blur strength on UI panels.": "Độ mờ trên bảng UI.", + "Text Shadow Width": "Độ rộng bóng văn bản", + "Strength of the text shadows": "Độ mạnh của bóng văn bản", + "Disables animations and transitions": "Tắt các hiệu ứng và chuyển động", + "Reduced Motion": "Giảm chuyển động", + "removes blur from window backgrounds": "Loại bỏ mờ từ hình nền cửa sổ", + "No Blur Effect": "Không có hiệu ứng mờ", + "Remove text shadow effect": "Loại bỏ hiệu ứng bóng đèn văn bản", + "No Text Shadows": "Không có bóng văn bản", + "Reduce chat height, and put a static sprite behind the chat window": "Giảm chiều cao của cuộc trò chuyện và đặt một sprite tĩnh phía sau cửa sổ trò chuyện", + "Waifu Mode": "Chế độ Waifu", + "Always show the full list of the Message Actions context items for chat messages, instead of hiding them behind '...'": "Luôn hiển thị danh sách đầy đủ các mục context Hành động Tin nhắn cho các tin nhắn trò chuyện, thay vì ẩn chúng sau '...'", + "Auto-Expand Message Actions": "Tự động mở rộng Hành động Tin nhắn", + "Alternative UI for numeric sampling parameters with fewer steps": "Giao diện người dùng thay thế cho các tham số mẫu số học với ít bước hơn", + "Zen Sliders": "Thanh trượt Zen", + "Entirely unrestrict all numeric sampling parameters": "Hoàn toàn không hạn chế tất cả các tham số mẫu số học", + "Mad Lab Mode": "Chế độ Phòng thí nghiệm điên", + "Time the AI's message generation, and show the duration in the chat log": "Đo thời gian tạo ra tin nhắn của trí tuệ nhân tạo và hiển thị thời lượng trong nhật ký trò chuyện", + "Message Timer": "Hẹn giờ Tin nhắn", + "Show a timestamp for each message in the chat log": "Hiển thị dấu thời gian cho mỗi tin nhắn trong nhật ký trò chuyện", + "Chat Timestamps": "Dấu thời gian Chat", + "Show an icon for the API that generated the message": "Hiển thị biểu tượng cho API đã tạo ra tin nhắn", + "Model Icon": "Biểu tượng Model", + "Show sequential message numbers in the chat log": "Hiển thị số tin nhắn tuần tự trong nhật ký trò chuyện", + "Message IDs": "ID Tin nhắn", + "Hide avatars in chat messages.": "Ẩn hình đại diện trong tin nhắn trò chuyện.", + "Hide Chat Avatars": "Ẩn hình đại diện trò chuyện", + "Show the number of tokens in each message in the chat log": "Hiển thị số lượng token trong mỗi tin nhắn trong nhật ký trò chuyện", + "Show Message Token Count": "Hiển thị Số lượng Token trong Tin nhắn", + "Single-row message input area. Mobile only, no effect on PC": "Khu vực nhập tin nhắn một hàng. Chỉ dành cho điện thoại di động, không ảnh hưởng đến PC", + "Compact Input Area (Mobile)": "Khu vực Nhập Dữ liệu Gọn nhẹ (Di động)", + "In the Character Management panel, show quick selection buttons for favorited characters": "Trong bảng Quản lý Nhân vật, hiển thị các nút lựa chọn nhanh cho các nhân vật được yêu thích", + "Characters Hotswap": "Thay đổi nhanh Nhân vật", + "Enable magnification for zoomed avatar display.": "Bật tính năng phóng to để hiển thị hình đại diện được phóng to.", + "Avatar Hover Magnification": "Phóng to hình đại diện khi di chuột", + "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "Bật hiệu ứng phóng to khi di chuột khi bạn hiển thị hình đại diện được phóng to sau khi nhấp vào hình ảnh của hình đại diện trong cuộc trò chuyện.", + "Show tagged character folders in the character list": "Hiển thị các thư mục nhân vật được gắn thẻ trong danh sách nhân vật", + "Tags as Folders": "Tags như Thư mục", + "Tags_as_Folders_desc": "Thay đổi gần đây: Thẻ phải được đánh dấu là thư mục trong menu Quản lý thẻ để hiển thị như vậy. Nhấp vào đây để đưa nó lên.", + "Character Handling": "Xử lý Nhân vật", + "If set in the advanced character definitions, this field will be displayed in the characters list.": "Nếu được thiết lập trong các định nghĩa nhân vật nâng cao, trường này sẽ được hiển thị trong danh sách nhân vật.", + "Char List Subheader": "Tiêu đề phụ danh sách Char", + "Character Version": "Phiên bản Nhân vật", + "Created by": "Được tạo bởi", + "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "Sử dụng kết hợp mờ, và tìm kiếm nhân vật trong danh sách bằng tất cả các trường dữ liệu, không chỉ bằng một phần của tên", + "Advanced Character Search": "Tìm kiếm Nhân vật Nâng cao", + "If checked and the character card contains a prompt override (System Prompt), use that instead": "Nếu được kiểm tra và thẻ nhân vật chứa một lệnh ghi đè (Lệnh hệ thống), hãy sử dụng thay vào đó", + "Prefer Character Card Prompt": "Ưu tiên Gợi ý từ Card", + "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Nếu được kiểm tra và thẻ nhân vật chứa một lệnh phá vỡ giam giữ (Hướng dẫn Lịch sử Bài viết), hãy sử dụng thay vào đó", + "Prefer Character Card Jailbreak": "Ưu tiên Jailbreak từ Card", + "never_resize_avatars_tooltip": "Tránh cắt xén và thay đổi kích thước hình ảnh ký tự đã nhập. Khi tắt, hãy cắt/thay đổi kích thước thành 512x768.", + "Never resize avatars": "Không bao giờ thay đổi kích thước hình đại diện", + "Show actual file names on the disk, in the characters list display only": "Hiển thị tên tệp thực tế trên đĩa, chỉ trong danh sách nhân vật", + "Show avatar filenames": "Hiển thị tên tệp hình đại diện", + "Prompt to import embedded card tags on character import. Otherwise embedded tags are ignored": "Nhắc nhập các thẻ thẻ nhúng trên thẻ nhân vật nhập khẩu. Nếu không, các thẻ nhúng sẽ bị bỏ qua", + "Import Card Tags": "Nhập Tags Thẻ", + "Hide character definitions from the editor panel behind a spoiler button": "Ẩn định nghĩa nhân vật từ bảng chỉnh sửa sau một nút spoil", + "Spoiler Free Mode": "Ẩn spoiler", + "Miscellaneous": "Linh tinh", + "Reload and redraw the currently open chat": "Tải lại và vẽ lại cuộc trò chuyện đang mở hiện tại", + "Reload Chat": "Tải lại Chat", + "Debug Menu": "Menu Debug", + "Smooth Streaming": "Streaming mượt", + "Experimental feature. May not work for all backends.": "Tính năng thực nghiệm. Có thể không hoạt động cho tất cả các Backends.", + "Slow": "Chậm", + "Fast": "Nhanh", + "Play a sound when a message generation finishes": "Phát ra âm thanh thông báo khi tin nhắn từ Char kết thúc", + "Message Sound": "Âm thanh Tin nhắn", + "Only play a sound when ST's browser tab is unfocused": "Chỉ phát âm thanh khi tab trình duyệt ST không được tập trung", + "Background Sound Only": "Chỉ Âm thanh Nền", + "Reduce the formatting requirements on API URLs": "Giảm yêu cầu định dạng trên URL của API", + "Relaxed API URLS": "URL API thư giãn", + "Ask to import the World Info/Lorebook for every new character with embedded lorebook. If unchecked, a brief message will be shown instead": "Hỏi để nhập World Info/Lorebook cho mỗi nhân vật mới có sẵn lorebook nhúng. Nếu không được kiểm tra, thay vào đó sẽ hiển thị một tin nhắn tóm tắt", + "Lorebook Import Dialog": "Nhập ví dụ lời thoại của Lorebook", + "Restore unsaved user input on page refresh": "Khôi phục đầu vào của người dùng chưa được lưu khi refresh trang", + "Restore User Input": "Khôi phục input của người dùng", + "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "Cho phép di chuyển một số thành phần giao diện người dùng bằng cách kéo chúng. Chỉ dành cho PC, không có tác dụng trên điền thoại", + "Movable UI Panels": "Bảng Giao diện người dùng Có thể di chuyển", + "MovingUI preset. Predefined/saved draggable positions": "Cài đặt trước MovingUI. Vị trí có thể kéo trước/saved", + "MUI Preset": "Cài đặt trước MUI:", + "Save movingUI changes to a new file": "Lưu các thay đổi của movingUI vào một tập tin mới", + "Reset MovingUI panel sizes/locations.": "Đặt lại kích thước/vị trí bảng điều khiển MovingUI.", + "Apply a custom CSS style to all of the ST GUI": "Áp dụng một kiểu CSS tùy chỉnh cho tất cả GUI của ST", + "Custom CSS": "CSS Tùy chỉnh", + "Expand the editor": "Mở rộng trình chỉnh sửa", + "Chat/Message Handling": "Xử lý Trò chuyện/Tin nhắn", + "# Messages to Load": "# tin nhắn. để tải", + "The number of chat history messages to load before pagination.": "Số lượng tin nhắn lịch sử trò chuyện cần tải trước khi phân trang.", + "(0 = All)": "(0 = Tất cả)", + "Streaming FPS": "FPS của Streaming", + "Update speed of streamed text.": "Tốc đọ của streaming văn bản.", + "Example Messages Behavior": "Hành vi Tin nhắn Mẫu", + "Gradual push-out": "Đẩy ra dần", + "Always include examples": "Luôn bao gồm các ví dụ", + "Never include examples": "Không bao giờ bao gồm các ví dụ", + "Send on Enter": "Gửi khi nhấn Enter", + "Disabled": "Vô hiệu", + "Automatic (PC)": "Tự động (Trên PC)", + "Press Send to continue": "Nhấn Gửi để tiếp tục", + "Show a button in the input area to ask the AI to continue (extend) its last message": "Hiển thị một nút trong khu vực nhập để yêu cầu trí tuệ nhân tạo tiếp tục (mở rộng) tin nhắn cuối cùng của nó", + "Quick 'Continue' button": "Nút 'Tiếp tục' nhanh", + "Show arrow buttons on the last in-chat message to generate alternative AI responses. Both PC and mobile": "Hiển thị nút mũi tên trên tin nhắn cuối cùng trong trò chuyện để tạo ra các phản hồi trí tuệ nhân tạo thay thế. Cả PC và điện thoại di động", + "Swipes": "Vuốt", + "Allow using swiping gestures on the last in-chat message to trigger swipe generation. Mobile only, no effect on PC": "Cho phép sử dụng cử chỉ vuốt trên tin nhắn cuối cùng trong trò chuyện để kích hoạt việc tạo ra vuốt. Chỉ dành cho di động, không ảnh hưởng đến PC", + "Gestures": "Cử chỉ", + "Auto-load Last Chat": "Tự động tải Đoạn trò chuyện Cuối cùng", + "Auto-scroll Chat": "Tự động cuộn Trò chuyện", + "Save edits to messages without confirmation as you type": "Lưu các chỉnh sửa vào các tin nhắn mà không cần xác nhận khi bạn gõ", + "Auto-save Message Edits": "Tự động lưu Sửa Tin nhắn", + "Confirm message deletion": "Xác nhận xóa tin nhắn", + "Auto-fix Markdown": "Tự động sửa Markdown", + "Disallow embedded media from other domains in chat messages": "Không cho phép nhúng phương tiện từ các miền khác vào tin nhắn trò chuyện.", + "Forbid External Media": "Cấm Phương tiện Ngoại tuyến", + "Allow {{char}}: in bot messages": "Cho phép {{char}}: trong các Tin nhắn Bot", + "Allow {{user}}: in bot messages": "Cho phép {{user}}: trong các Tin nhắn Bot", + "Skip encoding and characters in message text, allowing a subset of HTML markup as well as Markdown": "Bỏ qua mã hóa và ký tự trong văn bản tin nhắn, cho phép một tập con của đánh dấu HTML cũng như Markdown", + "Show tags in responses": "Hiển thị thẻ trong các phản hồi", + "Allow AI messages in groups to contain lines spoken by other group members": "Cho phép các tin nhắn của trí tuệ nhân tạo trong các nhóm chứa các dòng được nói bởi các thành viên khác trong nhóm", + "Relax message trim in Groups": "Giảm nhẹ việc cắt đoạn tin nhắn trong Nhóm", + "Log prompts to console": "Ghi nhận các Prompt vào bảng điều khiển", + "Requests logprobs from the API for the Token Probabilities feature": "Yêu cầu logprobs từ API cho bảng Xác suất Token", + "Request token probabilities": "Yêu cầu bảng xác suất token", + "Automatically reject and re-generate AI message based on configurable criteria": "Tự động từ chối và tạo lại tin nhắn của trí tuệ nhân tạo dựa trên các tiêu chí có thể cấu hình", + "Auto-swipe": "Tự động vuốt", + "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Bật chức năng tự động vuốt. Các cài đặt trong phần này chỉ có tác dụng khi tự động vuốt được bật", + "Minimum generated message length": "Độ dài tối thiểu của tin nhắn được tạo", + "If the generated message is shorter than these many characters, trigger an auto-swipe": "Nếu tin nhắn được tạo ra ngắn hơn điều này, kích hoạt tự động vuốt", + "Blacklisted words": "Từ trong danh sách đen", + "words you dont want generated separated by comma ','": "các từ bạn không muốn được tạo ra được phân tách bằng dấu phẩy ','", + "Blacklisted word count to swipe": "Số từ trong danh sách đen để vuốt", + "Minimum number of blacklisted words detected to trigger an auto-swipe": "Số lượng tối thiểu từ trong danh sách đen phát hiện để kích hoạt chức năng tự động vuốt", + "AutoComplete Settings": "Cài đặt Tự động Hoàn tất", + "Automatically hide details": "Tự động ẩn chi tiết", + "Determines how entries are found for autocomplete.": "Xác định cách tìm thấy các mục để tự động hoàn thành.", + "Autocomplete Matching": "Kết hợp", + "Starts with": "Bắt đầu với", + "Includes": "Bao gồm", + "Fuzzy": "Fuzzy", + "Sets the style of the autocomplete.": "Đặt kiểu tự động hoàn thành.", + "Autocomplete Style": "Phong cách", + "Follow Theme": "Đồng bộ giao diện", + "Dark": "Giao diện tối", + "Sets the font size of the autocomplete.": "Đặt kích thước phông chữ của tự động hoàn thành.", + "Sets the width of the autocomplete.": "Đặt chiều rộng của tự động hoàn thành.", + "Autocomplete Width": "Chiều rộng", + "chat input box": "hộp nhập trò chuyện", + "entire chat width": "toàn bộ chiều rộng trò chuyện", + "full window width": "chiều rộng toàn bộ cửa sổ", + "STscript Settings": "Cài đặt STscript", + "Sets default flags for the STscript parser.": "Đặt cờ mặc định cho trình phân tích cú pháp STscript.", + "Parser Flags": "Cờ phân tích cú pháp", + "Switch to stricter escaping, allowing all delimiting characters to be escaped with a backslash, and backslashes to be escaped as well.": "Chuyển sang lối thoát chặt chẽ hơn, cho phép thoát tất cả các ký tự phân cách bằng dấu gạch chéo ngược và dấu gạch chéo ngược cũng được thoát.", + "STRICT_ESCAPING": "STRICT_ESCAPING", + "Replace all {{getvar::}} and {{getglobalvar::}} macros with scoped variables to avoid double macro substitution.": "Thay thế tất cả macro {{getvar::}} và {{getglobalvar::}} bằng các biến trong phạm vi để tránh thay thế macro kép.", + "REPLACE_GETVAR": "REPLACE_GETVAR", + "Change Background Image": "Thay đổi Hình nền", + "Filter": "Bộ lọc", + "Automatically select a background based on the chat context": "Tự động chọn một nền dựa trên context trò chuyện", + "Auto-select": "Tự động chọn", + "System Backgrounds": "Nền Hệ thống", + "Chat Backgrounds": "Hình nền Chat", + "bg_chat_hint_1": "Hình nền trò chuyện được tạo bằng", + "bg_chat_hint_2": "tiện ích sẽ xuất hiện ở đây.", + "Extensions": "Tiện ích", + "Notify on extension updates": "Thông báo về các bản cập nhật của tiện ích", + "Manage extensions": "Quản lý tiện ích", + "Import Extension From Git Repo": "Nhập tiện ích từ Git Repo", + "Install extension": "Cài đặt tiện ích", + "Extras API:": "API bổ sung:", + "Auto-connect": "Tự động kết nối", + "Extras API URL": "URL API bổ sung", + "Extras API key (optional)": "Key API Phụ (tùy chọn)", + "Persona Management": "Quản lý Nhân cách", + "How do I use this?": "Tôi sử dụng cái này như thế nào?", + "Click for stats!": "Nhấp để xem thống kê!", + "Usage Stats": "Thống kê sử dụng", + "Backup your personas to a file": "Sao lưu nhân cách của bạn vào một tập tin", + "Backup": "Sao lưu", + "Restore your personas from a file": "Khôi phục nhân cách của bạn từ một tập tin", + "Restore": "Khôi phục", + "Create a dummy persona": "Tạo một nhân cách giả", + "Create": "Tạo", + "Toggle grid view": "Chuyển đổi chế độ xem lưới", + "No persona description": "[Không có mô tả]", + "Name": "Tên", + "Enter your name": "Nhập tên của bạn", + "Click to set a new User Name": "Đúp để đặt một tên Người dùng mới", + "Click to lock your selected persona to the current chat. Click again to remove the lock.": "Đúp để khóa nhân cách được chọn của bạn vào cuộc trò chuyện hiện tại. Nhấp một lần nữa để loại bỏ khóa.", + "Click to set user name for all messages": "Nhấp để đặt tên người dùng cho tất cả các tin nhắn", + "Persona Description": "Mô tả Nhân cách", + "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "Ví dụ: [{{user}} là một cô bé mèo người România 28 tuổi.]", + "Tokens persona description": "Mô tả Nhân cách", + "Position:": "Vị trí:", + "In Story String / Prompt Manager": "Trong Chuỗi Truyện / Quản lý Lời nhắc", + "Top of Author's Note": "Trên Ghi chú của Tác giả", + "Bottom of Author's Note": "Dưới Ghi chú của Tác giả", + "In-chat @ Depth": "Trong cuộc trò chuyện @ Độ sâu", + "Depth:": "Độ sâu:", + "Role:": "Vai trò:", + "System": "Hệ thống", + "User": "Người dùng", + "Assistant": "Trợ lý", + "Show notifications on switching personas": "Hiển thị thông báo khi chuyển đổi nhân cách", + "Character Management": "Quản lý Nhân vật", + "Locked = Character Management panel will stay open": "Được khóa = Bảng Quản lý Nhân vật sẽ được mở", + "Select/Create Characters": "Chọn/Tạo Nhân vật", + "Favorite characters to add them to HotSwaps": "Yêu thích các nhân vật để thêm chúng vào HotSwaps", + "Token counts may be inaccurate and provided just for reference.": "Số lượng mã thông báo có thể không chính xác và chỉ được cung cấp để tham khảo.", + "Total tokens": "Tổng số token", + "Calculating...": "Đang tính...", + "Tokens": "Token", + "Permanent tokens": "Token vĩnh viễn", + "Permanent": "Vĩnh viễn", + "About Token 'Limits'": "Giới thiệu về 'Giới hạn' Token", + "Toggle character info panel": "Chuyển đổi bảng thông tin nhân vật", + "Name this character": "Đặt tên cho nhân vật này", + "extension_token_counter": "Đếm Token:", + "Click to select a new avatar for this character": "Nhấp để chọn một hình đại diện mới cho nhân vật này", + "Add to Favorites": "Thêm vào Mục ưa thích", + "Advanced Definition": "Định nghĩa Nâng cao", + "Character Lore": "Lịch sử Nhân vật", + "Chat Lore": "Truyền thuyết trò chuyện", + "Export and Download": "Xuất và Tải xuống", + "Duplicate Character": "Nhân bản Nhân vật", + "Create Character": "Tạo Nhân vật", + "Delete Character": "Xóa Nhân vật", + "More...": "Thêm...", + "Link to World Info": "Liên kết đến World Info", + "Import Card Lore": "Nhập Card Lore", + "Scenario Override": "Ghi đè Kịch bản", + "Convert to Persona": "Chuyển đổi sang Persona (Nhân cách)", + "Rename": "Đổi tên", + "Link to Source": "Liên kết tới nguồn", + "Replace / Update": "Thay thế/Cập nhật", + "Import Tags": "Nhập thẻ", + "Search / Create Tags": "Tìm kiếm / Tạo Thẻ", + "View all tags": "Xem tất cả các tag", + "Creator's Notes": "Ghi chú của Tác giả", + "Show / Hide Description and First Message": "Hiện / Ẩn Mô tả và Tin nhắn Đầu tiên", + "Character Description": "Mô tả Nhân vật", + "Click to allow/forbid the use of external media for this character.": "Đúp để cho phép/cấm sử dụng phương tiện bên ngoài cho nhân vật này.", + "Ext. Media": "Ex. Tệp", + "Describe your character's physical and mental traits here.": "Mô tả ngoại hình và tính cách nhân vật của bạn ở đây.", + "First message": "Tin nhắn đầu tiên", + "Click to set additional greeting messages": "Bấm để set thêm câu chào :>", + "Alt. Greetings": "thay thế. Lời chào hỏi", + "This will be the first message from the character that starts every chat.": "Đây sẽ là câu chào đầu tiên của nhân vật mỗi khi mở đầu cuộc trò chuyện nè :>", + "Group Controls": "Điều khiển Nhóm", + "Chat Name (Optional)": "Tên Trò chuyện (Tùy chọn)", + "Click to select a new avatar for this group": "Nhấp để chọn một hình đại diện mới cho nhóm này", + "Group reply strategy": "Chiến lược phản hồi nhóm", + "Natural order": "Thứ tự tự nhiên", + "List order": "Thứ tự danh sách", + "Group generation handling mode": "Chế độ xử lý tạo nhóm", + "Swap character cards": "Trao đổi thẻ nhân vật", + "Join character cards (exclude muted)": "Tham gia thẻ nhân vật (loại trừ tắt tiếng)", + "Join character cards (include muted)": "Tham gia thẻ nhân vật (bao gồm cả tắt tiếng)", + "Inserted before each part of the joined fields.": "Được chèn trước mỗi phần của các trường đã nối.", + "Join Prefix": "Tham gia tiền tố", + "When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and with the name of the part (e.g.: description, personality, scenario, etc.)": "Khi chọn 'Tham gia thẻ nhân vật', tất cả các trường tương ứng của các nhân vật sẽ được nối với nhau.\rĐiều này có nghĩa là trong chuỗi câu chuyện chẳng hạn, tất cả các mô tả nhân vật sẽ được nối thành một văn bản lớn.\rNếu muốn tách các trường đó, bạn có thể xác định tiền tố hoặc hậu tố tại đây.\r\rGiá trị này hỗ trợ các macro thông thường và cũng sẽ thay thế {{char}} bằng tên của char có liên quan và bằng tên của phần đó (ví dụ: mô tả, tính cách, kịch bản, v.v.)", + "Inserted after each part of the joined fields.": "Được chèn sau mỗi phần của các trường đã nối.", + "Join Suffix": "Tham gia hậu tố", + "Set a group chat scenario": "Đặt một kịch bản trò chuyện nhóm", + "Click to allow/forbid the use of external media for this group.": "Đúp để cho phép/cấm sử dụng phương tiện bên ngoài cho nhóm này.", + "Restore collage avatar": "Khôi phục ảnh đại diện ghép", + "Allow self responses": "Cho phép tự phản hồi", + "Auto Mode": "Chế độ Tự động", + "Auto Mode delay": "Độ trễ chế độ tự động", + "Hide Muted Member Sprites": "Ẩn các thành viên bị câm", + "Current Members": "Thành viên hiện tại", + "Add Members": "Thêm thành viên", + "Create New Character": "Tạo Nhân vật Mới", + "Import Character from File": "Nhập Nhân vật từ Tệp", + "Import content from external URL": "Nhập nội dung từ link URL bên ngoài", + "Create New Chat Group": "Tạo Nhóm Trò chuyện Mới", + "Characters sorting order": "Thứ tự sắp xếp Nhân vật", + "A-Z": "A-Z", + "Z-A": "Z-A", + "Newest": "Mới nhất", + "Oldest": "Cũ nhất", + "Favorites": "Yêu thích", + "Recent": "Gần đây", + "Most chats": "Nhiều cuộc trò chuyện nhất", + "Least chats": "Ít cuộc trò chuyện nhất", + "Most tokens": "Nhiều token nhất", + "Least tokens": "Ít token nhất", + "Random": "Ngẫu nhiên", + "Toggle character grid view": "Chuyển đổi chế độ xem lưới nhân vật", + "Bulk_edit_characters": "Chỉnh sửa nhân vật theo lô", + "Bulk select all characters": "Chọn hàng loạt tất cả các ký tự", + "Bulk delete characters": "Xóa nhân vật theo lô", + "popup-button-save": "Lưu", + "popup-button-yes": "Đúng", + "popup-button-no": "KHÔNG", + "popup-button-cancel": "Hủy", + "popup-button-import": "Nhập", + "Advanced Definitions": "Các Định nghĩa Nâng cao", + "Prompt Overrides": "Ghi đè Prompt", + "(For Chat Completion and Instruct Mode)": "(Đối với chế độ hoàn thành trò chuyện và hướng dẫn)", + "Insert {{original}} into either box to include the respective default prompt from system settings.": "Chèn {{original}} vào bất kỳ hộp nào để bao gồm Prompt mặc định tương ứng từ cài đặt hệ thống.", + "Main Prompt": "Prompt Chính", + "Any contents here will replace the default Main Prompt used for this character. (v2 spec: system_prompt)": "Bất kỳ nội dung nào ở đây sẽ thay thế Lời nhắc Chính mặc định được sử dụng cho nhân vật này. (v2 spec: hệ thống_lời_nhắc)", + "Any contents here will replace the default Jailbreak Prompt used for this character. (v2 spec: post_history_instructions)": "Bất kỳ nội dung nào ở đây sẽ thay thế Lời nhắc Phá vỡ giam giữ mặc định được sử dụng cho nhân vật này. (v2 spec: hệ thống_lời_nhắc_sau_lịch_sử)", + "Creator's Metadata (Not sent with the AI prompt)": "Dữ liệu siêu dữ liệu của tác giả (Không được gửi kèm với Prompt AI)", + "Creator's Metadata": "Siêu dữ liệu của tác giả", + "(Not sent with the AI Prompt)": "(Không được gửi bằng Lời nhắc AI)", + "Everything here is optional": "Tất cả mọi thứ ở đây đều là tùy chọn", + "(Botmaker's name / Contact Info)": "(Tên của tác giả Bot / Thông tin Liên hệ)", + "(If you want to track character versions)": "(Nếu bạn muốn theo dõi phiên bản của nhân vật)", + "(Describe the bot, give use tips, or list the chat models it has been tested on. This will be displayed in the character list.)": "(Mô tả bot, cung cấp mẹo sử dụng hoặc liệt kê các model mà nó đã được thử nghiệm. Cái này sẽ được hiển thị trong danh sách nhân vật.)", + "Tags to Embed": "Tags để nhúng", + "(Write a comma-separated list of tags)": "(Viết một danh sách các tags được phân tách bằng dấu phẩy)", + "Personality summary": "Tóm tắt Tính cách", + "(A brief description of the personality)": "(Một mô tả ngắn gọn về tính cách)", + "Scenario": "Tình huống", + "(Circumstances and context of the interaction)": "(Hoàn cảnh và context của sự tương tác)", + "Character's Note": "Ghi chú của nhân vật", + "(Text to be inserted in-chat @ designated depth and role)": "(Văn bản sẽ được chèn vào cuộc trò chuyện @ độ sâu và vai trò được chỉ định)", + "@ Depth": "@ Chiều sâu", + "Role": "Vai trò", + "Talkativeness": "Mức nói lắm", + "How often the character speaks in group chats!": "Tần suất nhân vật này phát biểu trong các cuộc trò chuyện nhóm!", + "How often the character speaks in": "Tần suất nhân vật này phát biểu trong", + "group chats!": "các cuộc trò chuyện nhóm!", + "Shy": "Nhát", + "Normal": "Bình thường", + "Chatty": "Lắm mồm", + "Examples of dialogue": "Ví dụ về lời đối thoại", + "Important to set the character's writing style.": "Quan trọng là phải thiết lập phong cách viết của nhân vật.", + "(Examples of chat dialog. Begin each example with START on a new line.)": "(Các ví dụ về đoạn hội thoại trò chuyện. Bắt đầu mỗi ví dụ với START trên một dòng mới.)", + "Save": "Lưu", + "Chat History": "Lịch sử Trò chuyện", + "Import Chat": "Nhập trò chuyện", + "Copy to system backgrounds": "Sao chép vào nền hệ thống", + "Rename background": "Đổi tên nền background", + "Lock": "Khóa", + "Unlock": "Mở khóa", + "Delete background": "Xóa nền background", + "Chat Scenario Override": "Ghi đè kịch bản trò chuyện", + "Remove": "Xóa", + "Type here...": "Nhập vào đây...", + "Chat Lorebook": "Sách truyền thuyết trò chuyện cho", + "Chat Lorebook for": "Sách truyền thuyết trò chuyện cho", + "chat_world_template_txt": "Thông tin thế giới được chọn sẽ bị ràng buộc với cuộc trò chuyện này. Khi tạo phản hồi AI,\n nó sẽ được kết hợp với các mục từ sách truyền thuyết toàn cầu và nhân vật.", + "Select a World Info file for": "Chọn một tệp World Info cho", + "Primary Lorebook": "Sách Truyền thuyết Chính", + "A selected World Info will be bound to this character as its own Lorebook.": "World Info được chọn sẽ được gắn với nhân vật này như một Lorebook riêng của nó.", + "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "Khi tạo phản hồi của AI, nó sẽ được kết hợp với các mục từ một bộ chọn World Info.", + "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "Việc xuất khẩu một nhân vật cũng sẽ xuất khẩu tệp Sách Truyền thuyết được chọn được nhúng trong dữ liệu JSON.", + "Additional Lorebooks": "Sách Truyền thuyết Bổ sung", + "Associate one or more auxillary Lorebooks with this character.": "Liên kết một hoặc nhiều Sách Truyền thuyết phụ trợ với nhân vật này.", + "NOTE: These choices are optional and won't be preserved on character export!": "LƯU Ý: Các lựa chọn này là tùy chọn và sẽ không được bảo tồn khi xuất khẩu nhân vật!", + "Rename chat file": "Đổi tên tệp trò chuyện", + "Export JSONL chat file": "Xuất tệp trò chuyện JSONL", + "Download chat as plain text document": "Tải xuống cuộc trò chuyện dưới dạng tài liệu văn bản đơn giản", + "Delete chat file": "Xóa tệp trò chuyện", + "Use tag as folder": "Gắn thẻ dưới dạng thư mục", + "Delete tag": "Xóa tag", + "Entry Title/Memo": "Tiêu đề Đăng nhập/Ghi chú", + "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized❌ Disabled": "Trạng thái nhập WI:\r🔵 Hằng số\r🟢 Bình thường\r🔗 Được vector hóa\r❌ Bị vô hiệu hóa", + "WI_Entry_Status_Constant": "Không thay đổi", + "WI_Entry_Status_Normal": "Bình thường", + "WI_Entry_Status_Vectorized": "Vector hóa", + "WI_Entry_Status_Disabled": "Tàn tật", + "T_Position": "↑Char: Trước định nghĩa nhân vật\n↓Char: Sau định nghĩa nhân vật\n↑AN: Trước Ghi chú tác giả\n↓AN: Sau Ghi chú tác giả\n@D: Ở độ sâu", + "Before Char Defs": "Trước định nghĩa nhân vật", + "After Char Defs": "Sau định nghĩa nhân vật", + "Before EM": "↑EM", + "After EM": "↓EM", + "Before AN": "Trước AN", + "After AN": "Sau AN", + "at Depth System": "@D ⚙️", + "at Depth User": "@D 👤", + "at Depth AI": "@D 🤖", + "Depth": "Chiều sâu", + "Order:": "Thứ tự:", + "Order": "Thứ tự:", + "Trigger %:": "Cò súng %:", + "Probability": "Xác suất", + "Duplicate world info entry": "Mục nhập thông tin thế giới trùng lặp", + "Delete world info entry": "Xóa mục nhập thông tin thế giới", + "Comma separated (required)": "Phân tách bằng dấu phẩy (bắt buộc)", + "Primary Keywords": "Từ khóa chính", + "Keywords or Regexes": "Từ khóa hoặc Regex", + "Comma separated list": "Danh sách được phân tách bằng dấu phẩy", + "Switch to plaintext mode": "Chuyển sang chế độ bản rõ", + "Logic": "Logic", + "AND ANY": "VÀ BẤT KỲ", + "AND ALL": "VÀ TẤT CẢ", + "NOT ALL": "KHÔNG TẤT CẢ", + "NOT ANY": "KHÔNG BẤT KỲ", + "(ignored if empty)": "(bỏ qua nếu trống)", + "Optional Filter": "Bộ lọc Tùy chọn", + "Keywords or Regexes (ignored if empty)": "Từ khóa hoặc Regexes (bỏ qua nếu trống)", + "Comma separated list (ignored if empty)": "Danh sách được phân tách bằng dấu phẩy (bỏ qua nếu trống)", + "Use global setting": "Sử dụng cài đặt chung", + "Case-Sensitive": "Phân biệt chữ hoa chữ thường", + "Yes": "Có", + "No": "Không", + "Can be used to automatically activate Quick Replies": "Có thể được sử dụng để tự động kích hoạt Trả lời nhanh", + "Automation ID": "ID tự động", + "( None )": "( Không có )", + "Content": "Nội dung", + "Exclude from recursion": "Loại trừ khỏi đệ quy", + "Prevent further recursion (this entry will not activate others)": "Ngăn chặn đệ quy tiếp theo (mục này sẽ không kích hoạt mục khác)", + "Delay until recursion (this entry can only be activated on recursive checking)": "Trì hoãn cho đến khi đệ quy (mục này chỉ có thể được kích hoạt khi kiểm tra đệ quy)", + "What this keyword should mean to the AI, sent verbatim": "Nghĩa của từ khóa này đối với AI, gửi một cách nguyên văn", + "Filter to Character(s)": "Lọc đến Nhân vật", + "Character Exclusion": "Loại trừ Nhân vật", + "-- Characters not found --": "-- Không tìm thấy Nhân vật --", + "Inclusion Group": "Nhóm Bao gồm", + "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "Nhóm Bao gồm đảm bảo chỉ một mục từ một nhóm được kích hoạt tại một thời điểm, nếu nhiều mục được kích hoạt.\rHỗ trợ nhiều nhóm được phân tách bằng dấu phẩy.\r\rTài liệu: World Info - Inclusion Group", + "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "Ưu tiên mục nhập này: Khi được chọn, mục nhập này được ưu tiên trong số tất cả các lựa chọn.\rNếu nhiều ưu tiên được ưu tiên thì cái có 'Thứ tự' cao nhất sẽ được chọn.", + "Only one entry with the same label will be activated": "Chỉ một mục có cùng nhãn sẽ được kích hoạt", + "A relative likelihood of entry activation within the group": "Khả năng tương đối của việc kích hoạt mục nhập trong nhóm", + "Group Weight": "Trọng lượng nhóm", + "Selective": "Lựa chọn", + "Use Probability": "Sử dụng Xác suất", + "Add Memo": "Thêm bản ghi nhớ", + "Text or token ids": "Văn bản hoặc [id mã thông báo]", + "close": "đóng", + "prompt_manager_edit": "Biên tập", + "prompt_manager_name": "Tên", + "A name for this prompt.": "Tên cho Prompt này.", + "To whom this message will be attributed.": "Tin nhắn này sẽ được quy cho ai.", + "AI Assistant": "Trợ lý AI", + "prompt_manager_position": "Chức vụ", + "Injection position. Next to other prompts (relative) or in-chat (absolute).": "Vị trí tiêm. Bên cạnh các Prompt khác (tương đối) hoặc trong trò chuyện (tuyệt đối).", + "prompt_manager_relative": "Liên quan đến", + "prompt_manager_depth": "Chiều sâu", + "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "Độ sâu phun. 0 = sau tin nhắn cuối cùng, 1 = trước tin nhắn cuối cùng, v.v.", + "Prompt": "Prompt", + "The prompt to be sent.": "Lời nhắc được gửi đi.", + "This prompt cannot be overridden by character cards, even if overrides are preferred.": "Lời nhắc này không thể bị ghi đè bằng thẻ ký tự, ngay cả khi ưu tiên ghi đè.", + "prompt_manager_forbid_overrides": "Cấm ghi đè", + "reset": "đặt lại", + "save": "lưu", + "This message is invisible for the AI": "Tin nhắn này AI không thấy được đâu", + "Message Actions": "Hành động tin nhắn", + "Translate message": "Dịch tin nhắn", + "Generate Image": "Tạo Hình ảnh", + "Narrate": "Dẫn chuyện", + "Exclude message from prompts": "Loại trừ tin nhắn khỏi các Prompt", + "Include message in prompts": "Bao gồm tin nhắn trong các Prompt", + "Embed file or image": "Nhúng tệp hoặc hình ảnh", + "Create checkpoint": "Tạo điểm kiểm tra", + "Create Branch": "Tạo Chi nhánh", + "Copy": "Sao chép", + "Open checkpoint chat": "Mở trò chuyện điểm kiểm tra", + "Edit": "Chỉnh sửa", + "Confirm": "Xác nhận", + "Copy this message": "Sao chép tin nhắn này", + "Delete this message": "Xóa tin nhắn này", + "Move message up": "Di chuyển tin nhắn lên", + "Move message down": "Di chuyển tin nhắn xuống", + "Enlarge": "Phóng to", + "Welcome to SillyTavern!": "SillyTavern xin chào!", + "welcome_message_part_1": "Xem", + "welcome_message_part_2": "Tài liệu chính thức", + "welcome_message_part_3": null, + "welcome_message_part_4": "Kiểu", + "welcome_message_part_5": "trong trò chuyện để nhận lệnh và macro.", + "welcome_message_part_6": "Tham gia", + "Discord server": "Server Discord", + "welcome_message_part_7": "để biết thêm thông tin và nhận thông báo chính thức.", + "SillyTavern is aimed at advanced users.": "SillyTavern dành cho dân pro, dân chơi thứ thiệt.", + "If you're new to this, enable the simplified UI mode below.": "Nếu bạn chưa quen dùng lắm, bật chế độ UI đơn giản bên dưới nha.", + "Change it later in the 'User Settings' panel.": "Thay đổi nó sau trong bảng 'Cài đặt người dùng'.", + "Enable simple UI mode": "Bật chế độ giao diện người dùng đơn giản", + "Looking for AI characters?": "Bạn đang tìm kiếm các nhân vật AI à?", + "onboarding_import": "Nhập", + "from supported sources or view": "từ các nguồn hoặc chế độ xem được hỗ trợ", + "Sample characters": "Ký tự mẫu", + "Your Persona": "Nhân cách của bạn", + "Before you get started, you must select a persona name.": "Trước khi bắt đầu, bạn phải chọn một cái tên nhân vật đã.", + "welcome_message_part_8": "Điều này có thể được thay đổi bất cứ lúc nào thông qua", + "welcome_message_part_9": "biểu tượng.", + "Persona Name:": "Tên nhân vật:", + "Temporarily disable automatic replies from this character": "Tạm thời vô hiệu hóa các phản hồi tự động từ nhân vật này", + "Enable automatic replies from this character": "Bật phản hồi tự động từ nhân vật này", + "Trigger a message from this character": "Kích hoạt một tin nhắn từ nhân vật này", + "Move up": "Di chuyển lên", + "Move down": "Di chuyển xuống", + "View character card": "Xem thẻ nhân vật", + "Remove from group": "Xóa khỏi nhóm", + "Add to group": "Thêm vào nhóm", + "Alternate Greetings": "Lời chào thay thế", + "Alternate_Greetings_desc": "Chúng sẽ được hiển thị dưới dạng thao tác vuốt trên tin nhắn đầu tiên khi bắt đầu cuộc trò chuyện mới.\n Các thành viên trong nhóm có thể chọn một trong số họ để bắt đầu cuộc trò chuyện.", + "Alternate Greetings Hint": "Nhấp vào nút để bắt đầu!", + "(This will be the first message from the character that starts every chat)": "(Điều này sẽ là tin nhắn đầu tiên từ nhân vật mà bắt đầu mỗi cuộc trò chuyện)", + "Forbid Media Override explanation": "Khả năng sử dụng phương tiện truyền thông bên ngoài trong trò chuyện của nhân vật/nhóm hiện tại.", + "Forbid Media Override subtitle": "Phương tiện: hình ảnh, video, âm thanh. Bên ngoài: không được lưu trữ trên máy chủ cục bộ.", + "Always forbidden": "Luôn cấm", + "Always allowed": "Luôn luôn cho phép", + "View contents": "Xem nội dung", + "Remove the file": "Xóa tập tin", + "Unique to this chat": "Duy nhất cho cuộc trò chuyện này", + "Checkpoints inherit the Note from their parent, and can be changed individually after that.": "Điểm kiểm tra kế thừa Ghi chú từ cha mẹ của chúng và có thể được thay đổi riêng lẻ sau đó.", + "Include in World Info Scanning": "Bao gồm trong World Info scanning", + "Before Main Prompt / Story String": "Trước Lời nhắc chính/Chuỗi câu chuyện", + "After Main Prompt / Story String": "Sau Prompt chính/chuỗi câu chuyện", + "as": "BẰNG", + "Insertion Frequency": "Tần số chèn", + "(0 = Disable, 1 = Always)": "(0 = Tắt, 1 = Luôn luôn)", + "User inputs until next insertion:": "Đầu vào của người dùng cho đến lần chèn tiếp theo:", + "Character Author's Note (Private)": "Ghi chú của tác giả nhân vật (Riêng tư)", + "Won't be shared with the character card on export.": "Sẽ không được chia sẻ với thẻ nhân vật khi xuất.", + "Will be automatically added as the author's note for this character. Will be used in groups, but can't be modified when a group chat is open.": "Sẽ được tự động thêm vào làm ghi chú của tác giả cho nhân vật này. Sẽ được sử dụng theo nhóm, nhưng\n không thể sửa đổi khi cuộc trò chuyện nhóm đang mở.", + "Use character author's note": "Sử dụng ghi chú của tác giả nhân vật", + "Replace Author's Note": "Thay thế ghi chú của tác giả", + "Default Author's Note": "Ghi chú của tác giả mặc định", + "Will be automatically added as the Author's Note for all new chats.": "Sẽ được tự động thêm làm Ghi chú của tác giả cho tất cả các cuộc trò chuyện mới.", + "Chat CFG": "Trò chuyện CFG", + "1 = disabled": "1 = bị vô hiệu hóa", + "write short replies, write replies using past tense": "viết trả lời ngắn, viết trả lời dùng thì quá khứ", + "Positive Prompt": "Lời nhắc tích cực", + "Use character CFG scales": "Sử dụng thang đo CFG ký tự", + "Character CFG": "CFG nhân vật", + "Will be automatically added as the CFG for this character.": "Sẽ được tự động thêm làm CFG cho nhân vật này.", + "Global CFG": "CFG toàn cầu", + "Will be used as the default CFG options for every chat unless overridden.": "Sẽ được sử dụng làm tùy chọn CFG mặc định cho mọi cuộc trò chuyện trừ khi bị ghi đè.", + "CFG Prompt Cascading": "Xếp tầng nhắc nhở CFG", + "Combine positive/negative prompts from other boxes.": "Kết hợp những Prompt tích cực/tiêu cực từ các ô khác.", + "For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string.": "Ví dụ: việc đánh dấu vào các hộp trò chuyện, chung và ký tự sẽ kết hợp tất cả các Prompt phủ định thành một chuỗi được phân tách bằng dấu phẩy.", + "Always Include": "Luôn bao gồm", + "Chat Negatives": "Trò chuyện phủ định", + "Character Negatives": "Nhân vật tiêu cực", + "Global Negatives": "Tiêu cực toàn cầu", + "Custom Separator:": "Dấu phân cách tùy chỉnh:", + "Insertion Depth:": "Độ sâu chèn:", + "Token Probabilities": "Xác suất Mã thông báo", + "Select a token to see alternatives considered by the AI.": "Chọn một mã thông báo để xem các phương án thay thế được AI xem xét.", + "Not connected to API!": "Không kết nối với API!", + "Type a message, or /? for help": "Nhập gì đó đi bồ ơi, hoặc gõ /? để tui bày cho", + "Continue script execution": "Tiếp tục thực thi tập lệnh", + "Pause script execution": "Tạm dừng thực thi tập lệnh", + "Abort script execution": "Hủy bỏ việc thực thi tập lệnh", + "Abort request": "Hủy yêu cầu", + "Continue the last message": "Tiếp tục từ tin nhắn cuối cùng", + "Send a message": "Gửi tin nhắn", + "Close chat": "Đóng trò chuyện", + "Toggle Panels": "Bật bảng lên", + "Back to parent chat": "Quay lại cuộc trò chuyện chính", + "Save checkpoint": "Lưu diểm checkpoint", + "Convert to group": "Chuyển đổi thành nhóm", + "Start new chat": "Bắt đầu trò chuyện mới", + "Manage chat files": "Quản lý tệp trò chuyện", + "Delete messages": "Xóa tin nhắn", + "Regenerate": "Tạo lại", + "Ask AI to write your message for you": "Kêu AI viết tin nhắn hộ bạn", + "Impersonate": "Giả thoại danh", + "Continue": "Tiếp tục", + "Bind user name to that avatar": "Liên kết tên người dùng với avatar đó", + "Change persona image": "Thay đổi ảnh đại diện nhân cách", + "Select this as default persona for the new chats.": "Chọn cái này làm nhân cách mặc định cho các cuộc trò chuyện mới.", + "Delete persona": "Xóa nhân cách", + "These characters are the winners of character design contests and have outstandable quality.": "Những nhân vật này là người chiến thắng trong các cuộc thi thiết kế nhân vật và có chất lượng vượt trội.", + "Contest Winners": "Người chiến thắng cuộc thi", + "These characters are the finalists of character design contests and have remarkable quality.": "Những nhân vật này lọt vào vòng chung kết của các cuộc thi thiết kế nhân vật và có chất lượng vượt trội.", + "Featured Characters": "Nhân vật nổi bật", + "Attach a File": "Đính kèm tập tin", + "Open Data Bank": "Mở Ngân hàng dữ liệu", + "Enter a URL or the ID of a Fandom wiki page to scrape:": "Nhập URL hoặc ID của trang wiki Fandom để thu thập:", + "Examples:": "Ví dụ:", + "Example:": "Ví dụ:", + "Single file": "Tệp đơn", + "All articles will be concatenated into a single file.": "Tất cả các bài viết sẽ được nối lại thành một tệp duy nhất.", + "File per article": "Tập tin cho mỗi bài viết", + "Each article will be saved as a separate file.": "Không được khuyến khích. Mỗi bài viết sẽ được lưu thành một file riêng biệt.", + "Data Bank": "Dữ liệu ngân hàng", + "These files will be available for extensions that support attachments (e.g. Vector Storage).": "Các tệp này sẽ có sẵn cho các tiện ích mở rộng hỗ trợ tệp đính kèm (ví dụ: Bộ lưu trữ Vector).", + "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.": "Các loại tệp được hỗ trợ: Văn bản thuần túy, PDF, Markdown, HTML, EPUB.", + "Drag and drop files here to upload.": "Kéo và thả tập tin vào đây để tải lên.", + "Date (Newest First)": "Ngày (Mới nhất đầu tiên)", + "Date (Oldest First)": "Ngày (Cũ nhất đầu tiên)", + "Name (A-Z)": "Tên (A-Z)", + "Name (Z-A)": "Tên (Z-A)", + "Size (Smallest First)": "Kích thước (Nhỏ nhất đầu tiên)", + "Size (Largest First)": "Kích thước (Lớn nhất đầu tiên)", + "Bulk Edit": "Chỉnh sửa hàng loạt", + "Select All": "Chọn tất cả", + "Select None": "Chọn Không có", + "Global Attachments": "Tệp đính kèm toàn cầu", + "These files are available for all characters in all chats.": "Những tệp này có sẵn cho tất cả các ký tự trong tất cả các cuộc trò chuyện.", + "Character Attachments": "Tệp đính kèm ký tự", + "These files are available the current character in all chats they are in.": "Các tệp này có sẵn ký tự hiện tại trong tất cả các cuộc trò chuyện có chứa chúng.", + "Saved locally. Not exported.": "Đã lưu cục bộ. Không xuất khẩu.", + "Chat Attachments": "Tệp đính kèm trò chuyện", + "These files are available to all characters in the current chat.": "Những tệp này có sẵn cho tất cả các nhân vật trong cuộc trò chuyện hiện tại.", + "Enter a base URL of the MediaWiki to scrape.": "Nhập URL cơ sở của MediaWiki để thu thập.", + "Don't include the page name!": "Không bao gồm tên trang!", + "Enter web URLs to scrape (one per line):": "Nhập URL web để cạo (một URL trên mỗi dòng):", + "Enter a video URL to download its transcript.": "Nhập URL hoặc ID video để tải xuống bản ghi của nó.", + "Expression API": "Địa phương\nTiện ích bổ sung\nLLM", + "ext_sum_with": "Tóm tắt với:", + "ext_sum_main_api": "API chính", + "ext_sum_current_summary": "Tóm tắt hiện tại:", + "ext_sum_restore_previous": "Phục hồi trước đó", + "ext_sum_memory_placeholder": "Tóm tắt sẽ được tạo ở đây...", + "Trigger a summary update right now.": "Tóm tắt ngay bây giờ", + "ext_sum_force_text": "Tóm tắt ngay bây giờ", + "Disable automatic summary updates. While paused, the summary remains as-is. You can still force an update by pressing the Summarize now button (which is only available with the Main API).": "Tắt cập nhật tóm tắt tự động. Trong khi tạm dừng, tóm tắt vẫn giữ nguyên. Bạn vẫn có thể buộc cập nhật bằng cách nhấn nút Tóm tắt ngay (chỉ khả dụng với API chính).", + "ext_sum_pause": "Tạm ngừng", + "Omit World Info and Author's Note from text to be summarized. Only has an effect when using the Main API. The Extras API always omits WI/AN.": "Bỏ qua World Info và Ghi chú của tác giả khỏi văn bản cần tóm tắt. Chỉ có tác dụng khi sử dụng API chính. API bổ sung luôn bỏ qua WI/AN.", + "ext_sum_no_wi_an": "Không có WI/AN", + "ext_sum_settings_tip": "Chỉnh sửa Prompt tóm tắt, vị trí chèn, v.v.", + "ext_sum_settings": "Cài đặt tóm tắt", + "ext_sum_prompt_builder": "Trình tạo nhắc nhở", + "ext_sum_prompt_builder_1_desc": "Tiện ích mở rộng sẽ xây dựng Prompt riêng bằng cách sử dụng các thông báo chưa được tóm tắt. Chặn cuộc trò chuyện cho đến khi bản tóm tắt được tạo.", + "ext_sum_prompt_builder_1": "Nguyên, chặn", + "ext_sum_prompt_builder_2_desc": "Tiện ích mở rộng sẽ xây dựng Prompt riêng bằng cách sử dụng các thông báo chưa được tóm tắt. Không chặn cuộc trò chuyện trong khi bản tóm tắt đang được tạo. Không phải tất cả các chương trình phụ trợ đều hỗ trợ chế độ này.", + "ext_sum_prompt_builder_2": "Nguyên, không chặn", + "ext_sum_prompt_builder_3_desc": "Tiện ích mở rộng sẽ sử dụng trình tạo Prompt chính thông thường và thêm yêu cầu tóm tắt vào đó làm thông báo hệ thống cuối cùng.", + "ext_sum_prompt_builder_3": "Cổ điển, chặn", + "Summary Prompt": "Lời nhắc tóm tắt", + "ext_sum_restore_default_prompt_tip": "Khôi phục Prompt mặc định", + "ext_sum_prompt_placeholder": "Lời nhắc này sẽ được gửi tới AI để yêu cầu tạo bản tóm tắt. {{words}} sẽ phân giải thành tham số 'Số từ'.", + "ext_sum_target_length_1": "Độ dài tóm tắt mục tiêu", + "ext_sum_target_length_2": null, + "ext_sum_target_length_3": "từ)", + "ext_sum_api_response_length_1": "Độ dài phản hồi API", + "ext_sum_api_response_length_2": null, + "ext_sum_api_response_length_3": "mã thông báo)", + "ext_sum_0_default": "0 = mặc định", + "ext_sum_raw_max_msg": "[Thô] Số tin nhắn tối đa cho mỗi yêu cầu", + "ext_sum_0_unlimited": "0 = không giới hạn", + "Update frequency": "Tần số cập nhật", + "ext_sum_update_every_messages_1": "Cập nhật mỗi", + "ext_sum_update_every_messages_2": "tin nhắn", + "ext_sum_0_disable": "0 = vô hiệu hóa", + "ext_sum_auto_adjust_desc": "Cố gắng tự động điều chỉnh khoảng thời gian dựa trên số liệu trò chuyện.", + "ext_sum_update_every_words_1": "Cập nhật mỗi", + "ext_sum_update_every_words_2": "từ", + "ext_sum_both_sliders": "Nếu cả hai thanh trượt đều khác 0 thì cả hai sẽ kích hoạt cập nhật tóm tắt theo các khoảng thời gian tương ứng.", + "ext_sum_injection_template": "Mẫu tiêm", + "ext_sum_memory_template_placeholder": "{{tóm tắt}} sẽ chuyển sang nội dung tóm tắt hiện tại.", + "ext_sum_injection_position": "Vị trí tiêm", + "How many messages before the current end of the chat.": "Có bao nhiêu tin nhắn trước khi kết thúc cuộc trò chuyện hiện tại.", + "ext_regex_title": "Biểu thức chính quy", + "ext_regex_new_global_script": "+ Toàn cầu", + "ext_regex_new_scoped_script": "+ Phạm vi", + "ext_regex_import_script": "Nhập khẩu", + "ext_regex_global_scripts": "Tập lệnh toàn cầu", + "ext_regex_global_scripts_desc": "Có sẵn cho tất cả các nhân vật. Đã lưu vào cài đặt cục bộ.", + "ext_regex_scoped_scripts": "Tập lệnh có phạm vi", + "ext_regex_scoped_scripts_desc": "Chỉ có sẵn cho nhân vật này. Đã lưu vào dữ liệu thẻ.", + "Regex Editor": "Trình soạn thảo Regex", + "Test Mode": "Chê độ kiểm tra", + "ext_regex_desc": "Regex là công cụ tìm/thay thế chuỗi bằng biểu thức chính quy. Nếu bạn muốn tìm hiểu thêm, hãy nhấp vào ? bên cạnh tiêu đề.", + "Input": "Đầu vào", + "ext_regex_test_input_placeholder": "Nhập ở đây...", + "Output": "đầu ra", + "ext_regex_output_placeholder": "Trống", + "Script Name": "Tên tập lệnh", + "Find Regex": "Tìm biểu thức chính quy", + "Replace With": "Thay bằng", + "ext_regex_replace_string_placeholder": "Sử dụng {{match}} để bao gồm văn bản khớp từ Find Regex hoặc $1, $2, v.v. cho các nhóm nắm bắt.", + "Trim Out": "Cắt bỏ", + "ext_regex_trim_placeholder": "Cắt bỏ toàn bộ các phần không mong muốn khỏi kết quả khớp regex trước khi thay thế. Tách từng phần tử bằng dấu enter.", + "ext_regex_affects": "ảnh hưởng", + "ext_regex_user_input": "Đầu vào của người dùng", + "ext_regex_ai_output": "Đầu ra AI", + "Slash Commands": "Lệnh gạch chéo", + "ext_regex_min_depth_desc": "Khi áp dụng cho Prompt hoặc hiển thị, chỉ ảnh hưởng đến các tin nhắn có độ sâu ít nhất N cấp độ. 0 = tin nhắn cuối cùng, 1 = tin nhắn áp chót, v.v. Chỉ tính các mục WI @Depth và các tin nhắn có thể sử dụng được, tức là không bị ẩn hoặc hệ thống.", + "Min Depth": "Độ sâu tối thiểu", + "ext_regex_min_depth_placeholder": "Vô hạn", + "ext_regex_max_depth_desc": "Khi áp dụng cho Prompt hoặc màn hình, chỉ ảnh hưởng đến tin nhắn không quá N cấp độ. 0 = tin nhắn cuối cùng, 1 = tin nhắn áp chót, v.v. Chỉ tính các mục WI @Depth và các tin nhắn có thể sử dụng được, tức là không bị ẩn hoặc hệ thống.", + "ext_regex_other_options": "Sự lựa chọn khác", + "Only Format Display": "Chỉ hiển thị định dạng", + "ext_regex_only_format_prompt_desc": "Lịch sử trò chuyện sẽ không thay đổi, chỉ có Prompt khi yêu cầu được gửi (khi tạo).", + "Only Format Prompt (?)": "Chỉ định dạng nhắc nhở", + "Run On Edit": "Chạy trên Chỉnh sửa", + "ext_regex_substitute_regex_desc": "Thay thế {{macros}} trong Tìm Regex trước khi chạy nó", + "Substitute Regex": "Thay thế Regex", + "ext_regex_import_target": "Nhập vào:", + "ext_regex_disable_script": "Tắt tập lệnh", + "ext_regex_enable_script": "Bật tập lệnh", + "ext_regex_edit_script": "Chỉnh sửa tập lệnh", + "ext_regex_move_to_global": "Di chuyển đến các tập lệnh toàn cầu", + "ext_regex_move_to_scoped": "Di chuyển đến các tập lệnh có phạm vi", + "ext_regex_export_script": "Xuất tập lệnh", + "ext_regex_delete_script": "Xóa tập lệnh", + "Trigger Stable Diffusion": "Khuếch tán ổn định kích hoạt", + "sd_Yourself": "Bản thân bạn", + "sd_Your_Face": "Mặt của bạn", + "sd_Me": "Tôi", + "sd_The_Whole_Story": "Toàn bộ câu chuyện", + "sd_The_Last_Message": "Tin nhắn cuối cùng", + "sd_Raw_Last_Message": "Tin nhắn cuối cùng thô", + "sd_Background": "Lý lịch", + "Image Generation": "Tạo hình ảnh", + "sd_refine_mode": "Cho phép chỉnh sửa Prompt theo cách thủ công trước khi gửi chúng đến API thế hệ", + "sd_refine_mode_txt": "Chỉnh sửa Prompt trước khi tạo", + "sd_interactive_mode": "Tự động tạo hình ảnh khi gửi tin nhắn như “gửi cho tôi ảnh con mèo”.", + "sd_interactive_mode_txt": "Chế độ tương tác", + "sd_multimodal_captioning": "Sử dụng chú thích đa phương thức để tạo Prompt về chân dung người dùng và nhân vật dựa trên hình đại diện của họ.", + "sd_multimodal_captioning_txt": "Sử dụng chú thích đa phương thức cho ảnh chân dung", + "sd_expand": "Tự động mở rộng Prompt bằng mô hình tạo văn bản", + "sd_expand_txt": "Lời nhắc tự động nâng cao", + "sd_snap": "Điều chỉnh nhanh các yêu cầu tạo có tỷ lệ khung hình bắt buộc (chân dung, hình nền) về độ phân giải đã biết gần nhất, đồng thời cố gắng duy trì số lượng pixel tuyệt đối (được khuyến nghị cho SDXL).", + "sd_snap_txt": "Chụp độ phân giải được điều chỉnh tự động", + "Source": "Nguồn", + "sd_auto_url": "Ví dụ: {{auto_url}}", + "Authentication (optional)": "Xác thực (tùy chọn)", + "Example: username:password": "Ví dụ: tên người dùng:mật khẩu", + "Important:": "Quan trọng:", + "sd_auto_auth_warning_1": "chạy giao diện người dùng web SD với", + "sd_auto_auth_warning_2": "lá cờ! Máy chủ phải có thể truy cập được từ máy chủ SillyTavern.", + "sd_drawthings_url": "Ví dụ: {{drawthings_url}}", + "sd_drawthings_auth_txt": "chạy ứng dụng DrawThings với tính năng chuyển đổi API HTTP được bật trong giao diện người dùng! Máy chủ phải có thể truy cập được từ máy chủ SillyTavern.", + "sd_vlad_url": "Ví dụ: {{vlad_url}}", + "The server must be accessible from the SillyTavern host machine.": "Máy chủ phải có thể truy cập được từ máy chủ SillyTavern.", + "Hint: Save an API key in AI Horde API settings to use it here.": "Gợi ý: Lưu khóa API trong cài đặt API AI Horde để sử dụng tại đây.", + "Allow NSFW images from Horde": "Cho phép hình ảnh NSFW từ Horde", + "Sanitize prompts (recommended)": "Nhắc nhở vệ sinh (khuyến nghị)", + "Automatically adjust generation parameters to ensure free image generations.": "Tự động điều chỉnh các thông số tạo để đảm bảo tạo ra hình ảnh miễn phí.", + "Avoid spending Anlas": "Tránh chi tiêu Anlas", + "Opus tier": "(Cấp Opus)", + "View my Anlas": "Xem Anlas của tôi", + "These settings only apply to DALL-E 3": "Các cài đặt này chỉ áp dụng cho DALL-E 3", + "Image Style": "Kiểu ảnh", + "Image Quality": "Chất lượng hình ảnh", + "Standard": "Tiêu chuẩn", + "HD": "HD", + "sd_comfy_url": "Ví dụ: {{comfy_url}}", + "Open workflow editor": "Mở trình chỉnh sửa quy trình công việc", + "Create new workflow": "Tạo quy trình làm việc mới", + "Delete workflow": "Xóa quy trình làm việc", + "Enhance": "Nâng cao", + "Refine": "Lọc", + "Decrisper": "Bộ giải mã", + "Sampling steps": "Các bước lấy mẫu ()", + "Width": "Chiều rộng ()", + "Height": "Chiều cao ()", + "Resolution": "Nghị quyết", + "Model": "Người mẫu", + "Sampling method": "Phương pháp lấy mẫu", + "Karras (not all samplers supported)": "Karras (không phải tất cả các trình lấy mẫu đều được hỗ trợ)", + "SMEA versions of samplers are modified to perform better at high resolution.": "Các phiên bản lấy mẫu SMEA được sửa đổi để hoạt động tốt hơn ở độ phân giải cao.", + "SMEA": "SMEA", + "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "Các biến thể DYN của bộ lấy mẫu SMEA thường cho kết quả đầu ra đa dạng hơn nhưng có thể bị lỗi ở độ phân giải rất cao.", + "DYN": "DYN", + "Scheduler": "Người lập kế hoạch", + "Restore Faces": "Khôi phục khuôn mặt", + "Hires. Fix": "Thuê. Sửa chữa", + "Upscaler": "nâng cấp", + "Upscale by": "Cao cấp bởi", + "Denoising strength": "Mức độ khử noise", + "Hires steps (2nd pass)": "Thuê bước (đạt thứ 2)", + "Preset for prompt prefix and negative prompt": "Đặt trước cho tiền tố Prompt và Prompt phủ định", + "Style": "Phong cách", + "Save style": "Lưu kiểu", + "Delete style": "Xóa kiểu", + "Common prompt prefix": "Tiền tố nhắc chung", + "sd_prompt_prefix_placeholder": "Sử dụng {prompt} để chỉ định vị trí chèn Prompt được tạo", + "Negative common prompt prefix": "Tiền tố dấu nhắc chung phủ định", + "Character-specific prompt prefix": "Tiền tố nhắc nhở dành riêng cho ký tự", + "Won't be used in groups.": "Sẽ không được sử dụng trong nhóm.", + "sd_character_prompt_placeholder": "Bất kỳ đặc điểm nào mô tả ký tự hiện được chọn. Sẽ được thêm vào sau tiền tố nhắc chung.\nVí dụ: nữ, mắt xanh, tóc nâu, áo hồng", + "Character-specific negative prompt prefix": "Tiền tố nhắc phủ định dành riêng cho ký tự", + "sd_character_negative_prompt_placeholder": "Bất kỳ đặc điểm nào không xuất hiện cho ký tự đã chọn. Sẽ được thêm vào sau tiền tố dấu nhắc chung phủ định.\nVí dụ: đồ trang sức, giày dép, kính", + "Shareable": "Có thể chia sẻ", + "Image Prompt Templates": "Mẫu nhắc nhở hình ảnh", + "Vectors Model Warning": "Bạn nên xóa vectơ khi thay đổi mô hình trong khi trò chuyện. Nếu không, nó sẽ dẫn đến kết quả dưới mệnh giá.", + "Translate files into English before processing": "Dịch file sang tiếng Anh trước khi xử lý", + "Manager Users": "Quản lý người dùng", + "New User": "Người dùng mới", + "Status:": "Trạng thái:", + "Created:": "Tạo:", + "Display Name:": "Tên hiển thị:", + "User Handle:": "Xử lý người dùng:", + "Password:": "Mật khẩu:", + "Confirm Password:": "Xác nhận mật khẩu:", + "This will create a new subfolder...": "Điều này sẽ tạo một thư mục con mới trong thư mục /data/ với tên thư mục do người dùng xử lý.", + "Current Password:": "Mật khẩu hiện tại:", + "New Password:": "Mật khẩu mới:", + "Confirm New Password:": "Xác nhận mật khẩu mới:", + "Debug Warning": "Các chức năng trong danh mục này chỉ dành cho người dùng pro. Đừng nhấp vào bất cứ thứ gì nếu bạn không chắc chắn về hậu quả.", + "Execute": "Thực hiện", + "Are you sure you want to delete this user?": "Bạn có chắc chắn muốn xóa người dùng này?", + "Deleting:": "Đang xóa:", + "Also wipe user data.": "Đồng thời xóa dữ liệu người dùng.", + "Warning:": "Cảnh báo:", + "This action is irreversible.": "Hành động này không thể hoàn tác.", + "Type the user's handle below to confirm:": "Nhập tên người dùng bên dưới để xác nhận:", + "Import Characters": "Nhập ký tự", + "Enter the URL of the content to import": "Nhập URL của nội dung cần nhập", + "Supported sources:": "Các nguồn được hỗ trợ:", + "char_import_1": "Nhân vật Chub (Liên kết trực tiếp hoặc ID)", + "char_import_example": "Ví dụ:", + "char_import_2": "Chub (Nhập URL trực tiếp hoặc ID)", + "char_import_3": "JanitorAI (Nhập URL trực tiếp hoặc UUID)", + "char_import_4": "Pygmalion.chat (Nhập URL trực tiếp hoặc UUID)", + "char_import_5": "AICharacterCards.com (Nhập URL trực tiếp hoặc ID)", + "char_import_6": "Nhập PNG trực tiếp (tham khảo", + "char_import_7": "đối với các máy chủ được phép)", + "char_import_8": "RisuRealm (URL trực tiếp)", + "Supports importing multiple characters.": "Hỗ trợ nhập nhiều ký tự.", + "Write each URL or ID into a new line.": "Viết mỗi URL hoặc ID vào một dòng mới.", + "Export for character": "Xuất cho nhân vật", + "Export prompts for this character, including their order.": "Xuất Prompt cho ký tự này, bao gồm cả thứ tự của chúng.", + "Export all": "Xuất tất cả", + "Export all your prompts to a file": "Xuất tất cả Prompt của bạn sang một tệp", + "Insert prompt": "Chèn Prompt", + "Delete prompt": "Xóa Prompt", + "Import a prompt list": "Nhập danh sách Prompt", + "Export this prompt list": "Xuất danh sách Prompt này", + "Reset current character": "Đặt lại nhân vật hiện tại", + "New prompt": "Prompt mới", + "Prompts": "Prompts", + "Total Tokens:": "Tổng cộng token:", + "prompt_manager_tokens": "Bộ Tách từ", + "Are you sure you want to reset your settings to factory defaults?": "Bạn có chắc chắn muốn đặt lại cài đặt về mặc định ban đầu không?", + "Don't forget to save a snapshot of your settings before proceeding.": "Đừng quên sao lưu snapshot của cài đặt của bạn trước khi tiếp tục nha.", + "Settings Snapshots": "Cài đặt Snapshot", + "Record a snapshot of your current settings.": "Ghi lại Snapshot của cài đặt hiện tại.", + "Make a Snapshot": "Tạo một Snapshot", + "Restore this snapshot": "Khôi phục Snapshot này", + "Hi,": "CHÀO,", + "To enable multi-account features, restart the SillyTavern server with": "Để bật tính năng đa tài khoản, hãy khởi động lại máy chủ SillyTavern bằng", + "set to true in the config.yaml file.": "cách đặt enableUserAccounts thành true trong config.yaml.", + "Account Info": "Thông tin tài khoản", + "To change your user avatar, use the buttons below or select a default persona in the Persona Management menu.": "Để thay đổi hình đại diện người dùng của bạn, hãy sử dụng các nút bên dưới hoặc chọn nhân vật mặc định trong menu Quản lý Persona.", + "Set your custom avatar.": "Đặt avatar tùy chỉnh của bạn.", + "Remove your custom avatar.": "Xóa hình avatar của bạn.", + "Handle:": "Xử lý:", + "This account is password protected.": "Tài khoản này được bảo vệ bằng mật khẩu.", + "This account is not password protected.": "Tài khoản này không được bảo vệ bằng mật khẩu.", + "Account Actions": "Các thao tác tài khoản", + "Change Password": "Đổi mật khẩu", + "Manage your settings snapshots.": "Quản lý ảnh snapshots cài đặt của bạn.", + "Download a complete backup of your user data.": "Tải xuống bản sao lưu đầy đủ dữ liệu người dùng của bạn.", + "Download Backup": "Tải xuống bản sao lưu", + "Danger Zone": "Khu vực nguy hiểm", + "Reset your settings to factory defaults.": "Đặt lại cài đặt của bạn về mặc định ban đầu.", + "Reset Settings": "Đặt lại cài đặt", + "Wipe all user data and reset your account to factory settings.": "Xóa toàn bộ dữ liệu người dùng và khôi phục cài đặt gốc cho tài khoản của bạn.", + "Reset Everything": "Đặt lại mọi thứ", + "Reset Code:": "Đặt lại mã:", + "Want to update?": "Muốn cập nhật?", + "How to start chatting?": "Bắt đầu chat chit kiểu gì zậy?", + "Click _space": "Đúp vào", + "and select a": "và chọn ", + "Chat API": "Chat API", + "and pick a character.": "và chọn nhân vật.", + "You can browse a list of bundled characters in the": "Bạn có thể xem qua danh sách các nhân vật có sẵn", + "Download Extensions & Assets": "Tải xuống tiện ích mở rộng và Asests", + "menu within": "menu bên trong", + "Confused or lost?": "Đơ đầu hay lạc trôi?", + "click these icons!": "nhấp vào các biểu tượng này!", + "in the chat bar": "trong thanh trò chuyện", + "SillyTavern Documentation Site": "Tài liệu về SillyTavern", + "Extras Installation Guide": "Hướng dẫn cài đặt bổ sung", + "Still have questions?": "Bạn còn thắc mắc?", + "Join the SillyTavern Discord": "Tham gia Kênh Discord của SillyTavern", + "Post a GitHub issue": "Đăng một vấn đề trên GitHub", + "Contact the developers": "Liên hệ với Devs" +} diff --git a/jiuguan2025cc/public/locales/zh-cn.json b/jiuguan2025cc/public/locales/zh-cn.json new file mode 100644 index 0000000000000000000000000000000000000000..3b05b12fc64dc991e0f490dd22be715d93b78d87 --- /dev/null +++ b/jiuguan2025cc/public/locales/zh-cn.json @@ -0,0 +1,2113 @@ +{ + "Favorite": "星标", + "Tag": "标签", + "Duplicate": "复制", + "Persona": "用户角色", + "Delete": "删除", + "AI Response Configuration": "AI响应配置", + "AI Configuration panel will stay open": "AI配置面板将保持打开", + "clickslidertips": "单击滑块以手动输入值。", + "MAD LAB MODE ON": "疯狂实验室模式开启", + "Documentation on sampling parameters": "有关采样参数的文档", + "kobldpresets": "Kobold 预设", + "Import preset": "导入预设", + "Export preset": "导出预设", + "Delete the preset": "删除预设", + "guikoboldaisettings": "KoboldAI 用户界面设置", + "Update current preset": "更新当前预设", + "Rename current preset": "重命名当前预设", + "Save preset as": "另存预设为", + "Restore current preset": "恢复当前预设", + "novelaipresets": "NovelAI 预设", + "Default": "默认", + "openaipresets": "对话补全预设", + "Text Completion presets": "文本补全预设", + "response legth(tokens)": "回复长度(以词符数计)", + "Streaming": "流式传输", + "Streaming_desc": "逐位显示生成的回复", + "context size(tokens)": "上下文长度(以词符数计)", + "unlocked": "解锁", + "Only enable this if your model supports context sizes greater than 8192 tokens": "仅在您的模型支持大于8192个词符的上下文长度时启用此选项", + "Max prompt cost:": "最大提示词费用:", + "AI Module": "AI 模块", + "Changes the style of the generated text.": "更改生成文本的样式。", + "No Module": "无模块", + "Instruct": "指导", + "Prose Augmenter": "散文增强器", + "Text Adventure": "文字冒险", + "Temperature": "温度", + "rep.pen": "重复惩罚", + "Rep. Pen. Range.": "重复惩罚范围。", + "Rep. Pen. Slope": "重复惩罚斜率", + "Rep. Pen. Freq.": "频率重复惩罚", + "Rep. Pen. Presence": "存在重复惩罚", + "Min P": "Min P", + "TFS": "无尾采样", + "Top P": "Top P", + "Top A": "Top A", + "Top K": "Top K", + "Mirostat Tau": "Mirostat τ", + "Mirostat LR": "Mirostat 学习率", + "Typical P": "典型P", + "Linear": "Linear", + "Quad": "Quad", + "Conf": "Conf", + "Min Length": "最小长度", + "Phrase Repetition Penalty": "短语重复惩罚", + "Off": "关闭", + "Very light": "非常轻", + "Light": "轻", + "Medium": "中", + "Aggressive": "激进", + "Very aggressive": "非常激进", + "Preamble": "序文", + "Restore default prompt": "恢复默认提示词", + "Use style tags to modify the writing style of the output.": "使用样式标签修改输出的写作风格。", + "Banned Tokens": "禁用的词符", + "Sequences you don't want to appear in the output. One per line.": "您不希望出现在输出中的字符串。 每行一个。", + "Logit Bias": "Logit 偏置", + "Add": "添加", + "Helps to ban or reenforce the usage of certain words": "有助于禁止或加强某些单词的使用", + "Unlocked Context Size": "解锁上下文长度", + "Unrestricted maximum value for the context slider": "AI可见的最大上下文长度", + "Context Size (tokens)": "上下文长度(以词符数计)", + "Max Response Length (tokens)": "最大回复长度(以词符数计)", + "Multiple swipes per generation": "每次生成多个备选回复", + "Middle-out Transform": "Middle-out Transform", + "Auto": "Auto", + "Allow": "Allow", + "Forbid": "Forbid", + "Enable OpenAI completion streaming": "启用OpenAI文本补全流式传输", + "Display the response bit by bit as it is generated.": "随着回复的生成,逐词逐句地显示结果。", + "When this is off, responses will be displayed all at once when they are complete.": "当此选项关闭时,回复将在完成后一次性显示。", + "Frequency Penalty": "频率惩罚", + "Presence Penalty": "存在惩罚", + "Repetition Penalty": "重复惩罚", + "Quick Prompts Edit": "快速提示词编辑", + "Main": "主要", + "Auxiliary": "辅助的", + "Post-History Instructions": "后续历史指令", + "Utility Prompts": "实用提示词", + "Impersonation prompt": "AI帮答提示词", + "Prompt that is used for Impersonation function": "用于AI帮答功能的提示词", + "World Info Format Template": "世界信息格式模板", + "Restore default format": "恢复默认格式", + "Wraps activated World Info entries before inserting into the prompt.": "在插入提示词之前包裹激活的世界信息条目。", + "scenario_format_template_part_1": "使用", + "scenario_format_template_part_2": "标记插入内容的位置。", + "Scenario Format Template": "场景格式模板", + "Personality Format Template": "角色设定格式模板", + "Group Nudge Prompt Template": "群聊推进提示词模板", + "Sent at the end of the group chat history to force reply from a specific character.": "在群聊记录的末尾发送,以强制特定角色回复。", + "New Chat": "新聊天", + "Restore new chat prompt": "恢复新的聊天提示词", + "Set at the beginning of the chat history to indicate that a new chat is about to start.": "设置在聊天历史的开头,表示新的聊天即将开始。", + "New Group Chat": "新群聊", + "Restore new group chat prompt": "恢复默认提示词", + "Set at the beginning of the chat history to indicate that a new group chat is about to start.": "设置在聊天记录的开头,表示新的群聊即将开始。", + "New Example Chat": "新示例聊天", + "Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.": "设置在对话示例的开头,以表明新的示例聊天即将开始。", + "Continue nudge": "继续推进", + "Set at the end of the chat history when the continue button is pressed.": "当按下继续按钮时在聊天记录的末尾设置。", + "Replace empty message": "替换空消息", + "Send this text instead of nothing when the text box is empty.": "当文本框为空时,发送此文本而不是空白。", + "Seed": "种子", + "Set to get deterministic results. Use -1 for random seed.": "设置此值以得到确定性结果。使用 -1 表示随机种子。", + "Temperature controls the randomness in token selection": "温度控制词符选择中的随机性:\n- 低温(<1.0)导致更可预测的文本,优先选择高概率的词符。\n- 高温(>1.0)鼓励创造性和输出的多样性,更多地选择低概率的词符。\n将值设置为 1.0 以使用原始概率。", + "Top_K_desc": "Top K 设定了可以选择的最高概率词符的最大数量。", + "Top_P_desc": "Top P(又称核采样)将所有高概率词符聚集在一起,直到达到特定的百分比。\n换句话说,如果前两个词符分别都有 25% 的概率,而 Top-P 为 0.50,那么只有这两个词符会被考虑。\n将这个值设置为 1.0 就相当于关闭了这个功能。", + "Typical_P_desc": "典型P采样会根据词符与整体熵的平均差异来优先选择词符。\n那些累积概率接近特定阈值(比如 0.5)的词符会被保留,这样就能区分出那些含有平均信息量的词符。\n将这个值设置为 1.0 就相当于关闭了这个功能。", + "Min_P_desc": "Min P 设定了一个基础的最小概率,它会根据最高词符概率来进行优化。\n如果最高词符概率是 80%,而Min P设定为 0.1,那么只有那些概率高于8%的词符会被考虑。\n将这个值设置为 0 就相当于关闭了这个功能。", + "Top_A_desc": "Top A 设定了一个阈值,用于根据最高词符概率的平方来选择词符。\n如果 Top A 设定为 0.2,而最高词符概率是 50%,那么概率低于 5% 的词符会被排除(0.2 * 0.5^2)。\n将这个值设置为 0 就相当于关闭了这个功能。", + "Tail_Free_Sampling_desc": "无尾采样(TFS)通过分析词符概率变化率以及二阶导数来搜索分布中概率较低的尾部词符,\n词符会被保留到某个阈值(例如 0.3),这取决于统一的二阶导数。\n这个值越接近 0,被拒绝的词符数量就越多。将这个值设置为 1.0 就相当于关闭了这个功能。", + "rep.pen range": "重复惩罚范围", + "Mirostat": "Mirostat", + "Mode": "模式", + "Mirostat_Mode_desc": "值为 0 表示完全禁用 Mirostat。1 表示 Mirostat 1.0,2 表示 Mirostat 2.0", + "Tau": "τ", + "Mirostat_Tau_desc": "控制 Mirostat 输出的变化", + "Eta": "η", + "Mirostat_Eta_desc": "控制 Mirostat 的学习率", + "Ban EOS Token": "禁止 EOS 词符", + "Ban_EOS_Token_desc": "禁止使用 KoboldCpp 的序列结束 (EOS) 词符(可能还禁止使用 KoboldAI 的其他词符)。适合故事写作,但不应用于聊天和指导模式。", + "GBNF Grammar": "GBNF 语法", + "Type in the desired custom grammar": "输入所需的自定义语法", + "Samplers Order": "采样器顺序", + "Samplers will be applied in a top-down order. Use with caution.": "采样器将按自上而下的顺序应用。请谨慎使用。", + "Tail Free Sampling": "无尾采样", + "Load koboldcpp order": "加载koboldcpp顺序", + "Top K Sampling": "Top K 采样", + "Nucleus Sampling": "核采样", + "Top A Sampling": "Top A 采样", + "Unified Sampling": "Unified Sampling", + "Neutralize Samplers": "置采样器参数为失效值", + "Set all samplers to their neutral/disabled state.": "将所有采样器设置为失效/禁用状态。", + "Sampler Select": "采样器选择", + "Customize displayed samplers or add custom samplers.": "自定义显示的采样器或添加自定义采样器。", + "Epsilon Cutoff": "ε 截断", + "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "ε 截断设置了一个概率下限,低于该下限的词符将被排除在采样之外。\n以 1e-4 单位;合适的值为 3。将其设置为 0 以禁用。", + "Top nsigma": "Top nsigma", + "Eta Cutoff": "η 截断", + "Eta_Cutoff_desc": "η截断是特殊η采样技术的主要参数。 以1e-4为单位;合理的值为3。 设置为0以禁用。 有关详细信息,请参阅Hewitt等人的论文《Truncation Sampling as Language Model Desmoothing》(2022年)。", + "rep.pen decay": "重复惩罚衰减", + "Encoder Rep. Pen.": "编码器重复惩罚", + "No Repeat Ngram Size": "无重复n-gram大小", + "Skew": "倾斜", + "Max Tokens Second": "每秒最大词符数", + "Smooth Sampling": "平滑采样", + "Smooth_Sampling_desc": "允许您使用二次/三次变换来调整分布。较低的平滑因子值将更具创造性,通常在 0.2-0.3 之间是最佳点(假设曲线 = 1)。较高的平滑曲线值将使曲线更陡峭,这将更积极地惩罚低概率选择。1.0 曲线相当于仅使用平滑因子。", + "Smoothing Factor": "平滑系数", + "Smoothing Curve": "平滑曲线", + "Exclude Top Choices (XTC)": "Exclude Top Choices (XTC)", + "Threshold": "阈值", + "Probability": "可能性", + "DRY_Repetition_Penalty_desc": "DRY 会对那些会将输入末尾扩展为输入中之前出现过的序列的词符进行惩罚。将乘数设置为 0 以禁用。", + "DRY Repetition Penalty": "DRY 重复惩罚", + "DRY_Multiplier_desc": "将值设置为 > 0 以启用 DRY。控制最短惩罚序列的惩罚幅度。", + "Multiplier": "乘数", + "DRY_Base_desc": "控制惩罚随序列长度的增加而增长的速度。", + "Base": "基数", + "DRY_Allowed_Length_desc": "可以重复而不会受到惩罚的最长序列长度。", + "Allowed Length": "允许长度", + "Penalty Range": "惩罚范围", + "DRY_Sequence_Breakers_desc": "序列匹配不再继续的词符。用逗号分隔的带引号的字符串列表指定。", + "Sequence Breakers": "序列打断符", + "JSON-serialized array of strings.": "JSON 序列化的字符串数组。", + "Dynamic Temperature": "动态温度", + "Scale Temperature dynamically per token, based on the variation of probabilities": "根据概率的变化动态地缩放每个词符的温度。", + "Minimum Temp": "最小温度", + "Maximum Temp": "最大温度", + "Exponent": "指数", + "Mirostat (mode=1 is only for llama.cpp)": "Mirostat(mode=1 仅用于 llama.cpp)", + "Mirostat_desc": "Mirostat 是一个用于控制输出困惑度的恒温器", + "Mirostat Mode": "Mirostat 模式", + "Variability parameter for Mirostat outputs": "Mirostat 输出的变异性参数。", + "Mirostat Eta": "Mirostat η", + "Learning rate of Mirostat": "Mirostat 的学习率。", + "Beam search": "束搜索", + "A greedy, brute-force algorithm used in LLM sampling to find the most likely sequence of words or tokens. It expands multiple candidate sequences at once, maintaining a fixed number (beam width) of top sequences at each step.": "一种在LLM采样中使用的贪婪暴力算法,用于找到最可能的单词或标记序列。它一次扩展多个候选序列,在每一步保留固定数量(光束宽度)的最佳序列。", + "# of Beams": "光束数量", + "The number of sequences generated at each step with Beam Search.": "The number of sequences generated at each step with Beam Search.", + "Length Penalty": "长度惩罚", + "Penalize sequences based on their length.": "Penalize sequences based on their length.", + "Early Stopping": "提前停止", + "Controls the stopping condition for beam search. If checked, the generation stops as soon as there are '# of Beams' sequences. If not checked, a heuristic is applied and the generation is stopped when it's very unlikely to find better candidates.": "控制光束搜索的停止条件。勾选时,当生成到达‘光束数量’的序列时停止。如果未勾选,则采用启发式方法,当几乎不可能找到更好的候选项时停止生成。", + "Contrastive search": "对比搜索", + "Contrastive_search_txt": "通过利用大多数 LLM 表示空间的各向同性以鼓励多样性同时保持一致性的采样器。详见 Su 等人在 2022 年发表的论文 《A Contrastive Framework for Neural Text Generation》。", + "Penalty Alpha": "惩罚系数 α", + "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "对比搜索正则化项的强度。 将值设置为 0 以禁用对比搜索。", + "Do Sample": "进行采样", + "Add BOS Token": "添加序列开始词符", + "Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative": "在提示词的开头添加序列开始词符。 禁用此功能可以使回复更具创意", + "Ban the eos_token. This forces the model to never end the generation prematurely": "禁止序列结束词符。 这将强制模型永远不会提前结束生成", + "Ignore EOS Token": "忽略序列结束词符", + "Ignore the EOS Token even if it generates.": "即使生成了序列结束词符,也忽略它。", + "Skip Special Tokens": "跳过特殊词符", + "Request Model Reasoning": "Request Model Reasoning", + "Temperature Last": "温度放最后", + "Temperature_Last_desc": "温度采样器放到最后使用。这通常是合理的。\n当启用时:首先进行潜在词符的选择,然后应用温度来修正它们的相对概率(技术上是对数似然)。\n当禁用时:首先应用温度来修正所有词符的相对概率,然后从中选择潜在词符。\n禁用此项可以增大分布在尾部的词符概率,这可能加大得到不相关回复的几率。", + "Speculative Ngram": "推测性 Ngram", + "Use a different speculative decoding method without a draft model": "使用不同的推测解码方法(不采用草稿模型)。最好使用草稿模型。推测性 Ngram 的效果不太好。", + "Spaces Between Special Tokens": "特殊词符之间的空格", + "Seed_desc": "一个用于生成确定性和可复现的输出的随机种子。设置为 -1 时会使用随机种子。", + "LLaMA / Mistral / Yi models only": "LLaMA / Mistral / Yi模型专用。首先确保您选择了适当的词符化器。\n这项设置决定了你不想在结果中看到的字符串。\n每行一个字符串。可以是文本或者[词符id]。\n许多词符以空格开头。如果不确定,请使用词符计数器。", + "Global list": "Global list", + "Example: some text [42, 69, 1337]": "例如:\n一些文本\n[42, 69, 1337]", + "Preset-specific list": "Preset-specific list", + "CFG": "CFG", + "Classifier Free Guidance. More helpful tip coming soon": "无分类器指导(CFG)。更多有用的提示敬请期待。", + "Scale": "缩放比例", + "Negative Prompt": "负面提示词", + "Used if CFG Scale is unset globally, per chat or character": "如果CFG缩放比例未被全局设置,它将作用于所有聊天或角色", + "Add text here that would make the AI generate things you don't want in your outputs.": "请在此处添加文本,以避免生成您不希望出现在输出中的内容。", + "Grammar String": "语法字符串", + "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF 或 EBNF,取决于使用的后端。如果您使用这个,您应该知道该用哪一个。", + "JSON Schema": "JSON 结构", + "Type in the desired JSON schema": "输入所需的 JSON 结构", + "Top P & Min P": "Top P 和 Min P", + "Load default order": "加载默认顺序", + "Sampler Order": "取样器顺序", + "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "仅限 llama.cpp。确定采样器的顺序。如果 Mirostat 模式不为 0,则忽略采样器顺序。", + "Sampler Priority": "采样器优先级", + "Ooba only. Determines the order of samplers.": "确定采样器的顺序(仅适用于Ooba)", + "Aphrodite only. Determines the order of samplers. Skew is always applied post-softmax, so it's not included here.": "仅适用于 Aphrodite,用于确定采样器的顺序。偏移(Skew)始终在 softmax 后应用,因此不包含在这里。", + "Aphrodite only. Determines the order of samplers.": "仅适用于 Aphrodite。用于确定采样器的顺序。", + "Character Names Behavior": "角色名称行为", + "Helps the model to associate messages with characters.": "有助于模型将消息与角色关联起来。", + "None": "无", + "character_names_none": "不添加角色名称前缀。在群聊中可能导致错误行为,谨慎勾选。", + "character_names_default": "群聊和过去的角色除外。否则,请确保在提示词中提供了姓名。", + "Completion Object": "补全对象", + "character_names_completion": "适用限制:仅限拉丁字母数字和下划线。不适用于所有补全源,尤其是:Claude、MistralAI、Google。", + "Message Content": "消息内容", + "Prepend character names to message contents.": "在消息内容中添加角色名称。", + "Continue Postfix": "继续后缀", + "The next chunk of the continued message will be appended using this as a separator.": "将以此为分隔符附加后续消息的下一块。", + "Space": "空格", + "Newline": "换行", + "Double Newline": "双换行", + "Wrap user messages in quotes before sending": "在发送之前将用户消息用引号括起来", + "Wrap in Quotes": "用引号包裹", + "Wrap entire user message in quotes before sending.": "在发送之前用引号包裹整个用户消息。", + "Leave off if you use quotes manually for speech.": "如果您手动使用引号包裹对话,请忽略此项。", + "Continue prefill": "继续预填充", + "Continue sends the last message as assistant role instead of system message with instruction.": "继续发送的是作为助手角色的最后一条消息,而不是带有指示的系统消息。", + "Squash system messages": "压缩系统消息", + "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "将连续的系统消息合并为一条(不包括示例对话),可能会提高一些模型的连贯性。", + "Enable function calling": "启用函数调用", + "enable_functions_desc_1": "允许使用", + "enable_functions_desc_2": "功能工具", + "enable_functions_desc_3": "可以被各种扩展利用来提供附加功能。", + "Send inline images": "发送图片", + "image_inlining_hint_1": "如果模型支持,就可以在提示词中发送图片(例如 GPT-4V、Claude 3 或 Llava 13B)。\n发送消息时,点击", + "image_inlining_hint_2": "在这里(", + "image_inlining_hint_3": ")将图片添加到消息中。", + "Inline Image Quality": "图片画质", + "openai_inline_image_quality_auto": "自动", + "openai_inline_image_quality_low": "低", + "openai_inline_image_quality_high": "高", + "Use system prompt": "使用系统提示词", + "Merges_all_system_messages_desc_1": "合并所有系统消息,直到第一条具有非系统角色的消息,然后通过", + "Merges_all_system_messages_desc_2": "字段发送。", + "Request model reasoning": "请求思维链", + "Allows the model to return its thinking process.": "允许模型返回其思维过程。", + "Constrains effort on reasoning for reasoning models.": "限定模型推理的强度。\n当前支持低、中、高三种强度。\n降低推理强度可以让模型更快回复,并节省推理所用的词符数。。", + "Reasoning Effort": "推理强度", + "openai_reasoning_effort_low": "低", + "openai_reasoning_effort_medium": "中", + "openai_reasoning_effort_high": "高", + "Assistant Prefill": "AI预填", + "Expand the editor": "展开编辑器", + "Start Claude's answer with...": "以如下内容开始Claude的回答...", + "Assistant Impersonation Prefill": "AI帮答预填", + "Use system prompt (Claude 2.1+ only)": "使用系统提示词(仅适用于Claude 2.1+)", + "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "为支持的模型发送系统提示词。如果禁用,则用户消息将添加到提示词的开头。", + "Confirm token parsing with": "确认使用以下工具进行词符解析", + "Tokenizer": "词符化器", + "New preset": "新预设", + "Delete preset": "删除预设", + "View / Edit bias preset": "查看/编辑偏置预设", + "Add bias entry": "添加偏置条目", + "openai_logit_bias_no_items": "没有相关产品", + "Most tokens have a leading space.": "大多数词符都有一个前导空格。", + "API Connections": "API连接", + "api_no_connection": "无连接...", + "Text Completion": "文本补全", + "Chat Completion": "聊天补全", + "NovelAI": "NovelAI", + "AI Horde": "AI Horde", + "KoboldAI": "KoboldAI", + "AI Horde Website": "AI Horde 网站", + "Avoid sending sensitive information to the Horde.": "避免向 Horde 发送敏感信息。", + "Review the Privacy statement": "查看隐私声明", + "Register a Horde account for faster queue times": "注册 Horde 帐户以加快排队时间", + "Learn how to contribute your idle GPU cycles to the Horde": "了解如何将您的空闲GPU时钟周期共享给 Horde", + "Adjust context size to worker capabilities": "根据工作单元能力调整上下文长度", + "Adjust response length to worker capabilities": "根据工作单元能力调整响应长度", + "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "可以通过仅排队认证的工作单元来帮助处理不良回复。这可能会减慢回复速度。", + "Trusted workers only": "仅信任的工作单元", + "API key": "API密钥", + "Get it here:": "在此获取:", + "Register": "注册", + "View my Kudos": "查看我的荣誉", + "Enter": "输入", + "to use anonymous mode.": "以使用匿名模式。", + "Clear your API key": "清除您的API密钥", + "For privacy reasons, your API key will be hidden after you reload the page.": "出于隐私原因,重新加载页面后您的 API 密钥将被隐藏。", + "Models": "模型", + "Refresh models": "刷新模型", + "-- Horde models not loaded --": "-- Horde 模型未加载 --", + "Not connected...": "未连接...", + "API url": "API地址", + "Example: http://127.0.0.1:5000/api ": "示例:http://127.0.0.1:5000/api", + "Connect": "连接", + "Cancel": "取消", + "Novel API key": "Novel AI API 密钥", + "Get your NovelAI API Key": "获取您的 NovelAI API 密钥", + "Enter it in the box below": "在下面的框中输入", + "Novel AI Model": "Novel AI 模型", + "No connection...": "无连接...", + "API Type": "API 类型", + "Generic (OpenAI-compatible) [LM Studio, LiteLLM, etc.]": "通用(兼容 OpenAI)[LM Studio、LiteLLM 等]", + "TogetherAI API Key": "TogetherAI API 密钥", + "TogetherAI Model": "TogetherAI 模型", + "-- Connect to the API --": "-- 连接到API --", + "OpenRouter API Key": "OpenRouter API 密钥", + "Click Authorize below or get the key from": "点击下方授权或从以下位置获取密钥", + "View Remaining Credits": "查看剩余额度", + "OpenRouter Model": "OpenRouter 模型", + "Model Providers": "模型提供商", + "Automatically chooses an alternative provider if chosen providers can't serve your request.": "在当前选择的模型提供商无效时,自动选择备用的提供商。", + "Allow fallback providers": "允许后备提供者", + "InfermaticAI API Key": "InfermaticAI API 密钥", + "InfermaticAI Model": "InfermaticAI 模型", + "DreamGen API key": "DreamGen API 密钥", + "DreamGen Model": "DreamGen 模型", + "Mancer API key": "Mancer API 密钥", + "Mancer Model": "Mancer 模型", + "API key (optional)": "API密钥(可选)", + "Server url": "服务器URL", + "Example: 127.0.0.1:5000": "示例:127.0.0.1:5000", + "Model ID (optional)": "模型 ID(可选)", + "Make sure you run it with": "确保您在运行时加上", + "flag": "标志", + "Custom model (optional)": "自定义模型(可选)", + "Featherless Model Selection": "Featherless Model Selection", + "Search...": "搜索...", + "Search": "搜索", + "category": "分类", + "Top": "Top", + "New": "新建", + "All": "All", + "class": "All Classes", + "Toggle grid view": "切换网格视图", + "No model description": "[无描述]", + "vllm-project/vllm": "vllm-project/vllm(OpenAI API 包装器模式)", + "vLLM API key": "vLLM API 密钥", + "Example: 127.0.0.1:8000": "示例:http://127.0.0.1:8000", + "vLLM Model": "vLLM 模型", + "HuggingFace Token": "HuggingFace 代币", + "Endpoint URL": "端点 URL", + "Example: https://****.endpoints.huggingface.cloud": "例如:https://****.endpoints.huggingface.cloud", + "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine(用于OpenAI API的包装器)", + "Aphrodite API key": "Aphrodite API 密钥", + "Aphrodite Model": "Aphrodite 模型", + "ggerganov/llama.cpp": "ggerganov/llama.cpp", + "Example: 127.0.0.1:8080": "示例:127.0.0.1:8080", + "Example: 127.0.0.1:11434": "示例:127.0.0.1:11434", + "Ollama Model": "Ollama 模型", + "Download": "下载", + "Tabby API key": "Tabby API 密钥", + "Tabby Model": "Tabby 模型", + "must be set in Tabby's config.yml to switch models.": "必须在Tabby的config.yml内设置以切换模型", + "Use an admin API key.": "使用管理员API密钥。", + "koboldcpp API key (optional)": "koboldcpp API 密钥(可选)", + "Example: 127.0.0.1:5001": "示例:127.0.0.1:5001", + "Bypass status check": "跳过状态检查", + "Derive context size from backend": "从后端获取上下文长度", + "Authorize": "授权", + "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "使用OAuth流程获取您的OpenRouter API令牌。您将被重定向到openrouter.ai", + "Chat Completion Source": "聊天补全来源", + "Custom (OpenAI-compatible)": "自定义(兼容 OpenAI)", + "Reverse Proxy": "反向代理", + "Proxy Presets": "代理预设", + "Saved addresses and passwords.": "保存的地址和密码。", + "Save Proxy": "保存代理", + "Delete Proxy": "删除代理", + "Proxy Name": "代理名称", + "This will show up as your saved preset.": "这将显示为您保存的预设。", + "Proxy Server URL": "代理服务器 URL", + "Alternative server URL (leave empty to use the default value).": "备用服务器 URL(留空以使用默认值)。", + "Doesn't work? Try adding": "不起作用?在末尾添加", + "at the end!": "试试!", + "Proxy Password": "代理密码", + "Will be used as a password for the proxy instead of API key.": "将用作代理的密码,而不是 API 密钥。", + "Peek a password": "查看密码", + "Using a proxy that you're not running yourself is a risk to your data privacy.": "使用您自己未运行的代理会对您的数据隐私造成风险。", + "ANY support requests will be REFUSED if you are using a proxy.": "如果您使用代理,任何支持请求都将被拒绝。", + "Do not proceed if you do not agree to this!": "如果您不同意,请不要继续!", + "OpenAI API key": "OpenAI API 密钥", + "View API Usage Metrics": "查看API使用情况", + "Follow": "按照", + "these directions": "这些步骤", + "to get your OpenAI API key.": "获取您的 OpenAI API 密钥。", + "Use Proxy password field instead. This input will be ignored.": "请使用“代理密码”字段。此输入将被忽略。", + "OpenAI Model": "OpenAI 模型", + "Bypass API status check": "绕过API状态检查", + "Show External models (provided by API)": "显示外部模型(由API提供)", + "Claude API Key": "Claude API 密钥", + "Get your key from": "从以下位置获取您的密钥", + "Anthropic's developer console": "Anthropic 开发者控制台", + "Claude Model": "Claude 模型", + "Window AI Model": "Window AI 模型", + "Use extension settings": "使用扩展程序中的设定", + "Allow fallback routes Description": "如果所选模型无法响应您的请求,则自动选择备用模型。", + "Allow fallback models": "允许后备模型", + "Model Order": "OpenRouter 模型顺序", + "Alphabetically": "按字母顺序", + "Price": "价格(最便宜)", + "Context Size": "上下文长度", + "Group by vendors": "按厂商分组", + "Group by vendors Description": "将 OpenAI 模型放在一组,将 Anthropic 模型放在另一组,等等。可以与排序结合。", + "To use instruct formatting, switch to OpenRouter under Text Completion API.": "To use instruct formatting, switch to OpenRouter under Text Completion API.", + "Scale API Key": "Scale API密钥", + "Clear your cookie": "清除你的 Cookie", + "Alt Method": "备用方法", + "AI21 API Key": "AI21 API 密钥", + "AI21 Model": "AI21 模型", + "Google AI Studio API Key": "Google AI Studio API 密钥", + "Google Model": "Google 模型", + "MistralAI API Key": "MistralAI API 密钥", + "MistralAI Model": "MistralAI 模型", + "Groq API Key": "Groq API 密钥", + "Groq Model": "Groq 模型", + "NanoGPT API Key": "NanoGPT API Key", + "NanoGPT Model": "NanoGPT Model", + "DeepSeek API Key": "DeepSeek API 密钥", + "DeepSeek Model": "DeepSeek 模型", + "Perplexity API Key": "Perplexity API 密钥", + "Perplexity Model": "Perplexity 模型", + "Cohere API Key": "Cohere API 密钥", + "Cohere Model": "Cohere 模型", + "Block Entropy API Key": "Block Entropy API 密钥", + "Select a Model": "选择一个模型", + "Custom Endpoint (Base URL)": "自定义端点(基础 URL)", + "Example: http://localhost:1234/v1": "例如:http://localhost:1234/v1", + "Custom API Key": "自定义 API 密钥", + "(Optional)": "(可选)", + "Enter a Model ID": "输入模型名", + "Example: gpt-4o": "例如:gpt-4o", + "Available Models": "可用模型", + "Prompt Post-Processing": "提示词后处理", + "Applies additional processing to the prompt before sending it to the API.": "在将提示词发送到 API 之前对其进行额外处理。", + "prompt_post_processing_none": "未选择", + "prompt_post_processing_merge": "合并相同角色连续的发言", + "prompt_post_processing_semi": "半严格(强制对话角色交替)", + "prompt_post_processing_strict": "严格(强制对话角色交替、用户最先)", + "01.AI API Key": "01.AI API密钥", + "01.AI Model": "01.AI 模型", + "Additional Parameters": "附加参数", + "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "通过发送简短的测试消息验证您的API连接。请注意,您将因此消耗额度!", + "Test Message": "发送测试消息", + "Auto-connect to Last Server": "自动连接到上次的服务器", + "Missing key": "❌ 缺少密钥", + "Key saved": "密钥已保存", + "View hidden API keys": "查看隐藏的API密钥", + "AI Response Formatting": "AI回复格式化", + "Advanced Formatting": "高级格式化设置", + "Import Advanced Formatting settings": "导入高级格式化设置\n\n对于指导和上下文模板,你也可以提供旧版文件。", + "Master Import": "全局导入", + "Export Advanced Formatting settings": "导出高级格式化设置", + "Master Export": "全局导出", + "Context Template": "上下文模板", + "context_derived": "若可能,从模型的元数据获取。", + "Select your current Context Template": "选择你当前的上下文模板", + "Update current template": "更新当前模板", + "Rename current template": "重命名当前模板", + "Save template as": "将模板另存为", + "Import template": "导入模板", + "Export template": "导出模板", + "Restore current template": "还原当前模板", + "Delete the template": "删除模板", + "Story String": "故事字符串", + "Example Separator": "示例分隔符", + "Chat Start": "聊天开始", + "Context Formatting": "上下文格式", + "Always add character's name to prompt": "始终将角色名称添加到提示词", + "Generate only one line per request": "每次请求只生成一行", + "Collapse Consecutive Newlines": "折叠连续的换行符", + "Trim spaces": "修剪空格", + "Disabling is not recommended.": "不建议关闭。", + "Trim Incomplete Sentences": "修剪不完整的句子", + "Add Chat Start and Example Separator to a list of stopping strings.": "将聊天开始和示例分隔符添加到停止字符串列表中。", + "Separators as Stop Strings": "分隔符作为终止字符串", + "Add Character and User names to a list of stopping strings.": "将角色和用户名添加到停止字符串列表中。", + "Names as Stop Strings": "名称作为终止字符串", + "context_allow_post_history_instructions": "如果在角色卡中定义并且启用了“首选角色卡说明”,则在提示末尾包含后历史说明。\n不建议在文本补全模型中使用此功能,否则会导致输出错误。", + "Allow Post-History Instructions": "允许后历史说明", + "Instruct Template": "指导模板", + "instruct_derived": "如果可能,从模型元数据中获取", + "instruct_bind_to_context": "如果启用,上下文模板将根据所选的指导模板名称或偏好自动选择。", + "instruct_enabled": "启用指导模板", + "Select your current Instruct Template": "选择你当前的指导模板", + "Delete template": "删除模板", + "Activation Regex": "激活正则表达式", + "instruct_template_activation_regex_desc": "当连接到API或选择模型时,若模型名称与给定的正则表达式匹配,自动启用此指导模板。", + "Wrap Sequences with Newline": "用换行符包裹序列", + "Replace Macro in Sequences": "替换序列中的宏", + "Skip Example Dialogues Formatting": "跳过示例对话格式化", + "Include Names": "包括名称", + "Never": "永不", + "Groups and Past Personas": "群聊和过去的用户角色", + "Always": "永远", + "Instruct Sequences": "指令序列", + "User Message Sequences": "用户消息序列", + "Inserted before a User message and as a last prompt line when impersonating.": "插入到用户消息之前并作为模拟时的最后一行提示词。", + "User Prefix": "用户消息前缀", + "Inserted after a User message.": "插入到用户消息之后。", + "User Suffix": "用户消息后缀", + "Assistant Message Sequences": "助手消息序列", + "Inserted before an Assistant message and as a last prompt line when generating an AI reply.": "插入到助手消息之前并作为生成 AI 回复时的最后一行提示词。", + "Assistant Prefix": "助手消息前缀", + "Inserted after an Assistant message.": "插入于助手消息之后。", + "Assistant Suffix": "助手消息后缀", + "System Message Sequences": "系统消息序列", + "Inserted before a System (added by slash commands or extensions) message.": "插入到系统(由快捷命令或扩展添加)消息之前。", + "System Prefix": "系统消息前缀", + "Inserted after a System message.": "插入到系统消息之后。", + "System Suffix": "系统消息后缀", + "If enabled, System Sequences will be the same as User Sequences.": "如果启用,系统序列将与用户序列相同。", + "System same as User": "系统与用户相同", + "System Prompt Sequences": "系统提示词序列", + "Inserted before a System prompt.": "插入到系统提示词之前。", + "System Prompt Prefix": "系统提示词前缀", + "Inserted after a System prompt.": "在系统提示词后插入。", + "System Prompt Suffix": "系统提示词后缀", + "Misc. Sequences": "杂项序列", + "Inserted before the first Assistant's message.": "插入到第一个助理的消息之前。", + "First Assistant Prefix": "第一个助理前缀", + "instruct_last_output_sequence": "插入到最后一条助手消息之前或作为生成 AI 回复时的最后一行提示词(中立/系统角色除外)。", + "Last Assistant Prefix": "最后一个助理前缀", + "Inserted before the first User's message.": "插入在第一个用户的消息之前。", + "First User Prefix": "第一个用户前缀", + "instruct_last_input_sequence": "插入到最后一条用户消息之前。", + "Last User Prefix": "上次用户前缀", + "Will be inserted as a last prompt line when using system/neutral generation.": "当使用系统/中性生成时将作为最后的一行提示词插入。", + "System Instruction Prefix": "系统指令前缀", + "If a stop sequence is generated, everything past it will be removed from the output (inclusive).": "如果生成了停止序列,则该序列之后的所有内容都将从输出中删除(包括在内)。", + "Stop Sequence": "停止序列", + "Will be inserted at the start of the chat history if it doesn't start with a User message.": "如果聊天记录不是以用户消息开头,则会插入到聊天记录的开头。", + "User Filler Message": "用户填写信息", + "System Prompt": "系统提示词", + "sysprompt_enabled": "启用系统提示词", + "Select your current System Prompt": "选择当前的系统提示词", + "Update current prompt": "更新当前提示词", + "Rename current prompt": "重命名当前提示词", + "Save prompt as": "将提示词另存为", + "Restore current prompt": "还原当前提示词", + "Delete prompt": "删除提示词", + "Prompt Content": "提示词内容", + "Custom Stopping Strings": "自定义停止字符串", + "JSON serialized array of strings": "JSON序列化的字符串数组", + "Replace Macro in Stop Strings": "替换自定义停止字符串中的宏", + "Token Padding": "词符填充", + "Reasoning": "推理", + "reasoning_auto_parse": "Automatically parse reasoning blocks from main content between the reasoning prefix/suffix. Both fields must be defined and non-empty.", + "Auto-Parse": "自动解析", + "reasoning_auto_expand": "自动展开推理内容块。", + "Auto-Expand": "自动展开", + "reasoning_show_hidden": "对于隐藏推理内容的模型,展示其推理用时。", + "Show Hidden": "显示隐藏内容", + "reasoning_add_to_prompts": "将已有的推理块添加到提示词。若需新增一个推理块,请使用消息编辑菜单。", + "Add to Prompts": "添加到提示词", + "reasoning_max_additions": "Maximum number of reasoning blocks to be added per prompt, counting from the last message.", + "Max": "最大值", + "Reasoning Formatting": "推理内容格式化", + "reasoning_prefix": "插入在推理内容之前。", + "Prefix": "前缀", + "reasoning_suffix": "插入在推理内容之后。", + "Suffix": "后缀", + "reasoning_separator": "插入在推理内容和消息内容之间。", + "Separator": "分隔符", + "Miscellaneous": "杂项", + "Non-markdown strings": "非 Markdown 字符串", + "comma delimited,no spaces between": "以逗号分隔,无需空格", + "Start Reply With": "以...开始回复", + "Show reply prefix in chat": "在聊天中显示回复前缀", + "World Info": "世界信息", + "Locked = World Editor will stay open": "锁定 = 世界编辑器将保持打开状态", + "Worlds/Lorebooks": "世界/知识书", + "Active World(s) for all chats": "已启用的世界(全局有效)", + "-- World Info not found --": "-- 未找到世界信息 --", + "Global World Info/Lorebook activation settings": "全局世界信息/知识书激活设置", + "Click to expand": "单击展开", + "Scan Depth": "扫描深度", + "Context %": "上下文百分比", + "Budget Cap": "Token预算上限", + "(0 = disabled)": "(“0”为禁用)", + "Scan chronologically until reached min entries or token budget.": "按时间顺序扫描直到达到最少条目或词符预算。", + "Min Activations": "最小激活数", + "(disabled when max recursion steps are used)": "(当使用最大递归步数时禁用)", + "Max Depth": "最大深度", + "(0 = unlimited, use budget)": "(“0”为无限制,使用预算)", + "Cap the number of entry activation recursions": "限制条目激活递归的次数", + "Max Recursion Steps": "最大递归深度", + "0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc": "“0”为无限制,“1”为扫描一次且不递归,“2”为扫描一次且递归一次,依此类推\n(当使用最小激活次数时,此功能被禁用)", + "Insertion Strategy": "插入策略", + "Sorted Evenly": "均匀排序", + "Character Lore First": "角色世界书优先", + "Global Lore First": "全局世界书优先", + "Include names with each message into the context for scanning": "将每条消息的名称纳入上下文中以供扫描", + "Entries can activate other entries by mentioning their keywords": "条目可以通过提及它们的关键字来激活其他条目", + "Recursive Scan": "递归扫描", + "Lookup for the entry keys in the context will respect the case": "在上下文中查找条目键将继续区分大小写", + "Case Sensitive": "区分大小写", + "If the entry key consists of only one word, it would not be matched as part of other words": "如果条目键只由一个单词组成,则不会作为其他单词的一部分匹配", + "Match Whole Words": "匹配整个单词", + "Only the entries with the most number of key matches will be selected for Inclusion Group filtering": "仅选择具有最多关键匹配项的条目进行包含组过滤", + "Use Group Scoring": "使用群组评分", + "Alert if your world info is greater than the allocated budget.": "如果您的世界信息大于分配的预算,则会发出警报。", + "Alert On Overflow": "溢出警报", + "or": "或", + "--- Pick to Edit ---": "--- 选择以编辑 ---", + "Rename World Info": "重命名世界书", + "Open all Entries": "打开所有条目", + "Close all Entries": "关闭所有条目", + "New Entry": "新条目", + "Fill empty Memo/Titles with Keywords": "使用关键字填充空的备忘录/标题", + "Apply current sorting as Order": "应用当前排序作为顺序", + "Import World Info": "导入世界书", + "Export World Info": "导出世界书", + "Duplicate World Info": "复制世界书", + "Delete World Info": "删除世界书", + "Priority": "优先级", + "Custom": "自定义", + "Title A-Z": "标题 A-Z", + "Title Z-A": "标题 Z-A", + "Tokens ↗": "词符 ↗", + "Tokens ↘": "词符 ↘", + "Depth ↗": "深度 ↗", + "Depth ↘": "深度 ↘", + "Order ↗": "顺序 ↗", + "Order ↘": "顺序 ↘", + "UID ↗": "UID ↗", + "UID ↘": "UID ↘", + "Trigger% ↗": "触发频率% ↗", + "Trigger% ↘": "触发频率% ↘", + "Refresh": "刷新", + "User Settings": "用户设置", + "UI Language": "语言", + "Account": "帐户", + "Admin Panel": "管理员面板", + "Logout": "登出", + "Search Settings": "搜索设置", + "UI Theme": "UI主题", + "Import a theme file": "导入主题文件", + "Export a theme file": "导出主题文件", + "Delete a theme": "删除主题", + "Update a theme file": "更新主题文件", + "Save as a new theme": "另存为新主题", + "Avatar Style:": "头像样式:", + "Circle": "圆形", + "Square": "正方形", + "Rectangle": "矩形", + "Chat Style:": "聊天风格:", + "Flat": "扁平\n气泡\n文档", + "Bubbles": "气泡", + "Document": "文档", + "Specify colors for your theme.": "指定您的主题的颜色。", + "Theme Colors": "主题颜色", + "Main Text": "主要文本", + "Italics Text": "斜体文本", + "Underlined Text": "下划线文本", + "Quote Text": "引用文本", + "Shadow Color": "阴影颜色", + "Chat Background": "聊天背景", + "UI Background": "UI 背景", + "UI Border": "UI 边框", + "User Message Blur Tint": "用户消息模糊色调", + "AI Message Blur Tint": "AI 消息模糊色调", + "Chat Width": "页面宽度", + "Width of the main chat window in % of screen width": "主聊天窗口的宽度为屏幕宽度的 %", + "Font Scale": "字体比例", + "Font size": "字体大小", + "Blur Strength": "模糊强度", + "Blur strength on UI panels.": "UI 面板上的模糊强度。", + "Text Shadow Width": "文本阴影宽度", + "Strength of the text shadows": "文本阴影的强度", + "Disables animations and transitions": "禁用动画和过渡效果", + "Reduced Motion": "减少动态效果", + "removes blur from window backgrounds": "从窗口背景中移除模糊效果", + "No Blur Effect": "禁用模糊效果", + "Remove text shadow effect": "移除文本阴影效果", + "No Text Shadows": "禁用文本阴影", + "Reduce chat height, and put a static sprite behind the chat window": "缩小聊天窗口的高度,并在聊天窗口后面放置一个固定的表情图。", + "Waifu Mode": "视觉小说模式", + "Always show the full list of the Message Actions context items for chat messages, instead of hiding them behind '...'": "始终显示聊天消息的操作菜单完整列表,而不是将它们隐藏在“...”后面", + "Auto-Expand Message Actions": "自动展开消息操作菜单", + "Alternative UI for numeric sampling parameters with fewer steps": "为数字采样参数提供一个步骤更少的替代用户界面。", + "Zen Sliders": "禅意滑块", + "Entirely unrestrict all numeric sampling parameters": "完全解除所有数字采样参数的限制", + "Mad Lab Mode": "疯狂实验室模式", + "Time the AI's message generation, and show the duration in the chat log": "对 AI 生成消息的时间进行计时,并在聊天记录中显示。", + "Message Timer": "AI回复计时器", + "Show a timestamp for each message in the chat log": "在聊天日志中显示每条消息的时间戳", + "Chat Timestamps": "聊天时间戳", + "Show an icon for the API that generated the message": "显示此消息所用API的图标", + "Model Icon": "模型图标", + "Show sequential message numbers in the chat log": "在聊天记录中显示消息楼层", + "Message IDs": "显示消息楼层", + "Hide avatars in chat messages.": "在聊天记录中隐藏头像。", + "Hide Chat Avatars": "隐藏头像", + "Show the number of tokens in each message in the chat log": "在聊天记录中显示每条消息的词符数", + "Show Message Token Count": "显示消息词符数", + "Single-row message input area. Mobile only, no effect on PC": "将输入框限制为一行。仅适用于移动设备,对PC无影响", + "Compact Input Area (Mobile)": "紧凑输入区域(移动端)", + "Display swipe numbers for all messages, not just the last.": "显示所有信息的滑动编号,而非仅限最后一条。", + "Swipe # for All Messages": "给所有信息分配滑动编号 #", + "In the Character Management panel, show quick selection buttons for favorited characters": "在角色管理面板中,显示快速选择按钮以选择收藏的角色", + "Characters Hotswap": "角色卡热切换", + "Enable magnification for zoomed avatar display.": "启用放大功能以放大头像显示。", + "Avatar Hover Magnification": "头像悬停放大", + "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "启用在聊天中点击头像图像后显示放大的头像时的放大效果。", + "Show tagged character folders in the character list": "在角色列表中显示已标记的角色文件夹", + "Tags as Folders": "标签作为文件夹", + "Tags_as_Folders_desc": "最近更改:标签必须在标签管理菜单中标记为文件夹才能显示。单击此处将其调出。", + "Character Handling": "角色处理", + "If set in the advanced character definitions, this field will be displayed in the characters list.": "如果在高级角色定义中设置,此字段将显示在角色列表中。", + "Char List Subheader": "角色列表子标题", + "Character Version": "角色版本", + "Created by": "创作者", + "Defines on importing cards which action should be chosen for importing its listed tags. 'Ask' will always display the dialog.": "定义在导入卡片时应选择哪种操作来导入其列出的标签。“询问”将始终显示对话框。", + "Import Card Tags": "导入卡片标签", + "Ask": "询问", + "tag_import_none": "不导入", + "tag_import_all": "导入全部", + "tag_import_existing": "仅导入现有的", + "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "使用模糊匹配,在列表中通过所有数据字段搜索角色,而不仅仅是名称子字符串", + "Advanced Character Search": "高级角色搜索", + "If checked and the character card contains a prompt override (System Prompt), use that instead": "开启后,如果角色卡已包含系统提示词,则覆盖当前的系统提示词。", + "Prefer Character Card Prompt": "角色卡提示词优先", + "If checked and the character card contains a Post-History Instructions override, use that instead": "开启后,如果角色卡包含后历史指令覆盖,则使用它。", + "Prefer Character Card Instructions": "首选角色卡说明", + "never_resize_avatars_tooltip": "避免裁剪和调整导入的角色图像的大小。关闭时,裁剪/调整大小为 512x768。", + "Never resize avatars": "永不调整头像大小", + "Show actual file names on the disk, in the characters list display only": "在角色列表显示中,显示磁盘上实际的文件名。", + "Show avatar filenames": "显示头像文件名", + "Hide character definitions from the editor panel behind a spoiler button": "在编辑器面板中,将角色定义隐藏在一个剧透按钮后面。", + "Spoiler Free Mode": "防剧透模式", + "Reload and redraw the currently open chat": "重新加载并重新渲染当前打开的聊天", + "Reload Chat": "重新加载聊天", + "Debug Menu": "调试菜单", + "Smooth Streaming": "平滑流式传输", + "Experimental feature. May not work for all backends.": "实验性功能。可能不适用于所有后端。", + "Slow": "慢", + "Fast": "快", + "Play a sound when a message generation finishes": "当消息生成完毕时播放声音", + "Message Sound": "消息声音", + "Only play a sound when ST's browser tab is unfocused": "仅在ST的浏览器标签页未被打开时播放声音", + "Background Sound Only": "仅背景声音", + "Reduce the formatting requirements on API URLs": "减少API URL的格式化要求", + "Relaxed API URLS": "宽松的API URL", + "Ask to import the World Info/Lorebook for every new character with embedded lorebook. If unchecked, a brief message will be shown instead": "询问是否为每个具有嵌入的知识书的新角色导入世界信息/知识书。如果未选中,则会显示简短的消息", + "Lorebook Import Dialog": "知识书导入对话框", + "Enable auto-select of input text in some text fields when clicking/selecting them. Applies to popup input textboxes, and possible other custom input fields.": "启用在某些文本字段中单击/选择时自动选中文本的功能。适用于弹出输入框以及可能的其他自定义输入字段。", + "Auto-select Input Text": "自动选择输入文本", + "markdown_hotkeys_desc": "在特定文本输入框中,启用插入 Markdown 格式的快捷键。详情输入:“/help hotkeys”。", + "Markdown Hotkeys": "Markdown 快捷键", + "Restore unsaved user input on page refresh": "在页面刷新时恢复未保存的用户输入", + "Restore User Input": "恢复用户输入", + "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "允许通过拖动重新定位某些UI元素。仅适用于PC,对移动设备无影响", + "Movable UI Panels": "可移动 UI 面板", + "Reset MovingUI panel sizes/locations.": "重置 可移动UI 面板大小/位置。", + "mui_reset": "Reset", + "MovingUI preset. Predefined/saved draggable positions": "可移动UI预设。预定义/保存的可拖动位置", + "MUI Preset": "可移动 UI 预设", + "Save movingUI changes to a new file": "将可移动UI更改保存到新文件中", + "Apply a custom CSS style to all of the ST GUI": "将自定义CSS样式应用于所有ST GUI", + "Custom CSS": "自定义 CSS", + "Chat/Message Handling": "聊天/消息处理", + "# Messages to Load": "要加载 # 条消息", + "The number of chat history messages to load before pagination.": "分页前要加载的聊天历史消息数。", + "(0 = All)": "(“0”为全部)", + "Streaming FPS": "流式传输帧速率", + "Update speed of streamed text.": "文本流的更新速度。", + "Example Messages Behavior": "示例消息行为", + "Gradual push-out": "逐渐推出", + "Always include examples": "始终包含示例", + "Never include examples": "永不包含示例", + "Send on Enter": "按 Enter 发送", + "Disabled": "已禁用", + "Automatic (PC)": "自动(PC)", + "Enabled": "已启用", + "Press Send to continue": "按发送键以继续", + "Show a button in the input area to ask the AI to continue (extend) its last message": "在输入区域中显示一个按钮,要求AI继续(延长)其上一条消息", + "Quick 'Continue' button": "快速“继续”按钮", + "Show a button in the input area to ask the AI to impersonate your character for a single message": "在输入区域中显示一个按钮,让 AI 模仿你的角色发送一条消息。", + "Quick 'Impersonate' button": "快速“模仿”按钮", + "Show arrow buttons on the last in-chat message to generate alternative AI responses. Both PC and mobile": "在聊天窗口的最后一条信息上显示箭头按钮,以生成AI的其他回复选项。适用于电脑和手机端。", + "Swipes": "刷新回复按钮", + "Allow using swiping gestures on the last in-chat message to trigger swipe generation. Mobile only, no effect on PC": "允许在最后一条聊天消息上使用滑动手势触发滑动生成。仅适用于移动设备,对PC无影响", + "Gestures": "手势", + "Auto-load Last Chat": "自动加载上次聊天", + "Auto-scroll Chat": "自动滚动聊天", + "Save edits to messages without confirmation as you type": "在键入时保存对消息的编辑而无需确认", + "Auto-save Message Edits": "自动保存消息编辑", + "Confirm message deletion": "删除消息前确认", + "Auto-fix Markdown": "自动修复 Markdown", + "Disallow embedded media from other domains in chat messages": "禁止在聊天消息中嵌入来自其他域的媒体。", + "Forbid External Media": "禁止外部媒体", + "Allow {{char}}: in bot messages": "在机器人消息中允许 {{char}}: ", + "Allow {{user}}: in bot messages": "在机器人消息中允许 {{user}}: ", + "Skip encoding and characters in message text, allowing a subset of HTML markup as well as Markdown": "跳过消息文本中的编码和字符,允许一部分HTML标记以及Markdown", + "Show tags in responses": "在响应中显示标签", + "Allow AI messages in groups to contain lines spoken by other group members": "允许群聊中的AI输出群中其他成员说的话", + "Relax message trim in Groups": "减轻群聊中的消息修剪", + "Log prompts to console": "将提示词输出到控制台", + "Requests logprobs from the API for the Token Probabilities feature": "从API请求对数概率数据,用于实现词符概率功能。", + "Request token probabilities": "请求词符概率", + "In group chat, highlight the character(s) that are currently queued to generate responses and the order in which they will respond.": "在群聊中,突出显示当前排队等待生成响应的角色以及他们响应的顺序。", + "Show group chat queue": "显示群聊队列", + "Automatically reject and re-generate AI message based on configurable criteria": "根据可配置的条件自动拒绝并重新生成AI消息", + "Auto-swipe": "自动滑动", + "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "启用自动滑动功能。仅当启用自动滑动时,本节中的设置才会生效", + "Minimum generated message length": "生成的消息的最小长度", + "If the generated message is shorter than these many characters, trigger an auto-swipe": "如果生成的消息短于此长度,则触发自动滑动", + "Blacklisted words": "屏蔽词", + "words you dont want generated separated by comma ','": "不想生成的词语,用半角逗号“,”分隔", + "Blacklisted word count to swipe": "触发滑动的黑名单词语数量", + "Minimum number of blacklisted words detected to trigger an auto-swipe": "触发自动滑动刷新回复所需检测到的最少违禁词数量。", + "Automatically 'continue' a response if the model stopped before reaching a certain amount of tokens.": "当回复没有达到特定词符数时,自动让模型“继续”这个回复。", + "Auto-Continue": "自动继续", + "Allow for Chat Completion APIs": "允许使用聊天补全API", + "Target length (tokens)": "目标长度(以词符数计)", + "AutoComplete Settings": "自动补全设置", + "Automatically hide details": "自动隐藏详细信息", + "Determines how entries are found for autocomplete.": "确定如何找到自动补全的条目。", + "Autocomplete Matching": "匹配", + "Starts with": "以此开始:", + "Includes": "包括", + "Fuzzy": "模糊", + "Sets the style of the autocomplete.": "设置自动完成的样式。", + "Autocomplete Style": "风格", + "Follow Theme": "关注主题", + "Dark": "黑暗的", + "Keyboard": "键盘:", + "Select with Tab or Enter": "使用 Tab 或 Enter 选择", + "Select with Tab": "使用 Tab 选择", + "Select with Enter": "按 Enter 键选择", + "Sets the font size of the autocomplete.": "设置自动完成的字体大小。", + "Sets the width of the autocomplete.": "设置自动完成的宽度。", + "Autocomplete Width": "宽度", + "chat input box": "聊天输入框", + "entire chat width": "整个聊天宽度", + "full window width": "全窗口宽度", + "STscript Settings": "STscript设置", + "Sets default flags for the STscript parser.": "为 STscript 解析器设置默认标志。", + "Parser Flags": "解析器标志", + "Switch to stricter escaping, allowing all delimiting characters to be escaped with a backslash, and backslashes to be escaped as well.": "切换到更严格的转义,允许所有分隔字符用反斜杠转义,并且反斜杠也可以转义。", + "STRICT_ESCAPING": "严格转义", + "stscript_parser_flag_replace_getvar_label": "防止 {{getvar::}} {{getglobalvar::}} 宏具有自动评估的文字宏类值。\n例如,“{{newline}}”保留为文字字符串“{{newline}}”\n\n(这是通过在内部用范围变量替换 {{getvar::}} {{getglobalvar::}} 宏来实现的。)", + "REPLACE_GETVAR": "替换GETVAR", + "Change Background Image": "更改背景图片", + "Background Image": "背景图片", + "Filter": "搜索", + "Background Fitting": "背景图片尺寸", + "Classic": "经典", + "Cover": "填充", + "Contain": "不变换", + "Stretch": "拉伸", + "Center": "居中", + "Automatically select a background based on the chat context": "根据聊天上下文自动选择背景", + "Auto-select": "自动选择", + "System Backgrounds": "系统背景", + "Chat Backgrounds": "聊天背景", + "bg_chat_hint_1": "使用生成的聊天背景", + "bg_chat_hint_2": "扩展名将出现在这里。", + "Extensions": "扩展", + "Notify on extension updates": "在扩展更新时通知", + "Manage extensions": "管理扩展", + "Import Extension From Git Repo": "从Git存储库导入扩展", + "Install extension": "安装扩展", + "Extras API:": "扩展API:", + "Auto-connect": "自动连接", + "Extras API URL": "附加 API URL", + "Extras API key (optional)": "扩展API密钥(可选)", + "Persona Management": "用户角色管理", + "Click for stats!": "点击查看统计!", + "Usage Stats": "使用统计", + "Backup your personas to a file": "将用户角色备份到文件中", + "Backup": "备份", + "Restore your personas from a file": "从文件中恢复用户角色", + "Restore": "恢复", + "Create a dummy persona": "创建空白用户角色", + "Create": "创建", + "No persona description": "[没有描述]", + "Name": "名称", + "Enter your name": "输入您的名字", + "Click to set a new User Name": "点击设置新的用户名", + "Click to lock your selected persona to the current chat. Click again to remove the lock.": "单击以将您选择的用户角色锁定到当前聊天。再次单击以移除锁定。", + "Click to set user name for all messages": "点击为所有消息设置用户名", + "Persona Lore Alt+Click to open the lorebook": "Persona Lore\nAlt+Click to open the lorebook", + "Persona Description": "用户角色描述", + "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "示例:[{{user}}是一个28岁的罗马尼亚猫娘。]", + "Tokens persona description": "用户角色描述词符数", + "Position:": "位置:", + "None (disabled)": "无(已禁用)", + "In Story String / Prompt Manager": "在故事字符串/提示词管理器中", + "Top of Author's Note": "作者注的顶部", + "Bottom of Author's Note": "作者注的底部", + "In-chat @ Depth": "聊天的特定深度", + "Depth:": "深度:", + "Role:": "身份:", + "System": "系统", + "User": "用户", + "Assistant": "助手", + "Show notifications on switching personas": "切换用户角色时显示通知", + "Character Management": "角色管理", + "Locked = Character Management panel will stay open": "锁定 = 角色管理面板将保持打开状态", + "Select/Create Characters": "选择/创建角色", + "Favorite characters to add them to HotSwaps": "收藏角色以将它们添加到快速热切换区", + "Token counts may be inaccurate and provided just for reference.": "词符计数可能不准确,仅供参考。", + "Total tokens": "总词符数", + "Calculating...": "正在计算...", + "Tokens": "词符数", + "Permanent tokens": "永久词符", + "Permanent": "恒定的", + "About Token 'Limits'": "关于词符“限制”", + "Toggle character info panel": "切换角色信息面板", + "Name this character": "为这个角色命名", + "extension_token_counter": "词符:", + "Click to select a new avatar for this character": "单击以为此角色选择新的头像", + "Add to Favorites": "添加到收藏夹", + "Advanced Definition": "高级定义", + "world_button_title": "Character Lore\n\nClick to load\nShift-click to open 'Link to World Info' popup", + "Chat Lore Alt+Click to open the lorebook": "Chat Lore\nAlt+Click to open the lorebook", + "Export and Download": "导出并下载", + "Duplicate Character": "复制角色", + "Create Character": "创建角色", + "Delete Character": "删除角色", + "More...": "更多...", + "Link to World Info": "链接到世界书", + "Import Card Lore": "导入角色卡的世界书", + "Scenario Override": "场景覆盖", + "Convert to Persona": "转换为用户角色", + "Rename": "重命名", + "Link to Source": "来源链接", + "Replace / Update": "替换 / 更新", + "Import Tags": "导入标签", + "Search / Create Tags": "搜索/创建标签", + "View all tags": "查看所有标签", + "Creator's Notes": "创作者的注释", + "Character details are hidden.": "角色详情已隐藏。", + "Show / Hide Description and First Message": "显示/隐藏描述和第一条消息", + "Character Description": "角色描述", + "Click to allow/forbid the use of external media for this character.": "单击以允许/禁止此角色使用外部媒体。", + "Ext. Media": "扩展媒体", + "Describe your character's physical and mental traits here.": "在这里描述您角色的身体和精神特征。", + "First message": "第一条消息", + "Click to set additional greeting messages": "单击以设置其他问候消息", + "Alt. Greetings": "其他开场", + "This will be the first message from the character that starts every chat.": "这将是角色在每次聊天开始时发送的第一条消息。", + "Group Controls": "群聊控制", + "Chat Name (Optional)": "聊天名称(可选)", + "Chat Lore": "聊天知识", + "Click to select a new avatar for this group": "单击选择该群聊的新头像", + "Group reply strategy": "群聊发言顺序", + "Manual": "手动", + "Natural order": "自然顺序", + "List order": "从上到下", + "Group generation handling mode": "群组生成处理模式", + "Swap character cards": "交换角色卡", + "Join character cards (exclude muted)": "加入角色卡(不包括被禁言的)", + "Join character cards (include muted)": "加入角色卡(包括被禁言的)", + "Inserted before each part of the joined fields.": "插入到加入字段的每个部分之前。", + "Join Prefix": "加入前缀", + "When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and with the name of the part (e.g.: description, personality, scenario, etc.)": "当选择“合并角色卡”时,角色的所有相应字段将被合并在一起。这意味着在故事字符串中,例如,所有角色描述都将合并为一个大文本。如果您希望将这些字段分开,可以在此处定义前缀或后缀。此值支持普通宏,还会将 {{char}} 替换为相关角色的名称,将 替换为部分的名称(例如:描述、个性、场景等)", + "Inserted after each part of the joined fields.": "插入到加入字段的每个部分之后。", + "Join Suffix": "加入后缀", + "Set a group chat scenario": "设置群聊背景", + "Click to allow/forbid the use of external media for this group.": "单击以允许/禁止该组使用外部媒体。", + "Restore collage avatar": "恢复拼贴头像", + "Allow self responses": "允许自我回复", + "Auto Mode": "自动模式", + "Auto Mode delay": "自动模式延迟", + "Hide Muted Member Sprites": "隐藏拼贴头像中被禁言的成员", + "Current Members": "当前成员", + "Add Members": "添加成员", + "Create New Character": "新建角色", + "Import Character from File": "从文件导入角色", + "Import content from external URL": "从外部URL导入内容", + "Create New Chat Group": "创建新的群聊", + "Characters sorting order": "角色排序顺序", + "A-Z": "A-Z", + "Z-A": "Z-A", + "Newest": "最新", + "Oldest": "最旧", + "Favorites": "收藏夹", + "Recent": "最近", + "Most chats": "最多聊天", + "Least chats": "最少聊天", + "Most tokens": "最多词符", + "Least tokens": "最少词符", + "Random": "随机", + "Toggle character grid view": "切换角色网格视图", + "Bulk_edit_characters": "批量编辑角色", + "Bulk select all characters": "批量选择所有角色", + "Bulk delete characters": "批量删除角色", + "Bind user name to that avatar": "将用户名称绑定到该头像", + "Change persona image": "更改用户角色头像", + "Select this as default persona for the new chats.": "选择此项作为新聊天的默认用户角色。", + "Duplicate persona": "复制用户角色", + "Delete persona": "删除用户角色", + "popup-button-save": "保存", + "popup-button-yes": "是", + "popup-button-no": "否", + "popup-button-cancel": "取消", + "popup-button-import": "导入", + "popup-button-crop": "裁剪", + "Close popup": "关闭弹出窗口", + "Advanced Definitions": "高级定义", + "Prompt Overrides": "提示词覆盖", + "(For Chat Completion and Instruct Mode)": "(用于聊天补全和指导模式)", + "Insert {{original}} into either box to include the respective default prompt from system settings.": "将{{original}}插入到任一框中,以包含系统设置中的相应默认提示词。", + "Main Prompt": "主要提示词", + "Any contents here will replace the default Main Prompt used for this character. (v2 spec: system_prompt)": "此处的任何内容都将替换用于此角色的默认主提示词。(v2规范:system_prompt)", + "Any contents here will replace the default Post-History Instructions used for this character. (v2 spec: post_history_instructions)": "此处的任何内容都将替换此角色使用的默认后历史说明。\n(v2 规范:post_history_instructions)", + "Creator's Metadata (Not sent with the AI prompt)": "创作者的元数据(不与AI提示词一起发送)", + "Creator's Metadata": "创作者的元数据", + "(Not sent with the AI Prompt)": "(不随 AI 提示词发送)", + "Everything here is optional": "这里的一切都是可选的", + "(Botmaker's name / Contact Info)": "(角色制作者的姓名/联系信息)", + "(If you want to track character versions)": "(如果您想跟踪角色版本)", + "(Describe the bot, give use tips, or list the chat models it has been tested on. This will be displayed in the character list.)": "(描述角色,提供使用技巧,或列出已经测试过的聊天模型。这将显示在角色列表中。)", + "Tags to Embed": "嵌入的标签", + "(Write a comma-separated list of tags)": "(编写一个以逗号分隔的标签列表。)", + "Personality summary": "角色设定摘要", + "(A brief description of the personality)": "(角色设定的简要描述)", + "Scenario": "情景", + "(Circumstances and context of the interaction)": "(交互的情况和背景)", + "Character's Note": "角色备注", + "(Text to be inserted in-chat @ designated depth and role)": "(文本将插入聊天中指定的深度和角色)", + "@ Depth": "@ 深度", + "Role": "角色", + "Talkativeness": "发言频率", + "How often the character speaks in group chats!": "角色在群聊中发言的频率!", + "How often the character speaks in": "角色发言的频率", + "group chats!": "群聊中!", + "Shy": "低", + "Normal": "正常", + "Chatty": "高", + "Examples of dialogue": "对话示例", + "Important to set the character's writing style.": "设置角色的写作风格,很重要!", + "(Examples of chat dialog. Begin each example with START on a new line.)": "(聊天对话的示例,每个示例都另起一行以开头。)", + "Save": "保存", + "Chat History": "聊天记录", + "Import Chat": "导入聊天", + "Copy to system backgrounds": "复制到系统背景", + "Rename background": "重命名背景", + "Lock": "锁定", + "Unlock": "解锁", + "Delete background": "删除背景", + "Select a World Info file for": "选择一个世界书文件给", + "Primary Lorebook": "主要知识书", + "A selected World Info will be bound to this character as its own Lorebook.": "所选的世界信息将会于该角色绑定,作为该角色自己的知识书", + "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "在生成AI回复时,它将与全局世界信息选择器中的条目相结合。", + "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "导出角色还将导出嵌入在JSON数据中的所选知识书文件。", + "Additional Lorebooks": "附加知识书", + "Associate one or more auxillary Lorebooks with this character.": "将一个或多个辅助知识书与此角色关联。", + "NOTE: These choices are optional and won't be preserved on character export!": "注意:这些选项是可选的,并且不会在角色导出时被一并导出!", + "Rename chat file": "重命名聊天文件", + "Export JSONL chat file": "导出 .JSONL 聊天文件", + "Download chat as plain text document": "将聊天下载为纯文本文档", + "Delete chat file": "删除聊天文件", + "Drag to reorder tag": "拖动以排序", + "Use tag as folder": "标记为文件夹", + "Delete tag": "删除标签", + "Toggle entry's active state.": "切换条目激活状态。", + "Entry Title/Memo": "条目标题/备忘录", + "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized": "世界书条目状态:\r🔵 永久\r🟢 关键词\r🔗 向量化", + "WI_Entry_Status_Constant": "永久", + "WI_Entry_Status_Normal": "关键词", + "WI_Entry_Status_Vectorized": "向量化", + "T_Position": "↑Char:在角色定义之前\n↓Char:在角色定义之后\n↑AN:在作者注释之前\n↓AN:在作者注释之后\n@D:在深度D处", + "Before Char Defs": "角色定义之前", + "After Char Defs": "角色定义之后", + "Before EM": "↑EM", + "After EM": "↓EM", + "Before AN": "作者注释之前", + "After AN": "作者注释之后", + "at Depth System": "@D ⚙​​️", + "at Depth User": "@D 👤", + "at Depth AI": "@D 🤖", + "Depth": "深度", + "Order:": "顺序:", + "Order": "顺序", + "Trigger %:": "触发 %:", + "Duplicate world info entry": "重复的世界信息条目", + "Delete world info entry": "删除世界信息条目", + "Comma separated (required)": "逗号分隔(必填)", + "Primary Keywords": "主要关键字", + "Keywords or Regexes": "关键字或正则表达式", + "Comma separated list": "逗号分隔列表", + "Switch to plaintext mode": "切换到纯文本模式", + "Logic": "逻辑", + "AND ANY": "与任意", + "AND ALL": "与所有", + "NOT ALL": "非所有", + "NOT ANY": "非任何", + "(ignored if empty)": "(若为空则忽略)", + "Optional Filter": "可选过滤器", + "Keywords or Regexes (ignored if empty)": "关键字或正则表达式(如果为空则忽略)", + "Comma separated list (ignored if empty)": "逗号分隔列表(如果为空则忽略)", + "Use global setting": "使用全局设置", + "Case-Sensitive": "区分大小写", + "Use global": "使用全局", + "Yes": "是", + "No": "否", + "Whole Words": "Whole Words", + "Group Scoring": "Group Scoring", + "Can be used to automatically activate Quick Replies": "可用于自动激活快速回复", + "Automation ID": "自动化ID", + "( None )": "(没有任何)", + "delay_until_recursion_level": "Defines delay levels for recursive scans.\r\rInitially, only the first level (smallest number) will match.\rOnce no matches are found, the next level becomes eligible for matching.\rThis repeats until all levels are checked.\r\rTied to the \"Delay until recursion\" setting.", + "Recursion Level": "递归等级", + "Content": "内容", + "Non-recursable (will not be activated by another)": "不可递归(不会被其他条目激活)", + "Prevent further recursion (this entry will not activate others)": "防止进一步递归(本条目将不会激活其他条目)", + "Delay until recursion (can only be activated on recursive checking)": "延迟到递归(本条目只能在递归检查时激活)", + "What this keyword should mean to the AI, sent verbatim": "这个关键词对AI的含义,逐字发送", + "Inclusion Group": "包含组", + "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "包含组可确保每次仅激活组中的一项(如果触发了多项)。支持多个逗号分隔的组。文档:世界信息 - 包含组", + "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "优先考虑此条目:选中后,此条目在所有选择中优先考虑。如果优先考虑多个条目,则选择“顺序”最高的条目。", + "Prioritize": "确定优先级", + "Only one entry with the same label will be activated": "只有一个带有相同标签的条目将被激活", + "A relative likelihood of entry activation within the group": "组内进入激活的相对可能性", + "Group Weight": "组权重", + "Sticky entries will stay active for N messages after being triggered.": "粘性条目在被触发后将保持活跃状态​​ N 条消息。", + "Sticky": "黏性", + "Non-sticky": "无黏性", + "Entries with a cooldown can't be activated N messages after being triggered.": "具有冷却时间的条目在触发后 N 条消息内无法被激活。", + "Cooldown": "冷却", + "No cooldown": "无冷却", + "Entries with a delay can't be activated until there are N messages present in the chat.": "直到聊天中出现 N 条消息时,延迟的条目才能被激活。", + "Delay": "延迟", + "No delay": "无延迟", + "Filter to Characters or Tags": "绑定到角色或标签", + "Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry": "切换角色/标签筛选方式,将列出的角色和标签排除在匹配范围之外", + "Exclude": "排除", + "-- Characters not found --": "-- 未找到角色 --", + "Selective": "选择性", + "Use Probability": "使用概率", + "Add Memo": "添加备忘录", + "Text or token ids": "文本或 [token ID]", + "Type here...": "在此处输入...", + "close": "关闭", + "prompt_manager_edit": "编辑", + "prompt_manager_name": "姓名", + "A name for this prompt.": "此提示词的名称。", + "To whom this message will be attributed.": "此消息应归于谁。", + "AI Assistant": "AI助手", + "prompt_manager_position": "位置", + "Injection position. Relative (to other prompts in prompt manager) or In-chat @ Depth.": "注入位置。相对(相对于提示管理器中的其他提示)或在聊天中@深度。", + "prompt_manager_relative": "相对", + "prompt_manager_in_chat": "聊天中", + "prompt_manager_depth": "深度", + "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "注入深度。“0”为在最后一条消息之后,“1”为在最后一条消息之前,等等。", + "The content of this prompt is pulled from elsewhere and cannot be edited here.": "此提示词的内容是从其他地方提取的,无法在此处进行编辑。", + "Prompt": "提示词", + "The prompt to be sent.": "要发送的提示词。", + "This prompt cannot be overridden by character cards, even if overrides are preferred.": "即使选择覆盖,此提示词也不能被角色卡覆盖。", + "prompt_manager_forbid_overrides": "禁止覆盖", + "reset": "重置", + "save": "保存", + "This message is invisible for the AI": "此消息对AI不可见", + "Message Actions": "消息操作", + "Translate message": "翻译消息", + "Generate Image": "生成图片", + "Narrate": "朗读", + "Exclude message from prompts": "从提示词中排除消息", + "Include message in prompts": "将消息包含在提示词中", + "Embed file or image": "嵌入文件或图像", + "Create checkpoint": "创建检查点", + "Create Branch": "创建分支", + "Copy": "复制", + "Open checkpoint chat\nShift+Click to replace the existing checkpoint with a new one": "点击打开检查点聊天\nShift+单击来覆盖已有检查点", + "Edit": "编辑", + "Confirm": "确认", + "Copy this message": "复制此消息", + "Add a reasoning block": "添加一个推理块", + "Delete this message": "删除此消息", + "Move message up": "将消息上移", + "Move message down": "将消息下移", + "Thought for some time": "思考了一会", + "Confirm Edit": "确认", + "Remove reasoning": "删除推理内容", + "Cancel edit": "Cancel edit", + "Copy reasoning": "复制推理内容", + "Edit reasoning": "编辑推理内容", + "Enlarge": "放大", + "Caption": "标题", + "Swipe left": "Swipe left", + "Swipe right": "Swipe right", + "Welcome to SillyTavern!": "欢迎来到 SillyTavern!", + "SillyTavern is aimed at advanced users.": "SillyTavern 面向高级用户。", + "welcome_message_part_1": "阅读", + "welcome_message_part_2": "官方文档", + "welcome_message_part_3": "。", + "welcome_message_part_4": "类型", + "welcome_message_part_5": "在聊天中输入命令和宏。", + "welcome_message_part_6": "加入", + "Discord server": "Discord 服务器", + "welcome_message_part_7": "了解信息和公告。", + "Looking for AI characters?": "正在寻找 AI 角色?", + "onboarding_import": "导入", + "from supported sources or view": "来自受支持的来源或查看", + "Sample characters": "示例角色", + "Your Persona": "您的用户角色", + "Before you get started, you must select a persona name.": "在开始之前,您必须选择一个用户角色名称。", + "welcome_message_part_8": "您可随时通过", + "welcome_message_part_9": "图标来更改此设置。", + "Persona Name:": "用户角色名称:", + "Temporarily disable automatic replies from this character": "临时禁言此角色", + "Enable automatic replies from this character": "解除禁言此角色", + "Trigger a message from this character": "强制触发该角色发言", + "Move up": "向上移动", + "Move down": "向下移动", + "View character card": "查看角色卡片", + "Remove from group": "踢出群聊", + "Add to group": "拉入群聊", + "Alternate Greetings": "额外问候语", + "Alternate_Greetings_desc": "开始新聊天时,这些按钮将显示为第一条消息的滑动选项。\n群成员可以选择其中之一来发起对话。", + "alternate_greetings_hint_1": "点击", + "alternate_greetings_hint_2": "按钮即可开始!", + "Alternate Greeting #": "额外问候语 #", + "(This will be the first message from the character that starts every chat)": "(这是每次聊天开始时角色的第一条消息)", + "View contents": "查看内容", + "Remove the file": "删除文件", + "Author's Note": "作者注释", + "Unique to this chat": "仅对此聊天生效", + "Checkpoints inherit the Note from their parent, and can be changed individually after that.": "检查点从其父级继承注释,之后可以单独更改。", + "Include in World Info Scanning": "纳入世界信息扫描", + "Before Main Prompt / Story String": "主提示词/故事线之前", + "After Main Prompt / Story String": "主提示词/故事线之后", + "as": "作为", + "Insertion Frequency": "插入频率", + "(0 = Disable, 1 = Always)": "(“0”为禁用,“1”为始终)", + "User inputs until next insertion:": "用户输入直到下一次插入:", + "Character Author's Note (Private)": "人物作者注(私密)", + "Won't be shared with the character card on export.": "导出时不会与角色卡共享。", + "Will be automatically added as the author's note for this character. Will be used in groups, but can't be modified when a group chat is open.": "会自动添加为该角色的作者注解,在群聊中使用,但群聊开启时无法修改。", + "Use character author's note": "使用角色作者的注释", + "Replace Author's Note": "替换作者注", + "Default Author's Note": "默认作者注", + "Will be automatically added as the Author's Note for all new chats.": "将自动添加为所有新聊天的作者注释。", + "Chat CFG": "本聊天的CFG缩放", + "1 = disabled": "“1”为禁用", + "write short replies, write replies using past tense": "写简短的回复,用过去时写回复", + "Positive Prompt": "正面提示词", + "Use character CFG scales": "单独为各个角色设置CFG缩放", + "Character CFG": "角色CFG配置", + "Will be automatically added as the CFG for this character.": "将自动添加到该角色的CFG设置中。", + "Global CFG": "全局CFG", + "Will be used as the default CFG options for every chat unless overridden.": "除非被覆盖,否则将用作每次聊天的默认 CFG 选项。", + "CFG Prompt Cascading": "CFG 提示词级联", + "Combine positive/negative prompts from other boxes.": "结合来自其他框的正面/负面提示词。", + "For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string.": "例如,勾选聊天、全局和角色框会将所有负面提示词组合成以逗号分隔的字符串。", + "Always Include": "始终包含", + "Chat Negatives": "聊天负面信息", + "Character Negatives": "性格缺点", + "Global Negatives": "全局负面信息", + "Custom Separator:": "自定义分隔符:", + "Insertion Depth:": "插入深度:", + "Token Probabilities": "词符概率", + "Select a token to see alternatives considered by the AI.": "选择一个词符来查看 AI 考虑的替代方案。", + "Reroll with the entire prefix": "使用完整前缀重新生成", + "Not connected to API!": "未连接到API!", + "Type a message, or /? for help": "输入想发送的消息,或输入 /? 获取帮助", + "Continue script execution": "继续执行脚本", + "Pause script execution": "暂停执行脚本", + "Abort script execution": "中止执行脚本", + "Abort request": "中止请求", + "Ask AI to write your message for you": "让AI为您撰写消息", + "Continue the last message": "继续上一条消息", + "Send a message": "发送消息", + "Close chat": "关闭聊天", + "Toggle Panels": "切换面板", + "CFG Scale": "CFG缩放", + "Back to parent chat": "返回到父级聊天", + "Save checkpoint": "保存检查点", + "Convert to group": "转换为群聊", + "Start new chat": "开始新聊天", + "Manage chat files": "管理聊天文件", + "Delete messages": "删除消息", + "Regenerate": "重新生成", + "Impersonate": "AI 帮答", + "Continue": "继续", + "extension_install_1": "若想从此页安装扩展程序,你需要提前安装", + "extension_install_2": "。", + "extension_install_3": "点这个图标(", + "extension_install_4": ")前往扩展程序的代码仓库以了解如何使用它。", + "These characters are the winners of character design contests and have outstandable quality.": "这些角色都是角色设计大赛的获奖者,品质非常出色。", + "Contest Winners": "比赛获胜者", + "These characters are the finalists of character design contests and have remarkable quality.": "这些角色都是角色设计大赛的入围作品,品质十分出色。", + "Featured Characters": "特色角色", + "Download Extensions & Assets": "下载扩展和资源菜单", + "Load a custom asset list or select": "加载自定义资产列表或选择", + "to install 3rd party extensions.": "安装第三方扩展。", + "Assets URL": "资产网址", + "load_asset_list_desc": "根据资产列表文件加载扩展和资产列表。\n\n此字段中的默认资产 URL 指向官方第一方扩展和资产列表。\n如果您有自定义资产列表,可以在此处插入。\n\n要安装单个第三方扩展,请使用右上角的“安装扩展”按钮。", + "Load an asset list": "加载资产列表", + "Load Asset List": "加载资产列表", + "Characters": "人物", + "Attach a File": "附加文件", + "Enter a URL or the ID of a Fandom wiki page to scrape:": "输入要抓取的 Fandom wiki 页面的 URL 或 ID:", + "Examples:": "例:", + "Example:": "例:", + "Single file": "单个文件", + "All articles will be concatenated into a single file.": "所有文章将被合并为一个文件。", + "File per article": "每篇文章的文件数", + "Each article will be saved as a separate file.": "不推荐。每篇文章将保存为单独的文件。", + "Open Data Bank": "打开数据库", + "Data Bank": "数据库", + "These files will be available for extensions that support attachments (e.g. Vector Storage).": "这些文件将可用于支持附件的扩展(例如 Vector Storage)。", + "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.": "支持的文件类型:纯文本、PDF、Markdown、HTML、EPUB。", + "Drag and drop files here to upload.": "将文件拖放到此处进行上传。", + "Date (Newest First)": "日期(最新日期)", + "Date (Oldest First)": "日期(最早日期)", + "Name (A-Z)": "姓名(从 A 到 Z)", + "Name (Z-A)": "姓名 (Z-A)", + "Size (Smallest First)": "尺寸(最小)", + "Size (Largest First)": "尺寸(最大尺寸优先)", + "Bulk Edit": "批量编辑", + "Select All": "全选", + "Select None": "清空选择", + "Disable": "禁用", + "Enable": "启用", + "Global Attachments": "全局附件", + "These files are available for all characters in all chats.": "这些文件可供所有聊天中的所有角色使用。", + "Character Attachments": "角色附件", + "These files are available for the current character in all chats they are in.": "当前角色可以在其所在的所有聊天中使用这些文件。", + "Saved locally. Not exported.": "已本地保存。未导出。", + "Chat Attachments": "聊天附件", + "These files are available for all characters in the current chat.": "这些文件可供当前聊天中的所有角色使用。", + "Enter a base URL of the MediaWiki to scrape.": "输入要抓取的 MediaWiki 的基本 URL。", + "Don't include the page name!": "不要包含页面名称!", + "Enter web URLs to scrape (one per line):": "输入要抓取的网址(每行一个):", + "Enter a video URL to download its transcript.": "输入视频 URL 或 ID 即可下载其文本。", + "Image Captioning": "图像描述", + "Source": "来源", + "Local": "本地", + "Multimodal (OpenAI / Anthropic / llama / Google)": "多模式(OpenAI / Anthropic / llama / Google)", + "Extras": "更多", + "Horde": "Horde", + "API": "API", + "Text Generation WebUI (oobabooga)": "文本生成 WebUI (oobabooga)", + "Model": "模型", + "currently_selected": "[当前选定]", + "currently_loaded": "[当前正在加载]", + "Allow reverse proxy": "允许反向代理", + "Hint:": "提示:", + "Set your API keys and endpoints in the 'API Connections' tab first.": "首先在“API 连接”选项卡中设置您的 API 密钥和端点。", + "Caption Prompt": "图像描述提示词", + "Ask every time": "每次都询问", + "Message Template": "消息模板", + "(use _space": "(使用", + "macro)": "宏指令)", + "Automatically caption images": "自动为图像添加标题", + "Edit captions before saving": "保存前编辑标题", + "Included settings:": "包含的设置:", + "{{@key}}": "{{@key}}:", + "Profile name:": "配置名称:", + "Creating a Connection Profile": "新建API连接配置", + "Click on the setting name to omit it from the profile.": "点击设置名称以将其从连接配置中删除。", + "Enter a name:": "输入名字:", + "Connection Profile": "API连接配置", + "View connection profile details": "查看API连接配置详情", + "Create a new connection profile": "新建一个API连接配置", + "Update a connection profile": "更新API连接配置", + "Edit a connection profile": "编辑API连接配置", + "Reload a connection profile": "重载API连接配置", + "Delete a connection profile": "删除API连接配置", + "Omitted Settings:": "排除的设置:", + "Character Expressions": "角色表情", + "Use the selected API from Chat Translation extension settings.": "使用聊天翻译扩展程序中已选择的API。", + "Translate text to English before classification": "分类之前将文本翻译成英文", + "A single expression can have multiple sprites. Whenever the expression is chosen, a random sprite for this expression will be selected.": "A single expression can have multiple sprites. Whenever the expression is chosen, a random sprite for this expression will be selected.", + "Allow multiple sprites per expression": "Allow multiple sprites per expression", + "If the same expression is used again, re-roll the sprite. This only applies to expressions that have multiple available sprites assigned.": "If the same expression is used again, re-roll the sprite. This only applies to expressions that have multiple available sprites assigned.", + "Re-roll if same expression is used again": "Re-roll if same sprite is used again", + "Classifier API": "分类器 API", + "Select the API for classifying expressions.": "选择用于对表达式进行分类的API。", + "Main API": "当前连接的 API", + "WebLLM Extension": "WebLLM Extension", + "LLM Prompt": "大语言模型提示词", + "Will be used if the API doesn't support JSON schemas or function calling.": "如果 API 不支持 JSON 模式或函数调用,则会使用它。", + "Default / Fallback Expression": "默认/后备表达式", + "Set the default and fallback expression being used when no matching expression is found.": "设置在未找到匹配表达式时使用的默认表达式和后备表达式。", + "Custom Expressions": "自定义表达式", + "Can be set manually or with an _space": "可以手动设置或使用", + "space_ slash command.": "快捷命令来设置。", + "Open a chat to see the character expressions.": "打开聊天即可查看人物表情。", + "You are in offline mode. Click on the image below to set the expression.": "您处于离线模式。点击下方图片即可设置表情。", + "Sprite Folder Override": "表情文件夹覆盖", + "Use a forward slash to specify a subfolder. Example: _space": "使用正斜杠指定子文件夹。例如:", + "Upload sprite pack (ZIP)": "上传表情包(ZIP)", + "Remove all image overrides": "删除所有图片覆盖", + "Create new folder in the _space": "创建新文件夹到", + "folder of your user data directory and name it as the name of the character.": "用户数据目录的文件夹并将其命名为角色的名称。", + "Put images with expressions there. File names should follow the pattern:": "将带有表情的图像放在那里。文件名应遵循以下模式:", + "expression_label_pattern": "[表达式标签].[图像格式]", + "Sprite set:": "表情集:", + "upload_expression_request": "请输入表情名称(不用加后缀)。", + "upload_expression_naming_1": "素材名称必须符合所选表情 {{expression}} 的命名规范", + "upload_expression_naming_2": "当存在多个表情时,名称应由表情名称与合法后缀构成,允许使用横杠'-'或英文句号'.'作为分隔符。", + "upload_expression_replace": "点击“替换”以替换当前表情:", + "Show Gallery": "展示图库", + "ext_sum_title": "总结", + "ext_sum_with": "总结如下:", + "ext_sum_main_api": "主要 API", + "ext_sum_webllm": "WebLLM 扩展", + "ext_sum_current_summary": "当前摘要:", + "ext_sum_restore_tip": "恢复先前的摘要;重复使用以清除此聊天的摘要状态", + "ext_sum_restore_previous": "恢复上一个", + "ext_sum_memory_placeholder": "摘要将在这里生成...", + "ext_sum_force_tip": "立即触发摘要更新。", + "ext_sum_force_text": "现在总结", + "Disable automatic summary updates. While paused, the summary remains as-is. You can still force an update by pressing the Summarize now button (which is only available with the Main API).": "禁用自动摘要更新。暂停时,摘要保持原样。您仍然可以通过按“立即汇总”按钮(仅适用于主 API)强制更新。", + "ext_sum_pause": "暂停", + "Omit World Info and Author's Note from text to be summarized. Only has an effect when using the Main API. The Extras API always omits WI/AN.": "从要总结的文本中省略世界信息和作者注释。仅在使用主 API 时有效。附加 API 始终省略世界书/作者注。", + "ext_sum_no_wi_an": "无世界书/作者注", + "ext_sum_settings_tip": "编辑摘要提示词、插入位置等。", + "ext_sum_settings": "摘要设置", + "ext_sum_prompt_builder": "提示词生成器", + "ext_sum_prompt_builder_1_desc": "扩展将使用尚未汇总的消息构建自己的提示词。阻止聊天,直到生成摘要为止。", + "ext_sum_prompt_builder_1": "原始,阻塞", + "ext_sum_prompt_builder_2_desc": "扩展将使用尚未汇总的消息构建自己的提示词。在生成摘要时不会阻止聊天。并非所有后端都支持此模式。", + "ext_sum_prompt_builder_2": "原始,非阻塞", + "ext_sum_prompt_builder_3_desc": "扩展将使用常规主提示词生成器并将摘要请求添加为其作为最后的系统消息。", + "ext_sum_prompt_builder_3": "经典,阻塞", + "Summary Prompt": "摘要提示词", + "ext_sum_restore_default_prompt_tip": "恢复默认提示词", + "ext_sum_prompt_placeholder": "该提示词将被发送给 AI,以请求生成摘要。{{words}} 将解析为“字数”参数。", + "ext_sum_target_length_1": "目标摘要长度", + "ext_sum_target_length_2": "(", + "ext_sum_target_length_3": "字)", + "ext_sum_api_response_length_1": "API 响应长度", + "ext_sum_api_response_length_2": "(", + "ext_sum_api_response_length_3": "个词符)", + "ext_sum_0_default": "“0”为默认", + "ext_sum_raw_max_msg": "[原始] 每个请求的最大消息数", + "ext_sum_0_unlimited": "“0”为无限制", + "Update frequency": "更新频率", + "ext_sum_update_every_messages_1": "更新间隔", + "ext_sum_update_every_messages_2": "消息", + "ext_sum_0_disable": "“0”为禁用", + "ext_sum_auto_adjust_desc": "尝试根据聊天指标自动调整间隔。", + "ext_sum_update_every_words_1": "更新间隔(", + "ext_sum_update_every_words_2": "字)", + "ext_sum_both_sliders": "如果两个滑块都不为零,则两者都将按照各自的间隔触发摘要更新。", + "ext_sum_injection_template": "插入模板", + "ext_sum_memory_template_placeholder": "{{summary}} 将解析当前摘要内容。", + "ext_sum_injection_position": "插入位置", + "ext_sum_include_wi_scan_desc": "在 WI 扫描中包括最新摘要。", + "ext_sum_include_wi_scan": "纳入世界信息扫描", + "None (not injected)": "无(未注入)", + "ext_sum_injection_position_none": "摘要不会被注入到提示中。您仍然可以通过 {{summary}} 宏访问它。", + "How many messages before the current end of the chat.": "当前聊天结束前还有多少条消息。", + "Labels and Message": "标签和信息", + "Label": "标签", + "(label of the button, if no icon is chosen) ": "(如果没有选择图标,则为按钮的标签)", + "Title": "标题", + "(tooltip, leave empty to show message or /command)": "(工具提示,留空以显示消息或/命令)", + "Message / Command:": "消息/命令:", + "Word wrap": "自动换行", + "Tab size:": "标签大小:", + "Ctrl+Enter to execute": "使用 Ctrl+Enter 来执行", + "Context Menu": "上下文菜单", + "Chaining:": "链接:", + "Auto-Execute": "自动执行", + "Don't trigger auto-execute": "不触发自动执行", + "Invisible (auto-execute only)": "隐形(仅自动执行)", + "Execute on startup": "启动时执行", + "Execute on user message": "根据用户消息执行", + "Execute on AI message": "根据 AI 消息执行", + "Execute on chat change": "聊天内容改变时执行", + "Execute on new chat": "在新聊天中执行", + "Execute on group member draft": "起草群组成员时执行", + "Automation ID:": "自动化标识", + "Testing": "测试", + "Execute": "执行", + "Quick Reply": "快速回复", + "Enable Quick Replies": "启用快速回复", + "Combine Quick Replies": "合并快速回复", + "Show Popout Button": "(在电脑上)展示弹出式按钮", + "Global Quick Reply Sets": "全局快速回复集", + "Chat Quick Reply Sets": "聊天快速回复集", + "Edit Quick Replies": "编辑快速回复", + "Disable Send (Insert Into Input Field)": "禁用发送(插入输入字段)", + "Place Quick Reply Before Input": "在输入前放置快速回复", + "Inject user input automatically": "自动注入用户输入", + "(if disabled, use ": "(如果禁用,使用", + "macro for manual injection)": "宏用于手动注入)", + "Color": "颜色", + "Only apply color as accent": "仅应用颜色作为强调", + "ext_regex_title": "正则", + "ext_regex_new_global_script_desc": "新的全局正则表达式脚本", + "ext_regex_new_global_script": "新建全局正则", + "ext_regex_new_scoped_script_desc": "新的作用域正则表达式脚本", + "ext_regex_new_scoped_script": "新建局部正则", + "ext_regex_import_script": "导入正则", + "ext_regex_global_scripts": "全局正则脚本", + "ext_regex_global_scripts_desc": "影响所有角色,保存在本地设定中", + "ext_regex_scoped_scripts": "局部正则脚本", + "ext_regex_disallow_scoped": "不允许使用局部正则", + "ext_regex_allow_scoped": "允许使用局部正则", + "ext_regex_scoped_scripts_desc": "只影响当前角色,保存在角色卡片中", + "Regex Editor": "正则表达式编辑器", + "Test Mode": "测试模式", + "ext_regex_desc": "“正则”是一个使用“正则表达式”来查找/替换字符串的工具。如果您想了解更多信息,请点击标题旁边的“?”。", + "Input": "输入", + "ext_regex_test_input_placeholder": "在此输入...", + "Output": "输出", + "ext_regex_output_placeholder": "空", + "Script Name": "脚本名称", + "Find Regex": "查找正则表达式", + "Replace With": "替换为", + "ext_regex_replace_string_placeholder": "使用 {{match}} 包含来自“查找正则表达式”或“$1”、“$2”等的匹配文本作为捕获组。", + "Trim Out": "修剪掉", + "ext_regex_trim_placeholder": "在替换之前全局修剪正则表达式匹配中任何不需要的部分。用回车键分隔每个元素。", + "ext_regex_affects": "作用范围", + "ext_regex_user_input_desc": "用户发送的消息", + "ext_regex_user_input": "用户输入", + "ext_regex_ai_input_desc": "从生成式API中获取的信息。", + "ext_regex_ai_output": "AI输出", + "ext_regex_slash_desc": "通过 STscript 命令发送的消息。", + "Slash Commands": "快捷命令", + "ext_regex_wi_desc": "知识书/世界书 条目的内容。需要勾选“仅格式提示词”!", + "ext_regex_reasoning_desc": "推理块内容。当'仅格式提示词'被选中时,它会影响提示词里的推理内容。", + "ext_regex_min_depth_desc": "当应用于提示或显示时,仅影响深度至少为 N 级的消息。“0”为最后一条消息,“1”为倒数第二条消息等。仅计算 WI 条目 @Depth 和可用消息,即非隐藏或系统消息。", + "Min Depth": "最小深度", + "ext_regex_min_depth_placeholder": "无限", + "ext_regex_max_depth_desc": "当应用于提示词或显示时,仅影响深度不超过 N 级的消息。“0”为最后一条消息,“1”为倒数第二条消息等。仅计算世界信息条目 @Depth 和可用消息,即非隐藏或系统消息。", + "ext_regex_other_options": "其他选项", + "ext_regex_run_on_edit_desc": "当指定角色的消息被编辑时运行正则脚本。", + "Run On Edit": "在编辑时运行", + "ext_regex_substitute_regex_desc": "在运行正则表达式查找之前,替换 {{macros}}", + "Macro in Find Regex": "正则表达式查找时的宏", + "Don't substitute": "不替换", + "Substitute (raw)": "替换(原始)", + "Substitute (escaped)": "替换(转义)", + "Ephemerality": "短暂", + "ext_regex_only_format_visual_desc": "正则仅在聊天页面生效,聊天文件内的内容不会被改变。", + "Only Format Display": "仅格式显示", + "ext_regex_only_format_prompt_desc": "聊天记录不会改变,只有在请求发送时(生成时)才会出现提示词。", + "Only Format Prompt (?)": "仅格式提示词", + "ext_regex_import_target": "导入至:", + "ext_regex_disable_script": "禁用脚本", + "ext_regex_enable_script": "启用脚本", + "ext_regex_edit_script": "编辑脚本", + "ext_regex_move_to_global": "移至全局脚本", + "ext_regex_move_to_scoped": "移至作用域脚本", + "ext_regex_export_script": "导出脚本", + "ext_regex_delete_script": "删除脚本", + "Trigger Stable Diffusion": "触发Stable Diffusion", + "Abort current image generation task": "中止当前图像生成", + "Stop Image Generation": "停止图像生成", + "sd_Yourself": "你自己", + "sd_Your_Face": "你的脸", + "sd_Me": "我", + "sd_The_Whole_Story": "整个故事", + "sd_The_Last_Message": "最后的信息", + "sd_Raw_Last_Message": "原始最后一条消息", + "sd_Background": "背景", + "Image Generation": "图像生成", + "sd_refine_mode": "允许在将提示词发送到生成 API 之前手动编辑提示词", + "sd_refine_mode_txt": "生成之前编辑提示词", + "sd_function_tool": "Use the function tool to automatically detect intents to generate images.", + "sd_function_tool_txt": "Use function tool", + "sd_interactive_mode": "发送消息时自动生成图像,例如“给我发一张猫的照片”。", + "sd_interactive_mode_txt": "交互模式", + "sd_multimodal_captioning": "使用多模式字幕根据用户和角色的头像生成提示词。", + "sd_multimodal_captioning_txt": "使用多模式字幕来描绘肖像", + "sd_free_extend": "使用当前选择的 LLM 自动扩展自由模式主题提示(不是肖像或背景)。", + "sd_free_extend_txt": "延长自由模式提示", + "sd_free_extend_small": "(交互/命令)", + "sd_snap": "快照生成请求具有强制纵横比(肖像、背景)到最接近已知分辨率,同时尝试保留绝对像素数(推荐用于 SDXL)。", + "sd_snap_txt": "自动调整分辨率", + "sd_auto_url": "例如:{{auto_url}}", + "Authentication (optional)": "身份验证(可选)", + "Example: username:password": "例:用户名:密码", + "Important:": "重要:", + "sd_auto_auth_warning_1": "使用", + "sd_auto_auth_warning_2": "注意!服务器必须可从 SillyTavern 主机访问。", + "sd_drawthings_url": "例如:{{drawthings_url}}", + "sd_drawthings_auth_txt": "运行 DrawThings 应用程序并在 UI 中启用 HTTP API 开关!必须可以从 SillyTavern 主机访问服务器。", + "Model ID": "Model ID", + "e.g. black-forest-labs/FLUX.1-dev": "例如:black-forest-labs/FLUX.1-dev", + "sd_vlad_url": "例如:{{vlad_url}}", + "The server must be accessible from the SillyTavern host machine.": "必须能够从 SillyTavern 主机访问该服务器。", + "Hint: Save an API key in AI Horde API settings to use it here.": "提示:在 Horde AI API 设置中保存一个 API 密钥以便在此处使用它。", + "Allow NSFW images from Horde": "允许来自 Horde 的 NSFW 图片", + "Sanitize prompts (recommended)": "净化提示词(推荐)", + "Automatically adjust generation parameters to ensure free image generations.": "自动调整生成参数,确保图像生成自由。", + "Avoid spending Anlas": "避免花费 Anlas", + "Opus tier": "(作品层)", + "View my Anlas": "查看我的目录", + "These settings only apply to DALL-E 3": "这些设置仅适用于 DALL-E 3", + "Image Style": "图像风格", + "Image Quality": "画面质量", + "Standard": "标准", + "HD": "高清", + "sd_comfy_url": "例如:{{comfy_url}}", + "Open workflow editor": "打开工作流编辑器", + "Create new workflow": "创建新的工作流", + "Delete workflow": "删除工作流", + "Enhance": "提高", + "API Key": "API 密钥", + "Click to set": "点击设置", + "You can find your API key in the Stability AI dashboard.": "您可以在 Stability AI 仪表板中找到您的 API 密钥。", + "Style Preset": "风格预设", + "Prompt Upsampling": "提示词增强(Upsampling)", + "Sampling method": "采样方法", + "Scheduler": "调度器", + "Resolution": "分辨率", + "Upscaler": "图像扩大器", + "Sampling steps": "采样步数", + "Width": "宽度", + "Height": "高度", + "Swap width and height": "交换宽度和高度", + "Upscale by": "扩大倍数", + "Denoising strength": "去噪强度", + "Hires steps (2nd pass)": "高清修复步数(第二遍)", + "CLIP Skip": "片段跳过", + "Restore Faces": "面部修复", + "Hires. Fix": "高清修复", + "Karras": "Karras", + "Not all samplers supported.": "并非所有采样器都受支持。", + "sd_adetailer_face": "Use ADetailer with face model during the generation. The ADetailer extension must be installed on the backend.", + "Use ADetailer (Face)": "使用 ADetailer(脸部)", + "SMEA versions of samplers are modified to perform better at high resolution.": "SMEA 版本的采样器经过修改,在高分辨率下性能更佳。", + "SMEA": "中小企业协会", + "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "SMEA 采样器的 DYN 变体通常会产生更加多样化的输出,但在非常高的分辨率下可能会失败。", + "DYN": "动态", + "Decrisper": "去伪器", + "(-1 for random)": "(“-1”为随机)", + "Preset for prompt prefix and negative prompt": "提示词前缀和负面提示词的预设", + "Style": "风格", + "Save style": "保存风格", + "Delete style": "删除风格", + "Common prompt prefix": "常见提示词前缀", + "sd_prompt_prefix_placeholder": "使用 {prompt} 指定生成的提示词插入的位置", + "Negative common prompt prefix": "常见负面提示词前缀", + "Character-specific prompt prefix": "特定角色的提示词前缀", + "Won't be used in groups.": "不可供群聊使用。", + "sd_character_prompt_placeholder": "描述当前选定角色的任何特征。将添加在常见提示词前缀后。\n示例:女性、绿眼睛、棕色头发、粉色衬衫", + "Character-specific negative prompt prefix": "特定角色的负面提示词前缀", + "sd_character_negative_prompt_placeholder": "所选角色不应出现的任何特征。将添加在常见负面提示词前缀后。\n示例:珠宝、鞋子、眼镜", + "Shareable": "可共享", + "Chat Message Visibility (by source)": "聊天消息可见性(按来源)", + "Uncheck to hide the extension's messages in chat prompts.": "取消选中可在聊天提示中隐藏扩展消息。", + "Extensions Menu": "扩展菜单", + "Slash Command": "快捷命令", + "Interactive Mode": "交互模式", + "Function Tool": "Function Tool", + "Image Prompt Templates": "图像提示模板", + "Token Counter": "词符计数器", + "Type / paste in the box below to see the number of tokens in the text.": "在下方框中输入或粘贴你想要统计词符数量的文本。", + "Selected tokenizer:": "已选分词器:", + "Input:": "输入:", + "Tokens:": "词符:", + "Tokenized text:": "词符化文本:", + "Token IDs:": "词符ID:", + "ext_translate_btn_chat": "翻译聊天", + "ext_translate_btn_input": "翻译输入", + "ext_translate_delete_confirm_1": "你确定吗?", + "ext_translate_delete_confirm_2": "这将从当前聊天中的所有消息中删除翻译文本。此操作无法撤消。", + "ext_translate_title": "聊天翻译", + "ext_translate_auto_mode": "自动模式", + "ext_translate_mode_none": "没有任何", + "ext_translate_mode_responses": "翻译回复", + "ext_translate_mode_inputs": "翻译输入", + "ext_translate_mode_both": "翻译两者", + "ext_translate_mode_provider": "提供者", + "ext_translate_target_lang": "目标语言", + "ext_translate_clear": "清空设置", + "Select TTS Provider": "选择 文本转语音 的服务提供商", + "tts_enabled": "已启用", + "Narrate user messages": "朗读用户消息", + "Auto Generation": "自动生成", + "Requires auto generation to be enabled.": "需要启用自动生成功能。", + "Narrate by paragraphs (when streaming)": "按段朗读(流式播放时)", + "Narrate by paragraphs (when not streaming)": "按段朗读(非流式播放时)", + "Only narrate quotes": "只朗读引号内文本", + "Ignore text, even quotes, inside asterisk": "不朗读所有*星号内文本*,即使其被引号包裹", + "Narrate only the translated text": "只朗读翻译后文本", + "Skip codeblocks": "跳过代码块", + "Skip tagged blocks": "跳过标签块里的内容(<标签>跳过这里)", + "Pass Asterisks to TTS Engine": "将星号传递给文本转语音服务", + "Audio Playback Speed": "音频播放速度", + "Vector Storage": "向量存储", + "Vectorization Source": "向量化源", + "Local (Transformers)": "本地(Transformers)", + "Vectorization Model": "向量化模型", + "Keep model in memory": "将模型保存在内存中", + "Hint: Set the URL in the API connection settings.": "提示:在 API 连接设置中设置 URL。", + "The server MUST be started with the --embedding flag to use this feature!": "服务器必须使用 --embedding 标志启动才能使用此功能!", + "NomicAI API Key": "NomicAI API 密钥", + "Query messages": "查询消息", + "Score threshold": "分数阈值", + "Chunk boundary": "区块边界", + "World Info settings": "世界信息设置", + "Enable for World Info": "启用世界信息", + "Enabled for all entries": "对所有条目启用", + "Checked: all entries except ❌ status can be activated.": "勾选:除❌状态外的所有条目均可激活。", + "Unchecked: only entries with ❌ status can be activated.": "未选中:只有具有🔗状态的条目才可以被激活。", + "Max Entries": "最大条目数", + "File vectorization settings": "文件向量化设置", + "Enable for files": "为文件启用", + "Only chunk on custom boundary": "仅按自定义边界分块", + "Translate files into English before processing": "处理之前将文件翻译成英文", + "Message attachments": "消息附件", + "Size threshold (KB)": "大小阈值(KB)", + "Chunk size (chars)": "块大小(字符)", + "Chunk overlap (%)": "块重叠(%)", + "Retrieve chunks": "检索块", + "Data Bank files": "数据库文件", + "Injection Template": "注入模板", + "Injection Position": "注射位置", + "Vectorize All": "全部向量化", + "Purge Vectors": "清除向量", + "Chat vectorization settings": "聊天向量化设置", + "Enabled for chat messages": "已启用聊天消息", + "Retain#": "保持#", + "Insert#": "插入#", + "Vector Summarization": "向量摘要", + "Summarize chat messages for vector generation": "汇总聊天消息以生成向量", + "Warning: This will slow down vector generation drastically, as all messages have to be summarized first.": "警告:这将大大减慢向量生成速度,因为必须先汇总所有消息。", + "Summarize chat messages when sending": "发送时总结聊天消息", + "Warning: This might cause your sent messages to take a bit to process and slow down response time.": "警告:这可能会导致您发送的消息需要一点时间来处理并减慢响应时间。", + "Extras API": "附加 API", + "Only used when Main API or WebLLM Extension is selected.": "仅在 Main API 或 WebLLM 扩展被选中时使用。", + "Old messages are vectorized gradually as you chat. To process all previous messages, click the button below.": "随着您聊天,旧消息会逐渐向量化。\n要处理所有以前的消息,请单击下面的按钮。", + "View Stats": "查看统计数据", + "Manager Users": "管理用户", + "New User": "新用户", + "Status:": "地位:", + "Created:": "创建时间:", + "Display Name:": "显示名称:", + "User Handle:": "用户句柄:", + "Password:": "密码:", + "Confirm Password:": "确认密码:", + "This will create a new subfolder...": "这将在 /data/ 目录中创建一个新的子文件夹,以用户的句柄作为文件夹名称。", + "Note:": "提示:", + "this chat is temporary and will be deleted as soon as you leave it.": "此聊天会话是临时的,会在你离开时被删除。", + "Enter a new display name:": "输入一个新的昵称:", + "Current Password:": "当前密码:", + "New Password:": "新密码:", + "Confirm New Password:": "确认新密码:", + "Import Tags For _begin": "为", + "Import Tags For _end": "导入标签", + "Click remove on any tag to remove it from this import.
      Select one of the import options to finish importing the tags.": "单击任意标签上的“删除”可将其从本次导入中删除。\n选择其中一个导入选项以完成标签的导入。", + "Existing Tags": "现有标签", + "New Tags": "新标签", + "Folder Tags": "文件夹标签", + "The following tags will be auto-imported based on the currently selected folders": "根据当前选定的文件夹将自动导入以下标签", + "Import None": "不导入", + "Import All": "全部导入", + "Import Existing": "导入现有", + "Import": "导入", + "Chat Lorebook": "聊天知识书", + "Chat Lorebook for": "聊天知识书", + "chat_world_template_txt": "选定的世界信息将绑定到此聊天。生成 AI 回复时,\n它将与全球和角色传说书中的条目相结合。", + "chat_rename_1": "输入聊天的新名称:", + "chat_rename_2": "注意!!与其他文件重名会导致错误!!", + "chat_rename_3": "此举会将此聊天与标记为“检查点”的聊天解绑。", + "chat_rename_4": "(不需要在结尾添加 '.JSONL' 后缀)", + "Enter Checkpoint Name:": "输入检查点名称:", + "(Leave empty to auto-generate)": "(留空以自动生成)", + "The currently existing checkpoint will be unlinked and replaced with the new checkpoint, but can still be found in the Chat Management.": "当前检查点将会被解绑并替换为新的检查点,但仍可在聊天管理中找到。", + "Include Body Parameters": "包括主体参数", + "custom_include_body_desc": "聊天完成请求主体中要包含的参数(YAML 对象)\n\n示例:\n- top_k:20\n- repetition_penalty:1.1", + "Exclude Body Parameters": "排除主体参数", + "custom_exclude_body_desc": "要从聊天完成请求主体中排除的参数(YAML 数组)\n\n示例:\n- frequency_penalty\n- presence_penalty", + "Include Request Headers": "包含请求标头", + "custom_include_headers_desc": "聊天完成请求的附加标头(YAML 对象)\n\n示例:\n- CustomHeader:自定义值\n- AnotherHeader:自定义值", + "Functions in this category are for advanced users only. Don't click anything if you're not sure about the consequences.": "此类别中的功能仅供高级用户使用。如果您不确定后果,请不要点击任何内容。", + "THIS IS PERMANENT!": "此操作不可逆!", + "Also delete the chat files": "同时删除聊天文件", + "Are you sure you want to delete this user?": "您确定要删除该用户吗?", + "Deleting:": "删除:", + "Also wipe user data.": "同时清空用户数据", + "Warning:": "警告:", + "This action is irreversible.": "此操作不可逆。", + "Type the user's handle below to confirm:": "在下面输入此用户的用户句柄以确认删除操作:", + "Are you sure you want to duplicate this character?": "你确定要复制这个角色吗?", + "If you just want to start a new chat with the same character...": "如果你只是想要与此角色开启一个新的聊天,只需点击聊天左下方菜单中的“开始新聊天”按钮。", + "Forbid Media Override explanation": "当前角色/群聊成员使用外部媒体的能力。", + "Forbid Media Override subtitle": "媒体:图像、视频、音频。外部:不在本地服务器上托管。", + "forbid_media_global_state_forbidden": "(禁止)", + "forbid_media_global_state_allowed": "(允许)", + "Always forbidden": "始终禁止", + "Always allowed": "始终允许", + "help_format_1": "文本格式化命令:", + "help_format_2": "*文本*", + "help_format_3": "显示为", + "help_format_4": "斜体", + "help_format_5": "**文本**", + "help_format_6": "显示为", + "help_format_7": "大胆的", + "help_format_8": "***文本***", + "help_format_9": "显示为", + "help_format_10": "粗斜体", + "help_format_11": "__文本__", + "help_format_12": "显示为", + "help_format_13": "强调", + "help_format_14": "~~文本~~", + "help_format_15": "显示为", + "help_format_16": "删除线", + "help_format_17": "[文本](网址)", + "help_format_18": "显示为", + "help_format_19": "超级链接", + "help_format_20": "![文本](网址)", + "help_format_21": "显示为图像", + "help_format_22": "```文本```", + "help_format_23": "显示为代码块(反引号之间允许换行)", + "help_format_like_this": "像这样", + "help_format_24": "`文本`", + "help_format_25": "显示为", + "help_format_26": "内联代码", + "help_format_27": "> 文本", + "help_format_28": "显示为块引用(请注意 > 后面的空格)", + "help_format_29": "# 文本", + "help_format_30": "显示为大标题(注意空格)", + "help_format_32": "## 文本", + "help_format_33": "显示为中等标题(注意空格)", + "help_format_35": "### 文本", + "help_format_36": "显示为小标题(注意空格)", + "help_1": "您好!请选择您想要详细了解的帮助主题:", + "help_2": "斜线命令", + "help_or": "或者", + "help_3": "格式化", + "help_4": "热键", + "help_5": "{{宏}}", + "help_6": "还有其他问题吗?", + "help_7": "SillyTavern 官方文档网站", + "help_8": "有更多信息!", + "help_hotkeys_0": "热键/按键绑定", + "help_hotkeys_1": "上", + "help_hotkeys_2": "编辑聊天中的最后一条消息", + "help_hotkeys_3": "Ctrl+上", + "help_hotkeys_4": "编辑聊天中的最后一条用户消息", + "help_hotkeys_5": "左", + "help_hotkeys_6": "向左滑动", + "help_hotkeys_7": "右", + "help_hotkeys_8": "向右滑动(注意:当聊天栏中输入内容时,滑动热键将被禁用)", + "help_hotkeys_9": "Enter", + "help_hotkeys_10": "(选中聊天栏)", + "help_hotkeys_10_1": "向 AI 发送消息", + "help_hotkeys_11": "Ctrl+Enter", + "help_hotkeys_12": "重新生成最后的 AI 响应", + "help_hotkeys_13": "Alt+Enter", + "help_hotkeys_14": "继续上一次AI响应", + "help_hotkeys_15": "Esc", + "help_hotkeys_16": "停止 AI 响应生成、关闭 UI 面板、取消消息编辑", + "help_hotkeys_17": "Ctrl+Shift+上", + "help_hotkeys_18": "滚动到上下文行", + "help_hotkeys_19": "Ctrl+Shift+下", + "help_hotkeys_20": "滚动聊天到底部", + "help_hotkeys_21": "在输入框中生效,由这个图标标记:", + "help_hotkeys_22": "**加粗**", + "help_hotkeys_23": "*斜体*", + "help_hotkeys_24": "__下划线__", + "help_hotkeys_25": "`行内代码`", + "help_hotkeys_26": "~~删除线~~", + "Import Characters": "导入角色", + "Enter the URL of the content to import": "输入要导入的内容的URL", + "Supported sources:": "支持的来源:", + "char_import_1": "Chub 角色(直链或ID)", + "char_import_example": "例子:", + "char_import_2": "Chub 知识书(直链或ID)", + "char_import_3": "JanitorAI 角色(直链或UUID)", + "char_import_4": "Pygmalion.chat 角色(直链或UUID)", + "char_import_5": "AICharacterCards.com 角色(直链或ID)", + "char_import_6": "被允许的PNG直链(请参阅", + "char_import_7": ")", + "char_import_8": "RisuRealm 角色(直链)", + "Supports importing multiple characters.": "支持导入多个角色。", + "Write each URL or ID into a new line.": "将每个 URL 或 ID 写入新行。", + "Enter the Git URL of the extension to install": "输入扩展程序的 Git URL 以安装", + "Disclaimer:": "免责声明:", + "Please be aware that using external extensions can have unintended side effects and may pose security risks. Always make sure you trust the source before importing an extension. We are not responsible for any damage caused by third-party extensions.": "使用外部的扩展程序可能存在意料外的副作用和安全隐患。在导入扩展程序前,请一定确认其来源可信。我们不为第三方扩展程序造成的任何损失负责。", + "Prompt Itemization": "提示词拆分", + "Show Raw Prompt": "显示原始提示词", + "Copy Prompt": "复制提示词", + "Show Prompt Differences": "显示提示词差异", + "API/Model:": "API/模型:", + "Preset:": "预设:", + "Tokenizer:": "分词器:", + "Only the white numbers really matter. All numbers are estimates. Grey color items may not have been included in the context due to certain prompt format settings.": "只有白色的数字作数。所有数字均为估算。\n 灰色的数字可能因特定的提示词处理规则而被排除在外。", + "System Info:": "系统信息:", + "Prompt Tokens:": "提示词Token:", + "World Info:": "世界书:", + "Chat History:": "聊天记录:", + "Extensions:": "扩展程序:", + "Bias:": "Bias:", + "Total Tokens in Prompt:": "提示词的总Token数量:", + "Max Context": "最大上下文:", + "(Context Size - Response Length)": "(上下文长度 - 回复长度)", + "System-wide Replacement Macros (in order of evaluation):": "系统范围的替换宏(按评估顺序):", + "help_macros_1": "仅适用于斜线命令批处理。替换为上一个命令的返回结果。", + "help_macros_2": "仅插入一个换行符。", + "help_macros_3": "修剪此宏周围的换行符。", + "help_macros_4": "没有操作,只是一个空字符串。", + "help_macros_5": "API 设置中定义的全局提示。仅在高级定义提示覆盖中有效。", + "help_macros_6": "用户输入", + "help_macros_7": "角色的主提示覆盖", + "help_macros_8": "角色越狱提示覆盖", + "help_macros_9": "角色描述", + "help_macros_10": "人物性格", + "help_macros_11": "角色场景", + "help_macros_12": "您当前的角色描述", + "help_macros_13": "角色对话示例", + "help_macros_14": "未格式化的对话示例", + "(only for Story String)": "(仅适用于故事字符串)", + "help_macros_summary": "“Summarize”扩展生成的最新聊天摘要(如果有)。", + "help_macros_15": "您当前的用户角色名称", + "help_macros_16": "角色的名字", + "help_macros_17": "角色的版本号", + "help_macros_18": "以逗号分隔的群成员名称列表或单人聊天中的角色名称。别名:{{charIfNotGroup}}", + "help_groupNotMuted": "与 {{group}} 相同,但排除被禁言的成员", + "help_macros_19": "当前选定的 API 的文本生成模型名称。", + "Can be inaccurate!": "不一定准确!", + "help_macros_20": "最新聊天消息的文本。", + "help_macros_lastUser": "最后的用户聊天消息文本。", + "help_macros_lastChar": "最后的角色聊天消息文本。", + "help_macros_21": "最新聊天消息的索引号。对于斜线命令批处理很有用。", + "help_macros_22": "上下文中包含的第一条消息的 ID。要求在当前会话中至少运行一次生成。", + "help_macros_firstDisplayedMessageId": "第一条载入可见聊天的消息的ID", + "help_macros_23": "最后一条聊天消息中当前滑动的 ID(以 1 为基数)。如果最后一条消息是用户或提示隐藏的,则为空字符串。", + "help_macros_24": "最后一条聊天消息中的滑动次数。如果最后一条消息是用户隐藏或提示隐藏的,则为空字符串。", + "help_macros_reverse": "反转宏的内容。", + "help_macros_25": "您可以在此处留言,宏将被替换为空白内容。AI 看不到。", + "help_macros_26": "当前时间", + "help_macros_27": "当前日期", + "help_macros_28": "当前工作日", + "help_macros_29": "当前 ISO 时间(24 小时制)", + "help_macros_30": "当前 ISO 日期 (YYYY-MM-DD)", + "help_macros_31": "指定格式的当前日期/时间,例如德国日期/时间:", + "help_macros_32": "指定 UTC 时区偏移量的当前时间,例如 UTC-4 或 UTC+2", + "help_macros_33": "time1 和 time2 之间的时间差。接受时间和日期宏。(例如:{{timeDiff::{{isodate}} {{time}}::2024/5/11 12:30:00}})", + "help_macros_34": "距离上次用户消息发送的时间", + "help_macros_35": "为 AI 设置行为偏差,直到下一个用户输入。文本周围的引号很重要。", + "help_macros_36": "掷骰子。(例如:", + "space_ will roll a 6-sided dice and return a number between 1 and 6)": "将掷一个 6 面骰子并返回 1 到 6 之间的数字)", + "help_macros_37": "从列表中返回一个随机项目。(例如:", + "space_ will return 1 of the 4 numbers at random. Works with text lists too.": "将随机返回 4 个数字中的 1 个。也适用于文本列表。", + "help_macros_38": "随机的替代语法允许在列表项中使用逗号。", + "help_macros_39": "从列表中随机挑选一项。工作原理与 {{random}} 相同,具有相同的语法选项,但一旦挑选,挑选将一直持续到本次聊天,不会在连续消息和提示处理中重新滚动。", + "help_macros_40": "如果使用文本生成 WebUI 后端,则动态地将引号中的文本添加到禁用单词序列中。对其他后端不执行任何操作。可以在任何地方使用(角色描述、WI、AN 等)。文本周围的引号很重要。", + "help_macros_isMobile": "当为移动端时为\"true\",反之为\"false\"", + "Instruct Mode and Context Template Macros:": "指导模式和上下文模板宏:", + "(enabled in the Advanced Formatting settings)": "(在高级格式设置中启用)", + "help_macros_41": "令牌中允许的最大提示长度 = (上下文长度 - 响应长度)", + "help_macros_42": "上下文模板示例对话分隔符", + "help_macros_43": "上下文模板聊天开始行", + "help_macros_44": "主系统提示(如果选择,则覆盖字符提示,或 instructSystemPrompt)", + "help_macros_45": "指示系统提示", + "help_macros_46": "指示系统提示前缀序列", + "help_macros_47": "指示系统提示后缀序列", + "help_macros_48": "指示用户前缀序列", + "help_macros_49": "指示用户后缀序列", + "help_macros_50": "指导助理前缀序列", + "help_macros_51": "指导助理后缀序列", + "help_macros_52": "指导助理第一个输出序列", + "help_macros_53": "指导助手最后输出序列", + "help_macros_54": "指示系统消息前缀序列", + "help_macros_55": "指示系统消息后缀序列", + "help_macros_56": "指示系统指令前缀", + "help_macros_57": "指示第一个用户消息填充器", + "help_macros_58": "指示停止顺序", + "help_macros_first_user": "指示用户第一个输入序列", + "help_macros_last_user": "指示用户最后输入序列", + "Chat variables Macros:": "聊天变量宏:", + "Local variables = unique to the current chat": "局部变量 = 当前聊天所独有", + "Global variables = works in any chat for any character": "全局变量 = 适用于任何角色的任何聊天", + "Scoped variables = works in STscript": "范围变量 = 在 STscript 中有效", + "help_macros_59": "替换为局部变量“name”的值", + "help_macros_60": "替换为空字符串,将局部变量“name”设置为“value”", + "help_macros_61": "替换为空字符串,将“increment”的数值添加到局部变量“name”", + "help_macros_62": "替换为变量“name”的值增加 1 的结果", + "help_macros_63": "替换为变量“name”的值减 1 的结果", + "help_macros_64": "替换为全局变量“name”的值", + "help_macros_65": "替换为空字符串,将全局变量“name”设置为“value”", + "help_macros_66": "替换为空字符串,将“increment”的数值添加到全局变量“name”", + "help_macros_67": "替换为全局变量“name”的值增加 1 的结果", + "help_macros_68": "替换为全局变量“name”的值减 1 的结果", + "help_macros_69": "替换为范围变量“name”的值", + "help_macros_70": "用范围变量“name”的索引处的项目值(对于数组/列表或对象/字典)替换", + "Choose what to export": "选择您想要导出什么:", + "{{name}}": "{{name}}", + "Choose what to import": "选择您想要导入什么:", + "If necessary, you can later restore this chat file from the /backups folder": "若需要,您可稍后在 /backups 文件夹中恢复此聊天文件。", + "Also delete the current chat file": "同时删除当前聊天文件", + "Persona Lorebook for": "Persona Lorebook for", + "persona_world_template_txt": "A selected World Info will be bound to this persona. When generating an AI reply,\n it will be combined with the entries from global, character and chat lorebooks.", + "Export for character": "导出角色", + "Export prompts for this character, including their order.": "导出此角色的提示词,包括其顺序。", + "Export all": "全部导出", + "Export all your prompts to a file": "将所有提示词导出到文件", + "Insert prompt": "插入提示词", + "Import a prompt list": "导入提示词列表", + "Export this prompt list": "导出此提示词列表", + "Reset current character": "重置当前角色", + "New prompt": "新提示词", + "Prompts": "提示词", + "Total Tokens:": "总词符数:", + "prompt_manager_tokens": "词符", + "Are you sure you want to connect to the following proxy URL?": "你确定要连接到下面的代理URL吗?", + "Encountered an error while processing your request.": "处理请求时遇到了问题。", + "Check you have credits available on your": "检查您的 ", + "OpenAI account quora_error": "OpenAI 账号余额是否充足", + "dot quota_error": "。", + "If you have sufficient credits, please try again later.": "若您有足够的余额,请稍后再试。", + "Are you sure you want to reset your settings to factory defaults?": "您确定要将您的设置重置为出厂默认设置吗?", + "Don't forget to save a snapshot of your settings before proceeding.": "在继续之前,不要忘记保存您的设置快照。", + "Enter your password below to confirm:": "输入您的密码以确认:", + "Chat Scenario Override": "聊天场景覆盖", + "Remove": "移除", + "Unique to this chat.": "仅对此聊天生效。", + "All group members will use the following scenario text instead of what is specified in their character cards.": "All group members will use the following scenario text instead of what is specified in their character cards.", + "The following scenario text will be used instead of the value set in the character card.": "The following scenario text will be used instead of the value set in the character card.", + "Checkpoints inherit the scenario override from their parent, and can be changed individually after that.": "Checkpoints inherit the scenario override from their parent, and can be changed individually after that.", + "Settings Snapshots": "设置快照", + "Record a snapshot of your current settings.": "记录当前设置的快照。", + "Make a Snapshot": "制作快照", + "Restore this snapshot": "恢复此快照", + "Download Model": "下载模型", + "Downloader Options": "下载器选项", + "Extra parameters for downloading/HuggingFace API": "下载/HuggingFace API 的额外参数。如果不确定,请将其留空。", + "Revision": "修订", + "Folder Name": "输出文件夹名称", + "HF Token": "HF代币", + "Include Patterns": "包含模式", + "Glob patterns of files to include in the download.": "要包含在下载中的文件的全局模式。每个模式用换行符分隔。", + "Exclude Patterns": "排除模式", + "Glob patterns of files to exclude in the download.": "下载中要排除的文件的 Glob 模式。每个模式用换行符分隔。", + "Tag Management": "标签管理", + "Save your tags to a file": "将标签保存为文件", + "Restore tags from a file": "从文件中恢复标签", + "Create a new tag": "新建一个标签", + "Drag handle to reorder. Click name to rename. Click color to change display.": "拖拽左侧三条横线以排序,点击名字以重命名,点击调色盘以切换颜色。", + "Click on the folder icon to use this tag as a folder.": "点击文件夹图标来将此标签作为一个文件夹。", + "Use alphabetical sorting": "按字母顺序排列", + "tags_sorting_desc": "启用后,标签在创建或重命名时会自动按字母顺序排序。\n禁用后,新标签会追加到末尾。\n\n如果通过拖动手动重新排列标签,则自动排序将被禁用。", + "Are you sure you want to delete the theme?": "你确定要删除这个主题吗?", + "Hi,": "嗨,", + "To enable multi-account features, restart the SillyTavern server with": "要启用多帐户功能,请使用以下命令重新启动 SillyTavern 服务器", + "set to true in the config.yaml file.": "在 config.yaml 文件中设置为 true。", + "Account Info": "帐户信息", + "To change your user avatar, use the buttons below or select a default persona in the Persona Management menu.": "要更改您的用户头像,请使用下面的按钮或在角色管理菜单中选择一个默认角色。", + "Set your custom avatar.": "设置您的自定义头像。", + "Remove your custom avatar.": "删除您的自定义头像。", + "Handle:": "账号:", + "This account is password protected.": "此帐户受密码保护。", + "This account is not password protected.": "此帐户没有密码保护。", + "Account Actions": "帐户操作", + "Change Password": "修改密码", + "Manage your settings snapshots.": "管理您的设置快照。", + "Download a complete backup of your user data.": "下载您所有的用户数据的完整备份。", + "Download Backup": "下载备份", + "Danger Zone": "危险操作", + "Reset your settings to factory defaults.": "将您的设置重置为默认值。", + "Reset Settings": "重置设置", + "Wipe all user data and reset your account to factory settings.": "删除所有用户数据并将您的账号重置为默认设置。", + "Reset Everything": "重置一切", + "This will delete all your settings and data. There will be no undo button. Make sure you have a backup before proceeding.": "This will delete all your settings and data. There will be no undo button.\n Make sure you have a backup before proceeding.", + "Account reset code has been posted to the server console.": "Account reset code has been posted to the server console.", + "Reset Code:": "重置代码:", + "Want to update?": "获取最新版本", + "How to start chatting?": "如何快速开始聊天?", + "Click _space": "点击", + "and connect to an": "并连接一个", + "and pick a character.": "并选择一个角色。", + "You can add more": "你可以点击右侧添加更多", + "or_welcome": "或从其他网站中", + "from other websites": "。", + "Go to the": "您可前往此处", + "menu within": "(在这里:", + "to install additional features.": ")以安装拓展功能。", + "Confused or lost?": "遇到了不懂的内容?", + "click these icons!": "点击左侧这种图标!", + "in the chat bar": "至聊天框", + "SillyTavern Documentation Site": "访问 SillyTavern 帮助文档", + "Still have questions?": "仍有疑问?", + "Join the SillyTavern Discord": "加入 SillyTavern 的 Discord群组", + "Post a GitHub issue": "在 GitHub 发布问题", + "Contact the developers": "联系开发者", + "If you're connected to an API, try asking me something!": "若您已经配置好API,尝试发送些什么吧!", + "Title/Memo": "标题(备忘)", + "Strategy": "触发策略", + "Position": "插入位置", + "Trigger %": "触发概率%" +} diff --git a/jiuguan2025cc/public/locales/zh-tw.json b/jiuguan2025cc/public/locales/zh-tw.json new file mode 100644 index 0000000000000000000000000000000000000000..af9f1071233a50e643f945a645f7cfa9c63a4a83 --- /dev/null +++ b/jiuguan2025cc/public/locales/zh-tw.json @@ -0,0 +1,2627 @@ +{ + "Favorite": "我的最愛", + "Tag": "標籤", + "Duplicate": "複製", + "Persona": "使用者角色", + "Delete": "刪除", + "AI Response Configuration": "AI 回應設定", + "AI Configuration panel will stay open": "上鎖 = AI 設定面板將保持開啟", + "clickslidertips": "點選滑桿旁的數字以手動輸入。", + "MAD LAB MODE ON": "瘋狂實驗室模式", + "Documentation on sampling parameters": "取樣參數的說明文件。", + "kobldpresets": "Kobold 預設設定檔", + "guikoboldaisettings": "GUI KoboldAI 設定", + "Update current preset": "更新預設設定檔", + "Save preset as": "另存新預設設定檔", + "Import preset": "匯入預設設定檔", + "Export preset": "匯出預設設定檔", + "Restore current preset": "還原目前預設設定檔", + "Delete the preset": "刪除預設設定檔", + "novelaipresets": "NovelAI 預設設定檔", + "Default": "預設", + "openaipresets": "OpenAI 預設設定檔", + "Text Completion presets": "文字補全預設設定檔", + "AI Module": "AI 模組", + "Changes the style of the generated text.": "變更生成文字的樣式。", + "No Module": "無模組", + "Instruct": "指示", + "Prose Augmenter": "散文增強器", + "Text Adventure": "文字冒險", + "response legth(tokens)": "回應長度(符元數)", + "Streaming": "即時串流", + "Streaming_desc": "逐字顯示生成中的回應內容。關閉時,回應將在生成完成後一次性顯示。", + "context size(tokens)": "上下文長度(符元數)", + "unlocked": "解鎖", + "Only enable this if your model supports context sizes greater than 8192 tokens": "僅在您的模型支援超過 8192 個符元的上下文長度時啟用此功能", + "Max prompt cost:": "最大提示詞費用:", + "Display the response bit by bit as it is generated.": "逐字顯示生成中的回應內容。", + "When this is off, responses will be displayed all at once when they are complete.": "關閉時,回應將在生成完成後一次全部顯示。", + "Temperature": "溫度", + "rep.pen": "重複懲罰", + "Rep. Pen. Range.": "重複懲罰範圍", + "Rep. Pen. Slope": "重複懲罰斜率", + "Rep. Pen. Freq.": "重複懲罰頻率", + "Rep. Pen. Presence": "重複懲罰存在", + "TFS": "TFS", + "Phrase Repetition Penalty": "片語重複懲罰", + "Off": "關閉", + "Very light": "非常輕", + "Light": "輕", + "Medium": "中等", + "Aggressive": "積極", + "Very aggressive": "非常積極", + "Unlocked Context Size": "解鎖上下文長度", + "Unrestricted maximum value for the context slider": "不限制上下文長度的最大值", + "Context Size (tokens)": "上下文長度(符元數)", + "Max Response Length (tokens)": "最大回應長度(符元數)", + "Multiple swipes per generation": "每次生成多次滑動", + "Enable OpenAI completion streaming": "啟用 OpenAI 補全串流", + "Frequency Penalty": "頻率懲罰", + "Presence Penalty": "存在懲罰", + "Count Penalty": "計數懲罰", + "Top K": "Top K", + "Top P": "Top P", + "Repetition Penalty": "重複懲罰", + "Min P": "Min P", + "Top A": "Top A", + "Quick Prompts Edit": "快速提示詞編輯", + "Main": "主要提示詞", + "NSFW": "NSFW", + "Jailbreak": "越獄", + "Utility Prompts": "實用提示詞", + "Impersonation prompt": "AI 扮演提示詞", + "Restore default prompt": "還原預設提示詞", + "Prompt that is used for Impersonation function": "用於「AI 扮演使用者」功能的提示詞", + "World Info Format Template": "世界資訊格式", + "Restore default format": "還原預設格式", + "Wraps activated World Info entries before inserting into the prompt.": "在插入提示詞前包裝已啟用的世界資訊條目。", + "scenario_format_template_part_1": "使用", + "scenario_format_template_part_2": "來標示要插入內容的位置。", + "Scenario Format Template": "場景格式", + "Personality Format Template": "個性格式", + "Group Nudge Prompt Template": "群組聊天格式微調", + "Sent at the end of the group chat history to force reply from a specific character.": "在群組聊天歷史結束時傳送以強制特定角色回覆", + "New Chat": "新聊天", + "Restore new chat prompt": "還原新聊天的提示詞", + "Set at the beginning of the chat history to indicate that a new chat is about to start.": "設定在聊天歷史的開頭以表明即將開始新的聊天", + "New Group Chat": "新群組聊天", + "Restore new group chat prompt": "還原預設群組聊天提示詞", + "Set at the beginning of the chat history to indicate that a new group chat is about to start.": "設定在聊天歷史的開頭以表明即將開始新的群組聊天", + "New Example Chat": "新範例聊天", + "Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.": "設定在對話範例的開頭以表明即將開始新的範例聊天", + "Continue nudge": "繼續輔助微調", + "Set at the end of the chat history when the continue button is pressed.": "按下「繼續」按鈕時,插入於聊天歷史的結尾", + "Replace empty message": "取代空白訊息", + "Send this text instead of nothing when the text box is empty.": "當文字框為空時,傳送此文字以取代空白。", + "Seed": "種子", + "Set to get deterministic results. Use -1 for random seed.": "設定數值以取得可重現的結果。使用 -1 作為隨機種子", + "Temperature controls the randomness in token selection": "溫度(Temperature)控制符元選擇的隨機性。\n- 低溫(<1.0):產生更可預測且具邏輯性的文字,優先選擇機率較高的符元。\n- 高溫(>1.0):提升創造性與輸出的多樣性,更常選擇機率較低的符元。\n將值設為 1.0 可使用原始機率。", + "Top_K_desc": "Top K 設定可以選擇的最高符元數量。\n例如,Top K 為 20,這意味著只保留排名前 20 的符元(無論它們的機率是多樣還是有限的)。\n設定為 0 以停用。", + "Top_P_desc": "Top P(又名核心取樣) 會將所有頂級符元加總,直到達到目標百分比。\n例如,如果前兩個符元都是 25%,而 Top P 設為 0.5,那麼只有前兩個符元會被考慮。\n設定為 1.0 以停用。", + "Typical P": "Typical P", + "Typical_P_desc": "Typical P 取樣根據符元偏離集合平均熵的程度進行優先排序。\n它會保留累積機率接近預設閾值 (例如 0.5) 的符元,強調那些具有平均資訊量的符元。\n設定為 1.0 以停用。", + "Min_P_desc": "Min P 設定基本最小機率。\n這個值會根據最高符元的機率進行調整。例如,如果最高符元機率為 80%,而 Min P 設為 0.1,那麼只有機率高於 8% 的符元會被考慮。\n設定為 0 以停用。", + "Top_A_desc": "Top A 根據最高符元機率的平方設定符元選擇的門檻。\n例如,如果 Top A 值為 0.2,而最高符元機率為 50%,那麼低於 5%(0.2 * 0.5^2) 的符元機率就會被排除。\n設定為 0 以停用。", + "Tail_Free_Sampling_desc": "無尾取樣 (Tail-Free Sampling, TFS) 會透過分析符元機率的變化率 (使用導數) 來尋找分佈中的低機率符元尾部。\n它會根據標準化的二階導數,保留直到某個閾值 (例如 0.3) 的符元。\n數值越接近 0,表示會棄去越多符元。設定為 1.0 以停用。", + "rep.pen range": "重複懲罰範圍", + "Mirostat": "Mirostat", + "Mode": "模式", + "Mirostat_Mode_desc": "0 表示完全停用 Mirostat。1 表示使用 Mirostat 1.0 版本,2 表示使用 Mirostat 2.0 版本。", + "Tau": "Tau", + "Mirostat_Tau_desc": "這個設定控制了 Mirostat 輸出的可變性。", + "Eta": "Eta", + "Mirostat_Eta_desc": "這個設定控制 Mirostat 的學習率。", + "Ban EOS Token": "禁止 EOS 符元", + "Ban_EOS_Token_desc": "對於 KoboldCpp(以及可能也適用於 KoboldAI 的其他符元),禁止使用序列結束 (End-of-Sequence, EOS) 符元。這個設定對於故事創作很有幫助,但不應該在聊天和指令模式中使用。", + "GBNF Grammar": "GBNF 語法", + "Type in the desired custom grammar": "輸入所需的自定義語法", + "Samplers Order": "取樣器順序", + "Samplers will be applied in a top-down order. Use with caution.": "取樣器將按從上到下的順序應用。請小心使用。", + "Tail Free Sampling": "無尾取樣", + "Load koboldcpp order": "載入 koboldcpp 順序", + "Preamble": "前言", + "Use style tags to modify the writing style of the output.": "使用樣式標籤修改輸出的寫作樣式。", + "Banned Tokens": "禁止的符元", + "Sequences you don't want to appear in the output. One per line.": "您不希望在輸出中出現的序列。每行一個,使用文字或符元 ID。", + "Logit Bias": "Logit 偏差", + "Add": "新增", + "Helps to ban or reenforce the usage of certain words": "有助於禁止或強化某些符元的使用", + "CFG Scale": "CFG 縮放比例", + "Negative Prompt": "負面提示詞", + "Add text here that would make the AI generate things you don't want in your outputs.": "在此新增文字,以防止 AI 在輸出中生成您不希望出現的內容。", + "Used if CFG Scale is unset globally, per chat or character": "若 CFG 縮放比例未被全域設定,它將作用於所有聊天或角色", + "Mirostat Tau": "Tau", + "Mirostat LR": "Mirostat 學習率", + "Min Length": "最小長度", + "Top K Sampling": "Top K 取樣", + "Nucleus Sampling": "核心取樣", + "Top A Sampling": "Top A 取樣", + "CFG": "CFG", + "Neutralize Samplers": "中和取樣器", + "Set all samplers to their neutral/disabled state.": "將所有取樣器設定為中性/停用狀態。", + "Sampler Select": "選擇取樣器", + "Customize displayed samplers or add custom samplers.": "自訂顯示的取樣器或新增自訂取樣器。", + "Epsilon Cutoff": "Epsilon 截斷", + "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "Epsilon 截斷設定排除符元的機率下限", + "Eta Cutoff": "Eta 截斷", + "Eta_Cutoff_desc": "Eta 截斷是特殊 Eta 取樣技術的主要參數。\n單位為 1e-4;合理值為 3。\n設為 0 以停用。\n詳細資訊請參見 Hewitt 等人於 2022 年撰寫的論文《Truncation Sampling as Language Model Desmoothing》。", + "rep.pen decay": "重複懲罰衰減", + "Encoder Rep. Pen.": "編碼器重複懲罰", + "No Repeat Ngram Size": "無重複 Ngram 大小", + "Skew": "Skew", + "Max Tokens Second": "最大符元/秒", + "Smooth Sampling": "平滑取樣", + "Smooth_Sampling_desc": "允許您使用二次/三次變換來調整分佈。較低的平滑因子值將更具創造性,通常在 0.2-0.3 之間是最佳點(假設曲線=1)。較高的平滑曲線值會使曲線更陡峭,這將更加激烈地懲罰低機率選擇。1.0 的曲線值相當於僅使用平滑因子。", + "Smoothing Factor": "平滑因子", + "Smoothing Curve": "平滑曲線", + "DRY_Repetition_Penalty_desc": "DRY 會懲罰那些將輸入的結尾擴充為已在先前輸入中出現過序列的符元。將乘法器設為 0 以停用。", + "DRY Repetition Penalty": "DRY 重複懲罰", + "DRY_Multiplier_desc": "將值設為大於 0 來啟用 DRY。控制對最短受懲罰序列的懲罰幅度。", + "Multiplier": "乘法器", + "DRY_Base_desc": "控制隨著序列長度增加,懲罰增加的速度。", + "Base": "基準值", + "DRY_Allowed_Length_desc": "可以重複而不受懲罰的最長序列長度。", + "Allowed Length": "允許長度", + "Penalty Range": "懲罰範圍", + "DRY_Sequence_Breakers_desc": "序列停止繼續配對的符元,使用引號包裹字串並以逗號分隔清單。", + "Sequence Breakers": "序列中斷器", + "JSON-serialized array of strings.": "序列化 JSON 的字串陣列。", + "Dynamic Temperature": "動態溫度", + "Scale Temperature dynamically per token, based on the variation of probabilities": "根據機率變化,動態調整每個符元的溫度", + "Minimum Temp": "最低溫度", + "Maximum Temp": "最高溫度", + "Exponent": "指數", + "Mirostat (mode=1 is only for llama.cpp)": "Mirostat(mode=1 僅適用於 llama.cpp)", + "Mirostat_desc": "Mirostat 是輸出困惑度的恆溫器。\nMirostat 會將輸出的困惑度與輸入的困惑度相配對,\n從而避免了重複陷阱(在這個陷阱中,隨著自回歸推理產生字串,輸出的困惑度趨於零)和混亂陷阱(困惑度發散)。\n有關詳細資訊,請參閱 Basu 等人於 2020 年發表的論文《A Neural Text Decoding Algorithm that Directly Controls Perplexity》。\n模式選擇 Mirostat 版本。0=停用,1=Mirostat 1.0(僅限 llama.cpp),2=Mirostat 2.0。", + "Mirostat Mode": "Mode", + "Variability parameter for Mirostat outputs": "Mirostat 輸出的變異性參數", + "Mirostat Eta": "Eta", + "Learning rate of Mirostat": "Mirostat 的學習率", + "Beam search": "Beam search(波束搜尋)", + "Helpful tip coming soon.": "更多有用提示訊息即將推出。", + "Number of Beams": "波束數量", + "Length Penalty": "長度懲罰", + "Early Stopping": "提前停止", + "Contrastive search": "對比搜尋", + "Contrastive_search_txt": "一種取樣器,透過利用大多數 LLM 的表示空間的等向性,鼓勵多樣性的同時保持一致性。詳細資訊請參閱 Su 等人於 2022 年發表的論文《A Contrastive Framework for Neural Text Generation》。", + "Penalty Alpha": "懲罰 Alpha", + "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "對比搜尋正則化項的強度。設定為 0 以停用 CS", + "Do Sample": "進行取樣", + "Add BOS Token": "新增 BOS 符元", + "Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative": "在提示詞的開頭新增 bos_token。停用此功能可以使回應更具創造性", + "Ban the eos_token. This forces the model to never end the generation prematurely": "禁止 eos_token。這迫使模型不會提前結束生成", + "Ignore EOS Token": "忽略 EOS 符元", + "Ignore the EOS Token even if it generates.": "即使生成也忽略 EOS 符元", + "Skip Special Tokens": "跳過特殊符元", + "Temperature Last": "最後的溫度", + "Temperature_Last_desc": "使用最後應用溫度取樣器。這幾乎總是明智的做法。\n啟用時:首先取樣一組合理的符元,然後應用溫度來調整它們的相對機率(技術上講,是 logits)。\n停用時:首先應用溫度調整所有符元的相對機率,然後從中取樣合理的符元。\n停用「最後應用溫度取樣」會增加分佈尾部的機率,這傾向於放大獲得不連貫回應的機會。", + "Speculative Ngram": "推測性 Ngram", + "Use a different speculative decoding method without a draft model": "使用不含草稿模型的不同推測性解碼方法。", + "Spaces Between Special Tokens": "特殊符元之間的空格", + "LLaMA / Mistral / Yi models only": "僅限 LLaMA/Mistral/Yi 模型", + "Example: some text [42, 69, 1337]": "範例:\n一些文字 [42, 69, 1337]", + "Classifier Free Guidance. More helpful tip coming soon": "無分類器導引。更多有用提示訊息即將推出", + "Scale": "比例", + "JSON Schema": "JSON 結構", + "Type in the desired JSON schema": "輸入所需的 JSON 結構", + "Grammar String": "語法字串", + "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF 或 EBNF,取決於所使用的後端。如果您使用此功能,應該知道是哪一種", + "Top P & Min P": "Top P 和 Min P", + "Load default order": "載入預設順序", + "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "僅適用於 llama.cpp。決定取樣器的順序。如果 Mirostat 模式不為 0,則忽略取樣器順序。", + "Sampler Priority": "取樣器優先順序", + "Ooba only. Determines the order of samplers.": "僅適用於 Ooba。決定取樣器的順序。", + "Character Names Behavior": "角色名稱行為", + "Helps the model to associate messages with characters.": "幫助模型將訊息與角色關聯起來。", + "None": "無", + "character_names_default": "除了團體和過去的使用者角色外。否則,請確保在提示中提供名字。", + "Don't add character names.": "不要新增角色名稱", + "Completion": "補全", + "character_names_completion": "字元限制:僅限拉丁字母數字和底線。不適用於所有來源,特別是:Claude、MistralAI、Google。", + "Add character names to completion objects.": "新增角色名稱來補充物件", + "Message Content": "訊息內容", + "Prepend character names to message contents.": "在訊息內容前新增角色名稱", + "Continue Postfix": "繼續後綴", + "The next chunk of the continued message will be appended using this as a separator.": "繼續訊息的下一塊將使用此作為分隔符號附加", + "Space": "空格", + "Newline": "換行", + "Double Newline": "雙換行", + "Wrap user messages in quotes before sending": "傳送前將使用者訊息用引號括起來", + "Wrap in Quotes": "用引號包裹", + "Wrap entire user message in quotes before sending.": "在傳送之前將整個使用者訊息用引號包裹。", + "Leave off if you use quotes manually for speech.": "如果您手動使用引號進行發言,請關閉。", + "Continue prefill": "繼續預先填充", + "Continue sends the last message as assistant role instead of system message with instruction.": "繼續將最後的訊息作為助理角色傳送,而不是帶有指令的系統訊息。", + "Squash system messages": "合併系統訊息", + "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "將連續的系統訊息合併為一個(不包括對話範例)。可能會提高某些模型的一致性。", + "Enable function calling": "啟用函式呼叫", + "Send inline images": "傳送內嵌圖片", + "image_inlining_hint_1": "如果模型支援(例如:GPT-4V、Claude 3 或 Llava 13B),則在提示詞中傳送圖片。\n使用任何訊息上的", + "image_inlining_hint_2": "動作或", + "image_inlining_hint_3": "選單來附加圖片文件到聊天中。", + "Inline Image Quality": "內嵌圖片品質", + "openai_inline_image_quality_auto": "自動", + "openai_inline_image_quality_low": "低", + "openai_inline_image_quality_high": "高", + "Use AI21 Tokenizer": "使用 AI21 分詞器", + "Use the appropriate tokenizer for Jurassic models, which is more efficient than GPT's.": "對於 Jurassic 模型使用適當的分詞器,比 GPT 的更高效", + "Use Google Tokenizer": "使用 Google 分詞器", + "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "透過 Google 模型的 API 使用適當的分詞器。提示詞處理速度較慢,但提供更準確的符元計數。", + "Use system prompt": "使用系統提示詞", + "(Gemini 1.5 Pro/Flash only)": "(僅限於 Gemini 1.5 Pro/Flash)", + "Merges_all_system_messages_desc_1": "合併所有系統訊息,直到第一則非系統角色的訊息,並透過 google 的", + "Merges_all_system_messages_desc_2": "欄位傳送,而不是與其餘提示詞內容一起傳送。", + "Assistant Prefill": "預先填充助理訊息", + "Start Claude's answer with...": "開始 Claude 的回答⋯", + "Assistant Impersonation Prefill": "助理扮演時的預先填充", + "Use system prompt (Claude 2.1+ only)": "使用系統提示詞(僅限 Claude 2.1+)", + "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "為支援的模型傳送系統提示詞。停用時,使用者訊息將新增到提示詞的開頭。", + "User first message": "使用者第一則訊息", + "Restore User first message": "還原使用者第一則訊息", + "Human message": "人類訊息、指令等。\n當空白時不加入任何內容,也就是需要一個帶有使用者角色的新提示詞。", + "New preset": "新預設設定檔", + "Delete preset": "刪除預設設定檔", + "View / Edit bias preset": "檢視/編輯 Bias 預設設定檔", + "Add bias entry": "新增 Bias 條目", + "Most tokens have a leading space.": "大多數符元有前導空格", + "API Connections": "API 連線", + "Text Completion": "文字補全", + "Chat Completion": "聊天補全", + "NovelAI": "NovelAI", + "AI Horde": "AI Horde", + "KoboldAI": "KoboldAI", + "Avoid sending sensitive information to the Horde.": "避免傳送敏感資訊到 Horde。", + "Review the Privacy statement": "檢視隱私聲明", + "Register a Horde account for faster queue times": "註冊 Horde 帳號以縮短等待時間", + "Learn how to contribute your idle GPU cycles to the Horde": "了解如何將閒置的 GPU 週期貢獻給 Horde", + "Adjust context size to worker capabilities": "根據 worker 的能力調整上下文長度", + "Adjust response length to worker capabilities": "根據 worker 的能力調整回應長度", + "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "僅將已批准的 worker 排隊,可以幫助處理不良回應。可能會延長回應時間。", + "Trusted workers only": "僅限受信任的 worker", + "API key": "API 金鑰", + "Get it here:": "在這裡取得:", + "Register": "註冊", + "View my Kudos": "瀏覽我的讚賞記錄", + "Enter": "輸入", + "to use anonymous mode.": "以使用匿名模式。", + "Clear your API key": "清除您的 API 金鑰", + "For privacy reasons, your API key will be hidden after you reload the page.": "基於安全性考量,重新載入頁面後,您的 API 金鑰將被隱藏。", + "Models": "模型", + "Refresh models": "重新整理模型", + "-- Horde models not loaded --": "-- Horde 模型未載入 --", + "Not connected...": "尚未連線⋯", + "API url": "API URL", + "Example: http://127.0.0.1:5000/api ": "範例:http://127.0.0.1:5000/api ", + "Connect": "連線", + "Cancel": "關閉", + "Novel API key": "NovelAI API 金鑰", + "Get your NovelAI API Key": "取得您的 NovelAI API 金鑰", + "Enter it in the box below": "請在下面的框中輸入", + "Novel AI Model": "NovelAI 模型", + "No connection...": "沒有連線⋯", + "API Type": "API 類型", + "Default (completions compatible)": "預設(相容補全)", + "TogetherAI API Key": "TogetherAI API 金鑰", + "TogetherAI Model": "TogetherAI 模型", + "-- Connect to the API --": "-- 連線到 API --", + "OpenRouter API Key": "OpenRouter API 金鑰", + "Click Authorize below or get the key from": "點選下方的授權或從以下取得金鑰", + "View Remaining Credits": "檢視剩餘點數", + "OpenRouter Model": "OpenRouter 模型", + "Model Providers": "模型供應商", + "InfermaticAI API Key": "InfermaticAI API 金鑰", + "InfermaticAI Model": "InfermaticAI 模型", + "DreamGen API key": "DreamGen API 金鑰", + "DreamGen Model": "DreamGen 模型", + "Mancer API key": "Mancer API 金鑰", + "Mancer Model": "Mancer 模型", + "Make sure you run it with": "確保您使用以下方式執行它", + "flag": "旗標", + "API key (optional)": "API 金鑰(可選)", + "Server url": "伺服器 URL", + "Example: 127.0.0.1:5000": "範例:127.0.0.1:5000", + "Custom model (optional)": "自訂模型(選填)", + "vllm-project/vllm": "vllm-project/vllm", + "vLLM API key": "vLLM API 金鑰", + "Example: 127.0.0.1:8000": "範例:127.0.0.1:8000", + "vLLM Model": "vLLM 模型", + "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite 引擎", + "Aphrodite API key": "Aphrodite API 金鑰", + "Aphrodite Model": "Aphrodite 模型", + "ggerganov/llama.cpp": "ggerganov/llama.cpp", + "Example: 127.0.0.1:8080": "範例:127.0.0.1:8080", + "Example: 127.0.0.1:11434": "範例:127.0.0.1:11434", + "Ollama Model": "Ollama 模型", + "Download": "下載", + "Tabby API key": "Tabby API 金鑰", + "koboldcpp API key (optional)": "KoboldCpp API 金鑰(可選)", + "Example: 127.0.0.1:5001": "範例:127.0.0.1:5001", + "Authorize": "授權", + "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "使用 OAuth 流程取得您的 OpenRouter API 符元。您將被重新導向到 openrouter.ai", + "Bypass status check": "繞過狀態檢查", + "Chat Completion Source": "聊天補全來源", + "Reverse Proxy": "反向代理伺服器", + "Proxy Presets": "代理伺服器預設設定檔", + "Saved addresses and passwords.": "已儲存的地址和密碼", + "Save Proxy": "儲存代理伺服器", + "Delete Proxy": "刪除代理伺服器", + "Proxy Name": "代理伺服器名稱", + "This will show up as your saved preset.": "這將顯示為您儲存的預設設定檔", + "Proxy Server URL": "代理伺服器 URL", + "Alternative server URL (leave empty to use the default value).": "替代伺服器 URL(留空以使用預設值)。", + "Remove your real OAI API Key from the API panel BEFORE typing anything into this box": "在此框中輸入任何內容之前,從 API 面板中刪除您的實際 OAI API 金鑰", + "We cannot provide support for problems encountered while using an unofficial OpenAI proxy": "我們無法為使用非官方 OpenAI 代理伺服器時遇到的問題提供支援", + "Doesn't work? Try adding": "不起作用?嘗試新增", + "at the end!": "在 URL 結尾!", + "Proxy Password": "代理伺服器密碼", + "Will be used as a password for the proxy instead of API key.": "將用作代理的密碼,而不是 API 金鑰", + "Peek a password": "顯示密碼", + "OpenAI API key": "OpenAI API 金鑰", + "View API Usage Metrics": "檢視 API 使用指標", + "Follow": "遵循", + "these directions": "這些指示", + "to get your OpenAI API key.": "以取得您的 OpenAI API 金鑰。", + "Use Proxy password field instead. This input will be ignored.": "請改用代理密碼欄位。此輸入將被忽略", + "OpenAI Model": "OpenAI 模型", + "Bypass API status check": "繞過 API 狀態檢查", + "Show External models (provided by API)": "顯示外部模型(由 API 提供)", + "Get your key from": "取得您的鑰匙", + "Anthropic's developer console": "Anthropic 的開發者控制台", + "Claude Model": "Claude 模型", + "Window AI Model": "Window AI 模型", + "Model Order": "模型順序", + "Alphabetically": "按字母順序", + "Price": "價格(最便宜的)", + "Context Size": "上下文長度", + "Group by vendors": "按供應商分組", + "Group by vendors Description": "將 OpenAI、Anthropic 等模型放各自供應商的群組中。可以與排序功能結合使用。", + "Allow fallback routes": "允許備援路徑", + "Allow fallback routes Description": "如果選擇的模型無法滿足要求,會自動選擇替代模型。", + "Scale API Key": "Scale API 金鑰", + "Clear your cookie": "清除您的 Cookie", + "Alt Method": "替代方法", + "AI21 API Key": "AI21 API 金鑰", + "AI21 Model": "AI21 模型", + "Google AI Studio API Key": "Google AI Studio API 金鑰", + "Google Model": "Google 模型", + "MistralAI API Key": "MistralAI API 金鑰", + "MistralAI Model": "MistralAI 模型", + "Groq API Key": "Groq API 金鑰", + "Groq Model": "Groq 模型", + "Perplexity API Key": "Perplexity API 金鑰", + "Perplexity Model": "Perplexity 模型", + "Cohere API Key": "Cohere API 金鑰", + "Cohere Model": "Cohere 模型", + "Custom Endpoint (Base URL)": "自訂端點(Base URL)", + "Custom API Key": "自訂 API 金鑰", + "Available Models": "可用模型", + "Prompt Post-Processing": "提示詞後處理", + "Applies additional processing to the prompt before sending it to the API.": "這個選項會在將提示詞送往 API 之前,對它進行額外的處理。", + "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "透過傳送簡短的測試訊息來驗證您的 API 連線。請注意,您將因此獲得榮譽!", + "Test Message": "測試訊息", + "Auto-connect to Last Server": "自動連接至上次使用的伺服器", + "Missing key": "❌ 鑰匙遺失", + "Key saved": "✔️ 金鑰已儲存", + "View hidden API keys": "檢視隱藏的 API 金鑰", + "AI Response Formatting": "AI 回應進階格式化", + "Advanced Formatting": "進階格式化", + "Context Template": "上下文範本", + "Auto-select this preset for Instruct Mode": "自動選擇此預設設定檔用於指令模式", + "Story String": "故事字串", + "Example Separator": "分隔符號範例", + "Chat Start": "聊天開始符號", + "Add Chat Start and Example Separator to a list of stopping strings.": "將聊天開始和範例分隔符號加入終止字串中。", + "Use as Stop Strings": "用作停止字串", + "context_allow_jailbreak": "如果在角色卡中定義了越獄,且啟用了「角色卡越獄優先」,則會在提示詞的結尾加入越獄內容。\n這不建議用於文字完成模型,因為可能導致不良的輸出結果。", + "Allow Jailbreak": "允許越獄", + "Context Order": "上下文順序", + "Summary": "摘要", + "Author's Note": "作者備註", + "Example Dialogues": "對話範例", + "Hint": "提示訊息", + "In-Chat Position not affected": "摘要和作者的注釋順序僅在未設定聊天中位置時受影響。", + "Instruct Mode": "指示模式", + "Enabled": "啟用", + "instruct_bind_to_context": "啟用後,系統將根據所選擇的指令範本名稱或偏好,自動選取對應的上下文範本。", + "Bind to Context": "附加到上下文", + "Presets": "預設設定檔", + "Auto-select this preset on API connection": "在 API 連線時自動選擇此預設", + "Activation Regex": "啟用正規表示式", + "Wrap Sequences with Newline": "用換行符包裹序列", + "Replace Macro in Sequences": "取代序列中的巨集", + "Skip Example Dialogues Formatting": "跳過對話範例的格式設定", + "Include Names": "包含名稱", + "Force for Groups and Personas": "強制用於群組和使用者角色", + "System Prompt": "系統提示詞", + "Instruct Mode Sequences": "指示模式序列", + "System Prompt Wrapping": "系統提示詞換行", + "Inserted before a System prompt.": "插入在系統提示詞之前。", + "System Prompt Prefix": "系統提示詞前綴", + "Inserted after a System prompt.": "插入在系統提示詞之後。", + "System Prompt Suffix": "系統提示詞後綴", + "Chat Messages Wrapping": "聊天訊息換行", + "Inserted before a User message and as a last prompt line when impersonating.": "插入在使用者訊息之前,並在扮演使用者時作為最後一行提示詞。", + "User Message Prefix": "使用者訊息前綴", + "Inserted after a User message.": "插入在使用者提示詞之後。", + "User Message Suffix": "使用者訊息後綴", + "Inserted before an Assistant message and as a last prompt line when generating an AI reply.": "插入在助理訊息之前,並在生成 AI 回覆時作為最後一行提示詞。", + "Assistant Message Prefix": "助理訊息前綴", + "Inserted after an Assistant message.": "插入在助理訊息之後。", + "Assistant Message Suffix": "助理訊息後綴", + "Inserted before a System (added by slash commands or extensions) message.": "插入在系統(透過斜線命令或擴充功能增加)訊息之前。", + "System Message Prefix": "系統訊息前綴", + "Inserted after a System message.": "插入在系統訊息之後", + "System Message Suffix": "系統訊息後綴", + "If enabled, System Sequences will be the same as User Sequences.": "啟用後,系統序列將與使用者序列相同。", + "System same as User": "系統與使用者相同", + "Misc. Sequences": "其他序列", + "Inserted before the first Assistant's message.": "插入在第一則助理訊息之前。", + "First Assistant Prefix": "開頭助理前綴", + "instruct_last_output_sequence": "插入在最後一則助理訊息之前,或在生成 AI 回覆時作為最後一行提示詞(除了中立/系統角色)。", + "Last Assistant Prefix": "結尾助理前綴", + "Will be inserted as a last prompt line when using system/neutral generation.": "在使用系統/中立生成時作為最後一行提示詞插入。", + "System Instruction Prefix": "系統指令前綴", + "If a stop sequence is generated, everything past it will be removed from the output (inclusive).": "如果生成了停止序列,包括該序列以及之後的所有內容將從輸出中刪除。", + "Stop Sequence": "停止序列", + "Will be inserted at the start of the chat history if it doesn't start with a User message.": "如果聊天歷史不是以使用者訊息開始,將在聊天歷史的開頭插入。", + "User Filler Message": "使用者填充訊息", + "Context Formatting": "上下文格式", + "(Saved to Context Template)": "(已儲存到上下文範本)", + "Always add character's name to prompt": "總是將角色名稱新增到提示詞中", + "Generate only one line per request": "每次請求僅生成一行", + "Trim Incomplete Sentences": "修剪不完整的句子", + "Include Newline": "包含換行符號", + "Misc. Settings": "其他設定", + "Collapse Consecutive Newlines": "折疊連續的換行符號", + "Trim spaces": "修剪空格", + "Tokenizer": "分詞器 Tokenizer", + "Token Padding": "符元填充", + "Start Reply With": "開始回覆", + "AI reply prefix": "AI 回覆前綴", + "Show reply prefix in chat": "在聊天中顯示回覆前綴", + "Non-markdown strings": "非 Markdown 字串", + "separate with commas w/o space between": "用逗號分隔,之間無空格", + "Custom Stopping Strings": "自訂停止字串", + "JSON serialized array of strings": "JSON 序列化字串陣列", + "Replace Macro in Stop Strings": "取代自訂停止字串中的巨集", + "Auto-Continue": "自動繼續", + "Allow for Chat Completion APIs": "允許聊天補全 API", + "Target length (tokens)": "目標長度(符元)", + "World Info": "世界資訊", + "Locked = World Editor will stay open": "上鎖 = 世界編輯器將保持開啟", + "Worlds/Lorebooks": "世界/知識書", + "Active World(s) for all chats": "所有聊天啟用中的世界書", + "-- World Info not found --": "-- 未找到世界資訊 --", + "Global World Info/Lorebook activation settings": "全域世界資訊/知識書啟動設定", + "Click to expand": "點選展開", + "Scan Depth": "掃描深度", + "Context %": "上下文百分比", + "Budget Cap": "預算上限", + "(0 = disabled)": "(0 = 停用)", + "Scan chronologically until reached min entries or token budget.": "按時間順序掃描直到達到最小條目或符元預算", + "Min Activations": "最小啟動次數", + "Max Depth": "最大深度", + "(0 = unlimited, use budget)": "(0 = 無限制,使用預算)", + "Insertion Strategy": "插入策略", + "Sorted Evenly": "均等排序", + "Character Lore First": "角色知識書優先", + "Global Lore First": "全域知識書優先", + "Entries can activate other entries by mentioning their keywords": "條目可以透過提及其關鍵字來啟用其他條目", + "Recursive Scan": "遞迴掃描", + "Lookup for the entry keys in the context will respect the case": "在上下文中查詢條目鍵將區分大小寫", + "Case Sensitive": "區分大小寫", + "If the entry key consists of only one word, it would not be matched as part of other words": "如果條目鍵僅包含一個詞,則不會作為其他詞的一部分進行配對", + "Match Whole Words": "完全配對", + "Only the entries with the most number of key matches will be selected for Inclusion Group filtering": "只有符合最多鍵值數量的條目將被選中進行包含群組過濾", + "Use Group Scoring": "使用群組評分", + "Alert if your world info is greater than the allocated budget.": "如果您的世界資訊超過分配的預算則提醒", + "Alert On Overflow": "溢位時警告", + "New": "新增", + "or": "或", + "--- Pick to Edit ---": "--- 選擇編輯 ---", + "Rename World Info": "重新命名世界資訊", + "Open all Entries": "展開所有條目", + "Close all Entries": "收合所有條目", + "New Entry": "新條目", + "Fill empty Memo/Titles with Keywords": "用關鍵字填充空的備忘錄/標題", + "Import World Info": "匯入世界資訊", + "Export World Info": "匯出世界資訊", + "Duplicate World Info": "複製世界資訊", + "Delete World Info": "刪除世界資訊", + "Search...": "搜尋⋯", + "Search": "搜尋", + "Priority": "優先順序", + "Custom": "自訂", + "Title A-Z": "標題 A-Z", + "Title Z-A": "標題 Z-A", + "Tokens ↗": "符元 ↗", + "Tokens ↘": "符元 ↘", + "Depth ↗": "深度 ↗", + "Depth ↘": "深度 ↘", + "Order ↗": "順序 ↗", + "Order ↘": "順序 ↘", + "UID ↗": "UID ↗", + "UID ↘": "UID ↘", + "Trigger% ↗": "觸發% ↗", + "Trigger% ↘": "觸發% ↘", + "Refresh": "重新整理", + "User Settings": "使用者設定", + "Simple": "簡單", + "Advanced": "進階", + "UI Language": "介面語言:", + "Account": "帳號", + "Admin Panel": "管理面板", + "Logout": "登出", + "Search Settings": "搜尋設定", + "UI Theme": "介面主題", + "Import a theme file": "匯入主題檔", + "Export a theme file": "匯出主題檔", + "Delete a theme": "刪除主題", + "Update a theme file": "更新主題檔", + "Save as a new theme": "另存為新主題", + "Avatar Style:": "頭像樣式", + "Circle": "圓形", + "Square": "方形", + "Rectangle": "矩形", + "Chat Style:": "對話框樣式:", + "Flat": "扁平", + "Bubbles": "氣泡", + "Document": "文件", + "Specify colors for your theme.": "為您的介面主題指定顏色", + "Theme Colors": "介面主題顏色", + "Main Text": "主要文字", + "Italics Text": "斜體文字", + "Underlined Text": "帶底線的文字", + "Quote Text": "引用文字", + "Shadow Color": "陰影顏色", + "Chat Background": "聊天背景顏色", + "UI Background": "介面背景顏色", + "UI Border": "介面邊框顏色", + "User Message Blur Tint": "使用者訊息模糊色調", + "AI Message Blur Tint": "AI 訊息模糊色調", + "Chat Width": "對話框寬度", + "Width of the main chat window in % of screen width": "主聊天視窗寬度佔螢幕寬度的百分比", + "Font Scale": "字型比例", + "Font size": "字型大小", + "Blur Strength": "模糊強度", + "Blur strength on UI panels.": "UI 面板上的模糊強度", + "Text Shadow Width": "文字陰影寬度", + "Strength of the text shadows": "文字陰影的強度", + "Disables animations and transitions": "停用動畫和過渡效果", + "Reduced Motion": "停用動畫過渡效果", + "removes blur from window backgrounds": "從視窗背景中移除模糊效果,以加快算繪速度。", + "No Blur Effect": "停用模糊效果", + "Remove text shadow effect": "移除文字陰影效果。", + "No Text Shadows": "停用文字陰影效果", + "Reduce chat height, and put a static sprite behind the chat window": "減少聊天高度,並在聊天視窗後放置一個靜態 Sprite。", + "Waifu Mode": "視覺小說模式", + "Always show the full list of the Message Actions context items for chat messages, instead of hiding them behind '...'": "始終顯示聊天訊息的訊息動作上下文項目的完整列表,而不是將它們隱藏在「⋯」後面。", + "Auto-Expand Message Actions": "展開訊息快速編輯選單", + "Alternative UI for numeric sampling parameters with fewer steps": "數值取樣參數的替代 UI,步驟更少", + "Zen Sliders": "Zen 滑桿", + "Entirely unrestrict all numeric sampling parameters": "完全解除所有數值取樣參數的限制。", + "Mad Lab Mode": "瘋狂實驗室模式", + "Time the AI's message generation, and show the duration in the chat log": "計時 AI 的訊息生成,並在聊天記錄中顯示持續時間。", + "Message Timer": "訊息計時器", + "Show a timestamp for each message in the chat log": "在聊天記錄中為每條訊息顯示時間戳記。", + "Chat Timestamps": "對話框時間戳記", + "Show an icon for the API that generated the message": "顯示生成訊息的 API 圖示。", + "Model Icon": "顯示模型圖示", + "Show sequential message numbers in the chat log": "在聊天記錄中顯示連續的訊息編號。", + "Message IDs": "顯示訊息 ID", + "Hide avatars in chat messages.": "在聊天訊息中隱藏頭像", + "Hide Chat Avatars": "隱藏聊天頭像", + "Show the number of tokens in each message in the chat log": "在聊天記錄中顯示每條訊息中的符元數量", + "Show Message Token Count": "顯示訊息符元數", + "Single-row message input area. Mobile only, no effect on PC": "將聊天訊息輸入欄預設為單行顯示。僅適用於行動版,電腦版無效。", + "Compact Input Area (Mobile)": "緊湊的聊天訊息輸入欄(行動版)", + "In the Character Management panel, show quick selection buttons for favorited characters": "在角色管理面板中,顯示加入到最愛角色的快速選擇按鈕。", + "Characters Hotswap": "角色卡快捷選單", + "Enable magnification for zoomed avatar display.": "啟用放大顯示頭像", + "Avatar Hover Magnification": "頭像懸停時的放大倍數", + "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "當你在聊天中點選頭像的圖片後,這會啟用滑鼠懸停時的放大效果。", + "Show tagged character folders in the character list": "在角色列表中顯示標籤角色資料夾。", + "Tags as Folders": "標籤作為資料夾", + "Tags_as_Folders_desc": "標籤必須在「標籤管理」選單中標記為資料夾才可適用。點選這裡開啟。", + "Character Handling": "角色處理", + "If set in the advanced character definitions, this field will be displayed in the characters list.": "如果在進階角色定義中設定,這個欄位將顯示在角色清單中。", + "Char List Subheader": "角色列表子標題", + "Character Version": "角色版本", + "Created by": "創作者", + "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "使用模糊配對,並透過所有資料欄位在列表中搜尋角色,而不僅僅是透過名稱子字串。", + "Advanced Character Search": "進階角色搜尋", + "If checked and the character card contains a prompt override (System Prompt), use that instead": "如果選中並且角色卡包含提示詞覆寫(系統提示詞),則使用該提示詞。", + "Prefer Character Card Prompt": "角色卡主要提示詞優先", + "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "如果選中並且角色卡包含越獄覆寫(聊天歷史後指示),則使用該提示詞。", + "Prefer Character Card Jailbreak": "角色卡越獄優先", + "never_resize_avatars_tooltip": "避免裁剪與調整匯入的角色頭像大小。未啟用此選項時,圖片將被裁剪/調整為 512x768。此設定會關閉上傳頭像時的裁剪彈出視窗。", + "Never resize avatars": "永不調整頭像大小", + "Show actual file names on the disk, in the characters list display only": "僅在角色列表顯示實際檔案名稱。", + "Show avatar filenames": "顯示頭像檔案名稱", + "Prompt to import embedded card tags on character import. Otherwise embedded tags are ignored": "在角色匯入時提示詞匯入嵌入的卡片標籤。否則,嵌入的標籤將被忽略。", + "Import Card Tags": "匯入卡片中的標籤", + "Hide character definitions from the editor panel behind a spoiler button": "在編輯器面板中將角色定義隱藏在劇透按鈕後面。", + "Spoiler Free Mode": "無劇透模式", + "Miscellaneous": "其他", + "Reload and redraw the currently open chat": "重新載入並重繪目前開啟的聊天", + "Reload Chat": "重新載入聊天", + "Debug Menu": "偵錯選單", + "Smooth Streaming": "平滑串流", + "Experimental feature. May not work for all backends.": "實驗性功能。可能不適用於所有後端", + "Slow": "慢", + "Fast": "快", + "Play a sound when a message generation finishes": "訊息生成完成時播放音效。", + "Message Sound": "訊息音效", + "Only play a sound when ST's browser tab is unfocused": "僅在 ST 的瀏覽器分頁未聚焦時播放音效。", + "Background Sound Only": "僅作為背景音效", + "Reduce the formatting requirements on API URLs": "降低 API URL 的格式要求。", + "Relaxed API URLS": "寬鬆的 API URL 格式", + "Ask to import the World Info/Lorebook for every new character with embedded lorebook. If unchecked, a brief message will be shown instead": "當新角色含有知識書時,詢問是否要匯入嵌入的世界資訊/知識書。如果未選中,則會顯示簡短的訊息。", + "Lorebook Import Dialog": "匯入知識書對話框", + "Restore unsaved user input on page refresh": "在頁面重新整理時還原未儲存的使用者輸入。", + "Restore User Input": "還原使用者輸入", + "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "允許透過拖動重新定位某些 UI 元素。僅適用於 PC 版。", + "Movable UI Panels": "可拖動的 UI 模式", + "MovingUI preset. Predefined/saved draggable positions": "MovingUI 預設設定檔。預先定義/儲存可拖動位置。", + "MUI Preset": "MovingUI 預設設定檔", + "Save movingUI changes to a new file": "另存 MovingUI 變更為新檔案", + "Reset MovingUI panel sizes/locations.": "重設 MovingUI 面板大小/位置", + "Apply a custom CSS style to all of the ST GUI": "將自訂 CSS 樣式應用於所有 SillyTavern 介面", + "Custom CSS": "自訂 CSS 樣式", + "Expand the editor": "展開編輯器", + "Chat/Message Handling": "聊天/訊息處理", + "# Messages to Load": "每頁載入的訊息數", + "The number of chat history messages to load before pagination.": "每頁載入的聊天歷史訊息數", + "(0 = All)": "(0 = 全部)", + "Streaming FPS": "串流 FPS", + "Update speed of streamed text.": "更新串流文字的速度", + "Example Messages Behavior": "訊息行為範例:", + "Gradual push-out": "逐步推出", + "Always include examples": "總是包含範例", + "Never include examples": "永不包含範例", + "Send on Enter": "按下 Enter 鍵傳送:", + "Disabled": "停用", + "Automatic (PC)": "自動(PC)", + "Press Send to continue": "按下傳送繼續", + "Show a button in the input area to ask the AI to continue (extend) its last message": "在輸入區域顯示一個按鈕,請求 AI 繼續(擴充)其最後一則訊息", + "Quick 'Continue' button": "快速「繼續回應」按鈕", + "Show arrow buttons on the last in-chat message to generate alternative AI responses. Both PC and mobile": "在最後的聊天訊息中顯示箭頭按鈕,以生成替代的 AI 回應。適用於 PC 和行動版", + "Swipes": "滑動", + "Allow using swiping gestures on the last in-chat message to trigger swipe generation. Mobile only, no effect on PC": "允許在最後的聊天訊息上使用滑動手勢以觸發滑動生成。僅適用於行動版。", + "Gestures": "手勢", + "Auto-load Last Chat": "自動載入最後的聊天", + "Auto-scroll Chat": "自動滾動聊天", + "Save edits to messages without confirmation as you type": "在輸入時自動儲存訊息的編輯。", + "Auto-save Message Edits": "自動儲存編輯的訊息", + "Confirm message deletion": "刪除訊息前確認", + "Auto-fix Markdown": "自動修正 Markdown", + "Disallow embedded media from other domains in chat messages": "禁止在聊天訊息中嵌入來自其他領域的媒體。", + "Forbid External Media": "禁止使用外部媒體", + "Allow {{char}}: in bot messages": "允許機器人訊息中使用 {{char}}:", + "Allow {{user}}: in bot messages": "允許機器人訊息中使用 {{user}}:", + "Skip encoding and characters in message text, allowing a subset of HTML markup as well as Markdown": "跳過編碼訊息文字中的 < 和 > 字元,允許一部分 HTML 標記以及 Markdown", + "Show tags in responses": "在回應中顯示標籤", + "Allow AI messages in groups to contain lines spoken by other group members": "允許群組中的 AI 訊息包含其他群組成員說的話", + "Relax message trim in Groups": "放寬群組中的訊息修剪", + "Log prompts to console": "將提示詞記錄到控制台", + "Requests logprobs from the API for the Token Probabilities feature": "從 API 請求 logprobs 用於符元機率功能。", + "Request token probabilities": "請求符元機率", + "Automatically reject and re-generate AI message based on configurable criteria": "根據可設定標準自動拒絕並重新生成 AI 訊息。", + "Auto-swipe": "自動滑動", + "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "啟用自動滑動功能。此部分的設定僅在啟用自動滑動時有效。", + "Minimum generated message length": "生成訊息的最小長度", + "If the generated message is shorter than these many characters, trigger an auto-swipe": "如果生成的訊息比這個短,將觸發自動滑動。", + "Blacklisted words": "黑名單詞語", + "words you dont want generated separated by comma ','": "您不想生成的文字,使用逗號分隔", + "Blacklisted word count to swipe": "滑動的黑名單詞語數量", + "Minimum number of blacklisted words detected to trigger an auto-swipe": "偵測到的黑名單詞語數量觸發自動滑動的最小值。", + "AutoComplete Settings": "自動完成設定", + "Automatically hide details": "自動隱藏詳細資訊", + "Determines how entries are found for autocomplete.": "決定如何找到自動完成的條目", + "Autocomplete Matching": "自動完成配對", + "Starts with": "開始於", + "Includes": "包含", + "Fuzzy": "模糊", + "Sets the style of the autocomplete.": "設定自動完成的樣式", + "Autocomplete Style": "自動完成樣式", + "Follow Theme": "沿用介面主題", + "Dark": "深色", + "Sets the font size of the autocomplete.": "設定自動完成的字型大小", + "Sets the width of the autocomplete.": "設定自動完成的寬度", + "Autocomplete Width": "自動完成寬度", + "chat input box": "聊天輸入框", + "entire chat width": "整個聊天寬度", + "full window width": "全視窗寬度", + "STscript Settings": "STscript 設定", + "Sets default flags for the STscript parser.": "設定 STscript 解析器的預設象徵", + "Parser Flags": "解析器象徵", + "Switch to stricter escaping, allowing all delimiting characters to be escaped with a backslash, and backslashes to be escaped as well.": "切換到更嚴格的字元跳脫,允許所有分隔符號使用反斜線跳脫,反斜線自己也可以跳脫。", + "STRICT_ESCAPING": "STRICT_ESCAPING", + "Replace all {{getvar::}} and {{getglobalvar::}} macros with scoped variables to avoid double macro substitution.": "將所有 {{getvar::}} 和 {{getglobalvar::}} 巨集取代為區域變數以避免雙重巨集取代", + "REPLACE_GETVAR": "REPLACE_GETVAR", + "Change Background Image": "變更背景圖片", + "Filter": "篩選", + "Automatically select a background based on the chat context": "根據聊天上下文自動選擇背景", + "Auto-select": "自動選擇", + "System Backgrounds": "系統背景圖片", + "Chat Backgrounds": "聊天背景圖片", + "bg_chat_hint_1": "使用擴充功能", + "bg_chat_hint_2": "所產生的背景圖片將在此顯示。", + "Extensions": "擴充功能", + "Notify on extension updates": "擴充功能更新通知", + "Manage extensions": "管理擴充功能", + "Import Extension From Git Repo": "從 Git 倉庫匯入擴充功能", + "Install extension": "安裝擴充功能", + "Extras API:": "擴充功能 API:", + "Auto-connect": "自動連線", + "Extras API URL": "擴充功能 API URL", + "Extras API key (optional)": "擴充功能 API 金鑰(選填)", + "Persona Management": "使用者角色管理", + "How do I use this?": "我該如何使用這個?", + "Click for stats!": "點選以檢視統計資料!", + "Usage Stats": "統計資料", + "Backup your personas to a file": "備份您的使用者角色檔案", + "Backup": "備份", + "Restore your personas from a file": "還原您的使用者角色檔案", + "Restore": "還原", + "Create a dummy persona": "建立一個虛構使用者角色", + "Create": "建立", + "Toggle grid view": "切換為網格檢視", + "No persona description": "無使用者角色描述", + "Name": "名稱", + "Enter your name": "輸入您的名字", + "Click to set a new User Name": "設定新的使用者名稱", + "Click to lock your selected persona to the current chat. Click again to remove the lock.": "綁定目前所選的使用者角色至本次聊天。再次點選則可移除綁定。", + "Click to set user name for all messages": "設定所有訊息的使用者名稱", + "Persona Description": "使用者角色描述", + "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "範例:[{{user}} 是一個 28 歲的羅馬尼亞貓娘。]", + "Tokens persona description": "角色描述符元數", + "Position:": "插入位置:", + "In Story String / Prompt Manager": "提示詞管理器/故事字串中", + "Top of Author's Note": "作者備註的頂端", + "Bottom of Author's Note": "作者備註的底端", + "In-chat @ Depth": "聊天中 @ 深度", + "Depth:": "深度:", + "Role:": "角色:", + "System": "系統", + "User": "使用者", + "Assistant": "助理", + "Show notifications on switching personas": "切換角色時顯示通知", + "Character Management": "角色管理", + "Locked = Character Management panel will stay open": "上鎖 = 角色管理面板將保持開啟", + "Select/Create Characters": "選擇/建立角色", + "Favorite characters to add them to HotSwaps": "將角色加入到最愛來新增到快速切換", + "Token counts may be inaccurate and provided just for reference.": "符元計數可能不準確,僅供參考。", + "Total tokens": "符元總計", + "Calculating...": "計算中⋯", + "Tokens": "符元", + "Permanent tokens": "永久符元", + "Permanent": "永久", + "About Token 'Limits'": "關於符元數「限制」", + "Toggle character info panel": "切換角色資訊面板", + "Name this character": "為此角色命名", + "extension_token_counter": "符元:", + "Click to select a new avatar for this character": "點選以選擇此角色的新頭像", + "Add to Favorites": "新增至我的最愛", + "Advanced Definition": "進階定義", + "Character Lore": "角色知識書", + "Chat Lore": "聊天知識書", + "Export and Download": "匯出和下載", + "Duplicate Character": "複製角色", + "Create Character": "建立角色", + "Delete Character": "刪除角色", + "More...": "更多⋯", + "Link to World Info": "連結到世界資訊", + "Import Card Lore": "匯入角色卡知識書", + "Scenario Override": "場景覆寫", + "Convert to Persona": "轉換為使用者角色", + "Rename": "重新命名", + "Link to Source": "連結到來源", + "Replace / Update": "取代/更新", + "Import Tags": "匯入標籤", + "Search / Create Tags": "搜尋/建立標籤", + "View all tags": "檢視所有標籤", + "Creator's Notes": "創作者備註", + "Show / Hide Description and First Message": "顯示/隱藏描述和第一則訊息", + "Character Description": "角色描述", + "Click to allow/forbid the use of external media for this character.": "點選以允許/禁止此角色使用外部媒體", + "Ext. Media": "外部媒體權限", + "Describe your character's physical and mental traits here.": "在此描述角色的身體和心理特徵。", + "First message": "初始訊息", + "Click to set additional greeting messages": "點選以設定額外的問候訊息", + "Alt. Greetings": "額外問候語", + "This will be the first message from the character that starts every chat.": "這將是每次聊天開始時角色傳送的第一則訊息。", + "Group Controls": "群組控制", + "Chat Name (Optional)": "聊天名稱(選填)", + "Click to select a new avatar for this group": "點選以選擇此群組的新頭像", + "Group reply strategy": "群組回應策略", + "Natural order": "自然順序", + "List order": "清單順序", + "Group generation handling mode": "群組生成處理模式", + "Swap character cards": "交換角色卡", + "Join character cards (exclude muted)": "合併角色卡欄位(排除靜音)", + "Join character cards (include muted)": "合併角色卡欄位(包括靜音)", + "Inserted before each part of the joined fields.": "插入在合併欄位的每一部分之前。", + "Join Prefix": "加入前綴", + "When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and with the name of the part (e.g.: description, personality, scenario, etc.)": "選擇「合併角色卡欄位」時,所有角色的相關欄位將被合併。\r例如,在故事字串中,所有角色的描述將合併為一段大文字。\r若您希望這些欄位保持分隔,您可以在此定義前綴或後綴。\r\r此值支援常規巨集 {{macros}},並會將 {{char}} 替換為相關角色的名稱,可將 替換為欄位名稱(例如:角色描述、個性、場景等)。", + "Inserted after each part of the joined fields.": "插入在合併欄位的每一部分之後。", + "Join Suffix": "加入後綴", + "Set a group chat scenario": "設定群組聊天場景", + "Click to allow/forbid the use of external media for this group.": "點選以允許/禁止此群組使用外部媒體", + "Restore collage avatar": "還原預設頭像", + "Allow self responses": "允許自我回應", + "Auto Mode": "自動模式", + "Auto Mode delay": "自動模式延遲", + "Hide Muted Member Sprites": "於群組拼貼頭像中隱藏靜音成員", + "Current Members": "目前成員", + "Add Members": "新增成員", + "Create New Character": "建立角色", + "Import Character from File": "由本機檔案匯入角色", + "Import content from external URL": "由外部 URL 匯入內容", + "Create New Chat Group": "建立聊天群組", + "Characters sorting order": "角色排序依據", + "A-Z": "A-Z", + "Z-A": "Z-A", + "Newest": "最新", + "Oldest": "最舊", + "Favorites": "我的最愛", + "Recent": "最近", + "Most chats": "最常聊天", + "Least chats": "最少聊天", + "Most tokens": "最多符元", + "Least tokens": "最少符元", + "Random": "隨機", + "Toggle character grid view": "切換為角色網格檢視", + "Bulk_edit_characters": "批次編輯角色\n\n點選以切換角色\n「Shift+點選」可選擇/取消選擇範圍的角色\n右鍵以檢視動作\n右鍵以檢視動作", + "Bulk select all characters": "全選所有角色", + "Bulk delete characters": "批次刪除角色", + "popup-button-save": "儲存", + "popup-button-yes": "確定", + "popup-button-no": "取消", + "popup-button-cancel": "關閉", + "popup-button-import": "匯入", + "Advanced Definitions": "進階定義", + "Prompt Overrides": "提示詞覆寫", + "(For Chat Completion and Instruct Mode)": "(用於聊天補全和指令模式)", + "Insert {{original}} into either box to include the respective default prompt from system settings.": "在任一框中插入 {{original}} 以包含系統設定中的預設提示詞。", + "Main Prompt": "主要提示詞", + "Any contents here will replace the default Main Prompt used for this character. (v2 spec: system_prompt)": "此處的任何內容將取代此角色使用的預設主要提示詞。(v2 規範:system_prompt)", + "Any contents here will replace the default Jailbreak Prompt used for this character. (v2 spec: post_history_instructions)": "此處的任何內容將取代此角色使用的預設越獄提示詞。(v2 規範:post_history_instructions)", + "Creator's Metadata (Not sent with the AI prompt)": "創作者的中繼資料(不會與 AI 提示詞一起傳送)", + "Creator's Metadata": "創作者的中繼資料", + "(Not sent with the AI Prompt)": "(不與 AI 提示詞一起傳送)", + "Everything here is optional": "此處所有內容均為選填", + "(Botmaker's name / Contact Info)": "(機器人創作者的名字/聯絡資訊)", + "(If you want to track character versions)": "(若您想追蹤角色版本)", + "(Describe the bot, give use tips, or list the chat models it has been tested on. This will be displayed in the character list.)": "(描述機器人,提供使用技巧,或列出已測試的聊天模型。這將顯示在角色列表中。)", + "Tags to Embed": "嵌入標籤", + "(Write a comma-separated list of tags)": "(使用逗號分隔每個標籤)", + "Personality summary": "個性摘要", + "(A brief description of the personality)": "(關於角色性格的簡要描述)", + "Scenario": "場景設想", + "(Circumstances and context of the interaction)": "(互動情形與聊天背景)", + "Character's Note": "角色備註", + "(Text to be inserted in-chat @ designated depth and role)": "(在聊天中以指定角色於 @ 深度位置插入文字)", + "@ Depth": "@ 深度", + "Role": "角色", + "Talkativeness": "健談度", + "How often the character speaks in group chats!": "角色在群組聊天中說話的頻率!", + "How often the character speaks in": "角色說話的頻率", + "group chats!": "群組聊天!", + "Shy": "寡言", + "Normal": "正常", + "Chatty": "健談", + "Examples of dialogue": "對話範例", + "Important to set the character's writing style.": "設定角色的寫作樣式很重要。", + "(Examples of chat dialog. Begin each example with START on a new line.)": "(聊天對話範例。每個範例以新的行並以「START」開始。)", + "Chat History": "聊天記錄", + "Import Chat": "匯入聊天", + "Copy to system backgrounds": "複製到系統背景圖片", + "Rename background": "重新命名背景圖片", + "Lock": "上鎖", + "Unlock": "解鎖", + "Delete background": "刪除背景圖片", + "Chat Scenario Override": "聊天場景覆寫", + "Remove": "刪除", + "Type here...": "在此輸入⋯", + "Chat Lorebook": "聊天知識書", + "Chat Lorebook for": "聊天知識書", + "chat_world_template_txt": "選定的世界資訊將附加到此聊天。\n在生成 AI 回覆時,它將與全域和角色知識書中的條目結合。", + "Select a World Info file for": "選擇世界資訊檔案", + "Primary Lorebook": "主要知識書", + "A selected World Info will be bound to this character as its own Lorebook.": "選定的世界資訊將作為此角色的知識書附加到此角色。", + "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "生成 AI 回覆時,將與全域世界資訊選擇器中的條目結合。", + "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "匯出角色時,也會匯出嵌入 JSON 資料中的選定知識書檔案。", + "Additional Lorebooks": "額外的知識書", + "Associate one or more auxillary Lorebooks with this character.": "將一個或多個輔助知識書與此角色關聯。", + "NOTE: These choices are optional and won't be preserved on character export!": "請注意:此為額外選項,不會隨角色卡資料一同匯出!", + "Rename chat file": "重新命名聊天檔案", + "Export JSONL chat file": "匯出 JSONL 聊天檔案", + "Download chat as plain text document": "將聊天下載為純文字檔案", + "Delete chat file": "刪除聊天檔案", + "Drag to reorder tag": "拖動以重新排序標籤", + "Use tag as folder": "將標籤作為資料夾", + "Delete tag": "刪除標籤", + "Entry Title/Memo": "條目標題/備註", + "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized❌ Disabled": "世界資訊條目狀態:🔵常數 🟢正常 🔗向量 ❌停用", + "WI_Entry_Status_Constant": "🔵", + "WI_Entry_Status_Normal": "🟢", + "WI_Entry_Status_Vectorized": "🔗", + "WI_Entry_Status_Disabled": "❌", + "T_Position": "↑角色:角色定義之前\n↓角色:角色定義之後\n↑備註:作者備註之前\n↓備註:作者備註之後\n@深度", + "Before Char Defs": "角色定義之前", + "After Char Defs": "角色定義之後", + "Before EM": "範例訊息之前", + "After EM": "範例訊息之後", + "Before AN": "作者備註之前", + "After AN": "作者備註之後", + "at Depth System": "@D ⚙️ 在系統深度", + "at Depth User": "@D 👤 在使用者深度", + "at Depth AI": "@D 🤖 在 AI 深度", + "Depth": "深度", + "Order:": "順序:", + "Order": "順序", + "Trigger %:": "觸發%:", + "Probability": "機率", + "Duplicate world info entry": "複製世界資訊物件", + "Delete world info entry": "刪除世界資訊物件", + "Comma separated (required)": "逗號分隔(必填)", + "Primary Keywords": "主要關鍵字", + "Keywords or Regexes": "關鍵字或正規表示式", + "Comma separated list": "逗號分隔列表", + "Switch to plaintext mode": "切換到純文字模式", + "Logic": "邏輯", + "AND ANY": "AND 任何", + "AND ALL": "AND 所有", + "NOT ALL": "NOT 所有", + "NOT ANY": "NOT 任何", + "(ignored if empty)": "(如果為空則忽略)", + "Optional Filter": "選填過濾器", + "Keywords or Regexes (ignored if empty)": "關鍵字或正規表示式(如果為空則忽略)", + "Comma separated list (ignored if empty)": "逗號分隔列表(如果為空則忽略)", + "Use global setting": "使用全域設定", + "Case-Sensitive": "區分大小寫", + "Yes": "是", + "No": "否", + "Can be used to automatically activate Quick Replies": "可用於自動啟用快速回覆", + "Automation ID": "自動化 ID", + "( None )": "(無)", + "Content": "內容", + "Exclude from recursion": "不可遞迴(此條目不會被其他條目啟用)", + "Prevent further recursion (this entry will not activate others)": "防止進一步遞迴(此條目不會啟用其他條目)", + "Delay until recursion (this entry can only be activated on recursive checking)": "延遲遞迴(此條目只能在遞迴檢查時啟用)", + "What this keyword should mean to the AI, sent verbatim": "這個關鍵字對 AI 應意味著什麼,逐字傳送", + "Filter to Character(s)": "角色篩選", + "Character Exclusion": "角色排除", + "-- Characters not found --": "-- 未找到角色 --", + "Inclusion Group": "包含的群組", + "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "如果觸發多個條目,包含群組可確保一次僅啟動一組中的一個條目。\r支援多個以逗號分隔的群組。\r\r文件:世界資訊——包容性集團", + "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "優先考慮此條目:選取後,此條目將在所有選擇中優先。\r如果有多個優先順序,則選擇「順序」最高的一個。", + "Only one entry with the same label will be activated": "僅會啟用具有相同標籤的一個條目", + "A relative likelihood of entry activation within the group": "群組內條目啟用的相對可能性", + "Group Weight": "群組權重", + "Selective": "選擇性", + "Use Probability": "使用機率", + "Add Memo": "新增備忘錄", + "Text or token ids": "文字或符元 ID", + "close": "關閉", + "prompt_manager_edit": "編輯", + "prompt_manager_name": "名稱", + "A name for this prompt.": "這個提示詞的名稱。", + "To whom this message will be attributed.": "此訊息所屬的角色。", + "AI Assistant": "人工智慧助手", + "prompt_manager_position": "位置", + "Injection position. Next to other prompts (relative) or in-chat (absolute).": "注入位置。與其他提示詞相鄰(相對位置)或在聊天中(絕對位置)。", + "prompt_manager_relative": "相對位置", + "prompt_manager_depth": "深度", + "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "注入深度。0 = 在最後一則訊息之後,1 = 在最後一則訊息之前,以此類推。", + "Prompt": "提示詞", + "The prompt to be sent.": "要傳送的提示詞。", + "This prompt cannot be overridden by character cards, even if overrides are preferred.": "即使啟用優先覆寫,此提示詞也不能被角色卡片覆寫。", + "prompt_manager_forbid_overrides": "禁止覆寫", + "reset": "重設", + "save": "儲存", + "This message is invisible for the AI": "此訊息對 AI 不可見", + "Message Actions": "訊息動作", + "Translate message": "翻譯訊息", + "Generate Image": "生成圖片", + "Stop Image Generation": "終止圖片生成", + "Narrate": "朗讀訊息", + "Exclude message from prompts": "從提示詞中排除訊息", + "Include message in prompts": "在提示詞中包含訊息", + "Embed file or image": "嵌入檔案或圖片", + "Create checkpoint": "建立檢查點", + "Create Checkpoint": "建立檢查點", + "Create Branch": "建立分支", + "Copy": "複製", + "Open checkpoint chat": "開啟檢查點聊天", + "Edit": "編輯", + "Confirm": "確認", + "Copy this message": "複製此訊息", + "Delete this message": "刪除此訊息", + "Move message up": "上移訊息", + "Move message down": "下移訊息", + "Enlarge": "放大", + "Welcome to SillyTavern!": "歡迎來到 SillyTavern!", + "welcome_message_part_1": "閱讀", + "welcome_message_part_2": "官方文件", + "welcome_message_part_3": "。", + "welcome_message_part_4": "在聊天輸入框內輸入", + "welcome_message_part_5": "來顯示巨集或命令列表。", + "welcome_message_part_6": "加入", + "Discord server": "不和諧伺服器", + "welcome_message_part_7": "取得公告和資訊。", + "SillyTavern is aimed at advanced users.": "SillyTavern 專為進階使用者設計", + "If you're new to this, enable the simplified UI mode below.": "如果您是新手,請啟用下方的簡易 UI 模式", + "Change it later in the 'User Settings' panel.": "稍後可在「使用者設定」面板中變更", + "Enable simple UI mode": "啟用簡易 UI 模式", + "Looking for AI characters?": "正在尋找 AI 角色?", + "onboarding_import": "匯入", + "from supported sources or view": "從支援的來源或檢視", + "Sample characters": "範例角色", + "Your Persona": "您的使用者角色", + "Before you get started, you must select a persona name.": "在開始之前,您必須選擇一個使用者角色名稱", + "welcome_message_part_8": "這個隨時可以透過", + "welcome_message_part_9": "圖示來變更。", + "Persona Name:": "使用者角色名稱", + "Temporarily disable automatic replies from this character": "暫時停用此角色的自動回覆", + "Enable automatic replies from this character": "啟用此角色的自動回覆", + "Trigger a message from this character": "觸發此角色的訊息", + "Move up": "上移", + "Move down": "下移", + "View character card": "檢視角色卡", + "Remove from group": "從群組中移除", + "Add to group": "新增到群組", + "Alternate Greetings": "額外問候語", + "Alternate_Greetings_desc": "這些將在開始新聊天時顯示為第一則訊息的滑動選項。\n群組成員可以選擇其中之一來開始對話。", + "Alternate Greetings Hint": "額外問候語的提示訊息", + "(This will be the first message from the character that starts every chat)": "(這將是每次聊天開始時角色傳送的第一則訊息)", + "Forbid Media Override explanation": "此角色/群組在聊天中使用外部媒體的能力。", + "Forbid Media Override subtitle": "禁止媒體覆寫副標題", + "Always forbidden": "總是禁止", + "Always allowed": "總是允許", + "View contents": "檢視內容", + "Remove the file": "刪除檔案", + "Unique to this chat": "此聊天獨有", + "Checkpoints inherit the Note from their parent, and can be changed individually after that.": "檢查點繼承其上級的註釋,之後可以單獨更改", + "Include in World Info Scanning": "納入世界資訊掃描", + "Before Main Prompt / Story String": "在主要提示詞/故事字串之前", + "After Main Prompt / Story String": "在主要提示詞/故事字串之後", + "as": "作為", + "Insertion Frequency": "插入頻率", + "(0 = Disable, 1 = Always)": "(0 = 停用,1 = 永久)", + "User inputs until next insertion:": "使用者輸入直到下一次插入:", + "Character Author's Note (Private)": "角色作者備註(私人)", + "Won't be shared with the character card on export.": "匯出時不與角色卡共享。", + "Will be automatically added as the author's note for this character. Will be used in groups, but can't be modified when a group chat is open.": "將自動新增為此角色的作者備註。將在群組中使用,但在群組聊天開啟時無法修改", + "Use character author's note": "使用角色作者備註", + "Replace Author's Note": "取代作者註釋", + "Default Author's Note": "預設作者註釋", + "Will be automatically added as the Author's Note for all new chats.": "將自動新增為所有新聊天的作者備註", + "Chat CFG": "聊天 CFG", + "1 = disabled": "1 = 停用", + "write short replies, write replies using past tense": "撰寫簡短回覆,使用過去式撰寫回覆", + "Positive Prompt": "正面提示詞", + "Use character CFG scales": "使用角色 CFG 比例", + "Character CFG": "角色 CFG", + "Will be automatically added as the CFG for this character.": "將自動新增為此角色的 CFG", + "Global CFG": "全域 CFG", + "Will be used as the default CFG options for every chat unless overridden.": "將作為每次聊天的預設 CFG 選項,除非被覆寫", + "CFG Prompt Cascading": "CFG 提示詞級聯", + "Combine positive/negative prompts from other boxes.": "結合其他文字方塊中的正/負提示詞", + "For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string.": "例如:勾選聊天、全域和角色框將所有負面提示詞合併為一個逗號分隔的字串", + "Always Include": "總是包含", + "Chat Negatives": "聊天負面提示詞", + "Character Negatives": "角色負面提示詞", + "Global Negatives": "全域負面提示詞", + "Custom Separator:": "自訂分隔符號:", + "Insertion Depth:": "插入深度:", + "Token Probabilities": "符元機率", + "Select a token to see alternatives considered by the AI.": "選擇一個符元以檢視 AI 考慮的替代方案", + "Not connected to API!": "未連線到 API!", + "Type a message, or /? for help": "輸入訊息,或 /? 取得支援", + "Continue script execution": "繼續腳本執行", + "Pause script execution": "暫停腳本執行", + "Abort script execution": "中止腳本執行", + "Abort request": "中止請求", + "Continue the last message": "繼續生成最新訊息", + "Send a message": "傳送訊息", + "Close chat": "關閉聊天", + "Toggle Panels": "切換面板", + "Back to parent chat": "返回上層聊天", + "Save checkpoint": "儲存檢查點", + "Convert to group": "轉換為群組", + "Start new chat": "開始新聊天", + "Manage chat files": "管理聊天檔案", + "Delete messages": "刪除訊息", + "Regenerate": "重新生成", + "Ask AI to write your message for you": "請 AI 為您撰寫訊息", + "Impersonate": "AI 扮演使用者", + "Continue": "繼續", + "Bind user name to that avatar": "將使用者名稱附加到該頭像", + "Change persona image": "更改使用者角色圖片", + "Select this as default persona for the new chats.": "設定為新聊天的預設使用者角色", + "Delete persona": "刪除使用者角色", + "These characters are the winners of character design contests and have outstandable quality.": "這些角色都是角色設計比賽的優勝者,品質卓越。", + "Contest Winners": "比賽獲勝者", + "These characters are the finalists of character design contests and have remarkable quality.": "這些角色都是角色設計比賽的入圍作品,品質卓越。", + "Featured Characters": "特色角色", + "Attach a File": "上傳附件檔案", + "Open Data Bank": "開啟資料庫", + "Enter a URL or the ID of a Fandom wiki page to scrape:": "輸入 URL 或 Fandom 維基頁面的 ID 來抓取:", + "Examples:": "範例:", + "Example:": "範例:", + "Single file": "單個檔案", + "All articles will be concatenated into a single file.": "所有文章將連接成一個檔案。", + "File per article": "每篇文章一個檔案", + "Each article will be saved as a separate file.": "每篇文章將另存為一個檔案。", + "Data Bank": "資料庫", + "These files will be available for extensions that support attachments (e.g. Vector Storage).": "這些檔案將可用於支援附件的擴充功能(例如向量儲存)。", + "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.": "支援的檔案類型:純文字,PDF,Markdown,HTML,EPUB。", + "Drag and drop files here to upload.": "拖放檔案至此即可上傳。", + "Date (Newest First)": "日期(最新優先)", + "Date (Oldest First)": "日期(最舊優先)", + "Name (A-Z)": "名稱(A-Z)", + "Name (Z-A)": "名稱(Z-A)", + "Size (Smallest First)": "尺寸(由小到大)", + "Size (Largest First)": "尺寸(由大到小)", + "Bulk Edit": "批次編輯", + "Select All": "全選", + "Select None": "選擇無", + "Global Attachments": "全域附件", + "These files are available for all characters in all chats.": "適用於所有聊天、所有角色。", + "Character Attachments": "角色附件", + "These files are available the current character in all chats they are in.": "適用於該角色參與的所有聊天。", + "Saved locally. Not exported.": "僅本機儲存,不匯出。", + "Chat Attachments": "聊天附件", + "These files are available to all characters in the current chat.": "適用於本次聊天中的所有角色。", + "Enter a base URL of the MediaWiki to scrape.": "輸入要抓取的 MediaWiki 的基礎 URL。", + "Don't include the page name!": "不要包括頁面名稱!", + "Enter web URLs to scrape (one per line):": "輸入要抓取的網頁 URL(每行一個):", + "Enter a video URL to download its transcript.": "輸入影片 URL 來下載其文字記錄。", + "Expression API": "表達 API", + "Fallback Expression": "回退表達式", + "ext_sum_title": "聊天摘要", + "ext_sum_with": "摘要來源", + "ext_sum_main_api": "主要 API", + "ext_sum_current_summary": "摘要內容:", + "ext_sum_restore_previous": "還原為上一則", + "ext_sum_memory_placeholder": "將在此生成摘要⋯", + "Trigger a summary update right now.": "立即更新摘要內容。", + "ext_sum_force_text": "重新摘要", + "Disable automatic summary updates. While paused, the summary remains as-is. You can still force an update by pressing the Summarize now button (which is only available with the Main API).": "停用自動摘要更新。暫停時,摘要保持原樣。您仍可以透過點選「重新摘要」按鈕強制更新(僅適用於使用「主要 API」)。", + "ext_sum_pause": "暫停", + "Omit World Info and Author's Note from text to be summarized. Only has an effect when using the Main API. The Extras API always omits WI/AN.": "摘要時將省略世界資訊和作者備註。此選項僅適用於使用主要 API,擴充功能 API 始終自動省略世界資訊與作者備註。", + "ext_sum_no_wi_an": "排除世界資訊及作者備註", + "ext_sum_settings_tip": "編輯摘要提示、插入位置等", + "ext_sum_settings": "摘要設定", + "ext_sum_prompt_builder": "摘要提示詞產生器", + "ext_sum_prompt_builder_1_desc": "將使用尚未摘要的訊息以建立摘要提示詞,在完成摘要前將暫停聊天功能。", + "ext_sum_prompt_builder_1": "原始、阻塞", + "ext_sum_prompt_builder_2_desc": "將使用尚未摘要的訊息自動建立摘要提示詞,在完成摘要前仍可正常進行聊天。並非所有後端都支援此模式。", + "ext_sum_prompt_builder_2": "原始、非阻塞", + "ext_sum_prompt_builder_3_desc": "將使用常規主提示產生器,並將摘要請求新增至其中作為最後一則系統訊息。", + "ext_sum_prompt_builder_3": "經典、阻塞", + "Summary Prompt": "摘要提示詞", + "ext_sum_restore_default_prompt_tip": "還原為預設提示詞", + "ext_sum_prompt_placeholder": "此提示詞將傳送給 AI 以請求生成摘要。{{words}} 將解析為「字數」參數。", + "ext_sum_target_length_1": "目標摘要長度", + "ext_sum_target_length_2": "(", + "ext_sum_target_length_3": "字)", + "ext_sum_api_response_length_1": "API 響應長度", + "ext_sum_api_response_length_2": "(", + "ext_sum_api_response_length_3": "個符元)", + "ext_sum_0_default": "0 = 預設", + "ext_sum_raw_max_msg": "[原始] 每則請求的最大訊息數", + "ext_sum_0_unlimited": "0 = 無限制", + "Update frequency": "更新頻率", + "ext_sum_update_every_messages_1": "更新每", + "ext_sum_update_every_messages_2": " 訊息", + "ext_sum_0_disable": "0 = 停用", + "ext_sum_auto_adjust_desc": "嘗試根據聊天指標自動調整更新間隔。", + "ext_sum_update_every_words_1": "更新每", + "ext_sum_update_every_words_2": " 字", + "ext_sum_both_sliders": "若兩個滑桿數值皆不為零,則將各自按照其時間間隔更新摘要。", + "ext_sum_injection_template": "插入範本", + "ext_sum_memory_template_placeholder": "{{summary}} 會解析為目前的摘要內容。", + "ext_sum_injection_position": "插入位置", + "How many messages before the current end of the chat.": "距離本次聊天結尾前的訊息數量。", + "ext_regex_title": "正規表示式", + "ext_regex_new_global_script": "+ 全域", + "ext_regex_new_scoped_script": "+ 區域", + "ext_regex_import_script": "匯入腳本", + "ext_regex_global_scripts": "全域腳本", + "ext_regex_global_scripts_desc": "適用於所有角色,資料將儲存到本機。", + "ext_regex_scoped_scripts": "區域腳本", + "ext_regex_scoped_scripts_desc": "僅適用於目前角色,資料將儲存到該角色卡中。", + "Regex Editor": "正規表示式編輯器", + "Test Mode": "測試模式", + "ext_regex_desc": "正規表示式(Regex)是一種使用正規表示式尋找/取代字串的工具。如果您想了解更多,請點選標題旁邊的「?」", + "Input": "輸入", + "ext_regex_test_input_placeholder": "在此輸入⋯", + "Output": "輸出", + "ext_regex_output_placeholder": "空的", + "Script Name": "腳本名稱", + "Find Regex": "尋找正規表示式", + "Replace With": "取代為", + "ext_regex_replace_string_placeholder": "使用 {{match}} 來包含來自尋找正規表示式的匹配文字或 $1、$2 等捕獲組。", + "Trim Out": "修剪掉", + "ext_regex_trim_placeholder": "在取代之前,全域修剪正規表示式匹配中的任何不需要的部分。每個元素用輸入鍵分隔。", + "ext_regex_affects": "影響物件", + "ext_regex_user_input": "使用者輸入", + "ext_regex_ai_output": "AI 輸出", + "Slash Commands": "斜線命令", + "ext_regex_min_depth_desc": "當應用於提示或顯示時,僅影響至少 N 層深的訊息。0 = 最後一則訊息,1 = 倒數第二個訊息等。", + "Min Depth": "最小深度", + "ext_regex_min_depth_placeholder": "無限制", + "ext_regex_max_depth_desc": "當應用於提示或顯示時,僅影響不超過 N 層深度的訊息。0 = 最後一則訊息,1 = 倒數第二個訊息等。", + "ext_regex_other_options": "其他選項", + "Only Format Display": "僅修改聊天顯示", + "ext_regex_only_format_prompt_desc": "不修改聊天記錄,僅修改傳送訊息(請求文字生成時)時的系統提示詞。", + "Only Format Prompt (?)": "僅修改系統提示詞", + "Run On Edit": "編輯時執行", + "ext_regex_substitute_regex_desc": "在執行「尋找正規表達式」前,將 {{macros}}(巨集)替換為對應內容", + "Substitute Regex": "取代正規表示式", + "ext_regex_import_target": "匯入至:", + "ext_regex_disable_script": "停用腳本", + "ext_regex_enable_script": "啟用腳本", + "ext_regex_edit_script": "編輯腳本", + "ext_regex_move_to_global": "移至全域腳本", + "ext_regex_move_to_scoped": "移至區域腳本", + "ext_regex_export_script": "匯出腳本", + "ext_regex_delete_script": "刪除腳本", + "Trigger Stable Diffusion": "觸發 Stable Diffusion", + "sd_Yourself": "角色", + "sd_Your_Face": "角色的臉", + "sd_Me": "使用者", + "sd_The_Whole_Story": "整篇故事", + "sd_The_Last_Message": "最後一則訊息", + "sd_Raw_Last_Message": "最後一則原始訊息", + "sd_Background": "背景", + "Image Generation": "圖片生成設定", + "sd_refine_mode": "允許在傳送至生成 API 前,手動編輯提示詞字串", + "sd_refine_mode_txt": "生成前編輯提示詞", + "sd_interactive_mode": "當傳送「給我一張貓的圖片」這類訊息時,自動生成圖片。", + "sd_interactive_mode_txt": "互動模式", + "sd_multimodal_captioning": "根據使用者和角色的頭像,使用多模態模型描述生成肖像提示詞。", + "sd_multimodal_captioning_txt": "對肖像使用多模態模型描述", + "sd_expand": "使用文字生成模型自動擴寫提示詞。", + "sd_expand_txt": "自動潤飾提示詞", + "sd_snap": "對於具有特定長寬比的生成請求(如肖像、背景),將其調整至最接近的已知解析度,同時儘量保持絕對像素數(建議用於 SDXL)。", + "sd_snap_txt": "自動調整解析度", + "Source": "來源", + "sd_auto_url": "範例:{{auto_url}}", + "Authentication (optional)": "授權驗證(選填)", + "Example: username:password": "範例:帳號:密碼", + "Important:": "重要:", + "sd_auto_auth_warning_1": "使用", + "sd_auto_auth_warning_2": "旗標執行 SD Web UI!伺服器必須能夠被 SillyTavern 主機存取。", + "sd_drawthings_url": "範例:{{drawthings_url}}", + "sd_drawthings_auth_txt": "執行 DrawThings 應用程式並在介面中啟用 HTTP API 開關!伺服器必須能夠被 SillyTavern 主機存取。", + "sd_vlad_url": "範例:{{vlad_url}}", + "The server must be accessible from the SillyTavern host machine.": "伺服器必須能夠被 SillyTavern 主機存取。", + "Hint: Save an API key in AI Horde API settings to use it here.": "提示訊息:在 AI Horde API 設定中儲存一個 API 金鑰,以便在此使用。", + "Allow NSFW images from Horde": "允許來自 Horde 的 NSFW 圖片", + "Sanitize prompts (recommended)": "清理提示詞(建議)", + "Automatically adjust generation parameters to ensure free image generations.": "自動調整生成參數以確保生成免費的圖片。", + "Avoid spending Anlas": "避免消耗 Anlas 點數", + "Opus tier": "Opus 級別", + "View my Anlas": "檢視我的 Anlas 點數", + "These settings only apply to DALL-E 3": "此設定僅會套用在 DALL-E 3", + "Image Style": "圖片樣式", + "Image Quality": "圖片品質", + "Standard": "標準", + "HD": "高畫質", + "sd_comfy_url": "範例:{{comfy_url}}", + "Open workflow editor": "開啟 workflow 編輯器", + "Create new workflow": "建立新的 workflow", + "Delete workflow": "刪除 workflow", + "Enhance": "增強", + "Refine": "精煉", + "Decrisper": "德克里斯珀", + "Sampling steps": "取樣步數", + "Width": "寬度(Width)", + "Height": "高度(Height)", + "Resolution": "解析度", + "Model": "模型", + "Sampling method": "取樣方法", + "Karras (not all samplers supported)": "Karras(並非所有取樣器均受支援)", + "SMEA versions of samplers are modified to perform better at high resolution.": "SMEA 版本的取樣器經過修改,能在高解析度下表現更佳。", + "SMEA": "SMEA", + "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "SMEA 取樣器的 DYN 變體通常會產生更多樣化的輸出,但在非常高的解析度下可能會失敗。", + "DYN": "DYN", + "Scheduler": "排程器", + "Restore Faces": "修復臉部", + "Hires. Fix": "高解析度修正", + "Upscaler": "放大演演算法", + "Upscale by": "放大倍率", + "Denoising strength": "重繪幅度", + "Hires steps (2nd pass)": "高解析步驟(2nd pass)", + "Preset for prompt prefix and negative prompt": "提示詞前綴和負面提示詞的預設設定檔", + "Style": "樣式", + "Save style": "儲存樣式", + "Delete style": "刪除樣式", + "Common prompt prefix": "通用提示詞前綴", + "sd_prompt_prefix_placeholder": "使用 {prompt} 指定生成的提示詞將被插入的位置。", + "Negative common prompt prefix": "通用負面提示詞前綴", + "Character-specific prompt prefix": "角色提示詞前綴", + "Won't be used in groups.": "群聊中無效", + "sd_character_prompt_placeholder": "描述該角色的特徵。這些特徵將新增在通用提示詞前綴之後。例如:女性、綠色眼睛、棕色頭髮、粉紅色襯衫。", + "Character-specific negative prompt prefix": "角色負面提示詞前綴", + "sd_character_negative_prompt_placeholder": "不應出現在該角色上的任何特徵。這些特徵將新增在負面通用提示詞前綴之後。例如:珠寶、鞋子、眼鏡。", + "Shareable": "分享至角色卡", + "Image Prompt Templates": "圖片生成提示詞", + "Vectors Model Warning": "向量模型警告", + "Translate files into English before processing": "處理前將檔案翻譯成英文", + "Manager Users": "管理使用者", + "New User": "新使用者", + "Status:": "狀態:", + "Created:": "建立於:", + "Display Name:": "顯示名稱:", + "User Handle:": "使用者控制程式碼:", + "Password:": "密碼:", + "Confirm Password:": "確認密碼:", + "This will create a new subfolder...": "這將建立一個新的子資料夾⋯", + "Current Password:": "目前密碼:", + "New Password:": "新密碼:", + "Confirm New Password:": "確認新密碼:", + "Debug Warning": "偵錯警告", + "Execute": "執行", + "Are you sure you want to delete this avatar?": "您確定要刪除使用者嗎?", + "Deleting:": "刪除中:", + "Also wipe user data.": "同時清除使用者資料。", + "Warning:": "警告:", + "This action is irreversible.": "此動作不可逆轉。", + "Type the user's handle below to confirm:": "在下方輸入使用者的控制程式碼以確認:", + "Import Characters": "匯入角色", + "Enter the URL of the content to import": "輸入要匯入的內容的 URL", + "Supported sources:": "支援的來源:", + "char_import_1": "Chub 角色(直接連結或 ID)", + "char_import_example": "例子:", + "char_import_2": "Chub Lorebook(直接連結或 ID)", + "char_import_3": "JanitorAI 角色(直接連結或 ID)", + "char_import_4": "Pygmalion.chat 角色(直接連結或 ID)", + "char_import_5": "AICharacterCards.com 角色(直接連結或 ID)", + "char_import_6": "直接 PNG 連結(請參閱", + "char_import_7": "對於允許的主機)", + "char_import_8": "RisuRealm 角色(直接連結)", + "Supports importing multiple characters.": "支援匯入多個字元。", + "Write each URL or ID into a new line.": "將每個 URL 或 ID 寫入新行。", + "Export for character": "匯出字元", + "Export prompts for this character, including their order.": "匯出該角色的提示,包括其順序。", + "Export all": "全部匯出", + "Export all your prompts to a file": "將所有提示匯出到文件", + "Insert prompt": "插入提示", + "Delete prompt": "刪除提示", + "Import a prompt list": "匯入提示列表", + "Export this prompt list": "匯出此提示列表", + "Reset current character": "重設目前字元", + "New prompt": "新提示", + "Prompts": "提示", + "Total Tokens:": "代幣總數:", + "prompt_manager_tokens": "代幣", + "Are you sure you want to reset your settings to factory defaults?": "您確定要將設定重設為原廠預設值嗎?", + "Don't forget to save a snapshot of your settings before proceeding.": "在繼續之前,請不要忘記進行備份。", + "Settings Snapshots": "設定備份", + "Record a snapshot of your current settings.": "記錄目前設定的快照。", + "Make a Snapshot": "建立快照", + "Restore this snapshot": "還原此快照", + "Hi,": "嗨,", + "To enable multi-account features, restart the SillyTavern server with": "要啟用多帳號功能,請在 config.yaml 文件中將", + "set to true in the config.yaml file.": "設為 true 後重啟 SillyTavern 伺服器。", + "Account Info": "帳號資訊", + "To change your user avatar, use the buttons below or select a default persona in the Persona Management menu.": "要更改您的使用者頭像,請使用下方按鈕或在使用者角色管理選單中選擇一個預設人物。", + "Set your custom avatar.": "設定您的頭像。", + "Remove your custom avatar.": "移除您的頭像。", + "Handle:": "使用者名稱:", + "This account is password protected.": "這個帳號受到密碼保護。", + "This account is not password protected.": "這個帳號並未受到密碼保護。", + "Account Actions": "帳號動作", + "Change Password": "變更密碼", + "Manage your settings snapshots.": "管理您的設定值快照。", + "Download a complete backup of your user data.": "下載您的完整使用者備份。", + "Download Backup": "下載備份", + "Danger Zone": "危險區域", + "Reset your settings to factory defaults.": "將您的設定值還原為原廠預設值。", + "Reset Settings": "重設設定值", + "Wipe all user data and reset your account to factory settings.": "刪除您所有的使用者設定以及帳號資料,並恢復為系統預設值。", + "Reset Everything": "刪除所有資料", + "Reset Code:": "重設驗證碼:", + "Want to update?": "想更新到最新版嗎?", + "How to start chatting?": "如何開始聊天?", + "Click _space": "點選", + "and select a": "並擇一", + "Chat API": "聊天 API", + "and pick a character.": "並選擇一個角色。", + "You can browse a list of bundled characters in the": "您可以在", + "Download Extensions & Assets": "下載擴充功能&額外資源", + "menu within": "選單中瀏覽內建角色列表", + "Confused or lost?": "困惑或迷路了嗎?", + "click these icons!": "點選這些圖示!", + "in the chat bar": "到聊天欄中", + "SillyTavern Documentation Site": "SillyTavern 文件網站", + "Extras Installation Guide": "Extras 安裝指南", + "Still have questions?": "仍有更多問題?", + "Join the SillyTavern Discord": "加入 SillyTavern Discord", + "Post a GitHub issue": "發布 GitHub 問題", + "Contact the developers": "聯絡開發者", + "(-1 for random)": "(-1 表示隨機)", + "(Optional)": "(可選)", + "(use _space": "(使用", + "api_no_connection": "未連線⋯", + "No model description": "[無描述]", + "openai_logit_bias_no_items": "無項目", + "Any contents here will replace the default Post-History Instructions used for this character. (v2 specpost_history_instructions)": "此處填入的內容將取代該角色的預設聊天歷史後指示(Post-History Instructions)。\n(v2 格式:specpost_history_instructions)", + "comma delimited,no spaces between": "逗號分割,無需空格", + "e.g. black-forest-labs/FLUX.1-dev": "例如:black-forest-labs/FLUX.1-dev", + "Example: gpt-4o": "例如:gpt-4o", + "Example: http://localhost:1234/v1": "例如:http://localhost:1234/v1", + "popup-button-crop": "裁剪", + "(disabled when max recursion steps are used)": "(當最大遞迴步驟數使用時將停用)", + "A greedy, brute-force algorithm used in LLM sampling to find the most likely sequence of words or tokens. It expands multiple candidate sequences at once, maintaining a fixed number (beam width) of top sequences at each step.": "一種用於 LLM 抽樣的貪婪演演算法,用於尋找最可能的單詞或標記序列。該方法會同時展開多個候選序列,並在每一步中保持固定數量的頂級序列(beam width)。", + "A multiplicative factor to expand the overall area that the nodes take up.": "節點佔用該擴充功能區域的倍數。", + "Abort current image generation task": "終止目前的圖片生成任務", + "Add Character and User names to a list of stopping strings.": "將角色和使用者角色名稱新增至停止字元列表。", + "Alignment for rank nodes.": "對排名節點的對齊方式。", + "Always show the node full info panel at the bottom left of the timeline view. When off, show it near the node.": "始終將節點的完整資訊面板顯示在時間軸檢視的左下角。關閉時,將顯示在節點附近。", + "Always show the node tooltip at the bottom left of the timeline view. When off, show it near the node.": "始終將節點的工具提示欄顯示在時間軸檢視的左下角。關閉時,將顯示在節點附近。", + "Apply current sorting as Order": "應用此排序為順序", + "Cap the number of entry activation recursions": "限制入口啟動的遞迴次數", + "Caption": "標題", + "Close popup": "關閉彈出視窗", + "Color configuration for Timelines when 'Use UI Theme' in Style Settings is off.": "關閉「使用介面主題」的時間線顏色。", + "context_allow_post_history_instructions": "在文字完成模式中包含聊天歷史後指示(Post-History Instructions),但可能導致不良輸出。", + "Create a new connection profile": "建立新的連線設定檔", + "Defines on importing cards which action should be chosen for importing its listed tags. 'Ask' will always display the dialog.": "定義匯入角色卡時應採取的動作。選擇「詢問」將始終顯示對話框。", + "delay_until_recursion_level": "定義遞迴掃描的延遲層級。\r最初僅匹配第一層(數字最小的層級)。\r未找到匹配時,下一層將成為可匹配的層級。\r此過程會重複,直到所有層級都被檢查完畢。\r與「延遲至遞迴」設定相關聯。", + "Delete a connection profile": "刪除連線設定檔", + "Delete template": "刪除範本", + "Delete the template": "刪除此範本", + "Disabling is not recommended.": "不建議停用。", + "Display swipe numbers for all messages, not just the last.": "顯示所有訊息的滑動編號,而不僅是最後一條訊息。", + "Duplicate persona": "複製使用者角色", + "Edit a connection profile": "編輯連線設定檔", + "Enable auto-select of input text in some text fields when clicking/selecting them. Applies to popup input textboxes, and possible other custom input fields.": "啟用自動選擇輸入框中的文字,適用於彈出輸入框及其他自定義輸入框。", + "Entries with a cooldown can't be activated N messages after being triggered.": "設有冷卻時間的條目於觸發後的 N 條訊息內無法再次啟用。", + "Entries with a delay can't be activated until there are N messages present in the chat.": "有延遲的條目需等待聊天中出現 N 條訊息後才能啟用。", + "Expand swipe nodes when the timeline view first opens, and whenever the graph is refreshed. When off, you can expand them by long-pressing a node, or by pressing the Toggle Swipes button.": "時間線檢視首次開啟或重新整理時展開滑動節點。關閉時可透過長按節點或點選「切換滑動」按鈕展開。", + "Export Advanced Formatting settings": "匯出進階格式設定", + "Export template": "匯出範本", + "Find similar characters": "尋找相似角色", + "Height of a node, in pixels at zoom level 1.0.": "縮放等級為 1.0 時的節點像素高度。", + "How the automatic graph builder assigns a rank (layout depth) to graph nodes.": "自動圖表生成器分配圖節點等級(配置深度)的方式。", + "If checked and the character card contains a Post-History Instructions override, use that instead": "勾選後,將使用角色卡中的聊天歷史後指示(Post-History Instructions)覆蓋。", + "Import Advanced Formatting settings": "匯入進階格式設定\n也可提供舊版檔案作為提示詞和上下文範本使用", + "Import template": "匯入範本", + "In group chat, highlight the character(s) that are currently queued to generate responses and the order in which they will respond.": "在群組聊天中,突出顯示該生成回應的角色及順序。", + "Include names with each message into the context for scanning": "將每條訊息的名稱納入掃描上下文", + "Inserted before the first User's message": "插入到第一條使用者訊息前。", + "instruct_enabled": "啟用指令模式(Instruct Mode)", + "instruct_last_input_sequence": "插入到最後一條使用者訊息之前。", + "instruct_template_activation_regex_desc": "連線 API 或選擇模型時,若模型名稱符合所提供的正規表達式,則自動啟動該指令範本(Instruct Template)。", + "Load Asset List": "載入資源列表", + "load_asset_list_desc": "根據資源列表文件載入擴充功能及資源。\n\n該欄位中的預設資源 URL 指向官方擴充功能及資源列表。\n可在此插入您的自定義資源列表。\n\n若需安裝單個第三方擴充功能,請使用右上角的「安裝擴充功能」按鈕。", + "markdown_hotkeys_desc": "啟用快捷鍵以在某些文字輸入框中插入 Markdown 格式字元。詳見「/help hotkeys」。", + "Not all samplers supported.": "並非所有取樣器均受支援。", + "Open the timeline view. Same as the slash command '/tl'.": "開啟時間線檢視,與斜線指令「/tl」相同。", + "Penalize sequences based on their length.": "根據序列長度進行懲罰。", + "Reload a connection profile": "重新載入連線設定檔", + "Rename current preset": "重新命名此預設設定檔", + "Rename current prompt": "重新命名此提示詞", + "Rename current template": "重新命名此範本", + "Reset all Timelines settings to their default values.": "將所有時間軸設定重設為預設值。", + "Restore current prompt": "還原目前的提示詞", + "Restore current template": "還原目前的範本", + "Save prompt as": "另存提示詞為", + "Save template as": "另存範本為", + "sd_adetailer_face": "在生成過程中使用 ADetailer 臉部模型。需在後端安裝 ADetailer 擴充功能。", + "sd_free_extend": "自動使用目前選定的 LLM 擴充功能的「自由模式」提示詞(不包括肖像或背景)。", + "sd_function_tool": "使用功能工具自動偵測意圖以生成圖片。", + "Seed_desc": "用於生成確定性和可重現輸出的隨機種子。設定為 -1 時將使用隨機種子。", + "Select your current Context Template": "選擇您目前的上下文範本", + "Select your current Instruct Template": "選擇您目前的指令範本", + "Select your current System Prompt": "選擇您目前的系統提示詞", + "Separation between adjacent edges in the same rank.": "同一層級中相鄰邊之間的間距。", + "Separation between adjacent nodes in the same rank.": "同一層級中相鄰節點之間的間距。", + "Separation between each rank in the layout.": "配置中各層級之間的間距。", + "Settings for the visual appearance of the Timelines graph.": "時間線圖形的視覺外觀設定。", + "Show a button in the input area to ask the AI to impersonate your character for a single message": "於輸入框中新增按鈕,讓 AI 模仿您的角色傳送一則訊息。", + "Show a legend for colors corresponding to different characters and chat checkpoints.": "顯示一個圖例,標註不同角色和對話檢查點對應的顏色。", + "Show the AI character's avatar as the graph root node. When off, the root node is blank.": "將 AI 角色的頭像作為圖形的根節點;關閉時,根節點為空。", + "Sticky entries will stay active for N messages after being triggered.": "觸發後,置頂條目將在接下來的 N 條訊息中保持活躍。", + "stscript_parser_flag_replace_getvar_label": "防止 {{getvar::}} 和 {{getglobalvar::}} 巨集的字面巨集樣值被自動解析。\n例如,{{newline}} 將保持為字面字串 {{newline}}。\n\n(此功能透過內部將 {{getvar::}} 和 {{getglobalvar::}} 巨集替換為區域變數來實現。)", + "Style and routing of graph edges.": "圖形邊的樣式和路徑。", + "Swap width and height": "交換寬度與高度", + "Swipe left": "向左滑動", + "Swipe right": "向右滑動", + "Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry": "切換角色/標籤篩選,將列出的角色和標籤從此條目的匹配中排除", + "sysprompt_enabled": "啟用系統提示詞", + "The number of sequences generated at each step with Beam Search.": "在 Beam Search 中每一步生成的序列數量。", + "The visual appearance of a node in the graph.": "圖形中節點的視覺外觀。", + "Update a connection profile": "更新連線設定檔", + "Update current prompt": "更新此提示詞", + "Update current template": "更新此範本", + "Use GPU acceleration for positioning the full info panel that appears when you click a node. If the tooltip arrow tends to disappear, turning this off may help.": "啟用 GPU 加速來定位點選節點時出現的完整資訊面板。若發現工具提示箭頭經常消失,可考慮關閉此功能。", + "Use the colors of the ST GUI theme, instead of the colors configured in Color Settings specifically for this extension.": "使用使用者設定中的介面主題顏色,取代下方「顏色設定」中額外設定的顏色。", + "View connection profile details": "檢視連線設定檔詳細資訊", + "When enabled, nodes that have swipes splitting off of them will appear subtly larger, in addition to having the double border.": "啟用後,具分支滑動的節點將顯示雙重邊框,還會略微放大。", + "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized": "世界資訊條目狀態:\\r🔵 恆定\\r🟢 正常\\r🔗 向量化", + "Width of a node, in pixels at zoom level 1.0.": "縮放等級為 1.0 時,節點的像素寬度。", + "world_button_title": "角色背景設定\n「Shift+點選」可開啟「連結至世界資訊」彈窗", + "# of Beams": "# of Beams", + "01.AI API Key": "01.AI API 金鑰", + "01.AI Model": "01.AI 模型", + "Additional Parameters": "其他參數", + "All": "全部", + "Allow fallback models": "允許回退模型", + "Allow fallback providers": "允許回退供應商", + "Allow Post-History Instructions": "允許聊天歷史後指示", + "Allow reverse proxy": "允許反向代理", + "Alternate Greeting #": "備選問候語 #", + "alternate_greetings_hint_1": "點選", + "alternate_greetings_hint_2": "按鈕開始!", + "Always": "總是", + "ANY support requests will be REFUSED if you are using a proxy.": "使用代理時,所有支援請求均不予受理。", + "API": "API", + "API Key": "API 金鑰", + "Ask": "詢問", + "Ask every time": "每次都詢問", + "Assets URL": "資源 URL", + "Assistant Message Sequences": "助理訊息序列", + "Assistant Prefix": "助理訊息前綴", + "Assistant Suffix": "助理訊息後綴", + "Audio Playback Speed": "音檔播放速度", + "Auto-select Input Text": "自動選擇輸入文字", + "Automatically caption images": "自動產生圖片註解", + "Auxiliary": "輔助提示詞", + "Background Image": "背景圖片", + "Block Entropy API Key": "Block Entropy API 金鑰", + "Can be set manually or with an _space": "可以手動設定或使用 _space", + "Caption Prompt": "註解功能提示詞", + "category": "類別", + "Character Expressions": "角色情緒立繪", + "Character Node Color": "角色節點顏色", + "character_names_none": "避免使用角色名稱作為前綴。此功能在群組中可能表現不理想,需謹慎考慮。", + "Characters": "角色", + "Chat Message Visibility (by source)": "聊天訊息可見性(按來源)", + "Chat vectorization settings": "聊天向量化設定", + "Checked: all entries except ❌ status can be activated.": "勾選:除 ❌ 狀態外的所有條目均可啟動。", + "Checkpoint Color": "檢查點節點邊框顏色", + "Chunk boundary": "Chunk 邊界", + "Chunk overlap (%)": "Chunk 重疊(%)", + "Chunk size (chars)": "Chunk 大小(字元數)", + "class": "所有類別", + "Classifier API": "分類器 API", + "Click to set": "點選以設定", + "CLIP Skip": "CLIP 跳過", + "Completion Object": "完成物件", + "Conf": "設定檔", + "Connection Profile": "連線設定檔", + "Cooldown": "冷卻時間", + "Create new folder in the _space": "請在「SillyTavern/data/使用者資料夾", + "currently_loaded": "[目前已載入]", + "currently_selected": "[目前已選取]", + "Custom (OpenAI-compatible)": "自定義(相容 OpenAI)", + "Custom Expressions": "自定義角色表情", + "Data Bank files": "資料庫文件", + "Default / Fallback Expression": "預設/回退表情", + "Delay": "延遲", + "Delay until recursion (can only be activated on recursive checking)": "遞迴掃描延遲(僅在啟用遞迴掃描時可用)", + "Do not proceed if you do not agree to this!": "若不同意此條款,請勿繼續!", + "Edge Color": "邊緣顏色", + "Edit captions before saving": "在儲存前編輯註解", + "Enable for files": "啟用文件檔案向量化", + "Enable for World Info": "啟用世界資訊向量化", + "enable_functions_desc_1": "允許使用", + "enable_functions_desc_2": "功能工具", + "enable_functions_desc_3": "可供多種擴充功能利用,實現更多功能。", + "Enabled for all entries": "對所有條目啟用", + "Enabled for chat messages": "啟用聊天訊息向量化", + "Endpoint URL": "端點 URL", + "Enter a Model ID": "輸入模型 ID", + "Example: https://****.endpoints.huggingface.cloud": "例如:https://****.endpoints.huggingface.cloud", + "Exclude": "排除", + "Exclude Top Choices (XTC)": "排除頂端選項(XTC)", + "tag_import_existing": "現有項目", + "expression_label_pattern": "[情緒名稱].[圖檔格式](例如:neutral.png)。", + "ext_translate_auto_mode": "自動翻譯模式", + "ext_translate_btn_chat": "翻譯聊天內容", + "ext_translate_btn_input": "翻譯輸入內容", + "ext_translate_clear": "清除翻譯", + "ext_translate_mode_both": "翻譯輸入和回應", + "ext_translate_mode_inputs": "僅翻譯輸入", + "ext_translate_mode_none": "無翻譯", + "ext_translate_mode_provider": "翻譯提供者", + "ext_translate_mode_responses": "僅翻譯回應", + "ext_translate_target_lang": "目標語言", + "ext_translate_title": "聊天翻譯", + "Extensions Menu": "擴充功能選單", + "Extras": "擴充功能", + "Extras API": "擴充功能 API", + "Featherless Model Selection": "Featherless 模型選擇", + "File vectorization settings": "檔案向量化設定", + "Filter to Characters or Tags": "角色/標籤篩選", + "First User Prefix": "第一使用者前綴", + "folder of your user data directory and name it as the name of the character.": "」中新增資料夾,並將該資料夾命名為角色名稱(名稱需與使用者資料夾中的角色名稱一致)。", + "Group Scoring": "群組評分", + "Groups and Past Personas": "群組與過去的使用者角色設定", + "Hint:": "提示:", + "Hint: Set the URL in the API connection settings.": "提示:在 API 連線設定中設定 URL。", + "Horde": "Horde", + "HuggingFace Token": "HuggingFace 符元", + "Image Captioning": "圖片註解", + "Generate Caption": "產生圖片註解", + "Injection Position": "插入位置", + "Injection position. Relative (to other prompts in prompt manager) or In-chat @ Depth.": "插入位置(與提示詞管理器中的其他提示相比)或聊天中的深度位置。", + "Injection Template": "插入範本", + "Insert#": "插入#", + "Instruct Sequences": "指令序列", + "Instruct Template": "指令範本", + "Interactive Mode": "互動模式", + "Karras": "Karras", + "Keep model in memory": "將模型儲存在記憶體中", + "Keyboard": "鍵盤:", + "AI Horde Website": "AI Horde 網站", + "Last User Prefix": "最後使用者前綴", + "Linear": "線性", + "LLM": "LLM", + "LLM Prompt": "LLM 提示詞", + "Load a custom asset list or select": "載入或選擇自定義資源列表", + "Load an asset list": "載入資源列表", + "Local": "本機", + "Local (Transformers)": "本機(Transformers)", + "macro)": "巨集)", + "Main API": "主要 API", + "Markdown Hotkeys": "Markdown 快捷鍵", + "Master Export": "進階匯出", + "Master Import": "進階匯入", + "Max Entries": "最大條目數", + "Max Recursion Steps": "最大遞迴步數", + "Message attachments": "訊息附件", + "Message Template": "訊息範本", + "Model ID": "模型 ID", + "mui_reset": "重設", + "Multimodal (OpenAI / Anthropic / llama / Google)": "多模態(OpenAI/Anthropic/llama/Google)", + "must be set in Tabby's config.yml to switch models.": "須在 Tabby's config.yml 中設定以切換模型。", + "Names as Stop Strings": "將名稱用作停止字串", + "Never": "從不", + "NomicAI API Key": "NomicAI API 金鑰", + "Non-recursable (will not be activated by another)": "不可遞迴(不會被其他條目啟動)", + "None (disabled)": "無(已停用)", + "OK": "確定", + "Old messages are vectorized gradually as you chat. To process all previous messages, click the button below.": "舊訊息會在聊天時逐步向量化。\n若要處理所有先前訊息,請點選下方按鈕。", + "Only used when Main API or WebLLM Extension is selected.": "僅在選擇主要 API 或 WebLLM 擴充功能時使用。", + "Open a chat to see the character expressions.": "開啟聊天以檢視角色表情。", + "Post-History Instructions": "聊天歷史後指示", + "Prefer Character Card Instructions": "角色卡聊天歷史後指示優先", + "Prioritize": "優先處理", + "Prompt Content": "提示詞內容", + "prompt_manager_in_chat": "聊天中的提示詞管理", + "prompt_post_processing_none": "無", + "Purge Vectors": "清除向量", + "Put images with expressions there. File names should follow the pattern:": "將表情立繪放置於此,檔案名稱應遵循以下格式:", + "Quad": "四元數", + "Query messages": "查詢訊息", + "Quick Impersonate button": "快速模擬按鈕", + "Recursion Level": "遞迴層級", + "Remove all image overrides": "移除所有圖片覆蓋", + "Restore default": "恢復預設", + "Retain#": "保留#", + "Retrieve chunks": "檢索 Chunks", + "Sampler Order": "取樣順序", + "Score threshold": "分數閾值", + "sd_free_extend_small": "(互動/指令)", + "sd_free_extend_txt": "使用「自由模式」。由 LLM 自動擴寫圖片生成提示", + "sd_function_tool_txt": "使用功能工具", + "sd_prompt_-1": "聊天訊息範本", + "sd_prompt_-2": "功能工具提示詞", + "sd_prompt_0": "角色(第二人稱,你)", + "sd_prompt_1": "使用者(第一人稱,我)", + "sd_prompt_10": "肖像(多模態模式)", + "sd_prompt_11": "自由模式(由 LLM 自動擴寫)", + "sd_prompt_2": "場景(擷取場景資訊)", + "sd_prompt_3": "原始最後訊息", + "sd_prompt_4": "最後訊息", + "sd_prompt_5": "肖像(第二人稱,你)", + "sd_prompt_7": "背景", + "sd_prompt_8": "角色(多模態模式)", + "sd_prompt_9": "使用者(多模態模式)", + "Select a Model": "選擇模型", + "Select the API for classifying expressions.": "選擇分類表情的 API。", + "Select with Enter": "按 Enter 選擇", + "Select with Tab": "按 Tab 選擇", + "Select with Tab or Enter": "按 Tab 或 Enter 選擇", + "Separators as Stop Strings": "以分隔符號作為停止字串", + "Set the default and fallback expression being used when no matching expression is found.": "設定在無法配對表情時所使用的預設表情和備用圖片。", + "Set your API keys and endpoints in the API Connections tab first.": "請先在「API 連線」頁面中設定您的 API 金鑰和端點。", + "Show default images (emojis) if sprite missing": "無對應圖片時,顯示為預設表情符號(emoji)", + "Show group chat queue": "顯示群組聊天佇列", + "Size threshold (KB)": "大小閾值(KB)", + "Slash Command": "斜線命令", + "space_ slash command.": " 斜線命令。", + "Sprite Folder Override": "表情立繪資料夾覆蓋", + "Sprite set:": "立繪組:", + "Show Gallery": "檢視相簿", + "Sticky": "黏性", + "Style Preset": "樣式預設設定檔", + "Summarize chat messages for vector generation": "摘要聊天訊息以進行向量化處理", + "Summarize chat messages when sending": "傳送時摘要聊天內容", + "Swipe # for All Messages": "為所有訊息分配滑動編號 #", + "System Message Sequences": "系統訊息序列", + "System Prefix": "系統訊息前綴", + "System Prompt Sequences": "系統提示詞序列", + "System Suffix": "系統訊息後綴", + "Tabby Model": "Tabby 模型", + "tag_import_all": "全部匯入", + "tag_import_none": "不匯入", + "Text Generation WebUI (oobabooga)": "文字生成 WebUI (oobabooga)", + "The server MUST be started with the --embedding flag to use this feature!": "若要使用此功能,伺服器必須啟動時加上 --embedding 象徵。", + "Threshold": "閾值", + "to install 3rd party extensions.": "用於安裝第三方擴充功能。", + "Top": "頂端", + "Translate text to English before classification": "分類前,將訊息翻譯為英文", + "Uncheck to hide the extensions messages in chat prompts.": "不勾選即可隱藏聊天提示詞中的擴充功能訊息。", + "Unchecked: only entries with ❌ status can be activated.": "未勾選時:僅允許啟用狀態為 ❌ 的條目。", + "Unified Sampling": "統一取樣(Unified Sampling)", + "Upload sprite pack (ZIP)": "批次上傳立繪包(.ZIP)", + "Use a forward slash to specify a subfolder. Example: _space": "使用「/」來設定子目錄,例如:_space", + "Use ADetailer (Face)": "使用 ADetailer 進行臉部處理。", + "Use an admin API key.": "使用管理員的 API 金鑰。", + "Use global": "啟用全域設定", + "User Message Sequences": "使用者訊息序列", + "User Node Color": "使用者節點顏色", + "User Prefix": "使用者訊息前綴", + "User Suffix": "使用者訊息後綴", + "Using a proxy that youre not running yourself is a risk to your data privacy.": "使用非自行管理的代理服務存在資料隱私洩漏風險。", + "Vector Storage": "向量儲存", + "Vector Summarization": "向量摘要", + "Vectorization Model": "向量生成模型", + "Vectorization Source": "向量化來源", + "Vectorize All": "向量化全部資料", + "View Stats": "檢視統計資料", + "Warning: This might cause your sent messages to take a bit to process and slow down response time.": "警告:這可能會導致訊息處理速度變慢,並延長回應時間。", + "WarningThis might cause your sent messages to take a bit to process and slow down response time.": "警告:這將顯著減緩向量生成速度,因為所有訊息都需先進行摘要。", + "WebLLM Extension": "WebLLM 擴充功能", + "Whole Words": "匹配完整單字", + "Will be used if the API doesnt support JSON schemas or function calling.": "若 API 不支援 JSON 模式或函式呼叫,將使用此設定。", + "World Info settings": "世界資訊設定", + "You are in offline mode. Click on the image below to set the expression.": "您目前為離線狀態,請點選下方圖片進行表情設定。", + "You can find your API key in the Stability AI dashboard.": "API 金鑰可在 Stability AI 儀錶板中檢視。", + "Stop Inspecting": "停止檢查", + "Inspect Prompts": "檢查提示詞", + "Toggle prompt inspection": "切換提示詞檢查", + "Top nsigma": "Top nsigma", + "Controls the stopping condition for beam search. If checked, the generation stops as soon as there are '# of Beams' sequences. If not checked, a heuristic is applied and the generation is stopped when it's very unlikely to find better candidates.": "Controls the stopping condition for beam search. If checked, the generation stops as soon as there are '# of Beams' sequences. If not checked, a heuristic is applied and the generation is stopped when it's very unlikely to find better candidates.", + "Confirm token parsing with": "確認符元(Token)解析方式", + "KoboldAI Horde": "KoboldAI Horde", + "KoboldAI Horde Website": "KoboldAI Horde 網站", + "Derive context size from backend": "從後端推導上下文大小", + "Using a proxy that you're not running yourself is a risk to your data privacy.": "使用非自行管理的代理服務可能導致您的資料隱私外洩。", + "Claude API Key": "Claude API 金鑰", + "NanoGPT API Key": "NanoGPT API 金鑰", + "NanoGPT Model": "NanoGPT 模型", + "context_derived": "若可能,根據模型後設資料推導。", + "instruct_derived": "若可能,根據模型後設資料推導。", + "Inserted before the first User's message.": "插入於第一則使用者訊息之前。", + "0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc": "0 = 無限制,1 = 掃描一次不遞迴,2 = 掃描一次後遞迴一次 ⋯以此類推\n(啟用最小啟動次數時無效)", + "Quick 'Impersonate' button": "快速「AI 扮演使用者」按鈕", + "Manual": "手動", + "Any contents here will replace the default Post-History Instructions used for this character. (v2 spec: post_history_instructions)": "此處填入的內容將取代該角色的預設聊天歷史後指示(Post-History Instructions)。\n(v2 格式:specpost_history_instructions)", + "The content of this prompt is pulled from elsewhere and cannot be edited here.": "此提示內容由其他地方提取,無法在此進行編輯。", + "Open checkpoint chat\nShift+Click to replace the existing checkpoint with a new one": "開啟檢查點聊天\n使用「Shift+點選」將以新檢查點替換現有的。", + "Reroll with the entire prefix": "使用完整前綴重新生成", + "Disable": "停用", + "Enable": "啟用", + "These files are available for the current character in all chats they are in.": "這些檔案適用於該角色所在的所有聊天。", + "These files are available for all characters in the current chat.": "這些檔案適用於本次聊天中的所有角色。", + "Set your API keys and endpoints in the 'API Connections' tab first.": "請先於「API 連線」選單中設定 API 金鑰和端點。", + "Profile name:": "設定檔名稱:", + "Creating a Connection Profile": "建立連線設定檔", + "{{@key}}": "{{@key}}:", + "Enter a name:": "輸入名稱:", + "Omitted Settings:": "忽略的設定:", + "Will be used if the API doesn't support JSON schemas or function calling.": "將於 API 不支援 JSON 結構或函式呼叫時使用。", + "ext_sum_webllm": "WebLLM 擴充功能", + "ext_sum_restore_tip": "恢復先前的摘要;重複使用以清除此聊天的摘要狀態。", + "ext_sum_force_tip": "將立即更新摘要。", + "ext_sum_include_wi_scan_desc": "於掃描世界資訊時包含最新摘要。", + "ext_sum_include_wi_scan": "包含世界資訊掃描", + "None (not injected)": "無(不插入)", + "ext_sum_injection_position_none": "此摘要將不會插入提示詞中,但可透過 {{summary}} 巨集存取。", + "Labels and Message": "標籤與訊息", + "Label": "標籤", + "(label of the button, if no icon is chosen) ": "(若未選擇圖示,則為按鈕的標籤)", + "Title": "名稱", + "(tooltip, leave empty to show message or /command)": "(工具提示,留空以顯示訊息或 /command)", + "Message / Command:": "訊息/指令:", + "Word wrap": "自動換行", + "Tab size:": "標籤大小:", + "Ctrl+Enter to execute": "以 Ctrl+Enter 執行", + "Context Menu": "內容選單", + "Auto-Execute": "自動執行", + "Don't trigger auto-execute": "不觸發自動執行", + "Invisible (auto-execute only)": "隱藏(僅自動執行)", + "Execute on startup": "啟動時執行", + "Execute on user message": "根據使用者訊息執行", + "Execute on AI message": "根據 AI 訊息執行", + "Execute on chat change": "聊天內容變更時執行", + "Execute on new chat": "新增聊天時執行", + "Execute on group member draft": "群組成員變更時執行", + "Automation ID:": "自動化 ID:", + "Testing": "測試", + "Quick Reply": "快速回覆", + "Enable Quick Replies": "啟用快速回覆", + "Combine Quick Replies": "合併快速回覆", + "Show Popout Button": "顯示彈出按鈕(桌面版)", + "Global Quick Reply Sets": "全域快速回覆", + "Chat Quick Reply Sets": "聊天快速回覆", + "Edit Quick Replies": "編輯快速回覆", + "Disable Send (Insert Into Input Field)": "停用傳送(插入到輸入欄位)", + "Place Quick Reply Before Input": "在輸入前插入快速回覆", + "Inject user input automatically": "自動插入使用者輸入", + "(if disabled, use ": "(若停用,請使用", + "macro for manual injection)": "巨集進行手動插入)", + "Color": "顏色", + "Only apply color as accent": "僅使用顏色作為強調", + "ext_regex_new_global_script_desc": "新增「全域」正規表達式", + "ext_regex_new_scoped_script_desc": "新增「區域」正規表達式", + "ext_regex_disallow_scoped": "不使用區域正規表達式", + "ext_regex_allow_scoped": "使用區域正規表達式", + "ext_regex_user_input_desc": "使用者傳送的訊息。", + "ext_regex_ai_input_desc": "從生成式 API 接收到的訊息。", + "ext_regex_slash_desc": "使用 STscript 指令傳送的訊息。", + "ext_regex_wi_desc": "世界資訊/知識書條目內容。需要勾選「僅格式化提示詞」!", + "ext_regex_run_on_edit_desc": "當指定角色的訊息被編輯時執行正規腳本。", + "Macro in Find Regex": "巨集替換模式", + "Don't substitute": "不替換(純文字匹配)", + "Substitute (raw)": "原始替換(不處理 *、. 等特殊字元)", + "Substitute (escaped)": "轉義替換(將特殊字元 *、. 等當作普通文字處理)", + "Ephemerality": "暫時性", + "ext_regex_only_format_visual_desc": "僅改變聊天介面顯示的訊息,不修改聊天記錄檔案內容。", + "Hint: Save an API key in Horde KoboldAI API settings to use it here.": "提示:請於 Horde KoboldAI API 設定中儲存 API 金鑰以進行使用。", + "Prompt Upsampling": "提示提升(Upsampling)", + "Uncheck to hide the extension's messages in chat prompts.": "取消選取可在聊天提示詞中隱藏擴充功能的訊息。", + "ext_translate_delete_confirm_1": "確定要刪除嗎?", + "ext_translate_delete_confirm_2": "這將「永久刪除」本次聊天中所有訊息的翻譯文字,且無法復原。", + "Select TTS Provider": "選擇 TTS 提供者", + "tts_enabled": "啟用", + "Narrate user messages": "朗讀使用者訊息", + "Auto Generation": "自動生成", + "Requires auto generation to be enabled.": "需要啟用自動生成功能。", + "Narrate by paragraphs (when streaming)": "按段落朗讀(使用「串流」時)", + "Only narrate quotes": "僅朗讀「引號」中的文字", + "Ignore text, even quotes, inside asterisk": "忽略 *(星號)內的文字(包括「引號」)", + "Narrate only the translated text": "僅朗讀翻譯後的文字", + "Skip codeblocks": "跳過程式碼塊", + "Skip tagged blocks": "跳過 <標記> 塊", + "Pass Asterisks to TTS Engine": "將 *(星號)視為普通文字傳送至 TTS 引擎(否則忽略)", + "Warning: This will slow down vector generation drastically, as all messages have to be summarized first.": "警告:操作後將顯著降低向量生成速度,因為所有訊息都必須先進行摘要。", + "Note:": "注意:", + "this chat is temporary and will be deleted as soon as you leave it.": "此聊天為臨時聊天,離開後將被刪除。", + "Import Tags For _begin": "為", + "Import Tags For _end": "匯入標籤", + "Click remove on any tag to remove it from this import.
      Select one of the import options to finish importing the tags.": "點選任意標籤上的「移除」可將其於本次匯入中刪除。\n選擇一個匯入選項以完成標籤匯入。", + "Existing Tags": "現有標籤", + "New Tags": "新標籤", + "Folder Tags": "資料夾標籤", + "The following tags will be auto-imported based on the currently selected folders": "以下標籤將根據目前選擇的資料夾自動匯入", + "Import None": "不匯入", + "Import All": "全部匯入", + "Import Existing": "匯入現有標籤", + "Import": "匯入", + "chat_rename_1": "輸入此聊天檔案的新名稱:", + "chat_rename_2": "!! 使用已存在的檔案名稱將導致錯誤 !!", + "chat_rename_3": "這將斷開各檢查點間的連結。", + "chat_rename_4": "無需在結尾加上 `.jsonl`。", + "Include Body Parameters": "包含請求主體參數", + "custom_include_body_desc": "包含在 Chat Completion 請求體中的參數(YAML 格式)\n\n範例:\n- top_k: 20\n- repetition_penalty: 1.1", + "Exclude Body Parameters": "排除請求主體參數", + "custom_exclude_body_desc": "排除於 Chat Completion 請求體中的參數(YAML 格式)\n\n範例:\n- frequency_penalty\n- presence_penalty", + "Include Request Headers": "包含請求標頭(Request Headers)", + "custom_include_headers_desc": "新增於 Chat Completion 請求的自定義標頭(YAML 格式)\n\n範例:\n- CustomHeader: custom-value\n- AnotherHeader: custom-value", + "THIS IS PERMANENT!": "這是「永久性」的!", + "Also delete the chat files": "同時刪除此聊天檔案", + "Are you sure you want to duplicate this character?": "您確定要複製該角色嗎?", + "If you just want to start a new chat with the same character...": "若您只是想與該角色開始新聊天,請使用左下角選單中的「開始新聊天」。", + "forbid_media_global_state_forbidden": "(禁止)", + "forbid_media_global_state_allowed": "(允許)", + "help_format_1": "文字格式化命令:", + "help_format_2": "*文字*", + "help_format_3": "顯示為", + "help_format_4": "斜體", + "help_format_5": "**文字**", + "help_format_6": "顯示為", + "help_format_7": "粗體", + "help_format_8": "***text***", + "help_format_9": "顯示為", + "help_format_10": "粗斜體", + "help_format_11": "__文字__", + "help_format_12": "顯示為", + "help_format_13": "底線", + "help_format_14": "~~text~~", + "help_format_15": "顯示為", + "help_format_16": "刪除線", + "help_format_17": "[text](url)", + "help_format_18": "顯示為", + "help_format_19": "超連結", + "help_format_20": "![text](url)", + "help_format_21": "顯示為圖片", + "help_format_22": "```text```", + "help_format_23": "顯示為程式碼區塊(反引號內允許換行)", + "help_format_like_this": "像這樣", + "help_format_24": "`text`", + "help_format_25": "顯示為", + "help_format_26": "單行程式碼", + "help_format_27": "> text", + "help_format_28": "顯示為塊引用(注意 > 後的空格)", + "help_format_29": "# text", + "help_format_30": "顯示為一級標題(注意空格)", + "help_format_32": "## text", + "help_format_33": "顯示為二級標題(注意空格)", + "help_format_35": "### text", + "help_format_36": "顯示為三級標題(注意空格)", + "help_1": "您好!請選擇您想了解的幫助主題:", + "help_2": "斜線命令", + "help_or": "或", + "help_3": "格式化", + "help_4": "快捷鍵", + "help_5": "{{macros}}(巨集)", + "help_6": "還有問題嗎?請造訪", + "help_7": "SillyTavern 官方文件網站", + "help_8": " 了解更多資訊!", + "help_hotkeys_0": "聊天快捷鍵", + "help_hotkeys_1": "↑(方向鍵)", + "help_hotkeys_2": "編輯聊天中的最後一則訊息", + "help_hotkeys_3": "Ctrl+↑", + "help_hotkeys_4": "編輯聊天中的最後一則使用者訊息", + "help_hotkeys_5": "←(方向鍵)", + "help_hotkeys_6": "向左滑動", + "help_hotkeys_7": "→(方向鍵)", + "help_hotkeys_8": "向右滑動(注意:若聊天框中已有輸入,滑動快捷鍵將被停用)", + "help_hotkeys_9": "Enter", + "help_hotkeys_10": "(選中聊天框時)", + "help_hotkeys_10_1": "向 AI 傳送您的訊息", + "help_hotkeys_11": "Ctrl+Enter", + "help_hotkeys_12": "重新生成最後一則 AI 回應", + "help_hotkeys_13": "Alt+Enter", + "help_hotkeys_14": "繼續生成最後一則 AI 回應", + "help_hotkeys_15": "Esc 鍵", + "help_hotkeys_16": "停止 AI 回應生成,關閉使用者介面,取消訊息編輯", + "help_hotkeys_17": "Ctrl+Shift+↑", + "help_hotkeys_18": "滾動到上下文行", + "help_hotkeys_19": "Ctrl+Shift+↓", + "help_hotkeys_20": "Markdown 快捷鍵", + "help_hotkeys_21": "適用於聊天框和帶有此圖示的文字區域:", + "help_hotkeys_22": "**粗體**", + "help_hotkeys_23": "*斜體*", + "help_hotkeys_24": "__底線__", + "help_hotkeys_25": "`單行程式碼`", + "help_hotkeys_26": "~~刪除線~~", + "Show Raw Prompt": "顯示原始提示詞", + "Copy Prompt": "複製提示詞", + "Show Prompt Differences": "顯示提示詞差異", + "System-wide Replacement Macros (in order of evaluation):": "系統範圍替換巨集(按評估順序):", + "help_macros_1": "僅用於斜線命令批次處理。替換為前一條命令的返回結果。", + "help_macros_2": "插入一個換行符。", + "help_macros_3": "修剪巨集指令周圍的換行符。", + "help_macros_4": "無操作,僅返回空字串。", + "help_macros_5": "在 API 設定中定義的全域提示詞。僅在高階定義提示詞覆蓋中有效。", + "help_macros_6": "使用者輸入", + "help_macros_7": "角色的主要提示詞覆蓋", + "help_macros_8": "角色的聊天歷史後指示覆蓋", + "help_macros_9": "角色描述", + "help_macros_10": "角色的性格特徵", + "help_macros_11": "角色場景", + "help_macros_12": "您目前的使用者描述", + "help_macros_13": "角色對話範例", + "help_macros_14": "未格式化的對話範例", + "(only for Story String)": "(僅適用於故事字串)", + "help_macros_summary": "由「訊息摘要」擴充功能生成的最新聊天摘要(如果可用)。", + "help_macros_15": "您目前的使用者名稱", + "help_macros_16": "角色名稱", + "help_macros_17": "角色版本", + "help_macros_18": "以逗號分隔的群組成員名稱列表(包含靜音成員)或單人聊天中的角色名稱。別名:{{charIfNotGroup}}", + "help_groupNotMuted": "與 {{group}} 相同,但不包含靜音成員", + "help_macros_19": "目前所選之 API 的文字生成模型名稱。", + "Can be inaccurate!": "可能不準確!", + "help_macros_20": "最新聊天訊息的文字內容。", + "help_macros_lastUser": "最新使用者聊天訊息的文字內容。", + "help_macros_lastChar": "最新角色聊天訊息的文字內容。", + "help_macros_21": "最新聊天訊息的索引 # 編號。適用於斜線命令批次處理。", + "help_macros_22": "包含在上下文中的第一條訊息的 ID。需在目前對話中至少進行一次生成。", + "help_macros_23": "最新聊天訊息中所滑動的 ID(以 1 起始)。若最新訊息為使用者訊息或提示為隱藏,則為空字串。", + "help_macros_24": "最新聊天訊息中的滑動次數。如果最新訊息為使用者訊息或提示為隱藏,則為空字串。", + "help_macros_reverse": "反轉巨集的內容。", + "help_macros_25": "您可以在此留下備註,巨集將被替換為空白內容。對 AI 不可見。", + "help_macros_26": "目前時間", + "help_macros_27": "目前日期", + "help_macros_28": "目前星期幾", + "help_macros_29": "目前 ISO 時間(24 小時制)", + "help_macros_30": "目前 ISO 日期(YYYY-MM-DD)", + "help_macros_31": "指定格式的目前日期/時間,例如,德國日期/時間:", + "help_macros_32": "指定 UTC 時區偏移量的目前時間,例如 UTC-4 或 UTC+2", + "help_macros_33": "計算 time1 和 time2 之間的時間差。接受時間和日期巨集。(例如:{{timeDiff::{{isodate}} {{time}}::2024/5/11 12:30:00}})", + "help_macros_34": "上次使用者訊息傳送後的時間", + "help_macros_35": "設定 AI 的行為偏好,直到下一次使用者輸入。引號中的文字很重要。", + "help_macros_36": "擲骰子。(例如:", + "space_ will roll a 6-sided dice and return a number between 1 and 6)": "將擲一個六面骰並回傳 1 到 6 間的數字)", + "help_macros_37": "從列表中返回隨機一項。(例如:", + "space_ will return 1 of the 4 numbers at random. Works with text lists too.": "將隨機返回 4 個數字中的 1 個。也適用於文字列表。)", + "help_macros_38": "用於隨機的替代語法,允許在列表中使用逗號。", + "help_macros_39": "從列表中選擇隨機一項。工作原理與 {{random}} 相同,但選擇結果將在本次聊天中保持一致,不會在後續訊息或提示處理時重新滾動。", + "help_macros_40": "若使用 Text Generation WebUI 後端,動態將引號中的文字新增到停用單詞序列中。對其他後端無效。可在任何地方使用(角色描述、世界資訊、作者備註等)。引號內容很重要。", + "Instruct Mode and Context Template Macros:": "指令模式與上下文範本巨集:", + "(enabled in the Advanced Formatting settings)": "(在高階格式化設定中啟用)", + "help_macros_41": "允許的最大提示詞長度(以符元為單位)=(上下文大小 - 回應長度)", + "help_macros_42": "上下文範本對話範例分隔符號", + "help_macros_43": "上下文範本聊天開始行", + "help_macros_44": "主要提示詞(啟用後,將覆蓋角色提示詞或預設系統提示)", + "help_macros_45": "主要提示詞", + "help_macros_46": "指令系統提示詞前綴序列", + "help_macros_47": "指令系統提示詞後綴序列", + "help_macros_48": "指令使用者前綴序列", + "help_macros_49": "指令使用者後綴序列", + "help_macros_50": "指令助理前綴序列", + "help_macros_51": "指令助理後綴序列", + "help_macros_52": "指令助理的開頭輸出序列", + "help_macros_53": "指令助理的結尾輸出序列", + "help_macros_54": "指令系統訊息前綴序列", + "help_macros_55": "指令系統訊息後綴序列", + "help_macros_56": "指令系統指令前綴", + "help_macros_57": "指令第一則使用者訊息補全", + "help_macros_58": "指令停止序列", + "help_macros_first_user": "指令使用者開頭輸入序列", + "help_macros_last_user": "指令使用者結尾輸入序列", + "Chat variables Macros:": "聊天變數巨集:", + "Local variables = unique to the current chat": "區域變數 = 僅作用於本次聊天", + "Global variables = works in any chat for any character": "全域變數 = 作用於所有聊天中的所有角色", + "Scoped variables = works in STscript": "區域變數 = 適用於 STscript", + "help_macros_59": "替換為區域變數 \"name\" 的值", + "help_macros_60": "替換為空字串,並將區域變數 \"name\" 設定為 \"value\"", + "help_macros_61": "替換為空字串,並將 \"increment\" 數值新增到區域變數 \"name\"", + "help_macros_62": "替換為區域變數 \"name\" 的值增加 1 後的結果", + "help_macros_63": "替換為區域變數 \"name\" 的值減少 1 後的結果", + "help_macros_64": "替換為全域變數 \"name\" 的值", + "help_macros_65": "替換為空字串,並將全域變數 \"name\" 設定為 \"value\"", + "help_macros_66": "替換為空字串,並將 \"increment\" 數值新增到全域變數 \"name\"", + "help_macros_67": "替換為全域變數 \"name\" 的值增加 1 後的結果", + "help_macros_68": "替換為全域變數 \"name\" 的值減少 1 後的結果", + "help_macros_69": "替換為區域變數 \"name\" 的值", + "help_macros_70": "替換為區域變數 \"name\" 中指定索引(適用於陣列/列表或物件/字典)的值", + "{{name}}": "{{name}}", + "If necessary, you can later restore this chat file from the /backups folder": "若需要,您可以稍後從 /backups 資料夾恢復此聊天檔案", + "Also delete the current chat file": "同時刪除目前的聊天檔案", + "Are you sure you want to connect to the following proxy URL?": "您確定要連線到以下代理 URL 嗎?", + "Encountered an error while processing your request.": "處理您的請求時遇到錯誤。", + "Check you have credits available on your": "請檢查您的帳號中是否有可用餘額", + "OpenAI account quora_error": "OpenAI 帳號", + "dot quota_error": "。", + "If you have sufficient credits, please try again later.": "若餘額充足,請稍後重試。", + "Download Model": "下載模型", + "Downloader Options": "下載選項", + "Extra parameters for downloading/HuggingFace API": "下載/使用 HuggingFace API 的額外參數。\r若不確定,請留空。", + "Revision": "修訂", + "Folder Name": "輸出資料夾名稱", + "HF Token": "HF 符元", + "Include Patterns": "包含模式", + "Glob patterns of files to include in the download.": "要包含於下載中文件的全域模式。\r每行輸入一個模式。", + "Exclude Patterns": "排除模式", + "Glob patterns of files to exclude in the download.": "要排除於下載中的文件的全域模式。\r每行輸入一個模式。", + "Tag Management": "管理標籤", + "Save your tags to a file": "將標籤儲存到文件", + "Restore tags from a file": "從文件中恢復標籤", + "Create a new tag": "建立新標籤", + "Drag handle to reorder. Click name to rename. Click color to change display.": "拖動以重新排序。點選名稱重新命名。點選顏色更改顯示。", + "Click on the folder icon to use this tag as a folder.": "點選資料夾圖示以將此標籤作為資料夾。", + "Use alphabetical sorting": "按字母順序排序 ", + "tags_sorting_desc": "啟用後,標籤將在建立或重新命名時將自動按字母排序。\n停用時,新標籤將附加到結尾。\n若標籤被手動拖動重新排序,則自動排序將被停用。", + "and connect to an": "並連線到", + "You can add more": "您可加入更多", + "or_welcome": "或", + "from other websites": "以從其他網站新增。", + "Go to the": "前往", + "to install additional features.": "以安裝更多功能。", + "If you're connected to an API, try asking me something!": "若您已連線 API,嘗試問我一些問題吧!", + "Title/Memo": "標題/備註", + "Strategy": "插入策略", + "Position": "位置", + "Trigger %": "觸發%", + "Dialogue Colorizer": "對話著色器", + "Global Dialogue Settings": "全域對話設定", + "Chat Bubble Lightness": "聊天氣泡亮度", + "The lightness to use for the chat bubble color.": "設定聊天氣泡的亮度。", + "Character Dialogue Settings": "角色對話設定", + "Dialogue settings for characters.": "設定角色對話顏色。", + "The static color to use for character dialog if 'Color Source' is set to 'Static Color'.": "若將「顏色來源」設定為「靜態顏色」,請先設定該角色對話的靜態顏色。", + "Persona Dialogue Settings": "使用者對話設定", + "Persona Dialogue Settings Info": "設定使用者對話顏色。", + "Dialogue Color": "對話顏色", + "The color to use for this character's dialogue (quoted text). Overrides the global setting.": "該角色對話中引號文字的顏色。覆蓋全域設定。", + "Avatar Vibrant": "頭像顏色", + "Use a vibrant color dynamically calculated from the character's avatar.": "使用從角色頭像動態提取出的色彩。", + "Static Color": "靜態顏色", + "Use a specified static color.": "使用指定的靜態顏色。", + "Per-Character Only": "僅限特定角色", + "Use the default quote color except for characters with a specified override color.": "除非角色有指定的覆蓋顏色,否則使用預設的引號文字顏色。", + "Chat Bubbles": "聊天氣泡", + "Color the chat bubbles. Only works with the 'Bubbles' chat style.": "為聊天氣泡上色,僅適用於「氣泡」聊天樣式。", + "Quoted Text": "引號文字", + "Color quoted text.": "為引號文字上色。", + "Color both chat bubbles and quoted text.": "同時為聊天氣泡和引號文字上色。", + "Color Source": "顏色來源", + "The source to use for dialogue color.": "設定對話顏色的來源。", + "Color Targets": "顏色目標", + "Which elements to color.": "設定需要上色的元素。", + "Open Chat History": "開啟聊天記錄", + "Reset": "重設", + "Save": "儲存", + " folder of your user directory (typically 'data/default-user'). Place your expressions there.": "資料夾內,放置您的角色立繪(通常為「data/default-user」)。", + "Always show the node full info panel at the…e timeline view. When off, show it near the node.": "始終在時間軸檢視底端顯示節點的完整資訊面板。若關閉,則在節點附近顯示。", + "Always show the node tooltip at the bottom …e timeline view. When off, show it near the node.": "始終在時間軸檢視左下角顯示節點的提示框。若關閉,則在節點附近顯示。", + "Dialogue settings for user personas.": "Dialogue settings for user personas.", + "Expand swipe nodes when the timeline view f… a node, or by pressing the Toggle Swipes button.": "在時間軸檢視首次開啟時展開滑動節點,或透過按下「切換滑動」按鈕來展開節點。", + "Send as a character": "以角色身份傳送", + "Use GPU acceleration for positioning the fu…ow tends to disappear, turning this off may help.": "使用 GPU 加速來定位完整資訊面板。若面板頻繁消失,建議關閉此選項以解決問題。", + "Use the colors of the ST GUI theme, instead…n Color Settings specifically for this extension.": "使用使用者設定中的介面主題顏色,取代下方「顏色設定」中額外設定的顏色。", + "When enabled, nodes that have swipes splitt… larger, in addition to having the double border.": "啟用後,具有分支滑動的節點除了顯示雙重邊框外,還會顯示為更大的尺寸。", + "Brightness": "亮度", + "Character Tint Settings": "角色色調設定 *", + "Commands": "指令", + "Contrast": "對比度", + "Darken Unfocused Character Sprites": "暗化未聚焦的角色立繪", + "Delete tint": "儲存色調", + "Ease": "平滑過渡", + "Ease-In": "淡入", + "Ease-In-Out": "淡入 + 淡出", + "Ease-Out": "淡出", + "Emulate Character Card as Sprite": "[測試版] 模擬角色卡為角色立繪", + "Enable Character Tint (Requires Prome to be enabled)": "啟用角色色調", + "Enable Chat Tint": "啟用聊天色調", + "Enable Focus Mode": "啟用聚焦模式", + "Enable Prome": "啟用 Prome", + "Enable Sprite Shadow": "啟用角色立繪陰影效果", + "Enable Sprite Shake": "[測試版] 啟用角色立繪震動效果", + "Enable Traditional VN Mode": "啟用傳統視覺小說模式 *", + "Enable User Sprite": "啟用使用者立繪", + "Enable World Tint": "啟用世界色調", + "Features marked with a": "若想使用帶有", + "Focus Mode Animation": "聚焦模式動畫", + "Focus Mode Animation Speed": "聚焦模式動畫速度", + "Focus Mode Settings": "聚焦模式設定", + "Grayscale": "灰階", + "Hide Sheld (Message Box)": "隱藏聊天訊息欄位", + "Horizontal Letterbox": "水平遮罩", + "Hue": "色相", + "Invert": "反轉", + "Inverts the character colors.": "反轉角色顏色。", + "Inverts the world colors.": "反轉世界顏色。", + "Keybinds": "快捷鍵", + "Letterbox Color": "遮罩顏色", + "Letterbox Configuration*": "遮罩設定 *", + "Letterbox Mode": "遮罩模式", + "Letterbox Size": "遮罩大小", + "Makes the character black and white.": "使角色使用灰階效果。", + "Makes the character warmer in color.": "使角色色調更暖。", + "Makes the world black and white.": "使世界使用灰階效果。", + "Makes the world warmer in color.": "使世界色調更暖。", + "Note: Create a sprite folder in the ": "注意:請在", + "require Prome to be enabled.": "標記的功能,需要啟用「Prome」。", + "Saturate": "飽和", + "Saturates the character colors.": "增加角色顏色飽和度。", + "Saturates the world colors.": "增加世界顏色飽和度。", + "Save tint": "刪除色調", + "Select the animation for focus mode.": "選擇聚焦模式的動畫效果。", + "Select the color of the letterbox.": "選擇遮罩顏色。", + "Select the letterbox mode for the Prome VN UI.": "選擇 Prome 視覺小說介面的遮罩模式", + "Select the tint preset to use for the Prome VN UI.": "選擇用於 Prome 視覺小說介面的色調預設設定檔。", + "Sepia": "復古", + "Set the blur of the character shadow.": "設定角色陰影模糊程度。", + "Set the brightness of the character.": "設定角色亮度。", + "Set the brightness of the world.": "設定世界亮度。", + "Set the contrast of the character.": "設定角色對比度。", + "Set the contrast of the world.": "設定世界對比度。", + "Set the hue of the character.": "設定角色色相。", + "Set the hue of the world.": "設定世界色相。", + "Set the size of the letterbox.": "設定遮罩大小。", + "Set the speed of the focus animation.": "設定聚焦動畫速度。", + "Set the strength of the character blur.": "設定角色模糊強度。", + "Set the strength of the world blur.": "設定世界模糊強度。", + "Set the X offset of the character shadow.": "設定角色陰影的 X 軸偏移量。", + "Set the Y offset of the character shadow.": "設定角色陰影的 Y 軸偏移量。", + "Shadow Blur": "模糊陰影", + "Shadow X Offset": "X 軸偏移量", + "Shadow Y Offset": "Y 軸偏移量", + "Share World Tint With Characters": "角色適用世界色調 *", + "Sheld Configuration": "設定聊天訊息欄位", + "Sprite Configuration": "設定角色立繪 *", + "Sprite List": "角色立繪列表", + "Sprite Shadow Configuration": "設定角色立繪陰影", + "Tint Configuration": "設定色調", + "Tint Presets": "色調預設設定檔", + "Type the name of the sprite set to use for your pe…rites in the 'characters' folder in SillyTavern).": "輸入您要使用的個人角色立繪集名稱(需將立繪存放於 SillyTavern 中的「characters」資料夾內)。", + "User Sprite Configuration": "[測試版] 使用者立繪設定", + "Vertical Letterbox": "垂直遮罩", + "World Tint Settings": "設定世界色調", + "Prome (Visual Novel Extension)": "Prome(進階視覺小說模式)", + "Brought to you by": "由", + "and Prometheus.": "與 Prometheus(普羅米修斯十七號)呈獻。", + "Type the name of the sprite set to use for your persona. (Place your sprites in the 'characters' folder in SillyTavern).": "輸入您想用於個人立繪的立繪集名稱。(請將立繪放置在 SillyTavern 的「characters」資料夾中)。", + "Prome Keybinds": "Prome 的快捷鍵", + "Hide/Show SillyTavern's Sheld (Message Box)": "隱藏/顯示 SillyTavern 的聊天訊息欄位", + "Prome Commands": "Prome 指令", + "Show/Hide the letterbox (black bars) in the VN UI": "顯示/隱藏視覺小說模式中的黑邊(信箱模式)", + "Toggles focus mode on character sprites": "切換角色立繪的焦點模式", + "Sets the focus mode animation": "設定焦點模式動畫", + "Toggles the defocus tint on non-speaking character sprites": "切換非對話角色立繪的背景色", + "Toggles the shake animation when a character speaks on character sprites": "切換角色立繪對話時的震動動畫", + "Toggles sprite shadows on character sprites": "切換角色立繪的陰影效果", + "Toggles world/character tint on the VN UI": "切換視覺小說模式中的世界/角色色調", + "Toggles world tint on the VN UI": "切換視覺小說模式中的世界色調", + "Toggles character tint on the VN UI": "切換視覺小說模式中的角色色調", + "Toggles sharing world tint with character sprites (This will override Character Tint)": "切換角色立繪是否與世界色調共享色調(此操作將覆蓋角色色調設定)", + "Sets the expression of the user sprite": "設定使用者立繪的表情", + "Sets the user sprite set to use for the user sprite": "設定使用者立繪所使用的立繪集", + "Toggles the user sprite on the VN UI": "切換視覺小說模式中使用者立繪的顯示狀態", + "Close": "關閉", + "View this current chat's chat history.": "檢視本次聊天的聊天記錄。", + "WARNING: Functions in this category are for advanced users only. Don't click anything if you're not sure about the consequences.": "警告:此類功能僅適用於進階使用者。若您不確定使用後果,請勿點選任何按鈕。", + "Enter a new display name:": "輸入新的顯示名稱:", + "Enter Checkpoint Name:": "輸入檢查點名稱:", + "(Leave empty to auto-generate)": "(留空將自動命名)", + "The currently existing checkpoint will be unlinked and replaced with the new checkpoint, but can still be found in the Chat Management.": "此檢查點將取消連結並替換為新的檢查點,但仍可在「管理聊天檔案」中找到。", + "Enter the Git URL of the extension to install": "輸入欲安裝的擴充功能 Git URL", + "Disclaimer:": "免責宣告:", + "Please be aware that using external extensions can have unintended side effects and may pose security risks. Always make sure you trust the source before importing an extension. We are not responsible for any damage caused by third-party extensions.": "請注意,使用外部擴充功能可能會導致意想不到的副作用並存在安全風險。在匯入前,請務必確保您信任其來源。我們對於第三方擴充功能所引起的任何損害概不負責。", + "Prompt Itemization": "提示詞項目化", + "API/Model": "API/模型", + "Preset": "預設設定檔", + "Only the white numbers really matter. All numbers are estimates. Grey color items may not have been included in the context due to certain prompt format settings.": "所有數字均為估算值,僅白色數字真正重要。灰色項目可能因提示詞格式設定未納入上下文。", + "System Info:": "系統資訊:", + "Bias:": "Bias:", + "World Info:": "世界資訊:", + "Chat History:": "聊天記錄:", + "Extensions:": "擴充功能:", + "Total Tokens in Prompt:": "提示詞中的總符元數:", + "Max Context": "最大上下文長度", + "(Context Size - Response Length)": "(上下文長度 - 回應長度)", + ":": ":", + "API/Model:": "API/模型:", + "Preset:": "預設設定檔:", + "Tokenizer:": "分詞器:", + "Choose what to export": "選擇匯出內容", + "Text Completion Preset": "文字補全預設設定檔", + "Choose what to import": "選擇匯入內容", + "Enter your password below to confirm:": "請在下方輸入密碼以完成確認:", + "Unique to this chat.": "此設定僅適用於本次聊天。", + "The following scenario text will be used instead of the value set in the character card.": "以下場景內容將覆蓋角色卡中的設定值。", + "Checkpoints inherit the scenario override from their parent, and can be changed individually after that.": "檢查點將繼承父項的場景覆蓋值,但仍可獨立修改。", + "Are you sure you want to delete the theme?": "您確定要刪除介面主題嗎?", + "This will delete all your settings and data. There will be no undo button. Make sure you have a backup before proceeding.": "此操作將刪除所有設定與資料,且無法還原。進行重設前請務必完成備份。", + "Account reset code has been posted to the server console.": "帳號重設驗證碼已傳送至伺服器控制台。", + "Prompt Tokens:": "提示詞符元數:", + "All group members will use the following scenario text instead of what is specified in their character cards.": "所有群組聊天成員將使用以下場景內容,取代原有角色卡中指定的內容。", + "Toggle sidebar": "切換側邊欄", + "Show connection profiles": "顯示連線設定檔", + "View chat files": "檢視聊天檔案", + "New chat": "新聊天", + "Rename chat": "重新命名聊天", + "Delete chat": "刪除聊天", + "Are you sure?": "你確定嗎?", + "Enter new chat name": "輸入新的聊天名稱", + "No chat selected": "未選擇聊天", + "Draggable template not found. Side bar will not be added.": "未找到可拖動範本。側邊欄將不被新增。", + "Failed to find draggable or close button. Side bar will not be added.": "未找到可拖動項或關閉按鈕。側邊欄將不被新增。", + "Sidebar or toggle button not found": "未找到側邊欄或切換按鈕", + "Switch connection profile": "切換連線設定檔", + "Failed to get current API": "取得 API 失敗", + "Failed to get current model": "取得模型失敗", + "Aborting populateSideBar due to process id mismatch": "由於 populateSideBar ID 不匹配,中止填充側邊欄", + "Bronya Rand": "Bronya Rand(布洛妮婭·蘭德)", + "Toggles Prome, VN Mode and other Prome features.": "切換 Prome、視覺小說模式和其他 Prome 功能。", + "Only Show Last Message in Chat (Requires Prome to be enabled).": "僅顯示聊天中的最後一條訊息(需啟用 Prome)。", + "Emulates the character card of a character to be a sprite. (Requires Prome to be enabled).": "將角色的角色卡圖片模擬為角色立繪(需啟用 Prome)。", + "Shakes the character sprite when the character is speaking (Only works if Streaming is enabled in Preset Settings).": "當角色說話時,震動角色的立繪(僅在預設設定檔中啟用「串流」時有效)。", + "Focuses the current speaking character in chat. (Requires Prome to be enabled).": "聚焦聊天中目前正在說話的角色(要啟用 Prome)。", + "Darkens non-speaking (unfocused) characters. (Requires Prome to be enabled).": "使未說話(未聚焦)的角色變暗(需啟用 Prome)。", + "Auto-hides characters from the screen that haven't been in the conversation for a while up to X characters. (Requires Prome to be enabled).": "自動隱藏未參與會話一段時間的角色,最多 X 個角色(需啟用 Prome)。", + "Enables the ability to use a user sprite for your persona.": "啟用後,將為使用者的角色使用角色立繪功能。", + "Applies the world tint to character sprites (Requires Prome to be enabled. This will override your character tint settings).": "將世界色調應用於角色立繪(需啟用 Prome,這將覆蓋角色的色調設定)。", + "Tints the world background.": "為世界背景新增色調。", + "Tints the character sprites.": "為角色立繪新增色調(需啟用 Prome)。", + "Auto-Hide Sprites": "自動隱藏立繪", + "Max Visible Sprites": "最大顯示數", + "Set the maximum number of visible sprites that appears in the VN screen.": "設定視覺小說模式中,畫面可顯示的最大立繪數量。", + "Hide the message box (sheld) in the ST UI.": "隱藏 SillyTavern 介面中的聊天訊息欄位。", + "Enter the name of your sprite": "輸入立繪名稱", + "Start new chat?": "開始新聊天?", + "Delete the character?": "您確定要刪除角色嗎?", + "It will overwrite the World/Lorebook with the same name.": "它將覆蓋同名的世界資訊或知識書。", + "All information associated with its linked persona will be lost.": "與這位使用者相關的所有資訊都將遺失。", + "Are you sure you want to duplicate this persona?": "您確定要複製使用者角色嗎?", + "(If empty name is provided, this will unbind the name from this avatar)": "(若留空,則解除該名稱與頭像的綁定)", + "Enter a name for this persona:": "輸入使用者角色的名稱:", + "Are you sure you want to set \"${0}\" as the default persona?": "您確定要將「${0}」設為預設角色嗎?", + "This name and avatar will be used for all new chats, as well as existing chats where the user persona is not locked.": "此名稱和頭像將用於所有新對話,以及目前尚未綁定使用者角色的聊天。", + "Are you sure you want to remove the default persona?": "您確定要取消目前的使用者角色預設嗎?", + "Install for all users": "為所有使用者安裝", + "Install just for me": "為自己安裝", + "No Icon": "不使用圖示", + "Remove Quick Reply": "移除快速回覆", + "Are you sure you want to remove this Quick Reply?": "你確定要移除此快速回覆嗎?", + "Middle-out Transform": "中間向外變換", + "Auto": "自動", + "Allow": "允許", + "Forbid": "禁止", + "Aphrodite only. Determines the order of samplers. Skew is always applied post-softmax, so it's not included here.": "僅限 Aphrodite 使用。決定取樣器的順序。偏移總是在 softmax 後應用,因此不包括在此。", + "Aphrodite only. Determines the order of samplers.": "僅限 Aphrodite 使用。決定取樣器的順序。", + "Request model reasoning": "請求模型思維鏈", + "Allows the model to return its thinking process.": "讓模型回傳其思考過程。", + "Generic (OpenAI-compatible) [LM Studio, LiteLLM, etc.]": "通用(相容 OpenAI)[LM Studio, LiteLLM 等]", + "Model ID (optional)": "模型 ID(可選)", + "DeepSeek API Key": "DeepSeek API 金鑰", + "DeepSeek Model": "DeepSeek 模型", + "prompt_post_processing_merge": "合併連續角色", + "prompt_post_processing_semi": "半嚴格(交替角色)", + "prompt_post_processing_strict": "嚴格(使用者優先,交替角色)", + "Background Fitting": "背景填充", + "Classic": "經典", + "Cover": "覆蓋", + "Contain": "自適應", + "Stretch": "拉伸", + "Center": "置中", + "Persona Lore Alt+Click to open the lorebook": "「Alt+點選」可開啟角色知識書", + "Chat Lore Alt+Click to open the lorebook": "「Alt+點選」可開啟聊天知識書", + "Function Tool": "功能工具", + "Functions in this category are for advanced users only. Don't click anything if you're not sure about the consequences.": "此類功能僅供高階使用者使用。若不確定後果,請勿點選任何內容。", + "Are you sure you want to delete this user?": "確定要刪除該使用者嗎?", + "help_macros_isMobile": "目前是否在行動端使用:\"true\" 表示是,\"false\" 表示否", + "Persona Lorebook for": "角色知識書適用於", + "persona_world_template_txt": "選中的世界資訊將綁定到此角色。生成 AI 回覆時,會結合全域、角色及聊天知識書中的內容。", + "Key saved; press \"Test Message\" to verify.": "金鑰已儲存;請點選「測試訊息」進行驗證。", + "Preset name:": "預設設定檔名稱:", + "Hint: Use a character/group name to bind preset to a specific chat.": "提示:使用角色/群組名稱將綁定預設設定檔至特定對話。", + "Your preset contains proxy and/or custom endpoint settings.": "此預設設定檔包含代理和/或自訂端點設定。", + "Do you want to remove these fields before exporting?": "是否要在匯出前移除這些欄位?", + "Delete the preset? This action is irreversible and your current settings will be overwritten.": "確定刪除此預設設定檔?刪除後無法復原,且此設定將被覆蓋。", + "Update all": "全部更新", + "Automatically chooses an alternative provider if chosen providers can't serve your request.": "當所選提供者無法滿足您的請求時,自動選擇替代提供者。", + "Use extension settings": "使用擴充功能設定", + "To use instruct formatting, switch to OpenRouter under Text Completion API.": "若要使用指令格式,請在文字補全 API 下切換至 OpenRouter。", + "Automatically 'continue' a response if the model stopped before reaching a certain amount of tokens.": "如果模型在達到一定數量的符元前停止,則自動繼續生成回應。", + "Toggle entry's active state.": "切換條目的啟用狀態。", + "Non-sticky": "無黏性", + "No cooldown": "無冷卻時間", + "No delay": "無延遲", + "Included settings:": "包含設定:", + "Click on the setting name to omit it from the profile.": "點選設定名稱以從設定檔中省略。", + "Tints the chat background and/or character sprites.": "調整聊天背景或角色圖片的色調。", + "Only chunk on custom boundary": "僅在自定邊界進行分塊(chunk)", + "help_macros_firstDisplayedMessageId": "載入到可見聊天中的第一則訊息的 ID。", + "Couldn't import tags:": "無法匯入標籤:", + "Select providers. No selection = all providers.": "選擇供應商。未選擇=所有供應商。", + "Select a model": "選擇模型", + "Search models...": "搜尋模型⋯", + "[Currently loaded]": "[目前載入]", + "Search providers...": "搜尋供應商⋯", + "No-sticky": "無固定", + "Create a new World Info": "建立新世界資訊", + "Enter a name for the new file:": "輸入新檔案的名稱:", + "Valid World Info file name is required": "需要有效的世界資訊檔案名稱", + "World Info file has an invalid format": "世界資訊檔案格式無效", + "World Info file has no entries": "世界資訊檔案中無任何條目", + "Character not found.": "未找到該角色。", + "Open a chat to get a name of the chat-bound lorebook": "開啟聊天以取得綁定聊天的知識書名稱。", + "File is not valid: ${0}": "檔案無效或格式不正確:${0}", + "The world with ${0} is invalid or corrupted.": "世界 ${0} 無效或已損壞。", + "Deactivated all worlds": "已停用所有世界", + "No world found named: ${0}": "未找到名為 ${0} 的世界", + "Activated world: ${0}": "已啟用世界:${0}", + "Deactivated world: ${0}": "已停用世界:${0}", + "World was not active: ${0}": "世界 ${0} 未啟用", + "The world '${0}' has been imported and linked to the character successfully.": "世界「${0}」已成功匯入並綁定至角色。", + "World/Lorebook imported": "世界/知識書已匯入", + "Are you sure you want to import '${0}'?": "確定要匯入「${0}」嗎?", + "Built-in Extensions:": "內建擴充功能:", + "Installed Extensions:": "已安裝的擴充功能:", + "Loading third-party extensions... Please wait...": "正在載入第三方擴充功能,請稍候⋯", + "The page will be reloaded shortly...": "頁面即將重新載入⋯", + "Extensions state changed": "擴充功能狀態已更改", + "Error loading extensions. See browser console for details.": "載入擴充功能時出現錯誤。詳細資訊請檢視瀏覽器控制台。", + "You don't have permission to update global extensions.": "您無權更新全域擴充功能。", + "Extension update failed": "擴充功能更新失敗", + "Extension ${0} updated to ${1}": "擴充功能 ${0} 已更新至 ${1}", + "Reload the page to apply updates": "重新載入頁面以使用更新", + "You don't have permission to delete global extensions.": "您無權刪除全域擴充功能。", + "Are you sure you want to delete ${0}?": "確定要刪除 ${0} 嗎?", + "You don't have permission to move extensions.": "您無權移動擴充功能。", + "Are you sure you want to move ${0} to your local extensions? This will make it available only for you.": "確定要將 ${0} 移至本機擴充功能嗎?此後僅您可使用。", + "Are you sure you want to move ${0} to the global extensions? This will make it available for all users.": "確定要將 ${0} 移至全域擴充功能嗎?此後所有使用者皆可使用。", + "Extension ${0} moved.": "擴充功能 ${0} 已移動。", + "Extension ${0} deleted": "擴充功能 ${0} 已刪除。", + "Please wait...": "請稍候⋯", + "Installing extension": "正在安裝擴充功能", + "Extension installation failed": "擴充功能安裝失敗", + "Extension '${0}' by ${1} (version ${2}) has been installed successfully!": "擴充功能 '${0}' 由 ${1} 提供(版本 ${2})已成功安裝!", + "Extension installation successful": "擴充功能安裝成功", + "Extension updates available": "有可用的擴充功能更新", + "Auto-updating extensions. This may take several minutes.": "正在自動更新擴充功能。這可能需要幾分鐘時間。", + "Install": "安裝", + "Modules provided by your Extras API:": "由您的 Extras API 提供的模組:", + "Not connected to the API!": "未連線到 API!", + "ext_type_system": "這是內建的擴充功能,無法刪除,且會跟隨系統更新。", + "Valid": "已驗證", + "Request Model Reasoning": "請求模型推理", + "Global list": "全域列表", + "Preset-specific list": "特定預設設定檔列表", + "Constrains effort on reasoning for reasoning models.": "限制推理模型的推理耗費。\n目前支援的值為低、中和高。\n降低推理耗費可加快回應速度,並減少推理所使用的符元數量。", + "Reasoning Effort": "推理耗費", + "openai_reasoning_effort_low": "低", + "openai_reasoning_effort_medium": "中", + "openai_reasoning_effort_high": "高", + "Reasoning": "推理 Reasoning", + "reasoning_auto_parse": "自動解析主要內容中推理區塊,需定義且不為空的前綴與後綴欄位。", + "Auto-Parse": "自動解析", + "reasoning_auto_expand": "自動展開推理區塊。", + "Auto-Expand": "自動展開", + "reasoning_show_hidden": "顯示隱藏推理功能模型的推理時間", + "Show Hidden": "顯示隱藏內容", + "reasoning_add_to_prompts": "將現有推理區塊新增至提示詞中。若需新增推理區塊,請使用訊息編輯選單。", + "Add to Prompts": "新增至提示詞", + "reasoning_max_additions": "從最後一則訊息起算,每則提示詞中可新增的最大推理區塊數量。", + "Max": "最大值", + "Reasoning Formatting": "推理格式", + "reasoning_prefix": "插入於推理內容之前。", + "Prefix": "前綴", + "reasoning_suffix": "插入於推理內容之後。", + "Suffix": "後綴", + "reasoning_separator": "插入於推理內容與訊息內容之間。", + "Separator": "分隔符號", + "Character details are hidden.": "角色詳細資訊已隱藏。", + "Add a reasoning block": "新增推理區塊", + "Thought for some time": "思考了一段時間", + "Confirm Edit": "確認", + "Remove reasoning": "移除推理", + "Cancel edit": "取消編輯", + "Copy reasoning": "複製推理", + "Edit reasoning": "編輯推理", + "extension_install_1": "若要從此頁面下載擴充功能,您需要安裝", + "extension_install_2": "已安裝。", + "extension_install_3": "點選", + "extension_install_4": "圖示以存取擴充功能的儲存庫,檢視使用技巧。", + "Use the selected API from Chat Translation extension settings.": "使用擴充功能設定中,「聊天翻譯」所選的翻譯提供者(API)。", + "A single expression can have multiple sprites. Whenever the expression is chosen, a random sprite for this expression will be selected.": "單個同名表情可以有多張角色立繪。每次使用該表情時,會隨機擇一顯示。", + "Allow multiple sprites per expression": "允許單一表情使用多張立繪", + "If the same expression is used again, re-roll the sprite. This only applies to expressions that have multiple available sprites assigned.": "若再次使用相同的表情,將重新隨機選擇。此功能僅適用於分配了多張立繪的表情。", + "Re-roll if same expression is used again": "重複使用同名表情時,隨機選用其他立繪", + "upload_expression_request": "請輸入角色立繪名稱(不含副檔名)。", + "upload_expression_naming_1": "角色立繪名稱必須符合所選表情的命名規則:{{expression}}", + "upload_expression_naming_2": "對於多個表情,名稱必須包含表情名稱和有效的後綴,允許的分隔符號為「-」或「.」。", + "upload_expression_replace": "點選「取代」以取代現有表情:", + "ext_regex_reasoning_desc": "推理區塊內容。當「僅格式化提示詞」已勾選時,這也會影響新增至提示詞的推理內容。", + "Token Counter": "符元計數器", + "Type / paste in the box below to see the number of tokens in the text.": "在下框中輸入或貼上文字以檢視符元(Token)數量。", + "Selected tokenizer:": "選擇的分詞器:", + "Input:": "輸入:", + "Tokens:": "符元數:", + "Tokenized text:": "已符元化的文字:", + "Token IDs:": "符元 ID:", + "Narrate by paragraphs (when not streaming)": "按段落朗讀(不使用「串流」時)", + " folder (typically in ": "資料夾(通常位於 ", + "Copy to Clipboard": "複製到剪貼簿", + "Reset to Defaults": "重設為預設值", + "Toggles Guinevere features.": "切換 Guinevere 功能。", + "Update customCSS": "更新 customCSS", + "Apply Theme": "套用主題", + "Enable Guinevere": "啟用 Guinevere", + "Note: Themes can be made/applied by going to the ": "注意:主題可通過前往以下位置進行創建/應用", + "Theme Name": "主題名稱", + "An unknown error occurred while counting tokens. Further information may be available in console.": "計算符元時發生未知錯誤。更多資訊可能可在主控台(console)中查看。", + "Qvink Memory": "Qvink Memory(進階聊天記憶)", + "Toggle whether memory is enabled for this chat specifically (overrides all settings).": "切換是否為此聊天啟用記憶功能(將覆蓋所有設定)。", + "Toggle Chat Memory": "切換聊天記憶", + "Preview current memory state (the exact text that will be injected into your context).": "預覽目前記憶狀態(包含將嵌入上下文的具體內容)。", + "Copy ALL memories to clipboard (all memories in the entire chat, not just those injected).": "將所有記憶複製到剪貼簿(包含整個聊天的所有記憶,而非僅限於注入的部分)。", + "Just refreshes which memories are included and re-renders the memories under each message, doesn't change summaries. This is done automatically all the time, the button is here just in case.": "不影響摘要,僅更新已包含的聊天記憶,並重新顯示在每則訊息下方。此過程通常會自動執行,按鈕只是備用選項。", + "Active Settings Profile ": "目前設定檔", + "Create, edit, and save configuration profiles for this extension.": "建立、編輯及儲存此擴充功能的設定檔。", + "The currently selected profile": "目前選取的設定檔", + "Save current profile": "儲存此設定檔", + "Rename current profile": "重新命名此設定檔", + "Create new profile": "建立新設定檔", + "Restore current profile": "還原此設定檔", + "Delete current profile": "刪除此設定檔", + "Set as default profile for current character": "設為目前角色的預設設定檔", + "Summarization": "摘要", + "Customize the prompt used to summarize a given message": "自訂用於摘要指定訊息的提示詞", + "Edit the summary prompt": "編輯摘要提示", + "Preview the filled-in summary prompt, using the last message as an example.": "以最後一則訊息為例,預覽填充完成的摘要提示", + "Mass re-summarization. Brings up dialog to choose subsets of messages to summarize or re-summarize.": "批量重新摘要:開啟對話框以選擇訊息子集進行摘要或重新摘要。", + "Stop all summarization immediately.": "立即停止所有摘要。", + "New messages will be automatically summarized if they will be included in short-term memory.": "如果新訊息將被納入短期記憶,將自動進行摘要。", + "Auto Summarize": "自動摘要", + "Auto-summarization will be triggered before a new message is sent instead of after.": "自動摘要將在發送新訊息之前觸發。", + "Auto Summarize Before Generation": "在生成內容前自動摘要", + "Show the progress bar when auto-summarizing more than 1 message.": "在自動摘要多於 1 則訊息時顯示進度條。", + "Auto Summarize Progress Bar": "自動摘要進度條", + "Number of messages to delay summarization (0 = summarize up to the most recent message, 1 = lag behind by one message, etc.)": "延遲摘要的訊息數量(0 = 摘要至最新訊息,1 = 延遲摘要 1 則訊息,以此類推)。", + "Auto Summarize Message Lag": "自動摘要訊息延遲", + "Wait until this many messages before auto-summarizing them all in sequence (1 = summarize every message immediately, 2 = summarize when you have two ready, etc). Still summarizes one at a time.": "在訊息數量達到此設定值後,依序自動摘要(1 = 即時摘要每則訊息,2 = 等待 2 則訊息後再摘要,以此類推)。摘要將逐條執行。", + "Auto Summarize Batch Size": "自動摘要批次大小", + "The maximum number of messages back that auto-summarization will apply (-1 to disable).": "自動摘要可回溯的訊息最大數量(-1 表示禁用此功能)。", + "Auto Summarize Message Limit": "自動摘要訊息上限", + "Time in seconds to wait between summarizations. May be needed if you are using a external API with a rate limit.": "每次摘要的間隔時間(秒)。此設定適用於使用具有請求速率限制的外部 API。", + "Summarization Time Delay": "摘要時間延遲", + "The maximum token length a summary is allowed to be before cutting it off. Use the {{words}} macro in the summarization prompt to get this value.": "摘要在被截斷前允許的最大符元(token)長度。可在摘要提示中使用 {{words}} 巨集以取得此數值。", + "Summary Max Token Length": "摘要允許的最大符元長度", + "Editing a message will automatically trigger a re-summarization if it has already been summarized.": "編輯訊息時,若該訊息已被摘要,將自動觸發重新摘要。", + "Re-summarize on Edit": "編輯後重新摘要", + "Swiping a message will automatically trigger a re-summarization if it has already been summarized.": "滑動訊息後若已進行摘要,將自動觸發重新摘要。", + "Re-summarize on Swipe": "滑動後重新摘要", + "Block chat input while summarizing.": "在摘要進行時暫時禁用聊天訊息輸入。", + "Block Chat": "訊息輸入鎖定", + "Whether to use messages and/or summaries as context for summarization. You must use {{history}} in the summary prompt.": "決定是否在摘要中使用訊息及/或過往摘要作為背景資訊。需於摘要提示詞中,使用 {{history}}。", + "Message History": "訊息歷史", + "Messages": "僅訊息", + "Summaries": "僅摘要", + "Both": "訊息與摘要", + "Preview what the message history will look like": "預覽訊息歷史的顯示效果", + "How many previous messages to include in the summarization prompt as context.": "摘要提示中要包含多少先前訊息作為上下文。", + "Number of Previous Messages": "先前訊息數量", + "When including previous messages, also include user messages.": "包含先前訊息時,也包含使用者訊息。", + "Include Previous User Messages": "包含先前使用者訊息", + "The message to summarize will be inside the system instruct template itself. In unchecked (default), the message will instead be added separately after the prompt. Some models benefit from this, but it is not recommended.": "系統指令模板內將直接包含需要摘要的訊息。若未啟用此選項(預設設定),訊息會在提示後分開添加。儘管某些模型可能更適合此設定,但一般不建議使用。", + "Nest Message in Summary Prompt": "在摘要提示中內嵌訊息", + "WARNING: doesn't work great. Attempts to preserve context-shifting by including all the content that is sent in regular prompts (world info, description, personas, example messages, message history, etc). If your regular prompts are static, this can allow Context Shifting to work between summarizations, but it decreases the accuracy of summarization due to all the extra stuff in the prompt. It also can't be previewed as this injection is handled by ST, not the extension.": "警告:效果不佳。此功能嘗試透過在摘要時包含所有常規提示內容(如世界資訊、描述、角色設定、示範訊息、聊天歷史等)來保留上下文轉換。若您的常規提示為靜態內容,則可在摘要之間維持上下文轉換,但由於提示中包含大量額外資訊,將降低摘要的準確性。此外,此內容注入由 ST 處理,而非此擴充功能,因此無法進行預覽。", + "Include All Context Content": "包含所有上下文內容", + "Short-term Memory Injection": "短期記憶注入", + "Determines which messages are included in the short-term memory injection and where. If you change this and include messages that weren't summarized previously, you can either manually trigger a re-summarization or just wait until automatic summarization triggers.": "設定短期記憶注入中所包含的訊息及其插入位置。若更改此設定並包含先前未摘要的訊息,您可手動觸發重新摘要,或等待自動摘要啟動。", + "Edit the short-term memory prompt": "編輯短期記憶提示", + "Include User Messages": "包含使用者訊息", + "Include System Messages": "包含系統訊息", + "Include Thought Message": "包含思考訊息", + "Message Length Threshold": "訊息長度閾值", + "The minimum token length a message has to be in order to get summarized.": "可被摘要的訊息最小符元長度。", + "The max percent of the context that short-term memory can take up.": "短期記憶可佔用上下文的最大百分比。", + "Short-Term Context %": "短期記憶上下文%", + "Include short-term memory in the World Info Scan": "在世界資訊掃描中包含短期記憶", + "Do not inject": "不注入", + "Before main prompt": "主提示之前", + "After main prompt": "主提示之後", + "In chat at depth": "在對話中位於深度", + "Long-Term Memory Injection": "長期記憶注入", + "Determines where long-term messages are injected.": "決定長期訊息注入的位置。", + "Edit the long-term memory prompt": "編輯長期記憶提示", + "The max percent of the context that long-term memory can take up.": "長期記憶可佔用上下文的最大百分比。", + "Long-Term Context %": "長期記憶上下文%", + "Include long-term memory in the World Info Scan": "在世界資訊掃描中包含長期記憶", + "Misc.": "其他", + "Fill your console with debug messages": "將偵錯訊息填入主控台", + "Debug Mode": "偵錯模式", + "Display summarizations below each message": "在每則訊息下顯示摘要", + "Display Memories": "顯示記憶", + "Enable Memory in New Chats": "在新對話中啟用記憶", + "Limit Message History": "限制訊息歷史", + "Revert Settings": "還原設定", + "Auto-summarize user messages and include summaries in memory.": "自動摘要使用者訊息,並將該摘要納入記憶。", + "Auto-summarize system messages and include summaries in memory.": "自動摘要系統訊息,並將該摘要納入記憶。", + "Auto-summarize thought messages and include summaries in memory (from the Stepped Thinking extension).": "自動摘要思考訊息並將摘要納入記憶(來自 Stepped Thinking 擴充功能)。", + "Revert all settings to default (not the default profile, just the default that comes with the extension). Your other profiles won't be affected.": "將所有設定恢復為預設值(並非恢復至「預設設定檔」,而是擴充功能隨附的原始預設值)。其他設定檔將不受影響。", + "Limit the number of messages to send in regular prompts to this number (-1 for no limit). Message memories will still be sent.": "限制常規提示中傳送的訊息數量至此數值(-1 表示無限制)。訊息記憶仍將一併傳送。", + "Whether memory is enabled by default for new chats.": "是否在新對話中預設啟用記憶。", + "Summarize Chat": "摘要對話", + "Choose settings for the chat summarization. All message inclusion/exclusion settings from the main config profile are used, in addition to the following options.": "選擇聊天摘要的設定。摘要時將使用主要設定檔中的所有訊息包含/排除規則,並可額外設定以下選項。", + "Currently preparing to summarize:": "目前正在準備摘要:", + "Summarize messages with no existing summary": "摘要尚無摘要的訊息", + "Re-summarize messages with existing short-term memories": "重新摘要具有現有短期記憶的訊息", + "Re-summarize messages with existing long-term memories": "重新摘要具有現有長期記憶的訊息", + "Re-summarize messages with existing memories, but which are currently excluded from short-term and long-term memory": "重新摘要具有現有記憶,但目前被排除在短期和長期記憶之外的訊息", + "Re-summarize messages with existing memories that have been manually edited.": "重新摘要已手動編輯的訊息記憶", + "Type the folder name of the theme you want to apply.": "輸入您想套用的主題資料夾名稱。", + "Place your theme data in a folder.": "請將主題資料存於該資料夾內。", + "Unsure where to start? Type ": "不確定如何開始?輸入:", + " to apply the default Google Messages theme or click ": " 即可使用預設主題 Google Messages,或點擊", + "here": "這裡", + " to learn how to create your own theme.": " 以學習如何創建個人化主題。", + "Guinevere (UI Theme Extension)": "Guinevere(進階自定義 UI 主題)", + "and Guinaifen.": "和 Guinaifen(桂乃芬)呈獻。" +} diff --git a/jiuguan2025cc/public/login.html b/jiuguan2025cc/public/login.html new file mode 100644 index 0000000000000000000000000000000000000000..11456a22a601c0aee392c016ccbac212ac3dca68 --- /dev/null +++ b/jiuguan2025cc/public/login.html @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SillyTavern + + + +
      +
      +
      +
      +
      +

      + + Welcome to SillyTavern +

      +

      + Select an Account +

      +

      + Enter Login Details +

      +
      +
      + + + +
      +
      +
      +
      +
      +
      +
      +
      + + + + + + diff --git a/jiuguan2025cc/public/manifest.json b/jiuguan2025cc/public/manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..28df3de4cd76c1873b6e73b89c1a9a49a48e08ca --- /dev/null +++ b/jiuguan2025cc/public/manifest.json @@ -0,0 +1,30 @@ +{ + "name": "SillyTavern", + "short_name": "SillyTavern", + "start_url": "/", + "display": "standalone", + "theme_color": "#202124", + "background_color": "#202124", + "icons": [ + { + "src": "img/apple-icon-57x57.png", + "sizes": "57x57", + "type": "image/png" + }, + { + "src": "img/apple-icon-72x72.png", + "sizes": "72x72", + "type": "image/png" + }, + { + "src": "img/apple-icon-114x114.png", + "sizes": "114x114", + "type": "image/png" + }, + { + "src": "img/apple-icon-144x144.png", + "sizes": "144x144", + "type": "image/png" + } + ] +} diff --git a/jiuguan2025cc/public/robots.txt b/jiuguan2025cc/public/robots.txt new file mode 100644 index 0000000000000000000000000000000000000000..1f53798bb4fe33c86020be7f10c44f29486fd190 --- /dev/null +++ b/jiuguan2025cc/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / diff --git a/jiuguan2025cc/public/script.js b/jiuguan2025cc/public/script.js new file mode 100644 index 0000000000000000000000000000000000000000..21b2c3e337a234e1bde3ae9195488041552055a9 --- /dev/null +++ b/jiuguan2025cc/public/script.js @@ -0,0 +1,12034 @@ +import { + showdown, + moment, + Fuse, + DOMPurify, + hljs, + localforage, + Handlebars, + DiffMatchPatch, + SVGInject, + Popper, + initLibraryShims, + slideToggle, + default as libs, +} from './lib.js'; + +import { humanizedDateTime, favsToHotswap, getMessageTimeStamp, dragElement, isMobile, initRossMods } from './scripts/RossAscends-mods.js'; +import { userStatsHandler, statMesProcess, initStats } from './scripts/stats.js'; +import { + generateKoboldWithStreaming, + kai_settings, + loadKoboldSettings, + formatKoboldUrl, + getKoboldGenerationData, + kai_flags, + setKoboldFlags, +} from './scripts/kai-settings.js'; + +import { + textgenerationwebui_settings as textgen_settings, + loadTextGenSettings, + generateTextGenWithStreaming, + getTextGenGenerationData, + textgen_types, + getTextGenServer, + validateTextGenUrl, + parseTextgenLogprobs, + parseTabbyLogprobs, +} from './scripts/textgen-settings.js'; + +import { + world_info, + getWorldInfoPrompt, + getWorldInfoSettings, + setWorldInfoSettings, + world_names, + importEmbeddedWorldInfo, + checkEmbeddedWorld, + setWorldInfoButtonClass, + importWorldInfo, + wi_anchor_position, + world_info_include_names, +} from './scripts/world-info.js'; + +import { + groups, + selected_group, + saveGroupChat, + getGroups, + generateGroupWrapper, + is_group_generating, + resetSelectedGroup, + select_group_chats, + regenerateGroup, + group_generation_id, + getGroupChat, + renameGroupMember, + createNewGroupChat, + getGroupAvatar, + editGroup, + deleteGroupChat, + renameGroupChat, + importGroupChat, + getGroupBlock, + getGroupCharacterCards, + getGroupDepthPrompts, +} from './scripts/group-chats.js'; + +import { + collapseNewlines, + loadPowerUserSettings, + playMessageSound, + fixMarkdown, + power_user, + persona_description_positions, + loadMovingUIState, + getCustomStoppingStrings, + MAX_CONTEXT_DEFAULT, + MAX_RESPONSE_DEFAULT, + renderStoryString, + sortEntitiesList, + registerDebugFunction, + flushEphemeralStoppingStrings, + context_presets, + resetMovableStyles, + forceCharacterEditorTokenize, + applyPowerUserSettings, + generatedTextFiltered, +} from './scripts/power-user.js'; + +import { + setOpenAIMessageExamples, + setOpenAIMessages, + setupChatCompletionPromptManager, + prepareOpenAIMessages, + sendOpenAIRequest, + loadOpenAISettings, + oai_settings, + openai_messages_count, + chat_completion_sources, + getChatCompletionModel, + proxies, + loadProxyPresets, + selected_proxy, + initOpenAI, +} from './scripts/openai.js'; + +import { + generateNovelWithStreaming, + getNovelGenerationData, + getKayraMaxContextTokens, + getNovelTier, + loadNovelPreset, + loadNovelSettings, + nai_settings, + adjustNovelInstructionPrompt, + loadNovelSubscriptionData, + parseNovelAILogprobs, +} from './scripts/nai-settings.js'; + +import { + initBookmarks, + showBookmarksButtons, + updateBookmarkDisplay, +} from './scripts/bookmarks.js'; + +import { + horde_settings, + loadHordeSettings, + generateHorde, + checkHordeStatus, + getHordeModels, + adjustHordeGenerationParams, + MIN_LENGTH, +} from './scripts/horde.js'; + +import { + debounce, + delay, + trimToEndSentence, + countOccurrences, + isOdd, + sortMoments, + timestampToMoment, + download, + isDataURL, + getCharaFilename, + PAGINATION_TEMPLATE, + waitUntilCondition, + escapeRegex, + resetScrollHeight, + onlyUnique, + getBase64Async, + humanFileSize, + Stopwatch, + isValidUrl, + ensureImageFormatSupported, + flashHighlight, + isTrueBoolean, + toggleDrawer, + isElementInViewport, + copyText, + escapeHtml, + saveBase64AsFile, +} from './scripts/utils.js'; +import { debounce_timeout } from './scripts/constants.js'; + +import { doDailyExtensionUpdatesCheck, extension_settings, initExtensions, loadExtensionSettings, runGenerationInterceptors, saveMetadataDebounced } from './scripts/extensions.js'; +import { COMMENT_NAME_DEFAULT, executeSlashCommandsOnChatInput, getSlashCommandsHelp, initDefaultSlashCommands, isExecutingCommandsFromChatInput, pauseScriptExecution, processChatSlashCommands, stopScriptExecution } from './scripts/slash-commands.js'; +import { + tag_map, + tags, + filterByTagState, + isBogusFolder, + isBogusFolderOpen, + chooseBogusFolder, + getTagBlock, + loadTagsSettings, + printTagFilters, + getTagKeyForEntity, + printTagList, + createTagMapFromList, + renameTagKey, + importTags, + tag_filter_type, + compareTagsForSort, + initTags, + applyTagsOnCharacterSelect, + applyTagsOnGroupSelect, + tag_import_setting, +} from './scripts/tags.js'; +import { + SECRET_KEYS, + readSecretState, + secret_state, + writeSecret, +} from './scripts/secrets.js'; +import { EventEmitter } from './lib/eventemitter.js'; +import { markdownExclusionExt } from './scripts/showdown-exclusion.js'; +import { markdownUnderscoreExt } from './scripts/showdown-underscore.js'; +import { NOTE_MODULE_NAME, initAuthorsNote, metadata_keys, setFloatingPrompt, shouldWIAddPrompt } from './scripts/authors-note.js'; +import { registerPromptManagerMigration } from './scripts/PromptManager.js'; +import { getRegexedString, regex_placement } from './scripts/extensions/regex/engine.js'; +import { initLogprobs, saveLogprobsForActiveMessage } from './scripts/logprobs.js'; +import { FILTER_STATES, FILTER_TYPES, FilterHelper, isFilterState } from './scripts/filters.js'; +import { getCfgPrompt, getGuidanceScale, initCfg } from './scripts/cfg-scale.js'; +import { + force_output_sequence, + formatInstructModeChat, + formatInstructModePrompt, + formatInstructModeExamples, + getInstructStoppingSequences, + autoSelectInstructPreset, + formatInstructModeSystemPrompt, + selectInstructPreset, + instruct_presets, + selectContextPreset, +} from './scripts/instruct-mode.js'; +import { initLocales, t } from './scripts/i18n.js'; +import { getFriendlyTokenizerName, getTokenCount, getTokenCountAsync, initTokenizers, saveTokenCache, TOKENIZER_SUPPORTED_KEY } from './scripts/tokenizers.js'; +import { + user_avatar, + getUserAvatars, + getUserAvatar, + setUserAvatar, + initPersonas, + setPersonaDescription, + initUserAvatar, + updatePersonaConnectionsAvatarList, + isPersonaPanelOpen, +} from './scripts/personas.js'; +import { getBackgrounds, initBackgrounds, loadBackgroundSettings, background_settings } from './scripts/backgrounds.js'; +import { hideLoader, showLoader } from './scripts/loader.js'; +import { BulkEditOverlay, CharacterContextMenu } from './scripts/BulkEditOverlay.js'; +import { loadFeatherlessModels, loadMancerModels, loadOllamaModels, loadTogetherAIModels, loadInfermaticAIModels, loadOpenRouterModels, loadVllmModels, loadAphroditeModels, loadDreamGenModels, initTextGenModels, loadTabbyModels, loadGenericModels } from './scripts/textgen-models.js'; +import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags, isExternalMediaAllowed, getCurrentEntityId, preserveNeutralChat, restoreNeutralChat } from './scripts/chats.js'; +import { getPresetManager, initPresetManager } from './scripts/preset-manager.js'; +import { evaluateMacros, getLastMessageId, initMacros } from './scripts/macros.js'; +import { currentUser, setUserControls } from './scripts/user.js'; +import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup, fixToastrForDialogs } from './scripts/popup.js'; +import { renderTemplate, renderTemplateAsync } from './scripts/templates.js'; +import { initScrapers } from './scripts/scrapers.js'; +import { SlashCommandParser } from './scripts/slash-commands/SlashCommandParser.js'; +import { SlashCommand } from './scripts/slash-commands/SlashCommand.js'; +import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './scripts/slash-commands/SlashCommandArgument.js'; +import { SlashCommandBrowser } from './scripts/slash-commands/SlashCommandBrowser.js'; +import { initCustomSelectedSamplers, validateDisabledSamplers } from './scripts/samplerSelect.js'; +import { DragAndDropHandler } from './scripts/dragdrop.js'; +import { INTERACTABLE_CONTROL_CLASS, initKeyboard } from './scripts/keyboard.js'; +import { initDynamicStyles } from './scripts/dynamic-styles.js'; +import { SlashCommandEnumValue, enumTypes } from './scripts/slash-commands/SlashCommandEnumValue.js'; +import { commonEnumProviders, enumIcons } from './scripts/slash-commands/SlashCommandCommonEnumsProvider.js'; +import { initInputMarkdown } from './scripts/input-md-formatting.js'; +import { AbortReason } from './scripts/util/AbortReason.js'; +import { initSystemPrompts } from './scripts/sysprompt.js'; +import { registerExtensionSlashCommands as initExtensionSlashCommands } from './scripts/extensions-slashcommands.js'; +import { ToolManager } from './scripts/tool-calling.js'; +import { addShowdownPatch } from './scripts/util/showdown-patch.js'; +import { applyBrowserFixes } from './scripts/browser-fixes.js'; +import { initServerHistory } from './scripts/server-history.js'; +import { initSettingsSearch } from './scripts/setting-search.js'; +import { initBulkEdit } from './scripts/bulk-edit.js'; +import { deriveTemplatesFromChatTemplate } from './scripts/chat-templates.js'; +import { getContext } from './scripts/st-context.js'; +import { extractReasoningFromData, initReasoning, parseReasoningInSwipes, PromptReasoning, ReasoningHandler, removeReasoningFromString, updateReasoningUI } from './scripts/reasoning.js'; +import { accountStorage } from './scripts/util/AccountStorage.js'; + +// API OBJECT FOR EXTERNAL WIRING +globalThis.SillyTavern = { + libs, + getContext, +}; + +//exporting functions and vars for mods +export { + user_avatar, + setUserAvatar, + getUserAvatars, + getUserAvatar, + nai_settings, + isOdd, + countOccurrences, + renderTemplate, +}; + +/** + * Wait for page to load before continuing the app initialization. + */ +await new Promise((resolve) => { + if (document.readyState === 'complete') { + resolve(); + } else { + window.addEventListener('load', resolve); + } +}); + +showLoader(); + +// Configure toast library: +toastr.options.escapeHtml = true; // Prevent raw HTML inserts +toastr.options.timeOut = 4000; // How long the toast will display without user interaction +toastr.options.extendedTimeOut = 10000; // How long the toast will display after a user hovers over it +toastr.options.progressBar = true; // Visually indicate how long before a toast expires. +toastr.options.closeButton = true; // enable a close button +toastr.options.positionClass = 'toast-top-center'; // Where to position the toast container +toastr.options.onHidden = () => { + // If we have any dialog still open, the last "hidden" toastr will remove the toastr-container. We need to keep it alive inside the dialog though + // so the toasts still show up inside there. + fixToastrForDialogs(); +}; + +// Allow target="_blank" in links +DOMPurify.addHook('afterSanitizeAttributes', function (node) { + if ('target' in node) { + node.setAttribute('target', '_blank'); + node.setAttribute('rel', 'noopener'); + } +}); + +DOMPurify.addHook('uponSanitizeAttribute', (node, data, config) => { + if (!config['MESSAGE_SANITIZE']) { + return; + } + + /* Retain the classes on UI elements of messages that interact with the main UI */ + const permittedNodeTypes = ['BUTTON', 'DIV']; + if (config['MESSAGE_ALLOW_SYSTEM_UI'] && node.classList.contains('menu_button') && permittedNodeTypes.includes(node.nodeName)) { + return; + } + + switch (data.attrName) { + case 'class': { + if (data.attrValue) { + data.attrValue = data.attrValue.split(' ').map((v) => { + if (v.startsWith('fa-') || v.startsWith('note-') || v === 'monospace') { + return v; + } + + return 'custom-' + v; + }).join(' '); + } + break; + } + } +}); + +DOMPurify.addHook('uponSanitizeElement', (node, _, config) => { + if (!config['MESSAGE_SANITIZE']) { + return; + } + + // Replace line breaks with
      in unknown elements + if (node instanceof HTMLUnknownElement) { + node.innerHTML = node.innerHTML.replaceAll('\n', '
      '); + } + + const isMediaAllowed = isExternalMediaAllowed(); + if (isMediaAllowed) { + return; + } + + if (!(node instanceof Element)) { + return; + } + + let mediaBlocked = false; + + switch (node.tagName) { + case 'AUDIO': + case 'VIDEO': + case 'SOURCE': + case 'TRACK': + case 'EMBED': + case 'OBJECT': + case 'IMG': { + const isExternalUrl = (url) => (url.indexOf('://') > 0 || url.indexOf('//') === 0) && !url.startsWith(window.location.origin); + const src = node.getAttribute('src'); + const data = node.getAttribute('data'); + const srcset = node.getAttribute('srcset'); + + if (srcset) { + const srcsetUrls = srcset.split(','); + + for (const srcsetUrl of srcsetUrls) { + const [url] = srcsetUrl.trim().split(' '); + + if (isExternalUrl(url)) { + console.warn('External media blocked', url); + node.remove(); + mediaBlocked = true; + break; + } + } + } + + if (src && isExternalUrl(src)) { + console.warn('External media blocked', src); + mediaBlocked = true; + node.remove(); + } + + if (data && isExternalUrl(data)) { + console.warn('External media blocked', data); + mediaBlocked = true; + node.remove(); + } + + if (mediaBlocked && (node instanceof HTMLMediaElement)) { + node.autoplay = false; + node.pause(); + } + } + break; + } + + if (mediaBlocked) { + const entityId = getCurrentEntityId(); + const warningShownKey = `mediaWarningShown:${entityId}`; + + if (accountStorage.getItem(warningShownKey) === null) { + const warningToast = toastr.warning( + t`Use the 'Ext. Media' button to allow it. Click on this message to dismiss.`, + t`External media has been blocked`, + { + timeOut: 0, + preventDuplicates: true, + onclick: () => toastr.clear(warningToast), + }, + ); + + accountStorage.setItem(warningShownKey, 'true'); + } + } +}); + +// Event source init +export const event_types = { + APP_READY: 'app_ready', + EXTRAS_CONNECTED: 'extras_connected', + MESSAGE_SWIPED: 'message_swiped', + MESSAGE_SENT: 'message_sent', + MESSAGE_RECEIVED: 'message_received', + MESSAGE_EDITED: 'message_edited', + MESSAGE_DELETED: 'message_deleted', + MESSAGE_UPDATED: 'message_updated', + MESSAGE_FILE_EMBEDDED: 'message_file_embedded', + MESSAGE_REASONING_EDITED: 'message_reasoning_edited', + MESSAGE_REASONING_DELETED: 'message_reasoning_deleted', + MORE_MESSAGES_LOADED: 'more_messages_loaded', + IMPERSONATE_READY: 'impersonate_ready', + CHAT_CHANGED: 'chat_id_changed', + GENERATION_AFTER_COMMANDS: 'GENERATION_AFTER_COMMANDS', + GENERATION_STARTED: 'generation_started', + GENERATION_STOPPED: 'generation_stopped', + GENERATION_ENDED: 'generation_ended', + EXTENSIONS_FIRST_LOAD: 'extensions_first_load', + EXTENSION_SETTINGS_LOADED: 'extension_settings_loaded', + SETTINGS_LOADED: 'settings_loaded', + SETTINGS_UPDATED: 'settings_updated', + GROUP_UPDATED: 'group_updated', + MOVABLE_PANELS_RESET: 'movable_panels_reset', + SETTINGS_LOADED_BEFORE: 'settings_loaded_before', + SETTINGS_LOADED_AFTER: 'settings_loaded_after', + CHATCOMPLETION_SOURCE_CHANGED: 'chatcompletion_source_changed', + CHATCOMPLETION_MODEL_CHANGED: 'chatcompletion_model_changed', + OAI_PRESET_CHANGED_BEFORE: 'oai_preset_changed_before', + OAI_PRESET_CHANGED_AFTER: 'oai_preset_changed_after', + OAI_PRESET_EXPORT_READY: 'oai_preset_export_ready', + OAI_PRESET_IMPORT_READY: 'oai_preset_import_ready', + WORLDINFO_SETTINGS_UPDATED: 'worldinfo_settings_updated', + WORLDINFO_UPDATED: 'worldinfo_updated', + CHARACTER_EDITED: 'character_edited', + CHARACTER_PAGE_LOADED: 'character_page_loaded', + CHARACTER_GROUP_OVERLAY_STATE_CHANGE_BEFORE: 'character_group_overlay_state_change_before', + CHARACTER_GROUP_OVERLAY_STATE_CHANGE_AFTER: 'character_group_overlay_state_change_after', + USER_MESSAGE_RENDERED: 'user_message_rendered', + CHARACTER_MESSAGE_RENDERED: 'character_message_rendered', + FORCE_SET_BACKGROUND: 'force_set_background', + CHAT_DELETED: 'chat_deleted', + CHAT_CREATED: 'chat_created', + GROUP_CHAT_DELETED: 'group_chat_deleted', + GROUP_CHAT_CREATED: 'group_chat_created', + GENERATE_BEFORE_COMBINE_PROMPTS: 'generate_before_combine_prompts', + GENERATE_AFTER_COMBINE_PROMPTS: 'generate_after_combine_prompts', + GENERATE_AFTER_DATA: 'generate_after_data', + GROUP_MEMBER_DRAFTED: 'group_member_drafted', + WORLD_INFO_ACTIVATED: 'world_info_activated', + TEXT_COMPLETION_SETTINGS_READY: 'text_completion_settings_ready', + CHAT_COMPLETION_SETTINGS_READY: 'chat_completion_settings_ready', + CHAT_COMPLETION_PROMPT_READY: 'chat_completion_prompt_ready', + CHARACTER_FIRST_MESSAGE_SELECTED: 'character_first_message_selected', + // TODO: Naming convention is inconsistent with other events + CHARACTER_DELETED: 'characterDeleted', + CHARACTER_DUPLICATED: 'character_duplicated', + CHARACTER_RENAMED: 'character_renamed', + CHARACTER_RENAMED_IN_PAST_CHAT: 'character_renamed_in_past_chat', + /** @deprecated The event is aliased to STREAM_TOKEN_RECEIVED. */ + SMOOTH_STREAM_TOKEN_RECEIVED: 'stream_token_received', + STREAM_TOKEN_RECEIVED: 'stream_token_received', + STREAM_REASONING_DONE: 'stream_reasoning_done', + FILE_ATTACHMENT_DELETED: 'file_attachment_deleted', + WORLDINFO_FORCE_ACTIVATE: 'worldinfo_force_activate', + OPEN_CHARACTER_LIBRARY: 'open_character_library', + ONLINE_STATUS_CHANGED: 'online_status_changed', + IMAGE_SWIPED: 'image_swiped', + CONNECTION_PROFILE_LOADED: 'connection_profile_loaded', + TOOL_CALLS_PERFORMED: 'tool_calls_performed', + TOOL_CALLS_RENDERED: 'tool_calls_rendered', +}; + +export const eventSource = new EventEmitter([event_types.APP_READY]); + +eventSource.on(event_types.CHAT_CHANGED, processChatSlashCommands); + +export const characterGroupOverlay = new BulkEditOverlay(); +const characterContextMenu = new CharacterContextMenu(characterGroupOverlay); +eventSource.on(event_types.CHARACTER_PAGE_LOADED, characterGroupOverlay.onPageLoad); +console.debug('Character context menu initialized', characterContextMenu); + +// Markdown converter +export let mesForShowdownParse; //intended to be used as a context to compare showdown strings against +/** @type {import('showdown').Converter} */ +let converter; + +// array for prompt token calculations +console.debug('initializing Prompt Itemization Array on Startup'); +const promptStorage = localforage.createInstance({ name: 'SillyTavern_Prompts' }); +export let itemizedPrompts = []; + +export const systemUserName = 'SillyTavern System'; +export const neutralCharacterName = 'Assistant'; +let default_user_name = 'User'; +export let name1 = default_user_name; +export let name2 = systemUserName; +export let chat = []; +let chatSaveTimeout; +let importFlashTimeout; +export let isChatSaving = false; +let chat_create_date = ''; +let firstRun = false; +let settingsReady = false; +let currentVersion = '0.0.0'; +let displayVersion = 'SillyTavern'; + +let generatedPromptCache = ''; +let generation_started = new Date(); +/** @type {import('./scripts/char-data.js').v1CharData[]} */ +export let characters = []; +/** + * Stringified index of a currently chosen entity in the characters array. + * @type {string|undefined} Yes, we hate it as much as you do. + */ +export let this_chid; +let saveCharactersPage = 0; +export const default_avatar = 'img/ai4.png'; +export const system_avatar = 'img/five.png'; +export const comment_avatar = 'img/quill.png'; +export const default_user_avatar = 'img/user-default.png'; +export let CLIENT_VERSION = 'SillyTavern:UNKNOWN:Cohee#1207'; // For Horde header +let optionsPopper = Popper.createPopper(document.getElementById('options_button'), document.getElementById('options'), { + placement: 'top-start', +}); +let exportPopper = Popper.createPopper(document.getElementById('export_button'), document.getElementById('export_format_popup'), { + placement: 'left', +}); +let isExportPopupOpen = false; + +// Saved here for performance reasons +const messageTemplate = $('#message_template .mes'); +const chatElement = $('#chat'); + +let dialogueResolve = null; +let dialogueCloseStop = false; +export let chat_metadata = {}; +/** @type {StreamingProcessor} */ +export let streamingProcessor = null; +let crop_data = undefined; +let is_delete_mode = false; +let fav_ch_checked = false; +let scrollLock = false; +export let abortStatusCheck = new AbortController(); +let charDragDropHandler = null; + +/** @type {debounce_timeout} The debounce timeout used for chat/settings save. debounce_timeout.long: 1.000 ms */ +export const DEFAULT_SAVE_EDIT_TIMEOUT = debounce_timeout.relaxed; +/** @type {debounce_timeout} The debounce timeout used for printing. debounce_timeout.quick: 100 ms */ +export const DEFAULT_PRINT_TIMEOUT = debounce_timeout.quick; + +export const saveSettingsDebounced = debounce((loopCounter = 0) => saveSettings(loopCounter), DEFAULT_SAVE_EDIT_TIMEOUT); +export const saveCharacterDebounced = debounce(() => $('#create_button').trigger('click'), DEFAULT_SAVE_EDIT_TIMEOUT); + +/** + * Prints the character list in a debounced fashion without blocking, with a delay of 100 milliseconds. + * Use this function instead of a direct `printCharacters()` whenever the reprinting of the character list is not the primary focus. + * + * The printing will also always reprint all filter options of the global list, to keep them up to date. + */ +export const printCharactersDebounced = debounce(() => { printCharacters(false); }, DEFAULT_PRINT_TIMEOUT); + +/** + * @enum {string} System message types + */ +export const system_message_types = { + HELP: 'help', + WELCOME: 'welcome', + EMPTY: 'empty', + GENERIC: 'generic', + NARRATOR: 'narrator', + COMMENT: 'comment', + SLASH_COMMANDS: 'slash_commands', + FORMATTING: 'formatting', + HOTKEYS: 'hotkeys', + MACROS: 'macros', + WELCOME_PROMPT: 'welcome_prompt', + ASSISTANT_NOTE: 'assistant_note', +}; + +/** + * @enum {number} Extension prompt types + */ +export const extension_prompt_types = { + NONE: -1, + IN_PROMPT: 0, + IN_CHAT: 1, + BEFORE_PROMPT: 2, +}; + +/** + * @enum {number} Extension prompt roles + */ +export const extension_prompt_roles = { + SYSTEM: 0, + USER: 1, + ASSISTANT: 2, +}; + +export const MAX_INJECTION_DEPTH = 1000; + +const SAFETY_CHAT = [ + { + name: systemUserName, + force_avatar: system_avatar, + is_system: true, + is_user: false, + create_date: 0, + mes: 'You deleted a character/chat and arrived back here for safety reasons! Pick another character!', + }, +]; + +export let system_messages = {}; + +async function getSystemMessages() { + system_messages = { + help: { + name: systemUserName, + force_avatar: system_avatar, + is_user: false, + is_system: true, + mes: await renderTemplateAsync('help'), + }, + slash_commands: { + name: systemUserName, + force_avatar: system_avatar, + is_user: false, + is_system: true, + mes: '', + }, + hotkeys: { + name: systemUserName, + force_avatar: system_avatar, + is_user: false, + is_system: true, + mes: await renderTemplateAsync('hotkeys'), + }, + formatting: { + name: systemUserName, + force_avatar: system_avatar, + is_user: false, + is_system: true, + mes: await renderTemplateAsync('formatting'), + }, + macros: { + name: systemUserName, + force_avatar: system_avatar, + is_user: false, + is_system: true, + mes: await renderTemplateAsync('macros'), + }, + welcome: + { + name: systemUserName, + force_avatar: system_avatar, + is_user: false, + is_system: true, + uses_system_ui: true, + mes: await renderTemplateAsync('welcome', { displayVersion }), + }, + empty: { + name: systemUserName, + force_avatar: system_avatar, + is_user: false, + is_system: true, + mes: 'No one hears you. Hint: add more members to the group!', + }, + generic: { + name: systemUserName, + force_avatar: system_avatar, + is_user: false, + is_system: true, + mes: 'Generic system message. User `text` parameter to override the contents', + }, + welcome_prompt: { + name: systemUserName, + force_avatar: system_avatar, + is_user: false, + is_system: true, + mes: await renderTemplateAsync('welcomePrompt'), + extra: { + isSmallSys: true, + }, + }, + assistant_note: { + name: systemUserName, + force_avatar: system_avatar, + is_user: false, + is_system: true, + mes: await renderTemplateAsync('assistantNote'), + uses_system_ui: true, + extra: { + isSmallSys: true, + }, + }, + }; +} + +// Register configuration migrations +registerPromptManagerMigration(); + +$(document).ajaxError(function myErrorHandler(_, xhr) { + // Cohee: CSRF doesn't error out in multiple tabs anymore, so this is unnecessary + /* + if (xhr.status == 403) { + toastr.warning( + 'doubleCsrf errors in console are NORMAL in this case. If you want to run ST in multiple tabs, start the server with --disableCsrf option.', + 'Looks like you\'ve opened SillyTavern in another browser tab', + { timeOut: 0, extendedTimeOut: 0, preventDuplicates: true }, + ); + } */ +}); + +async function getClientVersion() { + try { + const response = await fetch('/version'); + const data = await response.json(); + CLIENT_VERSION = data.agent; + displayVersion = `SillyTavern ${data.pkgVersion}`; + currentVersion = data.pkgVersion; + + if (data.gitRevision && data.gitBranch) { + displayVersion += ` '${data.gitBranch}' (${data.gitRevision})`; + } + + $('#version_display').text(displayVersion); + $('#version_display_welcome').text(displayVersion); + } catch (err) { + console.error('Couldn\'t get client version', err); + } +} + +export function reloadMarkdownProcessor() { + converter = new showdown.Converter({ + emoji: true, + literalMidWordUnderscores: true, + parseImgDimensions: true, + tables: true, + underline: true, + simpleLineBreaks: true, + strikethrough: true, + disableForced4SpacesIndentedSublists: true, + extensions: [markdownUnderscoreExt()], + }); + + // Inject the dinkus extension after creating the converter + // Maybe move this into power_user init? + converter.addExtension(markdownExclusionExt(), 'exclusion'); + + return converter; +} + +export function getCurrentChatId() { + if (selected_group) { + return groups.find(x => x.id == selected_group)?.chat_id; + } + else if (this_chid !== undefined) { + return characters[this_chid]?.chat; + } +} + +export const talkativeness_default = 0.5; +export const depth_prompt_depth_default = 4; +export const depth_prompt_role_default = 'system'; +const per_page_default = 50; + +var is_advanced_char_open = false; + +/** + * The type of the right menu + * @typedef {'characters' | 'character_edit' | 'create' | 'group_edit' | 'group_create' | '' } MenuType + */ + +/** + * The type of the right menu that is currently open + * @type {MenuType} + */ +export let menu_type = ''; + +export let selected_button = ''; //which button pressed + +//create pole save +export let create_save = { + name: '', + description: '', + creator_notes: '', + post_history_instructions: '', + character_version: '', + system_prompt: '', + tags: '', + creator: '', + personality: '', + first_message: '', + avatar: '', + scenario: '', + mes_example: '', + world: '', + talkativeness: talkativeness_default, + alternate_greetings: [], + depth_prompt_prompt: '', + depth_prompt_depth: depth_prompt_depth_default, + depth_prompt_role: depth_prompt_role_default, + extensions: {}, +}; + +//animation right menu +export const ANIMATION_DURATION_DEFAULT = 125; +export let animation_duration = ANIMATION_DURATION_DEFAULT; +export let animation_easing = 'ease-in-out'; +let popup_type = ''; +let chat_file_for_del = ''; +export let online_status = 'no_connection'; + +export let api_server = ''; + +export let is_send_press = false; //Send generation + +let this_del_mes = -1; + +//message editing +var this_edit_mes_chname = ''; +var this_edit_mes_id; + +//settings +export let settings; +export let koboldai_settings; +export let koboldai_setting_names; +var preset_settings = 'gui'; +export let amount_gen = 80; //default max length of AI generated responses +export let max_context = 2048; + +var swipes = true; +export let extension_prompts = {}; + +export let main_api;// = "kobold"; +//novel settings +export let novelai_settings; +export let novelai_setting_names; +/** @type {AbortController} */ +let abortController; + +//css +var css_send_form_display = $('
      ').css('display'); + +var kobold_horde_model = ''; + +export let token; + +var PromptArrayItemForRawPromptDisplay; +var priorPromptArrayItemForRawPromptDisplay; + +/** The tag of the active character. (NOT the id) */ +export let active_character = ''; +/** The tag of the active group. (Coincidentally also the id) */ +export let active_group = ''; + +export const entitiesFilter = new FilterHelper(printCharactersDebounced); + +export function getRequestHeaders() { + return { + 'Content-Type': 'application/json', + 'X-CSRF-Token': token, + }; +} + +export function getSlideToggleOptions() { + return { + miliseconds: animation_duration * 1.5, + transitionFunction: animation_duration > 0 ? 'ease-in-out' : 'step-start', + }; +} + +$.ajaxPrefilter((options, originalOptions, xhr) => { + xhr.setRequestHeader('X-CSRF-Token', token); +}); + +/** + * Pings the STserver to check if it is reachable. + * @returns {Promise} True if the server is reachable, false otherwise. + */ +export async function pingServer() { + try { + const result = await fetch('api/ping', { + method: 'GET', + headers: getRequestHeaders(), + }); + + if (!result.ok) { + return false; + } + + return true; + } catch (error) { + console.error('Error pinging server', error); + return false; + } +} + +async function firstLoadInit() { + try { + const tokenResponse = await fetch('/csrf-token'); + const tokenData = await tokenResponse.json(); + token = tokenData.token; + } catch { + hideLoader(); + toastr.error(t`Couldn't get CSRF token. Please refresh the page.`, t`Error`, { timeOut: 0, extendedTimeOut: 0, preventDuplicates: true }); + throw new Error('Initialization failed'); + } + + initLibraryShims(); + addShowdownPatch(showdown); + reloadMarkdownProcessor(); + applyBrowserFixes(); + await getClientVersion(); + await readSecretState(); + await initLocales(); + initDefaultSlashCommands(); + initTextGenModels(); + initOpenAI(); + initSystemPrompts(); + initExtensions(); + initExtensionSlashCommands(); + ToolManager.initToolSlashCommands(); + await initPresetManager(); + await getSystemMessages(); + sendSystemMessage(system_message_types.WELCOME); + sendSystemMessage(system_message_types.WELCOME_PROMPT); + await getSettings(); + initKeyboard(); + initDynamicStyles(); + initTags(); + initBookmarks(); + initMacros(); + await getUserAvatars(true, user_avatar); + await getCharacters(); + await getBackgrounds(); + await initTokenizers(); + initBackgrounds(); + initAuthorsNote(); + await initPersonas(); + initRossMods(); + initStats(); + initCfg(); + initLogprobs(); + initInputMarkdown(); + initServerHistory(); + initSettingsSearch(); + initBulkEdit(); + initReasoning(); + await initScrapers(); + doDailyExtensionUpdatesCheck(); + await hideLoader(); + await fixViewport(); + await eventSource.emit(event_types.APP_READY); +} + +async function fixViewport() { + document.body.style.position = 'absolute'; + await delay(1); + document.body.style.position = ''; +} + +function cancelStatusCheck(reason = 'Manually cancelled status check') { + abortStatusCheck?.abort(new AbortReason(reason)); + abortStatusCheck = new AbortController(); + setOnlineStatus('no_connection'); +} + +export function displayOnlineStatus() { + if (online_status == 'no_connection') { + $('.online_status_indicator').removeClass('success'); + $('.online_status_text').text($('#API-status-top').attr('no_connection_text')); + } else { + $('.online_status_indicator').addClass('success'); + $('.online_status_text').text(online_status); + } +} + +/** + * Sets the duration of JS animations. + * @param {number} ms Duration in milliseconds. Resets to default if null. + */ +export function setAnimationDuration(ms = null) { + animation_duration = ms ?? ANIMATION_DURATION_DEFAULT; + // Set CSS variable to document + document.documentElement.style.setProperty('--animation-duration', `${animation_duration}ms`); +} + +/** + * Sets the currently active character + * @param {object|number|string} [entityOrKey] - An entity with id property (character, group, tag), or directly an id or tag key. If not provided, the active character is reset to `null`. + */ +export function setActiveCharacter(entityOrKey) { + active_character = entityOrKey ? getTagKeyForEntity(entityOrKey) : null; + if (active_character) active_group = null; +} + +/** + * Sets the currently active group. + * @param {object|number|string} [entityOrKey] - An entity with id property (character, group, tag), or directly an id or tag key. If not provided, the active group is reset to `null`. + */ +export function setActiveGroup(entityOrKey) { + active_group = entityOrKey ? getTagKeyForEntity(entityOrKey) : null; + if (active_group) active_character = null; +} + +/** + * Gets the itemized prompts for a chat. + * @param {string} chatId Chat ID to load + */ +export async function loadItemizedPrompts(chatId) { + try { + if (!chatId) { + itemizedPrompts = []; + return; + } + + itemizedPrompts = await promptStorage.getItem(chatId); + + if (!itemizedPrompts) { + itemizedPrompts = []; + } + } catch { + console.log('Error loading itemized prompts for chat', chatId); + itemizedPrompts = []; + } +} + +/** + * Saves the itemized prompts for a chat. + * @param {string} chatId Chat ID to save itemized prompts for + */ +export async function saveItemizedPrompts(chatId) { + try { + if (!chatId) { + return; + } + + await promptStorage.setItem(chatId, itemizedPrompts); + } catch { + console.log('Error saving itemized prompts for chat', chatId); + } +} + +/** + * Replaces the itemized prompt text for a message. + * @param {number} mesId Message ID to get itemized prompt for + * @param {string} promptText New raw prompt text + * @returns + */ +export async function replaceItemizedPromptText(mesId, promptText) { + if (!Array.isArray(itemizedPrompts)) { + itemizedPrompts = []; + } + + const itemizedPrompt = itemizedPrompts.find(x => x.mesId === mesId); + + if (!itemizedPrompt) { + return; + } + + itemizedPrompt.rawPrompt = promptText; +} + +/** + * Deletes the itemized prompts for a chat. + * @param {string} chatId Chat ID to delete itemized prompts for + */ +export async function deleteItemizedPrompts(chatId) { + try { + if (!chatId) { + return; + } + + await promptStorage.removeItem(chatId); + } catch { + console.log('Error deleting itemized prompts for chat', chatId); + } +} + +/** + * Empties the itemized prompts array and caches. + */ +export async function clearItemizedPrompts() { + try { + await promptStorage.clear(); + itemizedPrompts = []; + } catch { + console.log('Error clearing itemized prompts'); + } +} + +async function getStatusHorde() { + try { + const hordeStatus = await checkHordeStatus(); + setOnlineStatus(hordeStatus ? 'Connected' : 'no_connection'); + } + catch { + setOnlineStatus('no_connection'); + } + + return resultCheckStatus(); +} + +async function getStatusKobold() { + let endpoint = api_server; + + if (!endpoint) { + console.warn('No endpoint for status check'); + setOnlineStatus('no_connection'); + return resultCheckStatus(); + } + + try { + const response = await fetch('/api/backends/kobold/status', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + main_api, + api_server: endpoint, + }), + signal: abortStatusCheck.signal, + }); + + const data = await response.json(); + + setOnlineStatus(data?.model ?? 'no_connection'); + + if (!data.koboldUnitedVersion) { + throw new Error('Missing mandatory Kobold version in data:', data); + } + + // Determine instruct mode preset + autoSelectInstructPreset(online_status); + + // determine if we can use stop sequence and streaming + setKoboldFlags(data.koboldUnitedVersion, data.koboldCppVersion); + + // We didn't get a 200 status code, but the endpoint has an explanation. Which means it DID connect, but I digress. + if (online_status === 'no_connection' && data.response) { + toastr.error(data.response, t`API Error`, { timeOut: 5000, preventDuplicates: true }); + } + } catch (err) { + console.error('Error getting status', err); + setOnlineStatus('no_connection'); + } + + return resultCheckStatus(); +} + +async function getStatusTextgen() { + const url = '/api/backends/text-completions/status'; + + const endpoint = getTextGenServer(); + + if (!endpoint) { + console.warn('No endpoint for status check'); + setOnlineStatus('no_connection'); + return resultCheckStatus(); + } + + if ([textgen_types.GENERIC, textgen_types.OOBA].includes(textgen_settings.type) && textgen_settings.bypass_status_check) { + setOnlineStatus('Status check bypassed'); + return resultCheckStatus(); + } + + try { + const response = await fetch(url, { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + api_server: endpoint, + api_type: textgen_settings.type, + }), + signal: abortStatusCheck.signal, + }); + + const data = await response.json(); + + if (textgen_settings.type === textgen_types.MANCER) { + loadMancerModels(data?.data); + setOnlineStatus(textgen_settings.mancer_model); + } else if (textgen_settings.type === textgen_types.TOGETHERAI) { + loadTogetherAIModels(data?.data); + setOnlineStatus(textgen_settings.togetherai_model); + } else if (textgen_settings.type === textgen_types.OLLAMA) { + loadOllamaModels(data?.data); + setOnlineStatus(textgen_settings.ollama_model || 'Connected'); + } else if (textgen_settings.type === textgen_types.INFERMATICAI) { + loadInfermaticAIModels(data?.data); + setOnlineStatus(textgen_settings.infermaticai_model); + } else if (textgen_settings.type === textgen_types.DREAMGEN) { + loadDreamGenModels(data?.data); + setOnlineStatus(textgen_settings.dreamgen_model); + } else if (textgen_settings.type === textgen_types.OPENROUTER) { + loadOpenRouterModels(data?.data); + setOnlineStatus(textgen_settings.openrouter_model); + } else if (textgen_settings.type === textgen_types.VLLM) { + loadVllmModels(data?.data); + setOnlineStatus(textgen_settings.vllm_model); + } else if (textgen_settings.type === textgen_types.APHRODITE) { + loadAphroditeModels(data?.data); + setOnlineStatus(textgen_settings.aphrodite_model); + } else if (textgen_settings.type === textgen_types.FEATHERLESS) { + loadFeatherlessModels(data?.data); + setOnlineStatus(textgen_settings.featherless_model); + } else if (textgen_settings.type === textgen_types.TABBY) { + loadTabbyModels(data?.data); + setOnlineStatus(textgen_settings.tabby_model || data?.result); + } else if (textgen_settings.type === textgen_types.GENERIC) { + loadGenericModels(data?.data); + setOnlineStatus(textgen_settings.generic_model || data?.result || 'Connected'); + } else { + setOnlineStatus(data?.result); + } + + if (!online_status) { + setOnlineStatus('no_connection'); + } + + // Determine instruct mode preset + autoSelectInstructPreset(online_status); + + const supportsTokenization = response.headers.get('x-supports-tokenization') === 'true'; + supportsTokenization ? sessionStorage.setItem(TOKENIZER_SUPPORTED_KEY, 'true') : sessionStorage.removeItem(TOKENIZER_SUPPORTED_KEY); + + const wantsInstructDerivation = (power_user.instruct.enabled && power_user.instruct.derived); + const wantsContextDerivation = power_user.context_derived; + const wantsContextSize = power_user.context_size_derived; + const supportsChatTemplate = [textgen_types.KOBOLDCPP, textgen_types.LLAMACPP].includes(textgen_settings.type); + if (supportsChatTemplate && (wantsInstructDerivation || wantsContextDerivation || wantsContextSize)) { + const response = await fetch('/api/backends/text-completions/props', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + api_server: endpoint, + api_type: textgen_settings.type, + }), + }); + + if (response.ok) { + const data = await response.json(); + if (data) { + const { chat_template, chat_template_hash } = data; + if (wantsContextSize && 'default_generation_settings' in data) { + const backend_max_context = data['default_generation_settings']['n_ctx']; + const old_value = max_context; + if (max_context !== backend_max_context) { + setGenerationParamsFromPreset({ max_length: backend_max_context }); + } + if (old_value !== max_context) { + console.log(`Auto-switched max context from ${old_value} to ${max_context}`); + toastr.info(`${old_value} ⇒ ${max_context}`, 'Context Size Changed'); + } + } + console.log(`We have chat template ${chat_template.split('\n')[0]}...`); + const templates = await deriveTemplatesFromChatTemplate(chat_template, chat_template_hash); + if (templates) { + const { context, instruct } = templates; + if (wantsContextDerivation) { + selectContextPreset(context, { isAuto: true }); + } + if (wantsInstructDerivation) { + selectInstructPreset(instruct, { isAuto: true }); + } + } + } + } + } + + // We didn't get a 200 status code, but the endpoint has an explanation. Which means it DID connect, but I digress. + if (online_status === 'no_connection' && data.response) { + toastr.error(data.response, t`API Error`, { timeOut: 5000, preventDuplicates: true }); + } + } catch (err) { + if (err instanceof AbortReason) { + console.info('Status check aborted.', err.reason); + } else { + console.error('Error getting status', err); + + } + setOnlineStatus('no_connection'); + } + + return resultCheckStatus(); +} + +async function getStatusNovel() { + try { + const result = await loadNovelSubscriptionData(); + + if (!result) { + throw new Error('Could not load subscription data'); + } + + setOnlineStatus(getNovelTier()); + } catch { + setOnlineStatus('no_connection'); + } + + resultCheckStatus(); +} + +export function startStatusLoading() { + $('.api_loading').show(); + $('.api_button').addClass('disabled'); +} + +export function stopStatusLoading() { + $('.api_loading').hide(); + $('.api_button').removeClass('disabled'); +} + +export function resultCheckStatus() { + displayOnlineStatus(); + stopStatusLoading(); +} + + +/** + * Switches the currently selected character to the one with the given ID. (character index, not the character key!) + * + * If the character ID doesn't exist, if the chat is being saved, or if a group is being generated, this function does nothing. + * If the character is different from the currently selected one, it will clear the chat and reset any selected character or group. + * @param {number} id The ID of the character to switch to. + */ +export async function selectCharacterById(id) { + if (characters[id] === undefined) { + return; + } + + if (isChatSaving) { + toastr.info(t`Please wait until the chat is saved before switching characters.`, t`Your chat is still saving...`); + return; + } + + if (selected_group && is_group_generating) { + return; + } + + if (selected_group || String(this_chid) !== String(id)) { + //if clicked on a different character from what was currently selected + if (!is_send_press) { + await clearChat(); + cancelTtsPlay(); + resetSelectedGroup(); + this_edit_mes_id = undefined; + selected_button = 'character_edit'; + setCharacterId(id); + chat.length = 0; + chat_metadata = {}; + await getChat(); + } + } else { + //if clicked on character that was already selected + selected_button = 'character_edit'; + await unshallowCharacter(this_chid); + select_selected_character(this_chid); + } +} + +function getBackBlock() { + const template = $('#bogus_folder_back_template .bogus_folder_select').clone(); + return template; +} + +function getEmptyBlock() { + const icons = ['fa-dragon', 'fa-otter', 'fa-kiwi-bird', 'fa-crow', 'fa-frog']; + const texts = ['Here be dragons', 'Otterly empty', 'Kiwibunga', 'Pump-a-Rum', 'Croak it']; + const roll = new Date().getMinutes() % icons.length; + const emptyBlock = ` +
      + +

      ${texts[roll]}

      +

      There are no items to display.

      +
      `; + return $(emptyBlock); +} + +/** + * @param {number} hidden Number of hidden characters + */ +function getHiddenBlock(hidden) { + const hiddenBlock = ` +
      + +

      ${hidden} ${hidden > 1 ? 'characters' : 'character'} hidden.

      +
      +
      +
      `; + return $(hiddenBlock); +} + +function getCharacterBlock(item, id) { + let this_avatar = default_avatar; + if (item.avatar != 'none') { + this_avatar = getThumbnailUrl('avatar', item.avatar); + } + // Populate the template + const template = $('#character_template .character_select').clone(); + template.attr({ 'data-chid': id, 'id': `CharID${id}` }); + template.find('img').attr('src', this_avatar).attr('alt', item.name); + template.find('.avatar').attr('title', `[Character] ${item.name}\nFile: ${item.avatar}`); + template.find('.ch_name').text(item.name).attr('title', `[Character] ${item.name}`); + if (power_user.show_card_avatar_urls) { + template.find('.ch_avatar_url').text(item.avatar); + } + template.find('.ch_fav_icon').css('display', 'none'); + template.toggleClass('is_fav', item.fav || item.fav == 'true'); + template.find('.ch_fav').val(item.fav); + + const description = item.data?.creator_notes || ''; + if (description) { + template.find('.ch_description').text(description); + } + else { + template.find('.ch_description').hide(); + } + + const auxFieldName = power_user.aux_field || 'character_version'; + const auxFieldValue = (item.data && item.data[auxFieldName]) || ''; + if (auxFieldValue) { + template.find('.character_version').text(auxFieldValue); + } + else { + template.find('.character_version').hide(); + } + + // Display inline tags + const tagsElement = template.find('.tags'); + printTagList(tagsElement, { forEntityOrKey: id }); + + // Add to the list + return template; +} + +/** + * Prints the global character list, optionally doing a full refresh of the list + * Use this function whenever the reprinting of the character list is the primary focus, otherwise using `printCharactersDebounced` is preferred for a cleaner, non-blocking experience. + * + * The printing will also always reprint all filter options of the global list, to keep them up to date. + * + * @param {boolean} fullRefresh - If true, the list is fully refreshed and the navigation is being reset + */ +export async function printCharacters(fullRefresh = false) { + const storageKey = 'Characters_PerPage'; + const listId = '#rm_print_characters_block'; + + let currentScrollTop = $(listId).scrollTop(); + + if (fullRefresh) { + saveCharactersPage = 0; + currentScrollTop = 0; + await delay(1); + } + + // Before printing the personas, we check if we should enable/disable search sorting + verifyCharactersSearchSortRule(); + + // We are actually always reprinting filters, as it "doesn't hurt", and this way they are always up to date + printTagFilters(tag_filter_type.character); + printTagFilters(tag_filter_type.group_member); + + // We are also always reprinting the lists on character/group edit window, as these ones doesn't get updated otherwise + applyTagsOnCharacterSelect(); + applyTagsOnGroupSelect(); + + const entities = getEntitiesList({ doFilter: true }); + + $('#rm_print_characters_pagination').pagination({ + dataSource: entities, + pageSize: Number(accountStorage.getItem(storageKey)) || per_page_default, + sizeChangerOptions: [10, 25, 50, 100, 250, 500, 1000], + pageRange: 1, + pageNumber: saveCharactersPage || 1, + position: 'top', + showPageNumbers: false, + showSizeChanger: true, + prevText: '<', + nextText: '>', + formatNavigator: PAGINATION_TEMPLATE, + showNavigator: true, + callback: function (/** @type {Entity[]} */ data) { + $(listId).empty(); + if (power_user.bogus_folders && isBogusFolderOpen()) { + $(listId).append(getBackBlock()); + } + if (!data.length) { + $(listId).append(getEmptyBlock()); + } + let displayCount = 0; + for (const i of data) { + switch (i.type) { + case 'character': + $(listId).append(getCharacterBlock(i.item, i.id)); + displayCount++; + break; + case 'group': + $(listId).append(getGroupBlock(i.item)); + displayCount++; + break; + case 'tag': + $(listId).append(getTagBlock(i.item, i.entities, i.hidden, i.isUseless)); + break; + } + } + + const hidden = (characters.length + groups.length) - displayCount; + if (hidden > 0 && entitiesFilter.hasAnyFilter()) { + $(listId).append(getHiddenBlock(hidden)); + } + + eventSource.emit(event_types.CHARACTER_PAGE_LOADED); + }, + afterSizeSelectorChange: function (e) { + accountStorage.setItem(storageKey, e.target.value); + }, + afterPaging: function (e) { + saveCharactersPage = e; + }, + afterRender: function () { + $(listId).scrollTop(currentScrollTop); + }, + }); + + favsToHotswap(); + updatePersonaConnectionsAvatarList(); +} + +/** Checks the state of the current search, and adds/removes the search sorting option accordingly */ +function verifyCharactersSearchSortRule() { + const searchTerm = entitiesFilter.getFilterData(FILTER_TYPES.SEARCH); + const searchOption = $('#character_sort_order option[data-field="search"]'); + const selector = $('#character_sort_order'); + const isHidden = searchOption.attr('hidden') !== undefined; + + // If we have a search term, we are displaying the sorting option for it + if (searchTerm && isHidden) { + searchOption.removeAttr('hidden'); + searchOption.prop('selected', true); + flashHighlight(selector); + } + // If search got cleared, we make sure to hide the option and go back to the one before + if (!searchTerm && !isHidden) { + searchOption.attr('hidden', ''); + $(`#character_sort_order option[data-order="${power_user.sort_order}"][data-field="${power_user.sort_field}"]`).prop('selected', true); + } +} + +/** @typedef {object} Character - A character */ +/** @typedef {object} Group - A group */ + +/** + * @typedef {object} Entity - Object representing a display entity + * @property {Character|Group|import('./scripts/tags.js').Tag|*} item - The item + * @property {string|number} id - The id + * @property {'character'|'group'|'tag'} type - The type of this entity (character, group, tag) + * @property {Entity[]?} [entities=null] - An optional list of entities relevant for this item + * @property {number?} [hidden=null] - An optional number representing how many hidden entities this entity contains + * @property {boolean?} [isUseless=null] - Specifies if the entity is useless (not relevant, but should still be displayed for consistency) and should be displayed greyed out + */ + +/** + * Converts the given character to its entity representation + * + * @param {Character} character - The character + * @param {string|number} id - The id of this character + * @returns {Entity} The entity for this character + */ +export function characterToEntity(character, id) { + return { item: character, id, type: 'character' }; +} + +/** + * Converts the given group to its entity representation + * + * @param {Group} group - The group + * @returns {Entity} The entity for this group + */ +export function groupToEntity(group) { + return { item: group, id: group.id, type: 'group' }; +} + +/** + * Converts the given tag to its entity representation + * + * @param {import('./scripts/tags.js').Tag} tag - The tag + * @returns {Entity} The entity for this tag + */ +export function tagToEntity(tag) { + return { item: structuredClone(tag), id: tag.id, type: 'tag', entities: [] }; +} + +/** + * Builds the full list of all entities available + * + * They will be correctly marked and filtered. + * + * @param {object} param0 - Optional parameters + * @param {boolean} [param0.doFilter] - Whether this entity list should already be filtered based on the global filters + * @param {boolean} [param0.doSort] - Whether the entity list should be sorted when returned + * @returns {Entity[]} All entities + */ +export function getEntitiesList({ doFilter = false, doSort = true } = {}) { + let entities = [ + ...characters.map((item, index) => characterToEntity(item, index)), + ...groups.map(item => groupToEntity(item)), + ...(power_user.bogus_folders ? tags.filter(isBogusFolder).sort(compareTagsForSort).map(item => tagToEntity(item)) : []), + ]; + + // We need to do multiple filter runs in a specific order, otherwise different settings might override each other + // and screw up tags and search filter, sub lists or similar. + // The specific filters are written inside the "filterByTagState" method and its different parameters. + // Generally what we do is the following: + // 1. First swipe over the list to remove the most obvious things + // 2. Build sub entity lists for all folders, filtering them similarly to the second swipe + // 3. We do the last run, where global filters are applied, and the search filters last + + // First run filters, that will hide what should never be displayed + if (doFilter) { + entities = filterByTagState(entities); + } + + // Run over all entities between first and second filter to save some states + for (const entity of entities) { + // For folders, we remember the sub entities so they can be displayed later, even if they might be filtered + // Those sub entities should be filtered and have the search filters applied too + if (entity.type === 'tag') { + let subEntities = filterByTagState(entities, { subForEntity: entity, filterHidden: false }); + const subCount = subEntities.length; + subEntities = filterByTagState(entities, { subForEntity: entity }); + if (doFilter) { + // sub entities filter "hacked" because folder filter should not be applied there, so even in "only folders" mode characters show up + subEntities = entitiesFilter.applyFilters(subEntities, { clearScoreCache: false, tempOverrides: { [FILTER_TYPES.FOLDER]: FILTER_STATES.UNDEFINED }, clearFuzzySearchCaches: false }); + } + if (doSort) { + sortEntitiesList(subEntities, false); + } + entity.entities = subEntities; + entity.hidden = subCount - subEntities.length; + } + } + + // Second run filters, hiding whatever should be filtered later + if (doFilter) { + const beforeFinalEntities = filterByTagState(entities, { globalDisplayFilters: true }); + entities = entitiesFilter.applyFilters(beforeFinalEntities, { clearFuzzySearchCaches: false }); + + // Magic for folder filter. If that one is enabled, and no folders are display anymore, we remove that filter to actually show the characters. + if (isFilterState(entitiesFilter.getFilterData(FILTER_TYPES.FOLDER), FILTER_STATES.SELECTED) && entities.filter(x => x.type == 'tag').length == 0) { + entities = entitiesFilter.applyFilters(beforeFinalEntities, { tempOverrides: { [FILTER_TYPES.FOLDER]: FILTER_STATES.UNDEFINED }, clearFuzzySearchCaches: false }); + } + } + + // Final step, updating some properties after the last filter run + const nonTagEntitiesCount = entities.filter(entity => entity.type !== 'tag').length; + for (const entity of entities) { + if (entity.type === 'tag') { + if (entity.entities?.length == nonTagEntitiesCount) entity.isUseless = true; + } + } + + // Sort before returning if requested + if (doSort) { + sortEntitiesList(entities, false); + } + entitiesFilter.clearFuzzySearchCaches(); + return entities; +} + +export async function getOneCharacter(avatarUrl) { + const response = await fetch('/api/characters/get', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + avatar_url: avatarUrl, + }), + }); + + if (response.ok) { + const getData = await response.json(); + getData['name'] = DOMPurify.sanitize(getData['name']); + getData['chat'] = String(getData['chat']); + + const indexOf = characters.findIndex(x => x.avatar === avatarUrl); + + if (indexOf !== -1) { + characters[indexOf] = getData; + } else { + toastr.error(t`Character ${avatarUrl} not found in the list`, t`Error`, { timeOut: 5000, preventDuplicates: true }); + } + } +} + +function getCharacterSource(chId = this_chid) { + const character = characters[chId]; + + if (!character) { + return ''; + } + + const chubId = characters[chId]?.data?.extensions?.chub?.full_path; + + if (chubId) { + return `https://chub.ai/characters/${chubId}`; + } + + const pygmalionId = characters[chId]?.data?.extensions?.pygmalion_id; + + if (pygmalionId) { + return `https://pygmalion.chat/${pygmalionId}`; + } + + const githubRepo = characters[chId]?.data?.extensions?.github_repo; + + if (githubRepo) { + return `https://github.com/${githubRepo}`; + } + + const sourceUrl = characters[chId]?.data?.extensions?.source_url; + + if (sourceUrl) { + return sourceUrl; + } + + const risuId = characters[chId]?.data?.extensions?.risuai?.source; + + if (Array.isArray(risuId) && risuId.length && typeof risuId[0] === 'string' && risuId[0].startsWith('risurealm:')) { + const realmId = risuId[0].split(':')[1]; + return `https://realm.risuai.net/character/${realmId}`; + } + + return ''; +} + +export async function getCharacters() { + const response = await fetch('/api/characters/all', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({}), + }); + if (response.ok === true) { + characters.splice(0, characters.length); + const getData = await response.json(); + for (let i = 0; i < getData.length; i++) { + characters[i] = getData[i]; + characters[i]['name'] = DOMPurify.sanitize(characters[i]['name']); + + // For dropped-in cards + if (!characters[i]['chat']) { + characters[i]['chat'] = `${characters[i]['name']} - ${humanizedDateTime()}`; + } + + characters[i]['chat'] = String(characters[i]['chat']); + } + if (this_chid !== undefined) { + $('#avatar_url_pole').val(characters[this_chid].avatar); + } + + await getGroups(); + await printCharacters(true); + } +} + +async function delChat(chatfile) { + const response = await fetch('/api/chats/delete', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + chatfile: chatfile, + avatar_url: characters[this_chid].avatar, + }), + }); + if (response.ok === true) { + // choose another chat if current was deleted + const name = chatfile.replace('.jsonl', ''); + if (name === characters[this_chid].chat) { + chat_metadata = {}; + await replaceCurrentChat(); + } + await eventSource.emit(event_types.CHAT_DELETED, name); + } +} + +export async function replaceCurrentChat() { + await clearChat(); + chat.length = 0; + + const chatsResponse = await fetch('/api/characters/chats', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ avatar_url: characters[this_chid].avatar }), + }); + + if (chatsResponse.ok) { + const chats = Object.values(await chatsResponse.json()); + chats.sort((a, b) => sortMoments(timestampToMoment(a.last_mes), timestampToMoment(b.last_mes))); + + // pick existing chat + if (chats.length && typeof chats[0] === 'object') { + characters[this_chid].chat = chats[0].file_name.replace('.jsonl', ''); + $('#selected_chat_pole').val(characters[this_chid].chat); + saveCharacterDebounced(); + await getChat(); + } + + // start new chat + else { + characters[this_chid].chat = `${name2} - ${humanizedDateTime()}`; + $('#selected_chat_pole').val(characters[this_chid].chat); + saveCharacterDebounced(); + await getChat(); + } + } +} + +export async function showMoreMessages(messagesToLoad = null) { + const firstDisplayedMesId = $('#chat').children('.mes').first().attr('mesid'); + let messageId = Number(firstDisplayedMesId); + let count = messagesToLoad || power_user.chat_truncation || Number.MAX_SAFE_INTEGER; + + // If there are no messages displayed, or the message somehow has no mesid, we default to one higher than last message id, + // so the first "new" message being shown will be the last available message + if (isNaN(messageId)) { + messageId = getLastMessageId() + 1; + } + + console.debug('Inserting messages before', messageId, 'count', count, 'chat length', chat.length); + const prevHeight = $('#chat').prop('scrollHeight'); + const isButtonInView = isElementInViewport($('#show_more_messages')[0]); + + while (messageId > 0 && count > 0) { + let newMessageId = messageId - 1; + addOneMessage(chat[newMessageId], { insertBefore: messageId >= chat.length ? null : messageId, scroll: false, forceId: newMessageId }); + count--; + messageId--; + } + + if (messageId == 0) { + $('#show_more_messages').remove(); + } + + if (isButtonInView) { + const newHeight = $('#chat').prop('scrollHeight'); + $('#chat').scrollTop(newHeight - prevHeight); + } + + await eventSource.emit(event_types.MORE_MESSAGES_LOADED); +} + +export async function printMessages() { + let startIndex = 0; + let count = power_user.chat_truncation || Number.MAX_SAFE_INTEGER; + + if (chat.length > count) { + startIndex = chat.length - count; + $('#chat').append('
      Show more messages
      '); + } + + for (let i = startIndex; i < chat.length; i++) { + const item = chat[i]; + addOneMessage(item, { scroll: false, forceId: i, showSwipes: false }); + } + + // Scroll to bottom when all images are loaded + const images = document.querySelectorAll('#chat .mes img'); + let imagesLoaded = 0; + + for (let i = 0; i < images.length; i++) { + const image = images[i]; + if (image instanceof HTMLImageElement) { + if (image.complete) { + incrementAndCheck(); + } else { + image.addEventListener('load', incrementAndCheck); + } + } + } + + $('#chat .mes').removeClass('last_mes'); + $('#chat .mes').last().addClass('last_mes'); + hideSwipeButtons(); + showSwipeButtons(); + scrollChatToBottom(); + + function incrementAndCheck() { + imagesLoaded++; + if (imagesLoaded === images.length) { + scrollChatToBottom(); + } + } +} + +export async function clearChat() { + closeMessageEditor(); + extension_prompts = {}; + if (is_delete_mode) { + $('#dialogue_del_mes_cancel').trigger('click'); + } + $('#chat').children().remove(); + if ($('.zoomed_avatar[forChar]').length) { + console.debug('saw avatars to remove'); + $('.zoomed_avatar[forChar]').remove(); + } else { console.debug('saw no avatars'); } + + await saveItemizedPrompts(getCurrentChatId()); + itemizedPrompts = []; +} + +export async function deleteLastMessage() { + chat.length = chat.length - 1; + $('#chat').children('.mes').last().remove(); + await eventSource.emit(event_types.MESSAGE_DELETED, chat.length); +} + +export async function reloadCurrentChat() { + preserveNeutralChat(); + await clearChat(); + chat.length = 0; + + if (selected_group) { + await getGroupChat(selected_group, true); + } + else if (this_chid !== undefined) { + await getChat(); + } + else { + resetChatState(); + restoreNeutralChat(); + await getCharacters(); + await printMessages(); + await eventSource.emit(event_types.CHAT_CHANGED, getCurrentChatId()); + } + + hideSwipeButtons(); + showSwipeButtons(); +} + +/** + * Send the message currently typed into the chat box. + */ +export async function sendTextareaMessage() { + if (is_send_press) return; + if (isExecutingCommandsFromChatInput) return; + if (this_edit_mes_id) return; // don't proceed if editing a message + + let generateType; + // "Continue on send" is activated when the user hits "send" (or presses enter) on an empty chat box, and the last + // message was sent from a character (not the user or the system). + const textareaText = String($('#send_textarea').val()); + if (power_user.continue_on_send && + !hasPendingFileAttachment() && + !textareaText && + !selected_group && + chat.length && + !chat[chat.length - 1]['is_user'] && + !chat[chat.length - 1]['is_system'] + ) { + generateType = 'continue'; + } + + if (textareaText && !selected_group && this_chid === undefined && name2 !== neutralCharacterName) { + await newAssistantChat(); + } + + Generate(generateType); +} + +/** + * Formats the message text into an HTML string using Markdown and other formatting. + * @param {string} mes Message text + * @param {string} ch_name Character name + * @param {boolean} isSystem If the message was sent by the system + * @param {boolean} isUser If the message was sent by the user + * @param {number} messageId Message index in chat array + * @param {object} [sanitizerOverrides] DOMPurify sanitizer option overrides + * @param {boolean} [isReasoning] If the message is reasoning output + * @returns {string} HTML string + */ +export function messageFormatting(mes, ch_name, isSystem, isUser, messageId, sanitizerOverrides = {}, isReasoning = false) { + if (!mes) { + return ''; + } + + if (Number(messageId) === 0 && !isSystem && !isUser && !isReasoning) { + const mesBeforeReplace = mes; + const chatMessage = chat[messageId]; + mes = substituteParams(mes, undefined, ch_name); + if (chatMessage && chatMessage.mes === mesBeforeReplace && chatMessage.extra?.display_text !== mesBeforeReplace) { + chatMessage.mes = mes; + } + } + + mesForShowdownParse = mes; + + // Force isSystem = false on comment messages so they get formatted properly + if (ch_name === COMMENT_NAME_DEFAULT && isSystem && !isUser) { + isSystem = false; + } + + // Let hidden messages have markdown + if (isSystem && ch_name !== systemUserName) { + isSystem = false; + } + + // Prompt bias replacement should be applied on the raw message + if (!power_user.show_user_prompt_bias && ch_name && !isUser && !isSystem) { + mes = mes.replaceAll(substituteParams(power_user.user_prompt_bias), ''); + } + + if (!isSystem) { + function getRegexPlacement() { + try { + if (isReasoning) { + return regex_placement.REASONING; + } + if (isUser) { + return regex_placement.USER_INPUT; + } else if (chat[messageId]?.extra?.type === 'narrator') { + return regex_placement.SLASH_COMMAND; + } else { + return regex_placement.AI_OUTPUT; + } + } catch { + return regex_placement.AI_OUTPUT; + } + } + + const regexPlacement = getRegexPlacement(); + const usableMessages = chat.map((x, index) => ({ message: x, index: index })).filter(x => !x.message.is_system); + const indexOf = usableMessages.findIndex(x => x.index === Number(messageId)); + const depth = messageId >= 0 && indexOf !== -1 ? (usableMessages.length - indexOf - 1) : undefined; + + // Always override the character name + mes = getRegexedString(mes, regexPlacement, { + characterOverride: ch_name, + isMarkdown: true, + depth: depth, + }); + } + + if (power_user.auto_fix_generated_markdown) { + mes = fixMarkdown(mes, true); + } + + if (!isSystem && power_user.encode_tags) { + mes = mes.replaceAll('<', '<').replaceAll('>', '>'); + } + + // Make sure reasoning strings are always shown, even if they include "<" or ">" + [power_user.reasoning.prefix, power_user.reasoning.suffix].forEach((reasoningString) => { + if (!reasoningString || !reasoningString.trim().length) { + return; + } + // Only replace the first occurrence of the reasoning string + if (mes.includes(reasoningString)) { + mes = mes.replace(reasoningString, escapeHtml(reasoningString)); + } + }); + + if (!isSystem) { + // Save double quotes in tags as a special character to prevent them from being encoded + if (!power_user.encode_tags) { + mes = mes.replace(/<([^>]+)>/g, function (_, contents) { + return '<' + contents.replace(/"/g, '\ufffe') + '>'; + }); + } + + mes = mes.replace( + /```[\s\S]*?```|``[\s\S]*?``|`[\s\S]*?`|(".*?")|(\u201C.*?\u201D)|(\u00AB.*?\u00BB)|(\u300C.*?\u300D)|(\u300E.*?\u300F)|(\uFF02.*?\uFF02)/gm, + function (match, p1, p2, p3, p4, p5, p6) { + if (p1) { + // English double quotes + return `"${p1.slice(1, -1)}"`; + } else if (p2) { + // Curly double quotes “ ” + return `“${p2.slice(1, -1)}”`; + } else if (p3) { + // Guillemets « » + return `«${p3.slice(1, -1)}»`; + } else if (p4) { + // Corner brackets 「 」 + return `「${p4.slice(1, -1)}」`; + } else if (p5) { + // White corner brackets 『 』 + return `『${p5.slice(1, -1)}』`; + } else if (p6) { + // Fullwidth quotes " " + return `"${p6.slice(1, -1)}"`; + } else { + // Return the original match if no quotes are found + return match; + } + }, + ); + + // Restore double quotes in tags + if (!power_user.encode_tags) { + mes = mes.replace(/\ufffe/g, '"'); + } + + mes = mes.replaceAll('\\begin{align*}', '$$'); + mes = mes.replaceAll('\\end{align*}', '$$'); + mes = converter.makeHtml(mes); + + mes = mes.replace(/[\s\S]*?<\/code>/g, function (match) { + // Firefox creates extra newlines from
      s in code blocks, so we replace them before converting newlines to
      s. + return match.replace(/\n/gm, '\u0000'); + }); + mes = mes.replace(/\u0000/g, '\n'); // Restore converted newlines + mes = mes.trim(); + + mes = mes.replace(/[\s\S]*?<\/code>/g, function (match) { + return match.replace(/&/g, '&'); + }); + } + + if (!power_user.allow_name2_display && ch_name && !isUser && !isSystem) { + mes = mes.replace(new RegExp(`(^|\n)${escapeRegex(ch_name)}:`, 'g'), '$1'); + } + + /** @type {import('dompurify').Config & { RETURN_DOM_FRAGMENT: false; RETURN_DOM: false }} */ + const config = { + RETURN_DOM: false, + RETURN_DOM_FRAGMENT: false, + RETURN_TRUSTED_TYPE: false, + MESSAGE_SANITIZE: true, + ADD_TAGS: ['custom-style'], + ...sanitizerOverrides, + }; + mes = encodeStyleTags(mes); + mes = DOMPurify.sanitize(mes, config); + mes = decodeStyleTags(mes); + + return mes; +} + +/** + * Inserts or replaces an SVG icon adjacent to the provided message's timestamp. + * + * If the `extra.api` is "openai" and `extra.model` contains the substring "claude", + * the function fetches the "claude.svg". Otherwise, it fetches the SVG named after + * the value in `extra.api`. + * + * @param {JQuery} mes - The message element containing the timestamp where the icon should be inserted or replaced. + * @param {Object} extra - Contains the API and model details. + * @param {string} extra.api - The name of the API, used to determine which SVG to fetch. + * @param {string} extra.model - The model name, used to check for the substring "claude". + */ +function insertSVGIcon(mes, extra) { + // Determine the SVG filename + let modelName; + + // Claude on OpenRouter or Anthropic + if (extra.api === 'openai' && extra.model?.toLowerCase().includes('claude')) { + modelName = 'claude'; + } + // OpenAI on OpenRouter + else if (extra.api === 'openai' && extra.model?.toLowerCase().includes('openai')) { + modelName = 'openai'; + } + // OpenRouter website model or other models + else if (extra.api === 'openai' && (extra.model === null || extra.model?.toLowerCase().includes('/'))) { + modelName = 'openrouter'; + } + // Everything else + else { + modelName = extra.api; + } + + const insertOrReplaceSVG = (image, className, targetSelector, insertBefore) => { + image.onload = async function () { + let existingSVG = insertBefore ? mes.find(targetSelector).prev(`.${className}`) : mes.find(targetSelector).next(`.${className}`); + if (existingSVG.length) { + existingSVG.replaceWith(image); + } else { + if (insertBefore) mes.find(targetSelector).before(image); + else mes.find(targetSelector).after(image); + } + await SVGInject(image); + }; + }; + + const createModelImage = (className, targetSelector, insertBefore) => { + const image = new Image(); + image.classList.add('icon-svg', className); + image.src = `/img/${modelName}.svg`; + image.title = `${extra?.api ? extra.api + ' - ' : ''}${extra?.model ?? ''}`; + insertOrReplaceSVG(image, className, targetSelector, insertBefore); + }; + + createModelImage('timestamp-icon', '.timestamp'); + createModelImage('thinking-icon', '.mes_reasoning_header_title', true); +} + + +function getMessageFromTemplate({ + mesId, + swipeId, + characterName, + isUser, + avatarImg, + bias, + isSystem, + title, + timerValue, + timerTitle, + bookmarkLink, + forceAvatar, + timestamp, + tokenCount, + extra, +}) { + const mes = messageTemplate.clone(); + mes.attr({ + 'mesid': mesId, + 'swipeid': swipeId, + 'ch_name': characterName, + 'is_user': isUser, + 'is_system': !!isSystem, + 'bookmark_link': bookmarkLink, + 'force_avatar': !!forceAvatar, + 'timestamp': timestamp, + }); + mes.find('.avatar img').attr('src', avatarImg); + mes.find('.ch_name .name_text').text(characterName); + mes.find('.mes_bias').html(bias); + mes.find('.timestamp').text(timestamp).attr('title', `${extra?.api ? extra.api + ' - ' : ''}${extra?.model ?? ''}`); + mes.find('.mesIDDisplay').text(`#${mesId}`); + tokenCount && mes.find('.tokenCounterDisplay').text(`${tokenCount}t`); + title && mes.attr('title', title); + timerValue && mes.find('.mes_timer').attr('title', timerTitle).text(timerValue); + bookmarkLink && updateBookmarkDisplay(mes); + + updateReasoningUI(mes); + + if (power_user.timestamp_model_icon && extra?.api) { + insertSVGIcon(mes, extra); + } + + return mes; +} + +/** + * Re-renders a message block with updated content. + * @param {number} messageId Message ID + * @param {object} message Message object + * @param {object} [options={}] Optional arguments + * @param {boolean} [options.rerenderMessage=true] Whether to re-render the message content (inside .mes_text) + */ +export function updateMessageBlock(messageId, message, { rerenderMessage = true } = {}) { + const messageElement = $(`#chat [mesid="${messageId}"]`); + if (rerenderMessage) { + const text = message?.extra?.display_text ?? message.mes; + messageElement.find('.mes_text').html(messageFormatting(text, message.name, message.is_system, message.is_user, messageId, {}, false)); + } + + updateReasoningUI(messageElement); + + addCopyToCodeBlocks(messageElement); + appendMediaToMessage(message, messageElement); +} + +/** + * Appends image or file to the message element. + * @param {object} mes Message object + * @param {JQuery} messageElement Message element + * @param {boolean} [adjustScroll=true] Whether to adjust the scroll position after appending the media + */ +export function appendMediaToMessage(mes, messageElement, adjustScroll = true) { + // Add image to message + if (mes.extra?.image) { + const container = messageElement.find('.mes_img_container'); + const chatHeight = $('#chat').prop('scrollHeight'); + const image = messageElement.find('.mes_img'); + const text = messageElement.find('.mes_text'); + const isInline = !!mes.extra?.inline_image; + image.off('load').on('load', function () { + if (!adjustScroll) { + return; + } + const scrollPosition = $('#chat').scrollTop(); + const newChatHeight = $('#chat').prop('scrollHeight'); + const diff = newChatHeight - chatHeight; + $('#chat').scrollTop(scrollPosition + diff); + }); + image.attr('src', mes.extra?.image); + image.attr('title', mes.extra?.title || mes.title || ''); + container.addClass('img_extra'); + image.toggleClass('img_inline', isInline); + text.toggleClass('displayNone', !isInline); + + const imageSwipes = mes.extra.image_swipes; + if (Array.isArray(imageSwipes) && imageSwipes.length > 0) { + container.addClass('img_swipes'); + const counter = container.find('.mes_img_swipe_counter'); + const currentImage = imageSwipes.indexOf(mes.extra.image) + 1; + counter.text(`${currentImage}/${imageSwipes.length}`); + + const swipeLeft = container.find('.mes_img_swipe_left'); + swipeLeft.off('click').on('click', function () { + eventSource.emit(event_types.IMAGE_SWIPED, { message: mes, element: messageElement, direction: 'left' }); + }); + + const swipeRight = container.find('.mes_img_swipe_right'); + swipeRight.off('click').on('click', function () { + eventSource.emit(event_types.IMAGE_SWIPED, { message: mes, element: messageElement, direction: 'right' }); + }); + } + } + + // Add file to message + if (mes.extra?.file) { + messageElement.find('.mes_file_container').remove(); + const messageId = messageElement.attr('mesid'); + const template = $('#message_file_template .mes_file_container').clone(); + template.find('.mes_file_name').text(mes.extra.file.name); + template.find('.mes_file_size').text(humanFileSize(mes.extra.file.size)); + template.find('.mes_file_download').attr('mesid', messageId); + template.find('.mes_file_delete').attr('mesid', messageId); + messageElement.find('.mes_block').append(template); + } else { + messageElement.find('.mes_file_container').remove(); + } +} + +/** + * @deprecated Use appendMediaToMessage instead. + */ +export function appendImageToMessage(mes, messageElement) { + appendMediaToMessage(mes, messageElement); +} + +export function addCopyToCodeBlocks(messageElement) { + const codeBlocks = $(messageElement).find('pre code'); + for (let i = 0; i < codeBlocks.length; i++) { + hljs.highlightElement(codeBlocks.get(i)); + const copyButton = document.createElement('i'); + copyButton.classList.add('fa-solid', 'fa-copy', 'code-copy', 'interactable'); + copyButton.title = 'Copy code'; + codeBlocks.get(i).appendChild(copyButton); + copyButton.addEventListener('pointerup', async function () { + const text = codeBlocks.get(i).innerText; + await copyText(text); + toastr.info(t`Copied!`, '', { timeOut: 2000 }); + }); + } +} + + +/** + * Adds a single message to the chat. + * @param {object} mes Message object + * @param {object} [options] Options + * @param {string} [options.type='normal'] Message type + * @param {number} [options.insertAfter=null] Message ID to insert the new message after + * @param {boolean} [options.scroll=true] Whether to scroll to the new message + * @param {number} [options.insertBefore=null] Message ID to insert the new message before + * @param {number} [options.forceId=null] Force the message ID + * @param {boolean} [options.showSwipes=true] Whether to show swipe buttons + * @returns {void} + */ +export function addOneMessage(mes, { type = 'normal', insertAfter = null, scroll = true, insertBefore = null, forceId = null, showSwipes = true } = {}) { + let messageText = mes['mes']; + const momentDate = timestampToMoment(mes.send_date); + const timestamp = momentDate.isValid() ? momentDate.format('LL LT') : ''; + + if (mes?.extra?.display_text) { + messageText = mes.extra.display_text; + } + + // Forbidden black magic + // This allows to use "continue" on user messages + if (type === 'swipe' && mes.swipe_id === undefined) { + mes.swipe_id = 0; + mes.swipes = [mes.mes]; + } + + let avatarImg = getUserAvatar(user_avatar); + const isSystem = mes.is_system; + const title = mes.title; + generatedPromptCache = ''; + + //for non-user mesages + if (!mes['is_user']) { + if (mes.force_avatar) { + avatarImg = mes.force_avatar; + } else if (this_chid === undefined) { + avatarImg = system_avatar; + } else { + if (characters[this_chid].avatar !== 'none') { + avatarImg = getThumbnailUrl('avatar', characters[this_chid].avatar); + } else { + avatarImg = default_avatar; + } + } + //old processing: + //if messge is from sytem, use the name provided in the message JSONL to proceed, + //if not system message, use name2 (char's name) to proceed + //characterName = mes.is_system || mes.force_avatar ? mes.name : name2; + } else if (mes['is_user'] && mes['force_avatar']) { + // Special case for persona images. + avatarImg = mes['force_avatar']; + } + + // if mes.uses_system_ui is true, set an override on the sanitizer options + const sanitizerOverrides = mes.uses_system_ui ? { MESSAGE_ALLOW_SYSTEM_UI: true } : {}; + + messageText = messageFormatting( + messageText, + mes.name, + isSystem, + mes.is_user, + chat.indexOf(mes), + sanitizerOverrides, + false, + ); + const bias = messageFormatting(mes.extra?.bias ?? '', '', false, false, -1, {}, false); + let bookmarkLink = mes?.extra?.bookmark_link ?? ''; + + let params = { + mesId: forceId ?? chat.length - 1, + swipeId: mes.swipe_id ?? 0, + characterName: mes.name, + isUser: mes.is_user, + avatarImg: avatarImg, + bias: bias, + isSystem: isSystem, + title: title, + bookmarkLink: bookmarkLink, + forceAvatar: mes.force_avatar, + timestamp: timestamp, + extra: mes.extra, + tokenCount: mes.extra?.token_count ?? 0, + ...formatGenerationTimer(mes.gen_started, mes.gen_finished, mes.extra?.token_count, mes.extra?.reasoning_duration, mes.extra?.time_to_first_token), + }; + + const renderedMessage = getMessageFromTemplate(params); + + if (type !== 'swipe') { + if (!insertAfter && !insertBefore) { + chatElement.append(renderedMessage); + } + else if (insertAfter) { + const target = chatElement.find(`.mes[mesid="${insertAfter}"]`); + $(renderedMessage).insertAfter(target); + } else { + const target = chatElement.find(`.mes[mesid="${insertBefore}"]`); + $(renderedMessage).insertBefore(target); + } + } + + // Callers push the new message to chat before calling addOneMessage + const newMessageId = typeof forceId == 'number' ? forceId : chat.length - 1; + + const newMessage = $(`#chat [mesid="${newMessageId}"]`); + const isSmallSys = mes?.extra?.isSmallSys; + + if (isSmallSys === true) { + newMessage.addClass('smallSysMes'); + } + + if (Array.isArray(mes?.extra?.tool_invocations)) { + newMessage.addClass('toolCall'); + } + + //shows or hides the Prompt display button + let mesIdToFind = type === 'swipe' ? params.mesId - 1 : params.mesId; //Number(newMessage.attr('mesId')); + + //if we have itemized messages, and the array isn't null.. + if (params.isUser === false && Array.isArray(itemizedPrompts) && itemizedPrompts.length > 0) { + const itemizedPrompt = itemizedPrompts.find(x => Number(x.mesId) === Number(mesIdToFind)); + if (itemizedPrompt) { + newMessage.find('.mes_prompt').show(); + } + } + + newMessage.find('.avatar img').on('error', function () { + $(this).hide(); + $(this).parent().html('
      '); + }); + + if (type === 'swipe') { + const swipeMessage = chatElement.find(`[mesid="${chat.length - 1}"]`); + swipeMessage.attr('swipeid', params.swipeId); + swipeMessage.find('.mes_text').html(messageText).attr('title', title); + swipeMessage.find('.timestamp').text(timestamp).attr('title', `${params.extra.api} - ${params.extra.model}`); + updateReasoningUI(swipeMessage); + appendMediaToMessage(mes, swipeMessage); + if (power_user.timestamp_model_icon && params.extra?.api) { + insertSVGIcon(swipeMessage, params.extra); + } + + if (mes.swipe_id == mes.swipes.length - 1) { + swipeMessage.find('.mes_timer').text(params.timerValue).attr('title', params.timerTitle); + swipeMessage.find('.tokenCounterDisplay').text(`${params.tokenCount}t`); + } else { + swipeMessage.find('.mes_timer').empty(); + swipeMessage.find('.tokenCounterDisplay').empty(); + } + } else { + const messageId = forceId ?? chat.length - 1; + chatElement.find(`[mesid="${messageId}"] .mes_text`).append(messageText); + appendMediaToMessage(mes, newMessage); + showSwipes && hideSwipeButtons(); + } + + addCopyToCodeBlocks(newMessage); + + // Set the swipes counter for past messages, only visible if 'Show Swipes on All Message' is enabled + if (!params.isUser && newMessageId !== 0 && newMessageId !== chat.length - 1) { + const swipesNum = chat[newMessageId].swipes?.length; + const swipeId = chat[newMessageId].swipe_id + 1; + newMessage.find('.swipes-counter').text(formatSwipeCounter(swipeId, swipesNum)); + } + + if (showSwipes) { + $('#chat .mes').last().addClass('last_mes'); + $('#chat .mes').eq(-2).removeClass('last_mes'); + hideSwipeButtons(); + showSwipeButtons(); + } + + // Don't scroll if not inserting last + if (!insertAfter && !insertBefore && scroll) { + scrollChatToBottom(); + } +} + +/** + * Returns the URL of the avatar for the given character Id. + * @param {number} characterId Character Id + * @returns {string} Avatar URL + */ +export function getCharacterAvatar(characterId) { + const character = characters[characterId]; + const avatarImg = character?.avatar; + + if (!avatarImg || avatarImg === 'none') { + return default_avatar; + } + + return formatCharacterAvatar(avatarImg); +} + +export function formatCharacterAvatar(characterAvatar) { + return `characters/${characterAvatar}`; +} + +/** + * Formats the title for the generation timer. + * @param {Date} gen_started Date when generation was started + * @param {Date} gen_finished Date when generation was finished + * @param {number} tokenCount Number of tokens generated (0 if not available) + * @param {number?} [reasoningDuration=null] Reasoning duration (null if no reasoning was done) + * @param {number?} [timeToFirstToken=null] Time to first token + * @returns {Object} Object containing the formatted timer value and title + * @example + * const { timerValue, timerTitle } = formatGenerationTimer(gen_started, gen_finished, tokenCount); + * console.log(timerValue); // 1.2s + * console.log(timerTitle); // Generation queued: 12:34:56 7 Jan 2021\nReply received: 12:34:57 7 Jan 2021\nTime to generate: 1.2 seconds\nToken rate: 5 t/s + */ +function formatGenerationTimer(gen_started, gen_finished, tokenCount, reasoningDuration = null, timeToFirstToken = null) { + if (!gen_started || !gen_finished) { + return {}; + } + + const dateFormat = 'HH:mm:ss D MMM YYYY'; + const start = moment(gen_started); + const finish = moment(gen_finished); + const seconds = finish.diff(start, 'seconds', true); + const timerValue = `${seconds.toFixed(1)}s`; + const timerTitle = [ + `Generation queued: ${start.format(dateFormat)}`, + `Reply received: ${finish.format(dateFormat)}`, + `Time to generate: ${seconds} seconds`, + timeToFirstToken ? `Time to first token: ${timeToFirstToken / 1000} seconds` : '', + reasoningDuration > 0 ? `Time to think: ${reasoningDuration / 1000} seconds` : '', + tokenCount > 0 ? `Token rate: ${Number(tokenCount / seconds).toFixed(3)} t/s` : '', + ].filter(x => x).join('\n').trim(); + + if (isNaN(seconds) || seconds < 0) { + return { timerValue: '', timerTitle }; + } + + return { timerValue, timerTitle }; +} + +export function scrollChatToBottom() { + if (power_user.auto_scroll_chat_to_bottom) { + let position = chatElement[0].scrollHeight; + + if (power_user.waifuMode) { + const lastMessage = chatElement.find('.mes').last(); + if (lastMessage.length) { + const lastMessagePosition = lastMessage.position().top; + position = chatElement.scrollTop() + lastMessagePosition; + } + } + + chatElement.scrollTop(position); + } +} + +/** + * Substitutes {{macro}} parameters in a string. + * @param {string} content - The string to substitute parameters in. + * @param {Record} additionalMacro - Additional environment variables for substitution. + * @param {(x: string) => string} [postProcessFn] - Post-processing function for each substituted macro. + * @returns {string} The string with substituted parameters. + */ +export function substituteParamsExtended(content, additionalMacro = {}, postProcessFn = (x) => x) { + return substituteParams(content, undefined, undefined, undefined, undefined, true, additionalMacro, postProcessFn); +} + +/** + * Substitutes {{macro}} parameters in a string. + * @param {string} content - The string to substitute parameters in. + * @param {string} [_name1] - The name of the user. Uses global name1 if not provided. + * @param {string} [_name2] - The name of the character. Uses global name2 if not provided. + * @param {string} [_original] - The original message for {{original}} substitution. + * @param {string} [_group] - The group members list for {{group}} substitution. + * @param {boolean} [_replaceCharacterCard] - Whether to replace character card macros. + * @param {Record} [additionalMacro] - Additional environment variables for substitution. + * @param {(x: string) => string} [postProcessFn] - Post-processing function for each substituted macro. + * @returns {string} The string with substituted parameters. + */ +export function substituteParams(content, _name1, _name2, _original, _group, _replaceCharacterCard = true, additionalMacro = {}, postProcessFn = (x) => x) { + if (!content) { + return ''; + } + + const environment = {}; + + if (typeof _original === 'string') { + let originalSubstituted = false; + environment.original = () => { + if (originalSubstituted) { + return ''; + } + + originalSubstituted = true; + return _original; + }; + } + + const getGroupValue = (includeMuted) => { + if (typeof _group === 'string') { + return _group; + } + + if (selected_group) { + const members = groups.find(x => x.id === selected_group)?.members; + /** @type {string[]} */ + const disabledMembers = groups.find(x => x.id === selected_group)?.disabled_members ?? []; + const isMuted = x => includeMuted ? true : !disabledMembers.includes(x); + const names = Array.isArray(members) + ? members.filter(isMuted).map(m => characters.find(c => c.avatar === m)?.name).filter(Boolean).join(', ') + : ''; + return names; + } else { + return _name2 ?? name2; + } + }; + + if (_replaceCharacterCard) { + const fields = getCharacterCardFields(); + environment.charPrompt = fields.system || ''; + environment.charInstruction = environment.charJailbreak = fields.jailbreak || ''; + environment.description = fields.description || ''; + environment.personality = fields.personality || ''; + environment.scenario = fields.scenario || ''; + environment.persona = fields.persona || ''; + environment.mesExamples = () => { + const isInstruct = power_user.instruct.enabled && main_api !== 'openai'; + const mesExamplesArray = parseMesExamples(fields.mesExamples, isInstruct); + if (isInstruct) { + const instructExamples = formatInstructModeExamples(mesExamplesArray, name1, name2); + return instructExamples.join(''); + } + return mesExamplesArray.join(''); + }; + environment.mesExamplesRaw = fields.mesExamples || ''; + environment.charVersion = fields.version || ''; + environment.char_version = fields.version || ''; + } + + // Must be substituted last so that they're replaced inside {{description}} + environment.user = _name1 ?? name1; + environment.char = _name2 ?? name2; + environment.group = environment.charIfNotGroup = getGroupValue(true); + environment.groupNotMuted = getGroupValue(false); + environment.model = getGeneratingModel(); + + if (additionalMacro && typeof additionalMacro === 'object') { + Object.assign(environment, additionalMacro); + } + + return evaluateMacros(content, environment, postProcessFn); +} + + +/** + * Gets stopping sequences for the prompt. + * @param {boolean} isImpersonate A request is made to impersonate a user + * @param {boolean} isContinue A request is made to continue the message + * @returns {string[]} Array of stopping strings + */ +export function getStoppingStrings(isImpersonate, isContinue) { + const result = []; + + if (power_user.context.names_as_stop_strings) { + const charString = `\n${name2}:`; + const userString = `\n${name1}:`; + result.push(isImpersonate ? charString : userString); + + result.push(userString); + + if (isContinue && Array.isArray(chat) && chat[chat.length - 1]?.is_user) { + result.push(charString); + } + + // Add group members as stopping strings if generating for a specific group member or user. (Allow slash commands to work around name stopping string restrictions) + if (selected_group && (name2 || isImpersonate)) { + const group = groups.find(x => x.id === selected_group); + + if (group && Array.isArray(group.members)) { + const names = group.members + .map(x => characters.find(y => y.avatar == x)) + .filter(x => x && x.name && x.name !== name2) + .map(x => `\n${x.name}:`); + result.push(...names); + } + } + } + + result.push(...getInstructStoppingSequences()); + result.push(...getCustomStoppingStrings()); + + if (power_user.single_line) { + result.unshift('\n'); + } + + return result.filter(x => x).filter(onlyUnique); +} + +/** + * Background generation based on the provided prompt. + * @param {string} quiet_prompt Instruction prompt for the AI + * @param {boolean} quietToLoud Whether the message should be sent in a foreground (loud) or background (quiet) mode + * @param {boolean} skipWIAN whether to skip addition of World Info and Author's Note into the prompt + * @param {string} quietImage Image to use for the quiet prompt + * @param {string} quietName Name to use for the quiet prompt (defaults to "System:") + * @param {number} [responseLength] Maximum response length. If unset, the global default value is used. + * @param {number} force_chid Character ID to use for this generation run. Works in groups only. + * @returns + */ +export async function generateQuietPrompt(quiet_prompt, quietToLoud, skipWIAN, quietImage = null, quietName = null, responseLength = null, force_chid = null) { + console.log('got into genQuietPrompt'); + const responseLengthCustomized = typeof responseLength === 'number' && responseLength > 0; + let eventHook = () => { }; + try { + /** @type {GenerateOptions} */ + const options = { + quiet_prompt, + quietToLoud, + skipWIAN: skipWIAN, + force_name2: true, + quietImage: quietImage, + quietName: quietName, + force_chid: force_chid, + }; + if (responseLengthCustomized) { + TempResponseLength.save(main_api, responseLength); + eventHook = TempResponseLength.setupEventHook(main_api); + } + const result = await Generate('quiet', options); + return removeReasoningFromString(result); + } finally { + if (responseLengthCustomized && TempResponseLength.isCustomized()) { + TempResponseLength.restore(main_api); + TempResponseLength.removeEventHook(main_api, eventHook); + } + } +} + +/** + * Executes slash commands and returns the new text and whether the generation was interrupted. + * @param {string} message Text to be sent + * @returns {Promise} Whether the message sending was interrupted + */ +export async function processCommands(message) { + if (!message || !message.trim().startsWith('/')) { + return false; + } + await executeSlashCommandsOnChatInput(message, { + clearChatInput: true, + }); + return true; +} + +export function sendSystemMessage(type, text, extra = {}) { + const systemMessage = system_messages[type]; + + if (!systemMessage) { + return; + } + + const newMessage = { ...systemMessage, send_date: getMessageTimeStamp() }; + + if (text) { + newMessage.mes = text; + } + + if (type === system_message_types.SLASH_COMMANDS) { + newMessage.mes = getSlashCommandsHelp(); + } + + if (!newMessage.extra) { + newMessage.extra = {}; + } + + newMessage.extra = Object.assign(newMessage.extra, extra); + newMessage.extra.type = type; + + chat.push(newMessage); + addOneMessage(newMessage); + is_send_press = false; + if (type === system_message_types.SLASH_COMMANDS) { + const browser = new SlashCommandBrowser(); + const spinner = document.querySelector('#chat .last_mes .custom-slashHelp'); + const parent = spinner.parentElement; + spinner.remove(); + browser.renderInto(parent); + browser.search.focus(); + } +} + +/** + * Extracts the contents of bias macros from a message. + * @param {string} message Message text + * @returns {string} Message bias extracted from the message (or an empty string if not found) + */ +export function extractMessageBias(message) { + if (!message) { + return ''; + } + + try { + const biasHandlebars = Handlebars.create(); + const biasMatches = []; + biasHandlebars.registerHelper('bias', function (text) { + biasMatches.push(text); + return ''; + }); + const template = biasHandlebars.compile(message); + template({}); + + if (biasMatches && biasMatches.length > 0) { + return ` ${biasMatches.join(' ')}`; + } + + return ''; + } catch { + return ''; + } +} + +/** + * Removes impersonated group member lines from the group member messages. + * Doesn't do anything if group reply trimming is disabled. + * @param {string} getMessage Group message + * @returns Cleaned-up group message + */ +function cleanGroupMessage(getMessage) { + if (power_user.disable_group_trimming) { + return getMessage; + } + + const group = groups.find((x) => x.id == selected_group); + + if (group && Array.isArray(group.members) && group.members) { + for (let member of group.members) { + const character = characters.find(x => x.avatar == member); + + if (!character) { + continue; + } + + const name = character.name; + + // Skip current speaker. + if (name === name2) { + continue; + } + + const regex = new RegExp(`(^|\n)${escapeRegex(name)}:`); + const nameMatch = getMessage.match(regex); + if (nameMatch) { + getMessage = getMessage.substring(0, nameMatch.index); + } + } + } + return getMessage; +} + +function addPersonaDescriptionExtensionPrompt() { + const INJECT_TAG = 'PERSONA_DESCRIPTION'; + setExtensionPrompt(INJECT_TAG, '', extension_prompt_types.IN_PROMPT, 0); + + if (!power_user.persona_description || power_user.persona_description_position === persona_description_positions.NONE) { + return; + } + + const promptPositions = [persona_description_positions.BOTTOM_AN, persona_description_positions.TOP_AN]; + + if (promptPositions.includes(power_user.persona_description_position) && shouldWIAddPrompt) { + const originalAN = extension_prompts[NOTE_MODULE_NAME].value; + const ANWithDesc = power_user.persona_description_position === persona_description_positions.TOP_AN + ? `${power_user.persona_description}\n${originalAN}` + : `${originalAN}\n${power_user.persona_description}`; + + setExtensionPrompt(NOTE_MODULE_NAME, ANWithDesc, chat_metadata[metadata_keys.position], chat_metadata[metadata_keys.depth], extension_settings.note.allowWIScan, chat_metadata[metadata_keys.role]); + } + + if (power_user.persona_description_position === persona_description_positions.AT_DEPTH) { + setExtensionPrompt(INJECT_TAG, power_user.persona_description, extension_prompt_types.IN_CHAT, power_user.persona_description_depth, true, power_user.persona_description_role); + } +} + +/** + * Returns all extension prompts combined. + * @returns {Promise} Combined extension prompts + */ +async function getAllExtensionPrompts() { + const values = []; + + for (const prompt of Object.values(extension_prompts)) { + const value = prompt?.value?.trim(); + + if (!value) { + continue; + } + + const hasFilter = typeof prompt.filter === 'function'; + if (hasFilter && !await prompt.filter()) { + continue; + } + + values.push(value); + } + + return substituteParams(values.join('\n')); +} + +/** + * Wrapper to fetch extension prompts by module name + * @param {string} moduleName Module name + * @returns {Promise} Extension prompt + */ +export async function getExtensionPromptByName(moduleName) { + if (!moduleName) { + return ''; + } + + const prompt = extension_prompts[moduleName]; + + if (!prompt) { + return ''; + } + + const hasFilter = typeof prompt.filter === 'function'; + + if (hasFilter && !await prompt.filter()) { + return ''; + } + + return substituteParams(prompt.value); +} + +/** + * Returns the extension prompt for the given position, depth, and role. + * If multiple prompts are found, they are joined with a separator. + * @param {number} [position] Position of the prompt + * @param {number} [depth] Depth of the prompt + * @param {string} [separator] Separator for joining multiple prompts + * @param {number} [role] Role of the prompt + * @param {boolean} [wrap] Wrap start and end with a separator + * @returns {Promise} Extension prompt + */ +export async function getExtensionPrompt(position = extension_prompt_types.IN_PROMPT, depth = undefined, separator = '\n', role = undefined, wrap = true) { + const filterByFunction = async (prompt) => { + const hasFilter = typeof prompt.filter === 'function'; + if (hasFilter && !await prompt.filter()) { + return false; + } + return true; + }; + const promptPromises = Object.keys(extension_prompts) + .sort() + .map((x) => extension_prompts[x]) + .filter(x => x.position == position && x.value) + .filter(x => depth === undefined || x.depth === undefined || x.depth === depth) + .filter(x => role === undefined || x.role === undefined || x.role === role) + .filter(filterByFunction); + const prompts = await Promise.all(promptPromises); + + let values = prompts.map(x => x.value.trim()).join(separator); + if (wrap && values.length && !values.startsWith(separator)) { + values = separator + values; + } + if (wrap && values.length && !values.endsWith(separator)) { + values = values + separator; + } + if (values.length) { + values = substituteParams(values); + } + return values; +} + +export function baseChatReplace(value, name1, name2) { + if (value !== undefined && value.length > 0) { + const _ = undefined; + value = substituteParams(value, name1, name2, _, _, false); + + if (power_user.collapse_newlines) { + value = collapseNewlines(value); + } + + value = value.replace(/\r/g, ''); + } + return value; +} + +/** + * Returns the character card fields for the current character. + * @returns {{system: string, mesExamples: string, description: string, personality: string, persona: string, scenario: string, jailbreak: string, version: string}} + */ +export function getCharacterCardFields() { + const result = { system: '', mesExamples: '', description: '', personality: '', persona: '', scenario: '', jailbreak: '', version: '' }; + result.persona = baseChatReplace(power_user.persona_description?.trim(), name1, name2); + + const character = characters[this_chid]; + + if (!character) { + return result; + } + + const scenarioText = chat_metadata['scenario'] || character.scenario || ''; + result.description = baseChatReplace(character.description?.trim(), name1, name2); + result.personality = baseChatReplace(character.personality?.trim(), name1, name2); + result.scenario = baseChatReplace(scenarioText.trim(), name1, name2); + result.mesExamples = baseChatReplace(character.mes_example?.trim(), name1, name2); + result.system = power_user.prefer_character_prompt ? baseChatReplace(character.data?.system_prompt?.trim(), name1, name2) : ''; + result.jailbreak = power_user.prefer_character_jailbreak ? baseChatReplace(character.data?.post_history_instructions?.trim(), name1, name2) : ''; + result.version = character.data?.character_version ?? ''; + + if (selected_group) { + const groupCards = getGroupCharacterCards(selected_group, Number(this_chid)); + + if (groupCards) { + result.description = groupCards.description; + result.personality = groupCards.personality; + result.scenario = groupCards.scenario; + result.mesExamples = groupCards.mesExamples; + } + } + + return result; +} + +/** + * Parses an examples string. + * @param {string} examplesStr + * @returns {string[]} Examples array with block heading + */ +export function parseMesExamples(examplesStr, isInstruct) { + if (!examplesStr || examplesStr.length === 0 || examplesStr === '') { + return []; + } + + if (!examplesStr.startsWith('')) { + examplesStr = '\n' + examplesStr.trim(); + } + + const exampleSeparator = power_user.context.example_separator ? `${substituteParams(power_user.context.example_separator)}\n` : ''; + const blockHeading = main_api === 'openai' ? '\n' : (exampleSeparator || (isInstruct ? '\n' : '')); + const splitExamples = examplesStr.split(//gi).slice(1).map(block => `${blockHeading}${block.trim()}\n`); + + return splitExamples; +} + +export function isStreamingEnabled() { + const noStreamSources = [chat_completion_sources.SCALE]; + return ( + (main_api == 'openai' && + oai_settings.stream_openai && + !noStreamSources.includes(oai_settings.chat_completion_source) && + !(oai_settings.chat_completion_source == chat_completion_sources.OPENAI && ['o1-2024-12-17', 'o1'].includes(oai_settings.openai_model)) + ) + || (main_api == 'kobold' && kai_settings.streaming_kobold && kai_flags.can_use_streaming) + || (main_api == 'novel' && nai_settings.streaming_novel) + || (main_api == 'textgenerationwebui' && textgen_settings.streaming)); +} + +function showStopButton() { + $('#mes_stop').css({ 'display': 'flex' }); +} + +function hideStopButton() { + // prevent NOOP, because hideStopButton() gets called multiple times + if ($('#mes_stop').css('display') !== 'none') { + $('#mes_stop').css({ 'display': 'none' }); + eventSource.emit(event_types.GENERATION_ENDED, chat.length); + } +} + +class StreamingProcessor { + /** + * Creates a new streaming processor. + * @param {string} type Generation type + * @param {boolean} forceName2 If true, force the use of name2 + * @param {Date} timeStarted Date when generation was started + * @param {string} continueMessage Previous message if the type is 'continue' + * @param {PromptReasoning} promptReasoning Prompt reasoning instance + */ + constructor(type, forceName2, timeStarted, continueMessage, promptReasoning) { + this.result = ''; + this.messageId = -1; + /** @type {HTMLElement} */ + this.messageDom = null; + /** @type {HTMLElement} */ + this.messageTextDom = null; + /** @type {HTMLElement} */ + this.messageTimerDom = null; + /** @type {HTMLElement} */ + this.messageTokenCounterDom = null; + /** @type {HTMLTextAreaElement} */ + this.sendTextarea = document.querySelector('#send_textarea'); + this.type = type; + this.force_name2 = forceName2; + this.isStopped = false; + this.isFinished = false; + this.generator = this.nullStreamingGeneration; + this.abortController = new AbortController(); + this.firstMessageText = '...'; + this.timeStarted = timeStarted; + /** @type {number?} */ + this.timeToFirstToken = null; + this.createdAt = new Date(); + this.continueMessage = type === 'continue' ? continueMessage : ''; + this.swipes = []; + /** @type {import('./scripts/logprobs.js').TokenLogprobs[]} */ + this.messageLogprobs = []; + this.toolCalls = []; + // Initialize reasoning in its own handler + this.reasoningHandler = new ReasoningHandler(timeStarted); + /** @type {PromptReasoning} */ + this.promptReasoning = promptReasoning; + /** @type {string} */ + this.image = ''; + } + + /** + * Initializes DOM elements for the current message. + * @param {number} messageId Current message ID + * @param {boolean?} continueOnReasoning If continuing on reasoning + */ + async #checkDomElements(messageId, continueOnReasoning = null) { + if (this.messageDom === null || this.messageTextDom === null) { + this.messageDom = document.querySelector(`#chat .mes[mesid="${messageId}"]`); + this.messageTextDom = this.messageDom?.querySelector('.mes_text'); + this.messageTimerDom = this.messageDom?.querySelector('.mes_timer'); + this.messageTokenCounterDom = this.messageDom?.querySelector('.tokenCounterDisplay'); + } + if (continueOnReasoning) { + await this.reasoningHandler.process(messageId, false, this.promptReasoning); + } + this.reasoningHandler.updateDom(messageId); + } + + #updateMessageBlockVisibility() { + if (this.messageDom instanceof HTMLElement && Array.isArray(this.toolCalls) && this.toolCalls.length > 0) { + const shouldHide = ['', '...'].includes(this.result); + this.messageDom.classList.toggle('displayNone', shouldHide); + } + } + + markUIGenStarted() { + deactivateSendButtons(); + } + + markUIGenStopped() { + activateSendButtons(); + } + + async onStartStreaming(text) { + const continueOnReasoning = !!(this.type === 'continue' && this.promptReasoning.prefixReasoning); + if (continueOnReasoning) { + this.reasoningHandler.initContinue(this.promptReasoning); + } + + let messageId = -1; + + if (this.type == 'impersonate') { + this.sendTextarea.value = ''; + this.sendTextarea.dispatchEvent(new Event('input', { bubbles: true })); + } else { + await saveReply({ type: this.type, getMessage: text, fromStreaming: true }); + messageId = chat.length - 1; + await this.#checkDomElements(messageId, continueOnReasoning); + this.markUIGenStarted(); + } + hideSwipeButtons(); + scrollChatToBottom(); + return messageId; + } + + async onProgressStreaming(messageId, text, isFinal) { + const isImpersonate = this.type == 'impersonate'; + const isContinue = this.type == 'continue'; + + if (!isImpersonate && !isContinue && Array.isArray(this.swipes) && this.swipes.length > 0) { + for (let i = 0; i < this.swipes.length; i++) { + this.swipes[i] = cleanUpMessage(this.swipes[i], false, false, true, this.stoppingStrings); + } + } + + let processedText = cleanUpMessage(text, isImpersonate, isContinue, !isFinal, this.stoppingStrings); + + const charsToBalance = ['*', '"', '```']; + for (const char of charsToBalance) { + if (!isFinal && isOdd(countOccurrences(processedText, char))) { + const separator = char.length > 1 ? '\n' : ''; + processedText = processedText.trimEnd() + separator + char; + } + } + + if (isImpersonate) { + this.sendTextarea.value = processedText; + this.sendTextarea.dispatchEvent(new Event('input', { bubbles: true })); + } else { + const mesChanged = chat[messageId]['mes'] !== processedText; + await this.#checkDomElements(messageId); + this.#updateMessageBlockVisibility(); + const currentTime = new Date(); + chat[messageId]['mes'] = processedText; + chat[messageId]['gen_started'] = this.timeStarted; + chat[messageId]['gen_finished'] = currentTime; + if (!chat[messageId]['extra']) { + chat[messageId]['extra'] = {}; + } + chat[messageId]['extra']['time_to_first_token'] = this.timeToFirstToken; + + // Update reasoning + await this.reasoningHandler.process(messageId, mesChanged, this.promptReasoning); + processedText = chat[messageId]['mes']; + + // Token count update. + const tokenCountText = this.reasoningHandler.reasoning + processedText; + const currentTokenCount = isFinal && power_user.message_token_count_enabled ? getTokenCount(tokenCountText, 0) : 0; + if (currentTokenCount) { + chat[messageId]['extra']['token_count'] = currentTokenCount; + if (this.messageTokenCounterDom instanceof HTMLElement) { + this.messageTokenCounterDom.textContent = `${currentTokenCount}t`; + } + } + + if ((this.type == 'swipe' || this.type === 'continue') && Array.isArray(chat[messageId]['swipes'])) { + chat[messageId]['swipes'][chat[messageId]['swipe_id']] = processedText; + chat[messageId]['swipe_info'][chat[messageId]['swipe_id']] = { + 'send_date': chat[messageId]['send_date'], + 'gen_started': chat[messageId]['gen_started'], + 'gen_finished': chat[messageId]['gen_finished'], + 'extra': JSON.parse(JSON.stringify(chat[messageId]['extra'])), + }; + } + + const formattedText = messageFormatting( + processedText, + chat[messageId].name, + chat[messageId].is_system, + chat[messageId].is_user, + messageId, + {}, + false, + ); + if (this.messageTextDom instanceof HTMLElement) { + this.messageTextDom.innerHTML = formattedText; + } + + const timePassed = formatGenerationTimer(this.timeStarted, currentTime, currentTokenCount, this.reasoningHandler.getDuration(), this.timeToFirstToken); + if (this.messageTimerDom instanceof HTMLElement) { + this.messageTimerDom.textContent = timePassed.timerValue; + this.messageTimerDom.title = timePassed.timerTitle; + } + + this.setFirstSwipe(messageId); + } + + if (!scrollLock) { + scrollChatToBottom(); + } + } + + async onFinishStreaming(messageId, text) { + this.markUIGenStopped(); + await this.onProgressStreaming(messageId, text, true); + addCopyToCodeBlocks($(`#chat .mes[mesid="${messageId}"]`)); + + await this.reasoningHandler.finish(messageId); + + if (Array.isArray(this.swipes) && this.swipes.length > 0) { + const message = chat[messageId]; + const swipeInfoExtra = structuredClone(message.extra ?? {}); + delete swipeInfoExtra.token_count; + delete swipeInfoExtra.reasoning; + delete swipeInfoExtra.reasoning_duration; + const swipeInfo = { + send_date: message.send_date, + gen_started: message.gen_started, + gen_finished: message.gen_finished, + extra: swipeInfoExtra, + }; + const swipeInfoArray = Array(this.swipes.length).fill().map(() => structuredClone(swipeInfo)); + parseReasoningInSwipes(this.swipes, swipeInfoArray, message.extra?.reasoning_duration); + chat[messageId].swipes.push(...this.swipes); + chat[messageId].swipe_info.push(...swipeInfoArray); + } + + if (this.image) { + await processImageAttachment(chat[messageId], { imageUrl: this.image, parsedImage: null }); + appendMediaToMessage(chat[messageId], $(this.messageDom)); + } + + if (this.type !== 'impersonate') { + await eventSource.emit(event_types.MESSAGE_RECEIVED, this.messageId, this.type); + await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, this.messageId, this.type); + } else { + await eventSource.emit(event_types.IMPERSONATE_READY, text); + } + + syncMesToSwipe(messageId); + saveLogprobsForActiveMessage(this.messageLogprobs.filter(Boolean), this.continueMessage); + await saveChatConditional(); + unblockGeneration(); + generatedPromptCache = ''; + + const isAborted = this.abortController.signal.aborted; + if (!isAborted && power_user.auto_swipe && generatedTextFiltered(text)) { + return swipe_right(); + } + + playMessageSound(); + } + + onErrorStreaming() { + this.abortController.abort(); + this.isStopped = true; + + this.markUIGenStopped(); + generatedPromptCache = ''; + unblockGeneration(); + + const noEmitTypes = ['swipe', 'impersonate', 'continue']; + if (!noEmitTypes.includes(this.type)) { + eventSource.emit(event_types.MESSAGE_RECEIVED, this.messageId, this.type); + eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, this.messageId, this.type); + } + } + + setFirstSwipe(messageId) { + if (this.type !== 'swipe' && this.type !== 'impersonate') { + if (Array.isArray(chat[messageId]['swipes']) && chat[messageId]['swipes'].length === 1 && chat[messageId]['swipe_id'] === 0) { + chat[messageId]['swipes'][0] = chat[messageId]['mes']; + chat[messageId]['swipe_info'][0] = { + 'send_date': chat[messageId]['send_date'], + 'gen_started': chat[messageId]['gen_started'], + 'gen_finished': chat[messageId]['gen_finished'], + 'extra': JSON.parse(JSON.stringify(chat[messageId]['extra'])), + }; + } + } + } + + onStopStreaming() { + this.abortController.abort(); + this.isFinished = true; + } + + /** + * @returns {Generator<{ text: string, swipes: string[], logprobs: import('./scripts/logprobs.js').TokenLogprobs, toolCalls: any[], state: any }, void, void>} + */ + *nullStreamingGeneration() { + throw new Error('Generation function for streaming is not hooked up'); + } + + async generate() { + if (this.messageId == -1) { + this.messageId = await this.onStartStreaming(this.firstMessageText); + await delay(1); // delay for message to be rendered + scrollLock = false; + } + + // Stopping strings are expensive to calculate, especially with macros enabled. To remove stopping strings + // when streaming, we cache the result of getStoppingStrings instead of calling it once per token. + const isImpersonate = this.type == 'impersonate'; + const isContinue = this.type == 'continue'; + this.stoppingStrings = getStoppingStrings(isImpersonate, isContinue); + + try { + const sw = new Stopwatch(1000 / power_user.streaming_fps); + const timestamps = []; + for await (const { text, swipes, logprobs, toolCalls, state } of this.generator()) { + const now = Date.now(); + timestamps.push(now); + if (!this.timeToFirstToken) { + this.timeToFirstToken = now - this.createdAt.getTime(); + } + if (this.isStopped || this.abortController.signal.aborted) { + return this.result; + } + + this.toolCalls = toolCalls; + this.result = text; + this.swipes = Array.from(swipes ?? []); + if (logprobs) { + this.messageLogprobs.push(...(Array.isArray(logprobs) ? logprobs : [logprobs])); + } + // Get the updated reasoning string into the handler + this.reasoningHandler.updateReasoning(this.messageId, state?.reasoning); + this.image = state?.image ?? ''; + await eventSource.emit(event_types.STREAM_TOKEN_RECEIVED, text); + await sw.tick(async () => await this.onProgressStreaming(this.messageId, this.continueMessage + text)); + } + const seconds = (timestamps[timestamps.length - 1] - timestamps[0]) / 1000; + console.warn(`Stream stats: ${timestamps.length} tokens, ${seconds.toFixed(2)} seconds, rate: ${Number(timestamps.length / seconds).toFixed(2)} TPS`); + } + catch (err) { + // in the case of a self-inflicted abort, we have already cleaned up + if (!this.isFinished) { + console.error(err); + this.onErrorStreaming(); + } + return this.result; + } + + this.isFinished = true; + return this.result; + } +} + +/** + * Generates a message using the provided prompt. + * @param {string} prompt Prompt to generate a message from + * @param {string} api API to use. Main API is used if not specified. + * @param {boolean} instructOverride true to override instruct mode, false to use the default value + * @param {boolean} quietToLoud true to generate a message in system mode, false to generate a message in character mode + * @param {string} [systemPrompt] System prompt to use. Only Instruct mode or OpenAI. + * @param {number} [responseLength] Maximum response length. If unset, the global default value is used. + * @returns {Promise} Generated message + */ +export async function generateRaw(prompt, api, instructOverride, quietToLoud, systemPrompt, responseLength) { + if (!api) { + api = main_api; + } + + const abortController = new AbortController(); + const responseLengthCustomized = typeof responseLength === 'number' && responseLength > 0; + const isInstruct = power_user.instruct.enabled && api !== 'openai' && api !== 'novel' && !instructOverride; + const isQuiet = true; + let eventHook = () => { }; + + if (systemPrompt) { + systemPrompt = substituteParams(systemPrompt); + systemPrompt = isInstruct ? formatInstructModeSystemPrompt(systemPrompt) : systemPrompt; + prompt = api === 'openai' ? prompt : `${systemPrompt}\n${prompt}`; + } + + prompt = substituteParams(prompt); + prompt = api == 'novel' ? adjustNovelInstructionPrompt(prompt) : prompt; + prompt = isInstruct ? formatInstructModeChat(name1, prompt, false, true, '', name1, name2, false) : prompt; + prompt = isInstruct ? (prompt + formatInstructModePrompt(name2, false, '', name1, name2, isQuiet, quietToLoud)) : (prompt + '\n'); + + try { + if (responseLengthCustomized) { + TempResponseLength.save(api, responseLength); + } + let generateData = {}; + + switch (api) { + case 'kobold': + case 'koboldhorde': + if (preset_settings === 'gui') { + generateData = { prompt: prompt, gui_settings: true, max_length: amount_gen, max_context_length: max_context, api_server }; + } else { + const isHorde = api === 'koboldhorde'; + const koboldSettings = koboldai_settings[koboldai_setting_names[preset_settings]]; + generateData = getKoboldGenerationData(prompt, koboldSettings, amount_gen, max_context, isHorde, 'quiet'); + } + TempResponseLength.restore(api); + break; + case 'novel': { + const novelSettings = novelai_settings[novelai_setting_names[nai_settings.preset_settings_novel]]; + generateData = getNovelGenerationData(prompt, novelSettings, amount_gen, false, false, null, 'quiet'); + TempResponseLength.restore(api); + break; + } + case 'textgenerationwebui': + generateData = await getTextGenGenerationData(prompt, amount_gen, false, false, null, 'quiet'); + TempResponseLength.restore(api); + break; + case 'openai': { + generateData = [{ role: 'user', content: prompt.trim() }]; + if (systemPrompt) { + generateData.unshift({ role: 'system', content: systemPrompt.trim() }); + } + eventHook = TempResponseLength.setupEventHook(api); + } break; + } + + let data = {}; + + if (api === 'koboldhorde') { + data = await generateHorde(prompt, generateData, abortController.signal, false); + } else if (api === 'openai') { + data = await sendOpenAIRequest('quiet', generateData, abortController.signal); + } else { + const generateUrl = getGenerateUrl(api); + const response = await fetch(generateUrl, { + method: 'POST', + headers: getRequestHeaders(), + cache: 'no-cache', + body: JSON.stringify(generateData), + signal: abortController.signal, + }); + + if (!response.ok) { + throw await response.json(); + } + + data = await response.json(); + } + + // should only happen for text completions + // other frontend paths do not return data if calling the backend fails, + // they throw things instead + if (data.error) { + throw new Error(data.response); + } + + const message = cleanUpMessage(extractMessageFromData(data), false, false, true); + + if (!message) { + throw new Error('No message generated'); + } + + return message; + } finally { + if (responseLengthCustomized && TempResponseLength.isCustomized()) { + TempResponseLength.restore(api); + TempResponseLength.removeEventHook(api, eventHook); + } + } +} + +class TempResponseLength { + static #originalResponseLength = -1; + static #lastApi = null; + + static isCustomized() { + return this.#originalResponseLength > -1; + } + + /** + * Save the current response length for the specified API. + * @param {string} api API identifier + * @param {number} responseLength New response length + */ + static save(api, responseLength) { + if (api === 'openai') { + this.#originalResponseLength = oai_settings.openai_max_tokens; + oai_settings.openai_max_tokens = responseLength; + } else { + this.#originalResponseLength = amount_gen; + amount_gen = responseLength; + } + + this.#lastApi = api; + console.log('[TempResponseLength] Saved original response length:', TempResponseLength.#originalResponseLength); + } + + /** + * Restore the original response length for the specified API. + * @param {string|null} api API identifier + * @returns {void} + */ + static restore(api) { + if (this.#originalResponseLength === -1) { + return; + } + if (!api && this.#lastApi) { + api = this.#lastApi; + } + if (api === 'openai') { + oai_settings.openai_max_tokens = this.#originalResponseLength; + } else { + amount_gen = this.#originalResponseLength; + } + + console.log('[TempResponseLength] Restored original response length:', this.#originalResponseLength); + this.#originalResponseLength = -1; + this.#lastApi = null; + } + + /** + * Sets up an event hook to restore the original response length when the event is emitted. + * @param {string} api API identifier + * @returns {function(): void} Event hook function + */ + static setupEventHook(api) { + const eventHook = () => { + if (this.isCustomized()) { + this.restore(api); + } + }; + + switch (api) { + case 'openai': + eventSource.once(event_types.CHAT_COMPLETION_SETTINGS_READY, eventHook); + break; + default: + eventSource.once(event_types.GENERATE_AFTER_DATA, eventHook); + break; + } + + return eventHook; + } + + /** + * Removes the event hook for the specified API. + * @param {string} api API identifier + * @param {function(): void} eventHook Previously set up event hook + */ + static removeEventHook(api, eventHook) { + switch (api) { + case 'openai': + eventSource.removeListener(event_types.CHAT_COMPLETION_SETTINGS_READY, eventHook); + break; + default: + eventSource.removeListener(event_types.GENERATE_AFTER_DATA, eventHook); + break; + } + } +} + +/** + * Removes last message from the chat DOM. + * @returns {Promise} Resolves when the message is removed. + */ +function removeLastMessage() { + return new Promise((resolve) => { + const lastMes = $('#chat').children('.mes').last(); + if (lastMes.length === 0) { + return resolve(); + } + lastMes.hide(animation_duration, function () { + $(this).remove(); + resolve(); + }); + }); +} + +/** + * Runs a generation using the current chat context. + * @param {string} type Generation type + * @param {GenerateOptions} options Generation options + * @param {boolean} dryRun Whether to actually generate a message or just assemble the prompt + * @returns {Promise} Returns a promise that resolves when the text is done generating. + * @typedef {{automatic_trigger?: boolean, force_name2?: boolean, quiet_prompt?: string, quietToLoud?: boolean, skipWIAN?: boolean, force_chid?: number, signal?: AbortSignal, quietImage?: string, quietName?: string, depth?: number }} GenerateOptions + */ +export async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage, quietName, depth = 0 } = {}, dryRun = false) { + console.log('Generate entered'); + setGenerationProgress(0); + generation_started = new Date(); + + // Prevent generation from shallow characters + await unshallowCharacter(this_chid); + + // Occurs every time, even if the generation is aborted due to slash commands execution + await eventSource.emit(event_types.GENERATION_STARTED, type, { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage }, dryRun); + + // Don't recreate abort controller if signal is passed + if (!(abortController && signal)) { + abortController = new AbortController(); + } + + // OpenAI doesn't need instruct mode. Use OAI main prompt instead. + const isInstruct = power_user.instruct.enabled && main_api !== 'openai'; + const isImpersonate = type == 'impersonate'; + + if (!(dryRun || type == 'regenerate' || type == 'swipe' || type == 'quiet')) { + const interruptedByCommand = await processCommands(String($('#send_textarea').val())); + + if (interruptedByCommand) { + //$("#send_textarea").val('')[0].dispatchEvent(new Event('input', { bubbles:true })); + unblockGeneration(type); + return Promise.resolve(); + } + } + + // Occurs only if the generation is not aborted due to slash commands execution + await eventSource.emit(event_types.GENERATION_AFTER_COMMANDS, type, { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage }, dryRun); + + if (main_api == 'kobold' && kai_settings.streaming_kobold && !kai_flags.can_use_streaming) { + toastr.error(t`Streaming is enabled, but the version of Kobold used does not support token streaming.`, undefined, { timeOut: 10000, preventDuplicates: true }); + unblockGeneration(type); + return Promise.resolve(); + } + + if (isHordeGenerationNotAllowed()) { + unblockGeneration(type); + return Promise.resolve(); + } + + if (!dryRun) { + // Ping server to make sure it is still alive + const pingResult = await pingServer(); + + if (!pingResult) { + unblockGeneration(type); + toastr.error(t`Verify that the server is running and accessible.`, t`ST Server cannot be reached`); + throw new Error('Server unreachable'); + } + + // Hide swipes if not in a dry run. + hideSwipeButtons(); + // If generated any message, set the flag to indicate it can't be recreated again. + chat_metadata['tainted'] = true; + } + + if (selected_group && !is_group_generating) { + if (!dryRun) { + // Returns the promise that generateGroupWrapper returns; resolves when generation is done + return generateGroupWrapper(false, type, { quiet_prompt, force_chid, signal: abortController.signal, quietImage }); + } + + const characterIndexMap = new Map(characters.map((char, index) => [char.avatar, index])); + const group = groups.find((x) => x.id === selected_group); + + const enabledMembers = group.members.reduce((acc, member) => { + if (!group.disabled_members.includes(member) && !acc.includes(member)) { + acc.push(member); + } + return acc; + }, []); + + const memberIds = enabledMembers + .map((member) => characterIndexMap.get(member)) + .filter((index) => index !== undefined && index !== null); + + if (memberIds.length > 0) { + if (menu_type != 'character_edit') setCharacterId(memberIds[0]); + setCharacterName(''); + } else { + console.log('No enabled members found'); + unblockGeneration(type); + return Promise.resolve(); + } + } + + //#########QUIET PROMPT STUFF############## + //this function just gives special care to novel quiet instruction prompts + if (quiet_prompt) { + quiet_prompt = substituteParams(quiet_prompt); + quiet_prompt = main_api == 'novel' && !quietToLoud ? adjustNovelInstructionPrompt(quiet_prompt) : quiet_prompt; + } + + const hasBackendConnection = online_status !== 'no_connection'; + + // We can't do anything because we're not in a chat right now. (Unless it's a dry run, in which case we need to + // assemble the prompt so we can count its tokens regardless of whether a chat is active.) + if (!dryRun && !hasBackendConnection) { + is_send_press = false; + return Promise.resolve(); + } + + let textareaText; + if (type !== 'regenerate' && type !== 'swipe' && type !== 'quiet' && !isImpersonate && !dryRun) { + is_send_press = true; + textareaText = String($('#send_textarea').val()); + $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles: true })); + } else { + textareaText = ''; + if (chat.length && chat[chat.length - 1]['is_user']) { + //do nothing? why does this check exist? + } + else if (type !== 'quiet' && type !== 'swipe' && !isImpersonate && !dryRun && chat.length) { + chat.length = chat.length - 1; + await removeLastMessage(); + await eventSource.emit(event_types.MESSAGE_DELETED, chat.length); + } + } + + const isContinue = type == 'continue'; + + // Rewrite the generation timer to account for the time passed for all the continuations. + if (isContinue && chat.length) { + const prevFinished = chat[chat.length - 1]['gen_finished']; + const prevStarted = chat[chat.length - 1]['gen_started']; + + if (prevFinished && prevStarted) { + const timePassed = prevFinished - prevStarted; + generation_started = new Date(Date.now() - timePassed); + chat[chat.length - 1]['gen_started'] = generation_started; + } + } + + if (!dryRun) { + deactivateSendButtons(); + } + + let { messageBias, promptBias, isUserPromptBias } = getBiasStrings(textareaText, type); + + //********************************* + //PRE FORMATING STRING + //********************************* + + // These generation types should not attach pending files to the chat + const noAttachTypes = [ + 'regenerate', + 'swipe', + 'impersonate', + 'quiet', + 'continue', + 'ask_command', + ]; + //for normal messages sent from user.. + if ((textareaText != '' || (hasPendingFileAttachment() && !noAttachTypes.includes(type))) && !automatic_trigger && type !== 'quiet' && !dryRun) { + // If user message contains no text other than bias - send as a system message + if (messageBias && !removeMacros(textareaText)) { + sendSystemMessage(system_message_types.GENERIC, ' ', { bias: messageBias }); + } + else { + await sendMessageAsUser(textareaText, messageBias); + } + } + else if (textareaText == '' && !automatic_trigger && !dryRun && type === undefined && main_api == 'openai' && oai_settings.send_if_empty.trim().length > 0) { + // Use send_if_empty if set and the user message is empty. Only when sending messages normally + await sendMessageAsUser(oai_settings.send_if_empty.trim(), messageBias); + } + + let { + description, + personality, + persona, + scenario, + mesExamples, + system, + jailbreak, + } = getCharacterCardFields(); + + if (main_api !== 'openai') { + if (power_user.sysprompt.enabled) { + system = power_user.prefer_character_prompt && system ? system : baseChatReplace(power_user.sysprompt.content, name1, name2); + system = isInstruct ? formatInstructModeSystemPrompt(substituteParams(system, name1, name2, power_user.sysprompt.content)) : system; + } else { + // Nullify if it's not enabled + system = ''; + } + } + + // Depth prompt (character-specific A/N) + removeDepthPrompts(); + const groupDepthPrompts = getGroupDepthPrompts(selected_group, Number(this_chid)); + + if (selected_group && Array.isArray(groupDepthPrompts) && groupDepthPrompts.length > 0) { + groupDepthPrompts.forEach((value, index) => { + const role = getExtensionPromptRoleByName(value.role); + setExtensionPrompt('DEPTH_PROMPT_' + index, value.text, extension_prompt_types.IN_CHAT, value.depth, extension_settings.note.allowWIScan, role); + }); + } else { + const depthPromptText = baseChatReplace(characters[this_chid]?.data?.extensions?.depth_prompt?.prompt?.trim(), name1, name2) || ''; + const depthPromptDepth = characters[this_chid]?.data?.extensions?.depth_prompt?.depth ?? depth_prompt_depth_default; + const depthPromptRole = getExtensionPromptRoleByName(characters[this_chid]?.data?.extensions?.depth_prompt?.role ?? depth_prompt_role_default); + setExtensionPrompt('DEPTH_PROMPT', depthPromptText, extension_prompt_types.IN_CHAT, depthPromptDepth, extension_settings.note.allowWIScan, depthPromptRole); + } + + // First message in fresh 1-on-1 chat reacts to user/character settings changes + if (chat.length) { + chat[0].mes = substituteParams(chat[0].mes); + } + + // Collect messages with usable content + const canUseTools = ToolManager.isToolCallingSupported(); + const canPerformToolCalls = !dryRun && ToolManager.canPerformToolCalls(type) && depth < ToolManager.RECURSE_LIMIT; + let coreChat = chat.filter(x => !x.is_system || (canUseTools && Array.isArray(x.extra?.tool_invocations))); + if (type === 'swipe') { + coreChat.pop(); + } + + coreChat = await Promise.all(coreChat.map(async (chatItem, index) => { + let message = chatItem.mes; + let regexType = chatItem.is_user ? regex_placement.USER_INPUT : regex_placement.AI_OUTPUT; + let options = { isPrompt: true, depth: (coreChat.length - index - (isContinue ? 2 : 1)) }; + + let regexedMessage = getRegexedString(message, regexType, options); + regexedMessage = await appendFileContent(chatItem, regexedMessage); + + if (chatItem?.extra?.append_title && chatItem?.extra?.title) { + regexedMessage = `${regexedMessage}\n\n${chatItem.extra.title}`; + } + + return { + ...chatItem, + mes: regexedMessage, + index, + }; + })); + + const promptReasoning = new PromptReasoning(); + for (let i = coreChat.length - 1; i >= 0; i--) { + const depth = coreChat.length - i - (isContinue ? 2 : 1); + const isPrefix = isContinue && i === coreChat.length - 1; + coreChat[i] = { + ...coreChat[i], + mes: promptReasoning.addToMessage( + coreChat[i].mes, + getRegexedString( + String(coreChat[i].extra?.reasoning ?? ''), + regex_placement.REASONING, + { isPrompt: true, depth: depth }, + ), + isPrefix, + coreChat[i].extra?.reasoning_duration, + ), + }; + if (promptReasoning.isLimitReached()) { + break; + } + } + + // Determine token limit + let this_max_context = getMaxContextSize(); + + if (!dryRun) { + console.debug('Running extension interceptors'); + const aborted = await runGenerationInterceptors(coreChat, this_max_context, type); + + if (aborted) { + console.debug('Generation aborted by extension interceptors'); + unblockGeneration(type); + return Promise.resolve(); + } + } else { + console.debug('Skipping extension interceptors for dry run'); + } + + // Adjust token limit for Horde + let adjustedParams; + if (main_api == 'koboldhorde' && (horde_settings.auto_adjust_context_length || horde_settings.auto_adjust_response_length)) { + try { + adjustedParams = await adjustHordeGenerationParams(max_context, amount_gen); + } + catch { + unblockGeneration(type); + return Promise.resolve(); + } + if (horde_settings.auto_adjust_context_length) { + this_max_context = (adjustedParams.maxContextLength - adjustedParams.maxLength); + } + } + + // Fetches the combined prompt for both negative and positive prompts + const cfgGuidanceScale = getGuidanceScale(); + const useCfgPrompt = cfgGuidanceScale && cfgGuidanceScale.value !== 1; + + // Adjust max context based on CFG prompt to prevent overfitting + if (useCfgPrompt) { + const negativePrompt = getCfgPrompt(cfgGuidanceScale, true, true)?.value || ''; + const positivePrompt = getCfgPrompt(cfgGuidanceScale, false, true)?.value || ''; + if (negativePrompt || positivePrompt) { + const previousMaxContext = this_max_context; + const [negativePromptTokenCount, positivePromptTokenCount] = await Promise.all([getTokenCountAsync(negativePrompt), getTokenCountAsync(positivePrompt)]); + const decrement = Math.max(negativePromptTokenCount, positivePromptTokenCount); + this_max_context -= decrement; + console.log(`Max context reduced by ${decrement} tokens of CFG prompt (${previousMaxContext} -> ${this_max_context})`); + } + } + + console.log(`Core/all messages: ${coreChat.length}/${chat.length}`); + + // kingbri MARK: - Make sure the prompt bias isn't the same as the user bias + if ((promptBias && !isUserPromptBias) || power_user.always_force_name2 || main_api == 'novel') { + force_name2 = true; + } + + if (isImpersonate) { + force_name2 = false; + } + + let mesExamplesArray = parseMesExamples(mesExamples, isInstruct); + + ////////////////////////////////// + // Extension added strings + // Set non-WI AN + setFloatingPrompt(); + // Add persona description to prompt + addPersonaDescriptionExtensionPrompt(); + + // Add WI to prompt (and also inject WI to AN value via hijack) + // Make quiet prompt available for WIAN + setExtensionPrompt('QUIET_PROMPT', quiet_prompt || '', extension_prompt_types.IN_PROMPT, 0, true); + const chatForWI = coreChat.map(x => world_info_include_names ? `${x.name}: ${x.mes}` : x.mes).reverse(); + const { worldInfoString, worldInfoBefore, worldInfoAfter, worldInfoExamples, worldInfoDepth } = await getWorldInfoPrompt(chatForWI, this_max_context, dryRun); + setExtensionPrompt('QUIET_PROMPT', '', extension_prompt_types.IN_PROMPT, 0, true); + + // Add message example WI + for (const example of worldInfoExamples) { + const exampleMessage = example.content; + + if (exampleMessage.length === 0) { + continue; + } + + const formattedExample = baseChatReplace(exampleMessage, name1, name2); + const cleanedExample = parseMesExamples(formattedExample, isInstruct); + + // Insert depending on before or after position + if (example.position === wi_anchor_position.before) { + mesExamplesArray.unshift(...cleanedExample); + } else { + mesExamplesArray.push(...cleanedExample); + } + } + + // At this point, the raw message examples can be created + const mesExamplesRawArray = [...mesExamplesArray]; + + if (mesExamplesArray && isInstruct) { + mesExamplesArray = formatInstructModeExamples(mesExamplesArray, name1, name2); + } + + if (skipWIAN !== true) { + console.log('skipWIAN not active, adding WIAN'); + // Add all depth WI entries to prompt + flushWIDepthInjections(); + if (Array.isArray(worldInfoDepth)) { + worldInfoDepth.forEach((e) => { + const joinedEntries = e.entries.join('\n'); + setExtensionPrompt(`customDepthWI-${e.depth}-${e.role}`, joinedEntries, extension_prompt_types.IN_CHAT, e.depth, false, e.role); + }); + } + } else { + console.log('skipping WIAN'); + } + + // Inject all Depth prompts. Chat Completion does it separately + let injectedIndices = []; + if (main_api !== 'openai') { + injectedIndices = await doChatInject(coreChat, isContinue); + } + + // Insert character jailbreak as the last user message (if exists, allowed, preferred, and not using Chat Completion) + if (power_user.context.allow_jailbreak && power_user.prefer_character_jailbreak && main_api !== 'openai' && jailbreak) { + // Set "original" explicity to empty string since there's no original + jailbreak = substituteParams(jailbreak, name1, name2, ''); + + // When continuing generation of previous output, last user message precedes the message to continue + if (isContinue) { + coreChat.splice(coreChat.length - 1, 0, { mes: jailbreak, is_user: true }); + } + else { + coreChat.push({ mes: jailbreak, is_user: true }); + } + } + + let chat2 = []; + let continue_mag = ''; + const userMessageIndices = []; + const lastUserMessageIndex = coreChat.findLastIndex(x => x.is_user); + + for (let i = coreChat.length - 1, j = 0; i >= 0; i--, j++) { + if (main_api == 'openai') { + chat2[i] = coreChat[j].mes; + if (i === 0 && isContinue) { + chat2[i] = chat2[i].slice(0, chat2[i].lastIndexOf(coreChat[j].mes) + coreChat[j].mes.length); + continue_mag = coreChat[j].mes; + } + continue; + } + + chat2[i] = formatMessageHistoryItem(coreChat[j], isInstruct, false); + + if (j === 0 && isInstruct) { + // Reformat with the first output sequence (if any) + chat2[i] = formatMessageHistoryItem(coreChat[j], isInstruct, force_output_sequence.FIRST); + } + + if (lastUserMessageIndex >= 0 && j === lastUserMessageIndex && isInstruct) { + // Reformat with the last input sequence (if any) + chat2[i] = formatMessageHistoryItem(coreChat[j], isInstruct, force_output_sequence.LAST); + } + + // Do not suffix the message for continuation + if (i === 0 && isContinue) { + if (isInstruct) { + // Reformat with the last output sequence (if any) + chat2[i] = formatMessageHistoryItem(coreChat[j], isInstruct, force_output_sequence.LAST); + } + + chat2[i] = chat2[i].slice(0, chat2[i].lastIndexOf(coreChat[j].mes) + coreChat[j].mes.length); + continue_mag = coreChat[j].mes; + } + + if (coreChat[j].is_user) { + userMessageIndices.push(i); + } + } + + let addUserAlignment = isInstruct && power_user.instruct.user_alignment_message; + let userAlignmentMessage = ''; + + if (addUserAlignment) { + const alignmentMessage = { + name: name1, + mes: substituteParams(power_user.instruct.user_alignment_message), + is_user: true, + }; + userAlignmentMessage = formatMessageHistoryItem(alignmentMessage, isInstruct, force_output_sequence.FIRST); + } + + // Call combined AN into Generate + const beforeScenarioAnchor = (await getExtensionPrompt(extension_prompt_types.BEFORE_PROMPT)).trimStart(); + const afterScenarioAnchor = await getExtensionPrompt(extension_prompt_types.IN_PROMPT); + + const storyStringParams = { + description: description, + personality: personality, + persona: power_user.persona_description_position == persona_description_positions.IN_PROMPT ? persona : '', + scenario: scenario, + system: system, + char: name2, + user: name1, + wiBefore: worldInfoBefore, + wiAfter: worldInfoAfter, + loreBefore: worldInfoBefore, + loreAfter: worldInfoAfter, + mesExamples: mesExamplesArray.join(''), + mesExamplesRaw: mesExamplesRawArray.join(''), + }; + + const storyString = renderStoryString(storyStringParams); + + // Story string rendered, safe to remove + if (power_user.strip_examples) { + mesExamplesArray = []; + } + + let oaiMessages = []; + let oaiMessageExamples = []; + + if (main_api === 'openai') { + oaiMessages = setOpenAIMessages(coreChat); + oaiMessageExamples = setOpenAIMessageExamples(mesExamplesArray); + } + + // hack for regeneration of the first message + if (chat2.length == 0) { + chat2.push(''); + } + + let examplesString = ''; + let chatString = addChatsPreamble(addChatsSeparator('')); + let cyclePrompt = ''; + + async function getMessagesTokenCount() { + const encodeString = [ + beforeScenarioAnchor, + storyString, + afterScenarioAnchor, + examplesString, + userAlignmentMessage, + chatString, + modifyLastPromptLine(''), + cyclePrompt, + ].join('').replace(/\r/gm, ''); + return getTokenCountAsync(encodeString, power_user.token_padding); + } + + // Force pinned examples into the context + let pinExmString; + if (power_user.pin_examples) { + pinExmString = examplesString = mesExamplesArray.join(''); + } + + // Only add the chat in context if past the greeting message + if (isContinue && (chat2.length > 1 || main_api === 'openai')) { + cyclePrompt = chat2.shift(); + } + + // Collect enough messages to fill the context + let arrMes = new Array(chat2.length); + let tokenCount = await getMessagesTokenCount(); + let lastAddedIndex = -1; + + // Pre-allocate all injections first. + // If it doesn't fit - user shot himself in the foot + for (const index of injectedIndices) { + const item = chat2[index]; + + if (typeof item !== 'string') { + continue; + } + + tokenCount += await getTokenCountAsync(item.replace(/\r/gm, '')); + if (tokenCount < this_max_context) { + chatString = chatString + item; + arrMes[index] = item; + lastAddedIndex = Math.max(lastAddedIndex, index); + } else { + break; + } + } + + for (let i = 0; i < chat2.length; i++) { + // not needed for OAI prompting + if (main_api == 'openai') { + break; + } + + // Skip already injected messages + if (arrMes[i] !== undefined) { + continue; + } + + const item = chat2[i]; + + if (typeof item !== 'string') { + continue; + } + + tokenCount += await getTokenCountAsync(item.replace(/\r/gm, '')); + if (tokenCount < this_max_context) { + chatString = chatString + item; + arrMes[i] = item; + lastAddedIndex = Math.max(lastAddedIndex, i); + } else { + break; + } + } + + // Add user alignment message if last message is not a user message + const stoppedAtUser = userMessageIndices.includes(lastAddedIndex); + if (addUserAlignment && !stoppedAtUser) { + tokenCount += await getTokenCountAsync(userAlignmentMessage.replace(/\r/gm, '')); + chatString = userAlignmentMessage + chatString; + arrMes.push(userAlignmentMessage); + injectedIndices.push(arrMes.length - 1); + } + + // Unsparse the array. Adjust injected indices + const newArrMes = []; + const newInjectedIndices = []; + for (let i = 0; i < arrMes.length; i++) { + if (arrMes[i] !== undefined) { + newArrMes.push(arrMes[i]); + if (injectedIndices.includes(i)) { + newInjectedIndices.push(newArrMes.length - 1); + } + } + } + + arrMes = newArrMes; + injectedIndices = newInjectedIndices; + + if (main_api !== 'openai') { + setInContextMessages(arrMes.length - injectedIndices.length, type); + } + + // Estimate how many unpinned example messages fit in the context + tokenCount = await getMessagesTokenCount(); + let count_exm_add = 0; + if (!power_user.pin_examples) { + for (let example of mesExamplesArray) { + tokenCount += await getTokenCountAsync(example.replace(/\r/gm, '')); + examplesString += example; + if (tokenCount < this_max_context) { + count_exm_add++; + } else { + break; + } + } + } + + let mesSend = []; + console.debug('calling runGenerate'); + + if (isContinue) { + // Coping mechanism for OAI spacing + if (main_api === 'openai' && !cyclePrompt.endsWith(' ')) { + cyclePrompt += oai_settings.continue_postfix; + continue_mag += oai_settings.continue_postfix; + } + } + + const originalType = type; + + if (!dryRun) { + is_send_press = true; + } + + generatedPromptCache += cyclePrompt; + if (generatedPromptCache.length == 0 || type === 'continue') { + console.debug('generating prompt'); + chatString = ''; + arrMes = arrMes.reverse(); + arrMes.forEach(function (item, i, arr) { + // OAI doesn't need all of this + if (main_api === 'openai') { + return; + } + + // Cohee: This removes a newline from the end of the last message in the context + // Last prompt line will add a newline if it's not a continuation + // In instruct mode it only removes it if wrap is enabled and it's not a quiet generation + if (i === arrMes.length - 1 && type !== 'continue') { + if (!isInstruct || (power_user.instruct.wrap && type !== 'quiet')) { + item = item.replace(/\n?$/, ''); + } + } + + mesSend[mesSend.length] = { message: item, extensionPrompts: [] }; + }); + } + + let mesExmString = ''; + + function setPromptString() { + if (main_api == 'openai') { + return; + } + + console.debug('--setting Prompt string'); + mesExmString = pinExmString ?? mesExamplesArray.slice(0, count_exm_add).join(''); + + if (mesSend.length) { + mesSend[mesSend.length - 1].message = modifyLastPromptLine(mesSend[mesSend.length - 1].message); + } + } + + function modifyLastPromptLine(lastMesString) { + //#########QUIET PROMPT STUFF PT2############## + + // Add quiet generation prompt at depth 0 + if (quiet_prompt && quiet_prompt.length) { + + // here name1 is forced for all quiet prompts..why? + const name = name1; + //checks if we are in instruct, if so, formats the chat as such, otherwise just adds the quiet prompt + const quietAppend = isInstruct ? formatInstructModeChat(name, quiet_prompt, false, true, '', name1, name2, false) : `\n${quiet_prompt}`; + + //This begins to fix quietPrompts (particularly /sysgen) for instruct + //previously instruct input sequence was being appended to the last chat message w/o '\n' + //and no output sequence was added after the input's content. + //TODO: respect output_sequence vs last_output_sequence settings + //TODO: decide how to prompt this to clarify who is talking 'Narrator', 'System', etc. + if (isInstruct) { + lastMesString += quietAppend; // + power_user.instruct.output_sequence + '\n'; + } else { + lastMesString += quietAppend; + } + + + // Ross: bailing out early prevents quiet prompts from respecting other instruct prompt toggles + // for sysgen, SD, and summary this is desireable as it prevents the AI from responding as char.. + // but for idle prompting, we want the flexibility of the other prompt toggles, and to respect them as per settings in the extension + // need a detection for what the quiet prompt is being asked for... + + // Bail out early? + if (!isInstruct && !quietToLoud) { + return lastMesString; + } + } + + + // Get instruct mode line + if (isInstruct && !isContinue) { + const name = (quiet_prompt && !quietToLoud && !isImpersonate) ? (quietName ?? 'System') : (isImpersonate ? name1 : name2); + const isQuiet = quiet_prompt && type == 'quiet'; + lastMesString += formatInstructModePrompt(name, isImpersonate, promptBias, name1, name2, isQuiet, quietToLoud); + } + + // Get non-instruct impersonation line + if (!isInstruct && isImpersonate && !isContinue) { + const name = name1; + if (!lastMesString.endsWith('\n')) { + lastMesString += '\n'; + } + lastMesString += name + ':'; + } + + // Add character's name + // Force name append on continue (if not continuing on user message or first message) + const isContinuingOnFirstMessage = chat.length === 1 && isContinue; + if (!isInstruct && force_name2 && !isContinuingOnFirstMessage) { + if (!lastMesString.endsWith('\n')) { + lastMesString += '\n'; + } + if (!isContinue || !(chat[chat.length - 1]?.is_user)) { + lastMesString += `${name2}:`; + } + } + + return lastMesString; + } + + // Clean up the already generated prompt for seamless addition + function cleanupPromptCache(promptCache) { + // Remove the first occurrance of character's name + if (promptCache.trimStart().startsWith(`${name2}:`)) { + promptCache = promptCache.replace(`${name2}:`, '').trimStart(); + } + + // Remove the first occurrance of prompt bias + if (promptCache.trimStart().startsWith(promptBias)) { + promptCache = promptCache.replace(promptBias, ''); + } + + // Add a space if prompt cache doesn't start with one + if (!/^\s/.test(promptCache) && !isInstruct) { + promptCache = ' ' + promptCache; + } + + return promptCache; + } + + async function checkPromptSize() { + console.debug('---checking Prompt size'); + setPromptString(); + const jointMessages = mesSend.map((e) => `${e.extensionPrompts.join('')}${e.message}`).join(''); + const prompt = [ + beforeScenarioAnchor, + storyString, + afterScenarioAnchor, + mesExmString, + addChatsPreamble(addChatsSeparator(jointMessages)), + '\n', + modifyLastPromptLine(''), + generatedPromptCache, + ].join('').replace(/\r/gm, ''); + let thisPromptContextSize = await getTokenCountAsync(prompt, power_user.token_padding); + + if (thisPromptContextSize > this_max_context) { //if the prepared prompt is larger than the max context size... + if (count_exm_add > 0) { // ..and we have example mesages.. + count_exm_add--; // remove the example messages... + await checkPromptSize(); // and try agin... + } else if (mesSend.length > 0) { // if the chat history is longer than 0 + mesSend.shift(); // remove the first (oldest) chat entry.. + await checkPromptSize(); // and check size again.. + } else { + //end + console.debug(`---mesSend.length = ${mesSend.length}`); + } + } + } + + if (generatedPromptCache.length > 0 && main_api !== 'openai') { + console.debug('---Generated Prompt Cache length: ' + generatedPromptCache.length); + await checkPromptSize(); + } else { + console.debug('---calling setPromptString ' + generatedPromptCache.length); + setPromptString(); + } + + // For prompt bit itemization + let mesSendString = ''; + + async function getCombinedPrompt(isNegative) { + // Only return if the guidance scale doesn't exist or the value is 1 + // Also don't return if constructing the neutral prompt + if (isNegative && !useCfgPrompt) { + return; + } + + // OAI has its own prompt manager. No need to do anything here + if (main_api === 'openai') { + return ''; + } + + // Deep clone + let finalMesSend = structuredClone(mesSend); + + if (useCfgPrompt) { + const cfgPrompt = getCfgPrompt(cfgGuidanceScale, isNegative); + if (cfgPrompt.value) { + if (cfgPrompt.depth === 0) { + finalMesSend[finalMesSend.length - 1].message += + /\s/.test(finalMesSend[finalMesSend.length - 1].message.slice(-1)) + ? cfgPrompt.value + : ` ${cfgPrompt.value}`; + } else { + // TODO: Make all extension prompts use an array/splice method + const lengthDiff = mesSend.length - cfgPrompt.depth; + const cfgDepth = lengthDiff >= 0 ? lengthDiff : 0; + const cfgMessage = finalMesSend[cfgDepth]; + if (cfgMessage) { + if (!Array.isArray(finalMesSend[cfgDepth].extensionPrompts)) { + finalMesSend[cfgDepth].extensionPrompts = []; + } + finalMesSend[cfgDepth].extensionPrompts.push(`${cfgPrompt.value}\n`); + } + } + } + } + + // Add prompt bias after everything else + // Always run with continue + if (!isInstruct && !isImpersonate) { + if (promptBias.trim().length !== 0) { + finalMesSend[finalMesSend.length - 1].message += + /\s/.test(finalMesSend[finalMesSend.length - 1].message.slice(-1)) + ? promptBias.trimStart() + : ` ${promptBias.trimStart()}`; + } + } + + // Prune from prompt cache if it exists + if (generatedPromptCache.length !== 0) { + generatedPromptCache = cleanupPromptCache(generatedPromptCache); + } + + // Flattens the multiple prompt objects to a string. + const combine = () => { + // Right now, everything is suffixed with a newline + mesSendString = finalMesSend.map((e) => `${e.extensionPrompts.join('')}${e.message}`).join(''); + + // add a custom dingus (if defined) + mesSendString = addChatsSeparator(mesSendString); + + // add chat preamble + mesSendString = addChatsPreamble(mesSendString); + + let combinedPrompt = beforeScenarioAnchor + + storyString + + afterScenarioAnchor + + mesExmString + + mesSendString + + generatedPromptCache; + + combinedPrompt = combinedPrompt.replace(/\r/gm, ''); + + if (power_user.collapse_newlines) { + combinedPrompt = collapseNewlines(combinedPrompt); + } + + return combinedPrompt; + }; + + finalMesSend.forEach((item, i) => { + item.injected = injectedIndices.includes(finalMesSend.length - i - 1); + }); + + let data = { + api: main_api, + combinedPrompt: null, + description, + personality, + persona, + scenario, + char: name2, + user: name1, + worldInfoBefore, + worldInfoAfter, + beforeScenarioAnchor, + afterScenarioAnchor, + storyString, + mesExmString, + mesSendString, + finalMesSend, + generatedPromptCache, + main: system, + jailbreak, + naiPreamble: nai_settings.preamble, + }; + + // Before returning the combined prompt, give available context related information to all subscribers. + await eventSource.emit(event_types.GENERATE_BEFORE_COMBINE_PROMPTS, data); + + // If one or multiple subscribers return a value, forfeit the responsibillity of flattening the context. + return !data.combinedPrompt ? combine() : data.combinedPrompt; + } + + let finalPrompt = await getCombinedPrompt(false); + + const eventData = { prompt: finalPrompt, dryRun: dryRun }; + await eventSource.emit(event_types.GENERATE_AFTER_COMBINE_PROMPTS, eventData); + finalPrompt = eventData.prompt; + + let maxLength = Number(amount_gen); // how many tokens the AI will be requested to generate + let thisPromptBits = []; + + let generate_data; + switch (main_api) { + case 'koboldhorde': + case 'kobold': + if (main_api == 'koboldhorde' && horde_settings.auto_adjust_response_length) { + maxLength = Math.min(maxLength, adjustedParams.maxLength); + maxLength = Math.max(maxLength, MIN_LENGTH); // prevent validation errors + } + + generate_data = { + prompt: finalPrompt, + gui_settings: true, + max_length: maxLength, + max_context_length: max_context, + api_server, + }; + + if (preset_settings != 'gui') { + const isHorde = main_api == 'koboldhorde'; + const presetSettings = koboldai_settings[koboldai_setting_names[preset_settings]]; + const maxContext = (adjustedParams && horde_settings.auto_adjust_context_length) ? adjustedParams.maxContextLength : max_context; + generate_data = getKoboldGenerationData(finalPrompt, presetSettings, maxLength, maxContext, isHorde, type); + } + break; + case 'textgenerationwebui': { + const cfgValues = useCfgPrompt ? { guidanceScale: cfgGuidanceScale, negativePrompt: await getCombinedPrompt(true) } : null; + generate_data = await getTextGenGenerationData(finalPrompt, maxLength, isImpersonate, isContinue, cfgValues, type); + break; + } + case 'novel': { + const cfgValues = useCfgPrompt ? { guidanceScale: cfgGuidanceScale } : null; + const presetSettings = novelai_settings[novelai_setting_names[nai_settings.preset_settings_novel]]; + generate_data = getNovelGenerationData(finalPrompt, presetSettings, maxLength, isImpersonate, isContinue, cfgValues, type); + break; + } + case 'openai': { + let [prompt, counts] = await prepareOpenAIMessages({ + name2: name2, + charDescription: description, + charPersonality: personality, + Scenario: scenario, + worldInfoBefore: worldInfoBefore, + worldInfoAfter: worldInfoAfter, + extensionPrompts: extension_prompts, + bias: promptBias, + type: type, + quietPrompt: quiet_prompt, + quietImage: quietImage, + cyclePrompt: cyclePrompt, + systemPromptOverride: system, + jailbreakPromptOverride: jailbreak, + personaDescription: persona, + messages: oaiMessages, + messageExamples: oaiMessageExamples, + }, dryRun); + generate_data = { prompt: prompt }; + + // TODO: move these side-effects somewhere else, so this switch-case solely sets generate_data + // counts will return false if the user has not enabled the token breakdown feature + if (counts) { + parseTokenCounts(counts, thisPromptBits); + } + + if (!dryRun) { + setInContextMessages(openai_messages_count, type); + } + break; + } + } + + await eventSource.emit(event_types.GENERATE_AFTER_DATA, generate_data); + + if (dryRun) { + generatedPromptCache = ''; + return Promise.resolve(); + } + + /** + * Saves itemized prompt bits and calls streaming or non-streaming generation API. + * @returns {Promise|String|{fromStream}|string|undefined|Object>} + * @throws {Error|object} Error with message text, or Error with response JSON (OAI/Horde), or the actual response JSON (novel|textgenerationwebui|kobold) + */ + async function finishGenerating() { + if (power_user.console_log_prompts) { + console.log(generate_data.prompt); + } + + console.debug('rungenerate calling API'); + + showStopButton(); + + //set array object for prompt token itemization of this message + let currentArrayEntry = Number(thisPromptBits.length - 1); + let additionalPromptStuff = { + ...thisPromptBits[currentArrayEntry], + rawPrompt: generate_data.prompt || generate_data.input, + mesId: getNextMessageId(type), + allAnchors: await getAllExtensionPrompts(), + chatInjects: injectedIndices?.map(index => arrMes[arrMes.length - index - 1])?.join('') || '', + summarizeString: (extension_prompts['1_memory']?.value || ''), + authorsNoteString: (extension_prompts['2_floating_prompt']?.value || ''), + smartContextString: (extension_prompts['chromadb']?.value || ''), + chatVectorsString: (extension_prompts['3_vectors']?.value || ''), + dataBankVectorsString: (extension_prompts['4_vectors_data_bank']?.value || ''), + worldInfoString: worldInfoString, + storyString: storyString, + beforeScenarioAnchor: beforeScenarioAnchor, + afterScenarioAnchor: afterScenarioAnchor, + examplesString: examplesString, + mesSendString: mesSendString, + generatedPromptCache: generatedPromptCache, + promptBias: promptBias, + finalPrompt: finalPrompt, + charDescription: description, + charPersonality: personality, + scenarioText: scenario, + this_max_context: this_max_context, + padding: power_user.token_padding, + main_api: main_api, + instruction: main_api !== 'openai' && power_user.sysprompt.enabled ? substituteParams(power_user.prefer_character_prompt && system ? system : power_user.sysprompt.content) : '', + userPersona: (power_user.persona_description_position == persona_description_positions.IN_PROMPT ? (persona || '') : ''), + tokenizer: getFriendlyTokenizerName(main_api).tokenizerName || '', + presetName: getPresetManager()?.getSelectedPresetName() || '', + }; + + //console.log(additionalPromptStuff); + const itemizedIndex = itemizedPrompts.findIndex((item) => item.mesId === additionalPromptStuff.mesId); + + if (itemizedIndex !== -1) { + itemizedPrompts[itemizedIndex] = additionalPromptStuff; + } + else { + itemizedPrompts.push(additionalPromptStuff); + } + + console.debug(`pushed prompt bits to itemizedPrompts array. Length is now: ${itemizedPrompts.length}`); + + if (isStreamingEnabled() && type !== 'quiet') { + continue_mag = promptReasoning.removePrefix(continue_mag); + streamingProcessor = new StreamingProcessor(type, force_name2, generation_started, continue_mag, promptReasoning); + if (isContinue) { + // Save reply does add cycle text to the prompt, so it's not needed here + streamingProcessor.firstMessageText = ''; + } + + streamingProcessor.generator = await sendStreamingRequest(type, generate_data); + + hideSwipeButtons(); + let getMessage = await streamingProcessor.generate(); + let messageChunk = cleanUpMessage(getMessage, isImpersonate, isContinue, false); + + if (isContinue) { + getMessage = continue_mag + getMessage; + } + + const isStreamFinished = streamingProcessor && !streamingProcessor.isStopped && streamingProcessor.isFinished; + const isStreamWithToolCalls = streamingProcessor && Array.isArray(streamingProcessor.toolCalls) && streamingProcessor.toolCalls.length; + if (canPerformToolCalls && isStreamFinished && isStreamWithToolCalls) { + const lastMessage = chat[chat.length - 1]; + const hasToolCalls = ToolManager.hasToolCalls(streamingProcessor.toolCalls); + const shouldDeleteMessage = type !== 'swipe' && ['', '...'].includes(lastMessage?.mes) && ['', '...'].includes(streamingProcessor?.result); + hasToolCalls && shouldDeleteMessage && await deleteLastMessage(); + const invocationResult = await ToolManager.invokeFunctionTools(streamingProcessor.toolCalls); + const shouldStopGeneration = (!invocationResult.invocations.length && shouldDeleteMessage) || invocationResult.stealthCalls.length; + if (hasToolCalls) { + if (shouldStopGeneration) { + if (Array.isArray(invocationResult.errors) && invocationResult.errors.length) { + ToolManager.showToolCallError(invocationResult.errors); + } + unblockGeneration(type); + generatedPromptCache = ''; + streamingProcessor = null; + return; + } + + streamingProcessor = null; + depth = depth + 1; + await ToolManager.saveFunctionToolInvocations(invocationResult.invocations); + return Generate('normal', { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage, quietName, depth }, dryRun); + } + } + + if (isStreamFinished) { + await streamingProcessor.onFinishStreaming(streamingProcessor.messageId, getMessage); + streamingProcessor = null; + triggerAutoContinue(messageChunk, isImpersonate); + return Object.defineProperties(new String(getMessage), { + 'messageChunk': { value: messageChunk }, + 'fromStream': { value: true }, + }); + } + } else { + return await sendGenerationRequest(type, generate_data); + } + } + + return finishGenerating().then(onSuccess, onError); + + /** + * Handles the successful response from the generation API. + * @param data + * @returns {Promise|undefined>} + * @throws {Error} Throws an error if the response data contains an error message + */ + async function onSuccess(data) { + if (!data) return; + + if (data?.fromStream) { + return data; + } + + let messageChunk = ''; + + // if an error was returned in data (textgenwebui), show it and throw it + if (data.error) { + unblockGeneration(type); + generatedPromptCache = ''; + + if (data?.response) { + toastr.error(data.response, t`API Error`, { preventDuplicates: true }); + } + throw new Error(data?.response); + } + + //const getData = await response.json(); + let getMessage = extractMessageFromData(data); + let title = extractTitleFromData(data); + let reasoning = extractReasoningFromData(data); + let imageUrl = extractImageFromData(data); + kobold_horde_model = title; + + const swipes = extractMultiSwipes(data, type); + + messageChunk = cleanUpMessage(getMessage, isImpersonate, isContinue, false); + reasoning = getRegexedString(reasoning, regex_placement.REASONING); + + if (power_user.trim_spaces) { + reasoning = reasoning.trim(); + } + + if (isContinue) { + continue_mag = promptReasoning.removePrefix(continue_mag); + getMessage = continue_mag + getMessage; + } + + //Formating + const displayIncomplete = type === 'quiet' && !quietToLoud; + getMessage = cleanUpMessage(getMessage, isImpersonate, isContinue, displayIncomplete); + + if (isImpersonate) { + $('#send_textarea').val(getMessage)[0].dispatchEvent(new Event('input', { bubbles: true })); + generatedPromptCache = ''; + await eventSource.emit(event_types.IMPERSONATE_READY, getMessage); + } + else if (type == 'quiet') { + unblockGeneration(type); + return getMessage; + } + else { + // Without streaming we'll be having a full message on continuation. Treat it as a last chunk. + if (originalType !== 'continue') { + ({ type, getMessage } = await saveReply({ type, getMessage, title, swipes, reasoning, imageUrl })); + } + else { + ({ type, getMessage } = await saveReply({ type: 'appendFinal', getMessage, title, swipes, reasoning, imageUrl })); + } + + // This relies on `saveReply` having been called to add the message to the chat, so it must be last. + parseAndSaveLogprobs(data, continue_mag); + } + + if (canPerformToolCalls) { + const hasToolCalls = ToolManager.hasToolCalls(data); + const shouldDeleteMessage = type !== 'swipe' && ['', '...'].includes(getMessage); + hasToolCalls && shouldDeleteMessage && await deleteLastMessage(); + const invocationResult = await ToolManager.invokeFunctionTools(data); + const shouldStopGeneration = (!invocationResult.invocations.length && shouldDeleteMessage) || invocationResult.stealthCalls.length; + if (hasToolCalls) { + if (shouldStopGeneration) { + if (Array.isArray(invocationResult.errors) && invocationResult.errors.length) { + ToolManager.showToolCallError(invocationResult.errors); + } + unblockGeneration(type); + generatedPromptCache = ''; + return; + } + + depth = depth + 1; + await ToolManager.saveFunctionToolInvocations(invocationResult.invocations); + return Generate('normal', { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage, quietName, depth }, dryRun); + } + } + + if (type !== 'quiet') { + playMessageSound(); + } + + const isAborted = abortController && abortController.signal.aborted; + if (!isAborted && power_user.auto_swipe && generatedTextFiltered(getMessage)) { + is_send_press = false; + return swipe_right(); + } + + console.debug('/api/chats/save called by /Generate'); + await saveChatConditional(); + unblockGeneration(type); + streamingProcessor = null; + + if (type !== 'quiet') { + triggerAutoContinue(messageChunk, isImpersonate); + } + + // Don't break the API chain that expects a single string in return + return Object.defineProperty(new String(getMessage), 'messageChunk', { value: messageChunk }); + } + + /** + * Exception handler for finishGenerating + * @param {Error|object} exception Error or response JSON + * @throws {Error|object} Re-throws the exception + */ + function onError(exception) { + // if the response JSON was thrown (novel|textgenerationwebui|kobold), show the error message + if (typeof exception?.error?.message === 'string') { + toastr.error(exception.error.message, t`Text generation error`, { timeOut: 10000, extendedTimeOut: 20000 }); + } + + generatedPromptCache = ''; + + unblockGeneration(type); + console.log(exception); + streamingProcessor = null; + throw exception; + } +} + +/** + * Stops the generation and any streaming if it is currently running. + */ +export function stopGeneration() { + let stopped = false; + if (streamingProcessor) { + streamingProcessor.onStopStreaming(); + stopped = true; + } + if (abortController) { + abortController.abort('Clicked stop button'); + hideStopButton(); + stopped = true; + } + eventSource.emit(event_types.GENERATION_STOPPED); + return stopped; +} + +/** + * Injects extension prompts into chat messages. + * @param {object[]} messages Array of chat messages + * @param {boolean} isContinue Whether the generation is a continuation. If true, the extension prompts of depth 0 are injected at position 1. + * @returns {Promise} Array of indices where the extension prompts were injected + */ +async function doChatInject(messages, isContinue) { + const injectedIndices = []; + let totalInsertedMessages = 0; + messages.reverse(); + + for (let i = 0; i <= MAX_INJECTION_DEPTH; i++) { + // Order of priority (most important go lower) + const roles = [extension_prompt_roles.SYSTEM, extension_prompt_roles.USER, extension_prompt_roles.ASSISTANT]; + const names = { + [extension_prompt_roles.SYSTEM]: '', + [extension_prompt_roles.USER]: name1, + [extension_prompt_roles.ASSISTANT]: name2, + }; + const roleMessages = []; + const separator = '\n'; + const wrap = false; + + for (const role of roles) { + const extensionPrompt = String(await getExtensionPrompt(extension_prompt_types.IN_CHAT, i, separator, role, wrap)).trimStart(); + const isNarrator = role === extension_prompt_roles.SYSTEM; + const isUser = role === extension_prompt_roles.USER; + const name = names[role]; + + if (extensionPrompt) { + roleMessages.push({ + name: name, + is_user: isUser, + mes: extensionPrompt, + extra: { + type: isNarrator ? system_message_types.NARRATOR : null, + }, + }); + } + } + + if (roleMessages.length) { + const depth = isContinue && i === 0 ? 1 : i; + const injectIdx = depth + totalInsertedMessages; + messages.splice(injectIdx, 0, ...roleMessages); + totalInsertedMessages += roleMessages.length; + injectedIndices.push(...Array.from({ length: roleMessages.length }, (_, i) => injectIdx + i)); + } + } + + messages.reverse(); + return injectedIndices; +} + +function flushWIDepthInjections() { + //prevent custom depth WI entries (which have unique random key names) from duplicating + for (const key of Object.keys(extension_prompts)) { + if (key.startsWith('customDepthWI')) { + delete extension_prompts[key]; + } + } +} + +/** + * Unblocks the UI after a generation is complete. + * @param {string} [type] Generation type (optional) + */ +function unblockGeneration(type) { + // Don't unblock if a parallel stream is still running + if (type === 'quiet' && streamingProcessor && !streamingProcessor.isFinished) { + return; + } + + is_send_press = false; + activateSendButtons(); + showSwipeButtons(); + setGenerationProgress(0); + flushEphemeralStoppingStrings(); + flushWIDepthInjections(); +} + +export function getNextMessageId(type) { + return type == 'swipe' ? chat.length - 1 : chat.length; +} + +/** + * Determines if the message should be auto-continued. + * @param {string} messageChunk Current message chunk + * @param {boolean} isImpersonate Is the user impersonation + * @returns {boolean} Whether the message should be auto-continued + */ +export function shouldAutoContinue(messageChunk, isImpersonate) { + if (!power_user.auto_continue.enabled) { + console.debug('Auto-continue is disabled by user.'); + return false; + } + + if (typeof messageChunk !== 'string') { + console.debug('Not triggering auto-continue because message chunk is not a string'); + return false; + } + + if (isImpersonate) { + console.log('Continue for impersonation is not implemented yet'); + return false; + } + + if (is_send_press) { + console.debug('Auto-continue is disabled because a message is currently being sent.'); + return false; + } + + if (abortController && abortController.signal.aborted) { + console.debug('Auto-continue is not triggered because the generation was stopped.'); + return false; + } + + if (power_user.auto_continue.target_length <= 0) { + console.log('Auto-continue target length is 0, not triggering auto-continue'); + return false; + } + + if (main_api === 'openai' && !power_user.auto_continue.allow_chat_completions) { + console.log('Auto-continue for OpenAI is disabled by user.'); + return false; + } + + const textareaText = String($('#send_textarea').val()); + const USABLE_LENGTH = 5; + + if (textareaText.length > 0) { + console.log('Not triggering auto-continue because user input is not empty'); + return false; + } + + if (messageChunk.trim().length > USABLE_LENGTH && chat.length) { + const lastMessage = chat[chat.length - 1]; + const messageLength = getTokenCount(lastMessage.mes); + const shouldAutoContinue = messageLength < power_user.auto_continue.target_length; + + if (shouldAutoContinue) { + console.log(`Triggering auto-continue. Message tokens: ${messageLength}. Target tokens: ${power_user.auto_continue.target_length}. Message chunk: ${messageChunk}`); + return true; + } else { + console.log(`Not triggering auto-continue. Message tokens: ${messageLength}. Target tokens: ${power_user.auto_continue.target_length}`); + return false; + } + } else { + console.log('Last generated chunk was empty, not triggering auto-continue'); + return false; + } +} + +/** + * Triggers auto-continue if the message meets the criteria. + * @param {string} messageChunk Current message chunk + * @param {boolean} isImpersonate Is the user impersonation + */ +export function triggerAutoContinue(messageChunk, isImpersonate) { + if (selected_group) { + console.debug('Auto-continue is disabled for group chat'); + return; + } + + if (shouldAutoContinue(messageChunk, isImpersonate)) { + $('#option_continue').trigger('click'); + } +} + +export function getBiasStrings(textareaText, type) { + if (type == 'impersonate' || type == 'continue') { + return { messageBias: '', promptBias: '', isUserPromptBias: false }; + } + + let promptBias = ''; + let messageBias = extractMessageBias(textareaText); + + // If user input is not provided, retrieve the bias of the most recent relevant message + if (!textareaText) { + for (let i = chat.length - 1; i >= 0; i--) { + const mes = chat[i]; + if (type === 'swipe' && chat.length - 1 === i) { + continue; + } + if (mes && (mes.is_user || mes.is_system || mes.extra?.type === system_message_types.NARRATOR)) { + if (mes.extra?.bias?.trim()?.length > 0) { + promptBias = mes.extra.bias; + } + break; + } + } + } + + promptBias = messageBias || promptBias || power_user.user_prompt_bias || ''; + const isUserPromptBias = promptBias === power_user.user_prompt_bias; + + // Substitute params for everything + messageBias = substituteParams(messageBias); + promptBias = substituteParams(promptBias); + + return { messageBias, promptBias, isUserPromptBias }; +} + +/** + * @param {Object} chatItem Message history item. + * @param {boolean} isInstruct Whether instruct mode is enabled. + * @param {boolean|number} forceOutputSequence Whether to force the first/last output sequence for instruct mode. + */ +function formatMessageHistoryItem(chatItem, isInstruct, forceOutputSequence) { + const isNarratorType = chatItem?.extra?.type === system_message_types.NARRATOR; + const characterName = chatItem?.name ? chatItem.name : name2; + const itemName = chatItem.is_user ? chatItem['name'] : characterName; + const shouldPrependName = !isNarratorType; + + // Don't include a name if it's empty + let textResult = chatItem?.name && shouldPrependName ? `${itemName}: ${chatItem.mes}\n` : `${chatItem.mes}\n`; + + if (isInstruct) { + textResult = formatInstructModeChat(itemName, chatItem.mes, chatItem.is_user, isNarratorType, chatItem.force_avatar, name1, name2, forceOutputSequence); + } + + return textResult; +} + +/** + * Removes all {{macros}} from a string. + * @param {string} str String to remove macros from. + * @returns {string} String with macros removed. + */ +export function removeMacros(str) { + return (str ?? '').replace(/\{\{[\s\S]*?\}\}/gm, '').trim(); +} + +/** + * Inserts a user message into the chat history. + * @param {string} messageText Message text. + * @param {string} messageBias Message bias. + * @param {number} [insertAt] Optional index to insert the message at. + * @param {boolean} [compact] Send as a compact display message. + * @param {string} [name] Name of the user sending the message. Defaults to name1. + * @param {string} [avatar] Avatar of the user sending the message. Defaults to user_avatar. + * @returns {Promise} A promise that resolves to the message when it is inserted. + */ +export async function sendMessageAsUser(messageText, messageBias, insertAt = null, compact = false, name = name1, avatar = user_avatar) { + messageText = getRegexedString(messageText, regex_placement.USER_INPUT); + + const message = { + name: name, + is_user: true, + is_system: false, + send_date: getMessageTimeStamp(), + mes: substituteParams(messageText), + extra: { + isSmallSys: compact, + }, + }; + + if (power_user.message_token_count_enabled) { + message.extra.token_count = await getTokenCountAsync(message.mes, 0); + } + + // Lock user avatar to a persona. + if (avatar in power_user.personas) { + message.force_avatar = getUserAvatar(avatar); + } + + if (messageBias) { + message.extra.bias = messageBias; + message.mes = removeMacros(message.mes); + } + + await populateFileAttachment(message); + statMesProcess(message, 'user', characters, this_chid, ''); + + if (typeof insertAt === 'number' && insertAt >= 0 && insertAt <= chat.length) { + chat.splice(insertAt, 0, message); + await saveChatConditional(); + await eventSource.emit(event_types.MESSAGE_SENT, insertAt); + await reloadCurrentChat(); + await eventSource.emit(event_types.USER_MESSAGE_RENDERED, insertAt); + } else { + chat.push(message); + const chat_id = (chat.length - 1); + await eventSource.emit(event_types.MESSAGE_SENT, chat_id); + addOneMessage(message); + await eventSource.emit(event_types.USER_MESSAGE_RENDERED, chat_id); + await saveChatConditional(); + } + + return message; +} + +/** + * Gets the maximum usable context size for the current API. + * @param {number|null} overrideResponseLength Optional override for the response length. + * @returns {number} Maximum usable context size. + */ +export function getMaxContextSize(overrideResponseLength = null) { + if (typeof overrideResponseLength !== 'number' || overrideResponseLength <= 0 || isNaN(overrideResponseLength)) { + overrideResponseLength = null; + } + + let this_max_context = 1487; + if (main_api == 'kobold' || main_api == 'koboldhorde' || main_api == 'textgenerationwebui') { + this_max_context = (max_context - (overrideResponseLength || amount_gen)); + } + if (main_api == 'novel') { + this_max_context = Number(max_context); + if (nai_settings.model_novel.includes('clio')) { + this_max_context = Math.min(max_context, 8192); + } + if (nai_settings.model_novel.includes('kayra')) { + this_max_context = Math.min(max_context, 8192); + + const subscriptionLimit = getKayraMaxContextTokens(); + if (typeof subscriptionLimit === 'number' && this_max_context > subscriptionLimit) { + this_max_context = subscriptionLimit; + console.log(`NovelAI subscription limit reached. Max context size is now ${this_max_context}`); + } + } + if (nai_settings.model_novel.includes('erato')) { + // subscriber limits coming soon + this_max_context = Math.min(max_context, 8192); + + // Added special tokens and whatnot + this_max_context -= 10; + } + + this_max_context = this_max_context - (overrideResponseLength || amount_gen); + } + if (main_api == 'openai') { + this_max_context = oai_settings.openai_max_context - (overrideResponseLength || oai_settings.openai_max_tokens); + } + return this_max_context; +} + +function parseTokenCounts(counts, thisPromptBits) { + /** + * @param {any[]} numbers + */ + function getSum(...numbers) { + return numbers.map(x => Number(x)).filter(x => !Number.isNaN(x)).reduce((acc, val) => acc + val, 0); + } + const total = getSum(Object.values(counts)); + + thisPromptBits.push({ + oaiStartTokens: (counts?.start + counts?.controlPrompts) || 0, + oaiPromptTokens: getSum(counts?.prompt, counts?.charDescription, counts?.charPersonality, counts?.scenario) || 0, + oaiBiasTokens: counts?.bias || 0, + oaiNudgeTokens: counts?.nudge || 0, + oaiJailbreakTokens: counts?.jailbreak || 0, + oaiImpersonateTokens: counts?.impersonate || 0, + oaiExamplesTokens: (counts?.dialogueExamples + counts?.examples) || 0, + oaiConversationTokens: (counts?.conversation + counts?.chatHistory) || 0, + oaiNsfwTokens: counts?.nsfw || 0, + oaiMainTokens: counts?.main || 0, + oaiTotalTokens: total, + }); +} + +function addChatsPreamble(mesSendString) { + return main_api === 'novel' + ? substituteParams(nai_settings.preamble) + '\n' + mesSendString + : mesSendString; +} + +function addChatsSeparator(mesSendString) { + if (power_user.context.chat_start) { + return substituteParams(power_user.context.chat_start + '\n') + mesSendString; + } + + else { + return mesSendString; + } +} + +async function duplicateCharacter() { + if (this_chid === undefined || !characters[this_chid]) { + toastr.warning(t`You must first select a character to duplicate!`); + return ''; + } + + const confirmMessage = $(await renderTemplateAsync('duplicateConfirm')); + const confirm = await callGenericPopup(confirmMessage, POPUP_TYPE.CONFIRM); + + if (!confirm) { + console.log('User cancelled duplication'); + return ''; + } + + const body = { avatar_url: characters[this_chid].avatar }; + const response = await fetch('/api/characters/duplicate', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify(body), + }); + if (response.ok) { + toastr.success(t`Character Duplicated`); + const data = await response.json(); + await eventSource.emit(event_types.CHARACTER_DUPLICATED, { oldAvatar: body.avatar_url, newAvatar: data.path }); + await getCharacters(); + } + + return ''; +} + +export async function itemizedParams(itemizedPrompts, thisPromptSet, incomingMesId) { + const params = { + charDescriptionTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].charDescription), + charPersonalityTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].charPersonality), + scenarioTextTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].scenarioText), + userPersonaStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].userPersona), + worldInfoStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].worldInfoString), + allAnchorsTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].allAnchors), + summarizeStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].summarizeString), + authorsNoteStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].authorsNoteString), + smartContextStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].smartContextString), + beforeScenarioAnchorTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].beforeScenarioAnchor), + afterScenarioAnchorTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].afterScenarioAnchor), + zeroDepthAnchorTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].zeroDepthAnchor), // TODO: unused + thisPrompt_padding: itemizedPrompts[thisPromptSet].padding, + this_main_api: itemizedPrompts[thisPromptSet].main_api, + chatInjects: await getTokenCountAsync(itemizedPrompts[thisPromptSet].chatInjects), + chatVectorsStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].chatVectorsString), + dataBankVectorsStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].dataBankVectorsString), + modelUsed: chat[incomingMesId]?.extra?.model, + apiUsed: chat[incomingMesId]?.extra?.api, + presetName: itemizedPrompts[thisPromptSet].presetName || t`(Unknown)`, + }; + + const getFriendlyName = (value) => $(`#rm_api_block select option[value="${value}"]`).first().text() || value; + + if (params.apiUsed) { + params.apiUsed = getFriendlyName(params.apiUsed); + } + + if (params.this_main_api) { + params.mainApiFriendlyName = getFriendlyName(params.this_main_api); + } + + if (params.chatInjects) { + params.ActualChatHistoryTokens = params.ActualChatHistoryTokens - params.chatInjects; + } + + if (params.this_main_api == 'openai') { + //for OAI API + //console.log('-- Counting OAI Tokens'); + + //params.finalPromptTokens = itemizedPrompts[thisPromptSet].oaiTotalTokens; + params.oaiMainTokens = itemizedPrompts[thisPromptSet].oaiMainTokens; + params.oaiStartTokens = itemizedPrompts[thisPromptSet].oaiStartTokens; + params.ActualChatHistoryTokens = itemizedPrompts[thisPromptSet].oaiConversationTokens; + params.examplesStringTokens = itemizedPrompts[thisPromptSet].oaiExamplesTokens; + params.oaiPromptTokens = itemizedPrompts[thisPromptSet].oaiPromptTokens - (params.afterScenarioAnchorTokens + params.beforeScenarioAnchorTokens) + params.examplesStringTokens; + params.oaiBiasTokens = itemizedPrompts[thisPromptSet].oaiBiasTokens; + params.oaiJailbreakTokens = itemizedPrompts[thisPromptSet].oaiJailbreakTokens; + params.oaiNudgeTokens = itemizedPrompts[thisPromptSet].oaiNudgeTokens; + params.oaiImpersonateTokens = itemizedPrompts[thisPromptSet].oaiImpersonateTokens; + params.oaiNsfwTokens = itemizedPrompts[thisPromptSet].oaiNsfwTokens; + params.finalPromptTokens = + params.oaiStartTokens + + params.oaiPromptTokens + + params.oaiMainTokens + + params.oaiNsfwTokens + + params.oaiBiasTokens + + params.oaiImpersonateTokens + + params.oaiJailbreakTokens + + params.oaiNudgeTokens + + params.ActualChatHistoryTokens + + //charDescriptionTokens + + //charPersonalityTokens + + //allAnchorsTokens + + params.worldInfoStringTokens + + params.beforeScenarioAnchorTokens + + params.afterScenarioAnchorTokens; + // Max context size - max completion tokens + params.thisPrompt_max_context = (oai_settings.openai_max_context - oai_settings.openai_max_tokens); + + //console.log('-- applying % on OAI tokens'); + params.oaiStartTokensPercentage = ((params.oaiStartTokens / (params.finalPromptTokens)) * 100).toFixed(2); + params.storyStringTokensPercentage = (((params.afterScenarioAnchorTokens + params.beforeScenarioAnchorTokens + params.oaiPromptTokens) / (params.finalPromptTokens)) * 100).toFixed(2); + params.ActualChatHistoryTokensPercentage = ((params.ActualChatHistoryTokens / (params.finalPromptTokens)) * 100).toFixed(2); + params.promptBiasTokensPercentage = ((params.oaiBiasTokens / (params.finalPromptTokens)) * 100).toFixed(2); + params.worldInfoStringTokensPercentage = ((params.worldInfoStringTokens / (params.finalPromptTokens)) * 100).toFixed(2); + params.allAnchorsTokensPercentage = ((params.allAnchorsTokens / (params.finalPromptTokens)) * 100).toFixed(2); + params.selectedTokenizer = getFriendlyTokenizerName(params.this_main_api).tokenizerName; + params.oaiSystemTokens = params.oaiImpersonateTokens + params.oaiJailbreakTokens + params.oaiNudgeTokens + params.oaiStartTokens + params.oaiNsfwTokens + params.oaiMainTokens; + params.oaiSystemTokensPercentage = ((params.oaiSystemTokens / (params.finalPromptTokens)) * 100).toFixed(2); + } else { + //for non-OAI APIs + //console.log('-- Counting non-OAI Tokens'); + params.finalPromptTokens = await getTokenCountAsync(itemizedPrompts[thisPromptSet].finalPrompt); + params.storyStringTokens = await getTokenCountAsync(itemizedPrompts[thisPromptSet].storyString) - params.worldInfoStringTokens; + params.examplesStringTokens = await getTokenCountAsync(itemizedPrompts[thisPromptSet].examplesString); + params.mesSendStringTokens = await getTokenCountAsync(itemizedPrompts[thisPromptSet].mesSendString); + params.ActualChatHistoryTokens = params.mesSendStringTokens - (params.allAnchorsTokens - (params.beforeScenarioAnchorTokens + params.afterScenarioAnchorTokens)) + power_user.token_padding; + params.instructionTokens = await getTokenCountAsync(itemizedPrompts[thisPromptSet].instruction); + params.promptBiasTokens = await getTokenCountAsync(itemizedPrompts[thisPromptSet].promptBias); + + params.totalTokensInPrompt = + params.storyStringTokens + //chardefs total + params.worldInfoStringTokens + + params.examplesStringTokens + // example messages + params.ActualChatHistoryTokens + //chat history + params.allAnchorsTokens + // AN and/or legacy anchors + //afterScenarioAnchorTokens + //only counts if AN is set to 'after scenario' + //zeroDepthAnchorTokens + //same as above, even if AN not on 0 depth + params.promptBiasTokens; //{{}} + //- thisPrompt_padding; //not sure this way of calculating is correct, but the math results in same value as 'finalPrompt' + params.thisPrompt_max_context = itemizedPrompts[thisPromptSet].this_max_context; + params.thisPrompt_actual = params.thisPrompt_max_context - params.thisPrompt_padding; + + //console.log('-- applying % on non-OAI tokens'); + params.storyStringTokensPercentage = ((params.storyStringTokens / (params.totalTokensInPrompt)) * 100).toFixed(2); + params.ActualChatHistoryTokensPercentage = ((params.ActualChatHistoryTokens / (params.totalTokensInPrompt)) * 100).toFixed(2); + params.promptBiasTokensPercentage = ((params.promptBiasTokens / (params.totalTokensInPrompt)) * 100).toFixed(2); + params.worldInfoStringTokensPercentage = ((params.worldInfoStringTokens / (params.totalTokensInPrompt)) * 100).toFixed(2); + params.allAnchorsTokensPercentage = ((params.allAnchorsTokens / (params.totalTokensInPrompt)) * 100).toFixed(2); + params.selectedTokenizer = itemizedPrompts[thisPromptSet]?.tokenizer || getFriendlyTokenizerName(params.this_main_api).tokenizerName; + } + return params; +} + +export function findItemizedPromptSet(itemizedPrompts, incomingMesId) { + var thisPromptSet = undefined; + + for (var i = 0; i < itemizedPrompts.length; i++) { + console.log(`looking for ${incomingMesId} vs ${itemizedPrompts[i].mesId}`); + if (itemizedPrompts[i].mesId === incomingMesId) { + console.log(`found matching mesID ${i}`); + thisPromptSet = i; + PromptArrayItemForRawPromptDisplay = i; + console.log(`wanting to raw display of ArrayItem: ${PromptArrayItemForRawPromptDisplay} which is mesID ${incomingMesId}`); + console.log(itemizedPrompts[thisPromptSet]); + break; + } else if (itemizedPrompts[i].rawPrompt) { + priorPromptArrayItemForRawPromptDisplay = i; + } + } + return thisPromptSet; +} + +async function promptItemize(itemizedPrompts, requestedMesId) { + console.log('PROMPT ITEMIZE ENTERED'); + var incomingMesId = Number(requestedMesId); + console.debug(`looking for MesId ${incomingMesId}`); + var thisPromptSet = findItemizedPromptSet(itemizedPrompts, incomingMesId); + + if (thisPromptSet === undefined) { + console.log(`couldnt find the right mesId. looked for ${incomingMesId}`); + console.log(itemizedPrompts); + return null; + } + + const params = await itemizedParams(itemizedPrompts, thisPromptSet, incomingMesId); + const flatten = (rawPrompt) => Array.isArray(rawPrompt) ? rawPrompt.map(x => x.content).join('\n') : rawPrompt; + + const template = params.this_main_api == 'openai' + ? await renderTemplateAsync('itemizationChat', params) + : await renderTemplateAsync('itemizationText', params); + + const popup = new Popup(template, POPUP_TYPE.TEXT); + + /** @type {HTMLElement} */ + const diffPrevPrompt = popup.dlg.querySelector('#diffPrevPrompt'); + if (priorPromptArrayItemForRawPromptDisplay) { + diffPrevPrompt.style.display = ''; + diffPrevPrompt.addEventListener('click', function () { + const dmp = new DiffMatchPatch(); + const text1 = flatten(itemizedPrompts[priorPromptArrayItemForRawPromptDisplay].rawPrompt); + const text2 = flatten(itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt); + + dmp.Diff_Timeout = 2.0; + + const d = dmp.diff_main(text1, text2); + let ds = dmp.diff_prettyHtml(d); + // make it readable + ds = ds.replaceAll('background:#e6ffe6;', 'background:#b9f3b9; color:black;'); + ds = ds.replaceAll('background:#ffe6e6;', 'background:#f5b4b4; color:black;'); + ds = ds.replaceAll('¶', ''); + const container = document.createElement('div'); + container.innerHTML = DOMPurify.sanitize(ds); + const rawPromptWrapper = document.getElementById('rawPromptWrapper'); + rawPromptWrapper.replaceChildren(container); + $('#rawPromptPopup').slideToggle(); + }); + } else { + diffPrevPrompt.style.display = 'none'; + } + popup.dlg.querySelector('#copyPromptToClipboard').addEventListener('pointerup', async function () { + let rawPrompt = itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt; + let rawPromptValues = rawPrompt; + + if (Array.isArray(rawPrompt)) { + rawPromptValues = rawPrompt.map(x => x.content).join('\n'); + } + + await copyText(rawPromptValues); + toastr.info(t`Copied!`); + }); + + popup.dlg.querySelector('#showRawPrompt').addEventListener('click', async function () { + //console.log(itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt); + console.log(PromptArrayItemForRawPromptDisplay); + console.log(itemizedPrompts); + console.log(itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt); + + const rawPrompt = flatten(itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt); + + // Mobile needs special handholding. The side-view on the popup wouldn't work, + // so we just show an additional popup for this. + if (isMobile()) { + const content = document.createElement('div'); + content.classList.add('tokenItemizingMaintext'); + content.innerText = rawPrompt; + const popup = new Popup(content, POPUP_TYPE.TEXT, null, { allowVerticalScrolling: true, leftAlign: true }); + await popup.show(); + return; + } + + //let DisplayStringifiedPrompt = JSON.stringify(itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt).replace(/\n+/g, '
      '); + const rawPromptWrapper = document.getElementById('rawPromptWrapper'); + rawPromptWrapper.innerText = rawPrompt; + $('#rawPromptPopup').slideToggle(); + }); + + await popup.show(); +} + +function setInContextMessages(msgInContextCount, type) { + $('#chat .mes').removeClass('lastInContext'); + + if (type === 'swipe' || type === 'regenerate' || type === 'continue') { + msgInContextCount++; + } + + const lastMessageBlock = $('#chat .mes:not([is_system="true"])').eq(-msgInContextCount); + lastMessageBlock.addClass('lastInContext'); + + if (lastMessageBlock.length === 0) { + const firstMessageId = getFirstDisplayedMessageId(); + $(`#chat .mes[mesid="${firstMessageId}"`).addClass('lastInContext'); + } + + // Update last id to chat. No metadata save on purpose, gets hopefully saved via another call + const lastMessageId = Math.max(0, chat.length - msgInContextCount); + chat_metadata['lastInContextMessageId'] = lastMessageId; +} + +/** + * Sends a non-streaming request to the API. + * @param {string} type Generation type + * @param {object} data Generation data + * @returns {Promise} Response data from the API + * @throws {Error|object} + */ +export async function sendGenerationRequest(type, data) { + if (main_api === 'openai') { + return await sendOpenAIRequest(type, data.prompt, abortController.signal); + } + + if (main_api === 'koboldhorde') { + return await generateHorde(data.prompt, data, abortController.signal, true); + } + + const response = await fetch(getGenerateUrl(main_api), { + method: 'POST', + headers: getRequestHeaders(), + cache: 'no-cache', + body: JSON.stringify(data), + signal: abortController.signal, + }); + + if (!response.ok) { + throw await response.json(); + } + + return await response.json(); +} + +/** + * Sends a streaming request to the API. + * @param {string} type Generation type + * @param {object} data Generation data + * @returns {Promise} Streaming generator + */ +export async function sendStreamingRequest(type, data) { + if (abortController?.signal?.aborted) { + throw new Error('Generation was aborted.'); + } + + switch (main_api) { + case 'openai': + return await sendOpenAIRequest(type, data.prompt, streamingProcessor.abortController.signal); + case 'textgenerationwebui': + return await generateTextGenWithStreaming(data, streamingProcessor.abortController.signal); + case 'novel': + return await generateNovelWithStreaming(data, streamingProcessor.abortController.signal); + case 'kobold': + return await generateKoboldWithStreaming(data, streamingProcessor.abortController.signal); + default: + throw new Error('Streaming is enabled, but the current API does not support streaming.'); + } +} + +/** + * Gets the generation endpoint URL for the specified API. + * @param {string} api API name + * @returns {string} Generation URL + * @throws {Error} If the API is unknown + */ +export function getGenerateUrl(api) { + switch (api) { + case 'kobold': + return '/api/backends/kobold/generate'; + case 'koboldhorde': + return '/api/backends/koboldhorde/generate'; + case 'textgenerationwebui': + return '/api/backends/text-completions/generate'; + case 'novel': + return '/api/novelai/generate'; + default: + throw new Error(`Unknown API: ${api}`); + } +} + +function extractTitleFromData(data) { + if (main_api == 'koboldhorde') { + return data.workerName; + } + + return undefined; +} + +/** + * Extracts the image from the response data. + * @param {object} data Response data + * @param {object} [options] Extraction options + * @param {string} [options.mainApi] Main API to use + * @param {string} [options.chatCompletionSource] Chat completion source + * @returns {string} Extracted image + */ +function extractImageFromData(data, { mainApi = null, chatCompletionSource = null } = {}) { + switch (mainApi ?? main_api) { + case 'openai': { + switch (chatCompletionSource ?? oai_settings.chat_completion_source) { + case chat_completion_sources.MAKERSUITE: { + const inlineData = data?.responseContent?.parts?.find(x => x.inlineData)?.inlineData; + if (inlineData) { + return `data:${inlineData.mimeType};base64,${inlineData.data}`; + } + } break; + + } + } break; + } + + return undefined; +} + +/** + * parseAndSaveLogprobs receives the full data response for a non-streaming + * generation, parses logprobs for all tokens in the message, and saves them + * to the currently active message. + * @param {object} data - response data containing all tokens/logprobs + * @param {string} continueFrom - for 'continue' generations, the prompt + * */ +function parseAndSaveLogprobs(data, continueFrom) { + /** @type {import('./scripts/logprobs.js').TokenLogprobs[] | null} */ + let logprobs = null; + + switch (main_api) { + case 'novel': + // parser only handles one token/logprob pair at a time + logprobs = data.logprobs?.map(parseNovelAILogprobs) || null; + break; + case 'openai': + // OAI and other chat completion APIs must handle this earlier in + // `sendOpenAIRequest`. `data` for these APIs is just a string with + // the text of the generated message, logprobs are not included. + return; + case 'textgenerationwebui': + switch (textgen_settings.type) { + case textgen_types.LLAMACPP: { + logprobs = data?.completion_probabilities?.map(x => parseTextgenLogprobs(x.content, [x])) || null; + } break; + case textgen_types.KOBOLDCPP: + case textgen_types.VLLM: + case textgen_types.INFERMATICAI: + case textgen_types.APHRODITE: + case textgen_types.MANCER: + case textgen_types.TABBY: { + logprobs = parseTabbyLogprobs(data) || null; + } break; + } break; + default: + return; + } + + saveLogprobsForActiveMessage(logprobs, continueFrom); +} + +/** + * Extracts the message from the response data. + * @param {object} data Response data + * @param {string} activeApi If it's set, ignores active API + * @returns {string} Extracted message + */ +export function extractMessageFromData(data, activeApi = null) { + if (typeof data === 'string') { + return data; + } + + switch (activeApi ?? main_api) { + case 'kobold': + return data.results[0].text; + case 'koboldhorde': + return data.text; + case 'textgenerationwebui': + return data.choices?.[0]?.text ?? data.content ?? data.response ?? ''; + case 'novel': + return data.output; + case 'openai': + return data?.content?.find(p => p.type === 'text')?.text ?? data?.choices?.[0]?.message?.content ?? data?.choices?.[0]?.text ?? data?.text ?? data?.message?.content?.[0]?.text ?? data?.message?.tool_plan ?? ''; + default: + return ''; + } +} + +/** + * Extracts multiswipe swipes from the response data. + * @param {Object} data Response data + * @param {string} type Type of generation + * @returns {string[]} Array of extra swipes + */ +function extractMultiSwipes(data, type) { + const swipes = []; + + if (!data) { + return swipes; + } + + if (type === 'continue' || type === 'impersonate' || type === 'quiet') { + return swipes; + } + + if (main_api === 'openai' || (main_api === 'textgenerationwebui' && [textgen_types.MANCER, textgen_types.VLLM, textgen_types.APHRODITE, textgen_types.TABBY, textgen_types.INFERMATICAI].includes(textgen_settings.type))) { + if (!Array.isArray(data.choices)) { + return swipes; + } + + const multiSwipeCount = data.choices.length - 1; + + if (multiSwipeCount <= 0) { + return swipes; + } + + for (let i = 1; i < data.choices.length; i++) { + const text = data?.choices[i]?.message?.content ?? data?.choices[i]?.text ?? ''; + const cleanedText = cleanUpMessage(text, false, false, false); + swipes.push(cleanedText); + } + } + + return swipes; +} + +export function cleanUpMessage(getMessage, isImpersonate, isContinue, displayIncompleteSentences = false, stoppingStrings = null) { + if (!getMessage) { + return ''; + } + + // Add the prompt bias before anything else + if ( + power_user.user_prompt_bias && + !isImpersonate && + !isContinue && + power_user.user_prompt_bias.length !== 0 + ) { + getMessage = substituteParams(power_user.user_prompt_bias) + getMessage; + } + + // Allow for caching of stopping strings. getStoppingStrings is an expensive function, especially with macros + // enabled, so for streaming, we call it once and then pass it into each cleanUpMessage call. + if (!stoppingStrings) { + stoppingStrings = getStoppingStrings(isImpersonate, isContinue); + } + + for (const stoppingString of stoppingStrings) { + if (stoppingString.length) { + for (let j = stoppingString.length; j > 0; j--) { + if (getMessage.slice(-j) === stoppingString.slice(0, j)) { + getMessage = getMessage.slice(0, -j); + break; + } + } + } + } + + // Regex uses vars, so add before formatting + getMessage = getRegexedString(getMessage, isImpersonate ? regex_placement.USER_INPUT : regex_placement.AI_OUTPUT); + + if (power_user.collapse_newlines) { + getMessage = collapseNewlines(getMessage); + } + + // trailing invisible whitespace before every newlines, on a multiline string + // "trailing whitespace on newlines \nevery line of the string \n?sample text" -> + // "trailing whitespace on newlines\nevery line of the string\nsample text" + getMessage = getMessage.replace(/[^\S\r\n]+$/gm, ''); + + let nameToTrim = isImpersonate ? name2 : name1; + + if (isImpersonate) { + nameToTrim = power_user.allow_name2_display ? '' : name2; + } + else { + nameToTrim = power_user.allow_name1_display ? '' : name1; + } + + if (nameToTrim && getMessage.indexOf(`${nameToTrim}:`) == 0) { + getMessage = getMessage.substring(0, getMessage.indexOf(`${nameToTrim}:`)); + } + if (nameToTrim && getMessage.indexOf(`\n${nameToTrim}:`) >= 0) { + getMessage = getMessage.substring(0, getMessage.indexOf(`\n${nameToTrim}:`)); + } + if (getMessage.indexOf('<|endoftext|>') != -1) { + getMessage = getMessage.substring(0, getMessage.indexOf('<|endoftext|>')); + } + const isInstruct = power_user.instruct.enabled && main_api !== 'openai'; + const isNotEmpty = (str) => str && str.trim() !== ''; + if (isInstruct && power_user.instruct.stop_sequence) { + if (getMessage.indexOf(power_user.instruct.stop_sequence) != -1) { + getMessage = getMessage.substring(0, getMessage.indexOf(power_user.instruct.stop_sequence)); + } + } + // Hana: Only use the first sequence (should be <|model|>) + // of the prompt before <|user|> (as KoboldAI Lite does it). + if (isInstruct && isNotEmpty(power_user.instruct.input_sequence)) { + if (getMessage.indexOf(power_user.instruct.input_sequence) != -1) { + getMessage = getMessage.substring(0, getMessage.indexOf(power_user.instruct.input_sequence)); + } + } + if (isInstruct && power_user.instruct.input_sequence && isImpersonate) { + //getMessage = getMessage.replaceAll(power_user.instruct.input_sequence, ''); + power_user.instruct.input_sequence.split('\n') + .filter(line => line.trim() !== '') + .forEach(line => { + getMessage = getMessage.replaceAll(line, ''); + }); + } + if (isInstruct && power_user.instruct.output_sequence && !isImpersonate) { + //getMessage = getMessage.replaceAll(power_user.instruct.output_sequence, ''); + power_user.instruct.output_sequence.split('\n') + .filter(line => line.trim() !== '') + .forEach(line => { + getMessage = getMessage.replaceAll(line, ''); + }); + } + if (isInstruct && power_user.instruct.last_output_sequence && !isImpersonate) { + //getMessage = getMessage.replaceAll(power_user.instruct.last_output_sequence, ''); + power_user.instruct.last_output_sequence.split('\n') + .filter(line => line.trim() !== '') + .forEach(line => { + getMessage = getMessage.replaceAll(line, ''); + }); + } + // clean-up group message from excessive generations + if (selected_group) { + getMessage = cleanGroupMessage(getMessage); + } + + if (!power_user.allow_name2_display) { + const name2Escaped = escapeRegex(name2); + getMessage = getMessage.replace(new RegExp(`(^|\n)${name2Escaped}:\\s*`, 'g'), '$1'); + } + + if (isImpersonate) { + getMessage = getMessage.trim(); + } + + if (power_user.auto_fix_generated_markdown) { + getMessage = fixMarkdown(getMessage, false); + } + + const nameToTrim2 = isImpersonate + ? (!power_user.allow_name1_display ? name1 : '') + : (!power_user.allow_name2_display ? name2 : ''); + + if (nameToTrim2 && getMessage.startsWith(nameToTrim2 + ':')) { + getMessage = getMessage.replace(nameToTrim2 + ':', ''); + getMessage = getMessage.trimStart(); + } + + if (isImpersonate) { + getMessage = getMessage.trim(); + } + + if (!displayIncompleteSentences && power_user.trim_sentences) { + getMessage = trimToEndSentence(getMessage); + } + + if (power_user.trim_spaces && !PromptReasoning.getLatestPrefix()) { + getMessage = getMessage.trim(); + } + + return getMessage; +} + +/** + * Adds an image to the message. + * @param {object} message Message object + * @param {object} sources Image sources + * @param {ParsedImage} [sources.parsedImage] Parsed image + * @param {string} [sources.imageUrl] Image URL + * + * @returns {Promise} + */ +async function processImageAttachment(message, { parsedImage, imageUrl }) { + if (parsedImage?.image) { + saveImageToMessage(parsedImage, message); + return; + } + + if (!imageUrl) { + return; + } + + let url = imageUrl; + if (isDataURL(url)) { + const fileName = `inline_image_${Date.now().toString()}`; + const [mime, base64] = /^data:(.*?);base64,(.*)$/.exec(imageUrl).slice(1); + url = await saveBase64AsFile(base64, message.name, fileName, mime.split('/')[1]); + } + saveImageToMessage({ image: url, inline: true }, message); +} + +/** + * Saves a resulting message to the chat. + * @param {SaveReplyParams} params + * @returns {Promise} Promise when the message is saved + * + * @typedef {object} SaveReplyParams + * @property {string} type Type of generation + * @property {string} getMessage Generated message + * @property {boolean} [fromStreaming] If the message is from streaming + * @property {string} [title] Message tooltip + * @property {string[]} [swipes] Extra swipes + * @property {string} [reasoning] Message reasoning + * @property {string} [imageUrl] Link to an image + * + * @typedef {object} SaveReplyResult + * @property {string} type Type of generation + * @property {string} getMessage Generated message + */ +export async function saveReply({ type, getMessage, fromStreaming = false, title = '', swipes = [], reasoning = '', imageUrl = '' }) { + // Backward compatibility + if (arguments.length > 1 && typeof arguments[0] !== 'object') { + console.trace('saveReply called with positional arguments. Please use an object instead.'); + [type, getMessage, fromStreaming, title, swipes, reasoning, imageUrl] = arguments; + } + + if (type != 'append' && type != 'continue' && type != 'appendFinal' && chat.length && (chat[chat.length - 1]['swipe_id'] === undefined || + chat[chat.length - 1]['is_user'])) { + type = 'normal'; + } + + if (chat.length && (!chat[chat.length - 1]['extra'] || typeof chat[chat.length - 1]['extra'] !== 'object')) { + chat[chat.length - 1]['extra'] = {}; + } + + // Coerce null/undefined to empty string + if (chat.length && !chat[chat.length - 1]['extra']['reasoning']) { + chat[chat.length - 1]['extra']['reasoning'] = ''; + } + + if (!reasoning) { + reasoning = ''; + } + + let oldMessage = ''; + const generationFinished = new Date(); + const parsedImage = extractImageFromMessage(getMessage); + getMessage = parsedImage.getMessage; + if (type === 'swipe') { + oldMessage = chat[chat.length - 1]['mes']; + chat[chat.length - 1]['swipes'].length++; + if (chat[chat.length - 1]['swipe_id'] === chat[chat.length - 1]['swipes'].length - 1) { + chat[chat.length - 1]['title'] = title; + chat[chat.length - 1]['mes'] = getMessage; + chat[chat.length - 1]['gen_started'] = generation_started; + chat[chat.length - 1]['gen_finished'] = generationFinished; + chat[chat.length - 1]['send_date'] = getMessageTimeStamp(); + chat[chat.length - 1]['extra']['api'] = getGeneratingApi(); + chat[chat.length - 1]['extra']['model'] = getGeneratingModel(); + chat[chat.length - 1]['extra']['reasoning'] = reasoning; + chat[chat.length - 1]['extra']['reasoning_duration'] = null; + await processImageAttachment(chat[chat.length - 1], { parsedImage, imageUrl }); + if (power_user.message_token_count_enabled) { + const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes']; + chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0); + } + const chat_id = (chat.length - 1); + await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type); + addOneMessage(chat[chat_id], { type: 'swipe' }); + await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, chat_id, type); + } else { + chat[chat.length - 1]['mes'] = getMessage; + } + } else if (type === 'append' || type === 'continue') { + console.debug('Trying to append.'); + oldMessage = chat[chat.length - 1]['mes']; + chat[chat.length - 1]['title'] = title; + chat[chat.length - 1]['mes'] += getMessage; + chat[chat.length - 1]['gen_started'] = generation_started; + chat[chat.length - 1]['gen_finished'] = generationFinished; + chat[chat.length - 1]['send_date'] = getMessageTimeStamp(); + chat[chat.length - 1]['extra']['api'] = getGeneratingApi(); + chat[chat.length - 1]['extra']['model'] = getGeneratingModel(); + chat[chat.length - 1]['extra']['reasoning'] = reasoning; + chat[chat.length - 1]['extra']['reasoning_duration'] = null; + await processImageAttachment(chat[chat.length - 1], { parsedImage, imageUrl }); + if (power_user.message_token_count_enabled) { + const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes']; + chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0); + } + const chat_id = (chat.length - 1); + await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type); + addOneMessage(chat[chat_id], { type: 'swipe' }); + await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, chat_id, type); + } else if (type === 'appendFinal') { + oldMessage = chat[chat.length - 1]['mes']; + console.debug('Trying to appendFinal.'); + chat[chat.length - 1]['title'] = title; + chat[chat.length - 1]['mes'] = getMessage; + chat[chat.length - 1]['gen_started'] = generation_started; + chat[chat.length - 1]['gen_finished'] = generationFinished; + chat[chat.length - 1]['send_date'] = getMessageTimeStamp(); + chat[chat.length - 1]['extra']['api'] = getGeneratingApi(); + chat[chat.length - 1]['extra']['model'] = getGeneratingModel(); + chat[chat.length - 1]['extra']['reasoning'] += reasoning; + await processImageAttachment(chat[chat.length - 1], { parsedImage, imageUrl }); + // We don't know if the reasoning duration extended, so we don't update it here on purpose. + if (power_user.message_token_count_enabled) { + const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes']; + chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0); + } + const chat_id = (chat.length - 1); + await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type); + addOneMessage(chat[chat_id], { type: 'swipe' }); + await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, chat_id, type); + + } else { + console.debug('entering chat update routine for non-swipe post'); + chat[chat.length] = {}; + chat[chat.length - 1]['extra'] = {}; + chat[chat.length - 1]['name'] = name2; + chat[chat.length - 1]['is_user'] = false; + chat[chat.length - 1]['send_date'] = getMessageTimeStamp(); + chat[chat.length - 1]['extra']['api'] = getGeneratingApi(); + chat[chat.length - 1]['extra']['model'] = getGeneratingModel(); + chat[chat.length - 1]['extra']['reasoning'] = reasoning; + chat[chat.length - 1]['extra']['reasoning_duration'] = null; + if (power_user.trim_spaces) { + getMessage = getMessage.trim(); + } + chat[chat.length - 1]['mes'] = getMessage; + chat[chat.length - 1]['title'] = title; + chat[chat.length - 1]['gen_started'] = generation_started; + chat[chat.length - 1]['gen_finished'] = generationFinished; + + if (power_user.message_token_count_enabled) { + const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes']; + chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0); + } + + if (selected_group) { + console.debug('entering chat update for groups'); + let avatarImg = 'img/ai4.png'; + if (characters[this_chid].avatar != 'none') { + avatarImg = getThumbnailUrl('avatar', characters[this_chid].avatar); + } + chat[chat.length - 1]['force_avatar'] = avatarImg; + chat[chat.length - 1]['original_avatar'] = characters[this_chid].avatar; + chat[chat.length - 1]['extra']['gen_id'] = group_generation_id; + } + + await processImageAttachment(chat[chat.length - 1], { parsedImage, imageUrl: imageUrl }); + const chat_id = (chat.length - 1); + + !fromStreaming && await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type); + addOneMessage(chat[chat_id]); + !fromStreaming && await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, chat_id, type); + } + + const item = chat[chat.length - 1]; + if (item['swipe_info'] === undefined) { + item['swipe_info'] = []; + } + if (item['swipe_id'] !== undefined) { + const swipeId = item['swipe_id']; + item['swipes'][swipeId] = item['mes']; + item['swipe_info'][swipeId] = { + send_date: item['send_date'], + gen_started: item['gen_started'], + gen_finished: item['gen_finished'], + extra: JSON.parse(JSON.stringify(item['extra'])), + }; + } else { + item['swipe_id'] = 0; + item['swipes'] = []; + item['swipes'][0] = chat[chat.length - 1]['mes']; + item['swipe_info'][0] = { + send_date: chat[chat.length - 1]['send_date'], + gen_started: chat[chat.length - 1]['gen_started'], + gen_finished: chat[chat.length - 1]['gen_finished'], + extra: JSON.parse(JSON.stringify(chat[chat.length - 1]['extra'])), + }; + } + + if (Array.isArray(swipes) && swipes.length > 0) { + const swipeInfoExtra = structuredClone(item.extra ?? {}); + delete swipeInfoExtra.token_count; + delete swipeInfoExtra.reasoning; + delete swipeInfoExtra.reasoning_duration; + const swipeInfo = { + send_date: item.send_date, + gen_started: item.gen_started, + gen_finished: item.gen_finished, + extra: swipeInfoExtra, + }; + const swipeInfoArray = Array(swipes.length).fill().map(() => structuredClone(swipeInfo)); + parseReasoningInSwipes(swipes, swipeInfoArray, item.extra?.reasoning_duration); + item.swipes.push(...swipes); + item.swipe_info.push(...swipeInfoArray); + } + + statMesProcess(chat[chat.length - 1], type, characters, this_chid, oldMessage); + return { type, getMessage }; +} + +/** + * Syncs the current message and all its data into the swipe data at the given message ID (or the last message if no ID is given). + * + * If the swipe data is invalid in some way, this function will exit out without doing anything. + * @param {number?} [messageId=null] - The ID of the message to sync with the swipe data. If no ID is given, the last message is used. + * @returns {boolean} Whether the message was successfully synced + */ +export function syncMesToSwipe(messageId = null) { + if (!chat.length) { + return false; + } + + const targetMessageId = messageId ?? chat.length - 1; + if (targetMessageId >= chat.length || targetMessageId < 0) { + console.warn(`[syncMesToSwipe] Invalid message ID: ${messageId}`); + return false; + } + + const targetMessage = chat[targetMessageId]; + if (!targetMessage) { + return false; + } + + // No swipe data there yet, exit out + if (typeof targetMessage.swipe_id !== 'number') { + return false; + } + // If swipes structure is invalid, exit out (for now?) + if (!Array.isArray(targetMessage.swipe_info) || !Array.isArray(targetMessage.swipes)) { + return false; + } + // If the swipe is not present yet, exit out (will likely be copied later) + if (!targetMessage.swipes[targetMessage.swipe_id] || !targetMessage.swipe_info[targetMessage.swipe_id]) { + return false; + } + + const targetSwipeInfo = targetMessage.swipe_info[targetMessage.swipe_id]; + if (typeof targetSwipeInfo !== 'object') { + return false; + } + + targetMessage.swipes[targetMessage.swipe_id] = targetMessage.mes; + + targetSwipeInfo.send_date = targetMessage.send_date; + targetSwipeInfo.gen_started = targetMessage.gen_started; + targetSwipeInfo.gen_finished = targetMessage.gen_finished; + targetSwipeInfo.extra = structuredClone(targetMessage.extra); + + return true; +} + +/** + * Syncs swipe data back to the message data at the given message ID (or the last message if no ID is given). + * If the swipe ID is not provided, the current swipe ID in the message object is used. + * + * If the swipe data is invalid in some way, this function will exit out without doing anything. + * @param {number?} [messageId=null] - The ID of the message to sync with the swipe data. If no ID is given, the last message is used. + * @param {number?} [swipeId=null] - The ID of the swipe to sync. If no ID is given, the current swipe ID in the message object is used. + * @returns {boolean} Whether the swipe data was successfully synced to the message + */ +export function syncSwipeToMes(messageId = null, swipeId = null) { + if (!chat.length) { + return false; + } + + const targetMessageId = messageId ?? chat.length - 1; + if (targetMessageId >= chat.length || targetMessageId < 0) { + console.warn(`[syncSwipeToMes] Invalid message ID: ${messageId}`); + return false; + } + + const targetMessage = chat[targetMessageId]; + if (!targetMessage) { + return false; + } + + if (swipeId !== null) { + if (isNaN(swipeId) || swipeId < 0) { + console.warn(`[syncSwipeToMes] Invalid swipe ID: ${swipeId}`); + return false; + } + targetMessage.swipe_id = swipeId; + } + + // No swipe data there yet, exit out + if (typeof targetMessage.swipe_id !== 'number') { + return false; + } + // If swipes structure is invalid, exit out + if (!Array.isArray(targetMessage.swipe_info) || !Array.isArray(targetMessage.swipes)) { + return false; + } + + const targetSwipeId = targetMessage.swipe_id; + if (!targetMessage.swipes[targetSwipeId] || !targetMessage.swipe_info[targetSwipeId]) { + console.warn(`[syncSwipeToMes] Invalid swipe ID: ${targetSwipeId}`); + return false; + } + + const targetSwipeInfo = targetMessage.swipe_info[targetSwipeId]; + if (typeof targetSwipeInfo !== 'object') { + return false; + } + + targetMessage.mes = targetMessage.swipes[targetSwipeId]; + targetMessage.send_date = targetSwipeInfo.send_date; + targetMessage.gen_started = targetSwipeInfo.gen_started; + targetMessage.gen_finished = targetSwipeInfo.gen_finished; + targetMessage.extra = structuredClone(targetSwipeInfo.extra); + + return true; +} + +/** + * Saves the image to the message object. + * @param {ParsedImage} img Image object + * @param {object} mes Chat message object + * @typedef {{ image?: string, title?: string, inline?: boolean }} ParsedImage + */ +function saveImageToMessage(img, mes) { + if (mes && img.image) { + if (!mes.extra || typeof mes.extra !== 'object') { + mes.extra = {}; + } + mes.extra.image = img.image; + mes.extra.title = img.title; + mes.extra.inline_image = img.inline; + } +} + +export function getGeneratingApi() { + switch (main_api) { + case 'openai': + return oai_settings.chat_completion_source || 'openai'; + case 'textgenerationwebui': + return textgen_settings.type === textgen_types.OOBA ? 'textgenerationwebui' : textgen_settings.type; + default: + return main_api; + } +} + +function getGeneratingModel(mes) { + let model = ''; + switch (main_api) { + case 'kobold': + model = online_status; + break; + case 'novel': + model = nai_settings.model_novel; + break; + case 'openai': + model = getChatCompletionModel(); + break; + case 'textgenerationwebui': + model = online_status; + break; + case 'koboldhorde': + model = kobold_horde_model; + break; + } + return model; +} + +function extractImageFromMessage(getMessage) { + const regex = //g; + const results = regex.exec(getMessage); + const image = results ? results[1] : ''; + const title = results ? results[2] : ''; + getMessage = getMessage.replace(regex, ''); + return { getMessage, image, title, inline: true }; +} + +/** + * A function mainly used to switch 'generating' state - setting it to false and activating the buttons again + */ +export function activateSendButtons() { + is_send_press = false; + hideStopButton(); + delete document.body.dataset.generating; +} + +/** + * A function mainly used to switch 'generating' state - setting it to true and deactivating the buttons + */ +export function deactivateSendButtons() { + showStopButton(); + document.body.dataset.generating = 'true'; +} + +export function resetChatState() { + // replaces deleted charcter name with system user since it will be displayed next. + name2 = (this_chid === undefined && neutralCharacterName) ? neutralCharacterName : systemUserName; + //unsets expected chid before reloading (related to getCharacters/printCharacters from using old arrays) + setCharacterId(undefined); + // sets up system user to tell user about having deleted a character + chat.splice(0, chat.length, ...SAFETY_CHAT); + // resets chat metadata + chat_metadata = {}; + // resets the characters array, forcing getcharacters to reset + characters.length = 0; +} + +/** + * + * @param {'characters' | 'character_edit' | 'create' | 'group_edit' | 'group_create'} value + */ +export function setMenuType(value) { + menu_type = value; + // Allow custom CSS to see which menu type is active + document.getElementById('right-nav-panel').dataset.menuType = menu_type; +} + +export function setExternalAbortController(controller) { + abortController = controller; +} + +/** + * Sets a character array index. + * @param {number|string|undefined} value + */ +export function setCharacterId(value) { + switch (typeof value) { + case 'bigint': + case 'number': + this_chid = String(value); + break; + case 'string': + this_chid = !isNaN(parseInt(value)) ? value : undefined; + break; + case 'object': + this_chid = characters.indexOf(value) !== -1 ? String(characters.indexOf(value)) : undefined; + break; + case 'undefined': + this_chid = undefined; + break; + default: + console.error('Invalid character ID type:', value); + break; + } +} + +export function setCharacterName(value) { + name2 = value; +} + +/** + * Sets the API connection status of the application + * @param {string|'no_connection'} value Connection status value + */ +export function setOnlineStatus(value) { + const previousStatus = online_status; + online_status = value; + displayOnlineStatus(); + if (previousStatus !== online_status) { + eventSource.emitAndWait(event_types.ONLINE_STATUS_CHANGED, online_status); + } +} + +export function setEditedMessageId(value) { + this_edit_mes_id = value; +} + +export function setSendButtonState(value) { + is_send_press = value; +} + +/** + * Renames the currently selected character, updating relevant references and optionally renaming past chats. + * + * If no name is provided, a popup prompts for a new name. If the new name matches the current name, + * the renaming process is aborted. The function sends a request to the server to rename the character + * and handles updates to other related fields such as tags, lore, and author notes. + * + * If the renaming is successful, the character list is reloaded and the renamed character is selected. + * Optionally, past chats can be renamed to reflect the new character name. + * + * @param {string?} [name=null] - The new name for the character. If not provided, a popup will prompt for it. + * @param {object} [options] - Additional options. + * @param {boolean} [options.silent=false] - If true, suppresses popups and warnings. + * @param {boolean?} [options.renameChats=null] - If true, renames past chats to reflect the new character name. + * @returns {Promise} - Returns true if the character was successfully renamed, false otherwise. + */ + +export async function renameCharacter(name = null, { silent = false, renameChats = null } = {}) { + if (!name && silent) { + toastr.warning(t`No character name provided.`, t`Rename Character`); + return false; + } + if (this_chid === undefined) { + toastr.warning(t`No character selected.`, t`Rename Character`); + return false; + } + + const oldAvatar = characters[this_chid].avatar; + const newValue = name || await callGenericPopup('

      ' + t`New name:` + '

      ', POPUP_TYPE.INPUT, characters[this_chid].name); + + if (!newValue) { + toastr.warning(t`No character name provided.`, t`Rename Character`); + return false; + } + if (newValue === characters[this_chid].name) { + toastr.info(t`Same character name provided, so name did not change.`, t`Rename Character`); + return false; + } + + const body = JSON.stringify({ avatar_url: oldAvatar, new_name: newValue }); + const response = await fetch('/api/characters/rename', { + method: 'POST', + headers: getRequestHeaders(), + body, + }); + + try { + if (response.ok) { + const data = await response.json(); + const newAvatar = data.avatar; + + const oldName = getCharaFilename(null, { manualAvatarKey: oldAvatar }); + const newName = getCharaFilename(null, { manualAvatarKey: newAvatar }); + + // Replace other auxillery fields where was referenced by avatar key + // Tag List + renameTagKey(oldAvatar, newAvatar); + + // Addtional lore books + const charLore = world_info.charLore?.find(x => x.name == oldName); + if (charLore) { + charLore.name = newName; + saveSettingsDebounced(); + } + + // Char-bound Author's Notes + const charNote = extension_settings.note.chara?.find(x => x.name == oldName); + if (charNote) { + charNote.name = newName; + saveSettingsDebounced(); + } + + // Update active character, if the current one was the currently active one + if (active_character === oldAvatar) { + active_character = newAvatar; + saveSettingsDebounced(); + } + + await eventSource.emit(event_types.CHARACTER_RENAMED, oldAvatar, newAvatar); + + // Reload characters list + await getCharacters(); + + // Find newly renamed character + const newChId = characters.findIndex(c => c.avatar == data.avatar); + + if (newChId !== -1) { + // Select the character after the renaming + setCharacterId(undefined); + await selectCharacterById(newChId); + + // Async delay to update UI + await delay(1); + + if (this_chid === undefined) { + throw new Error('New character not selected'); + } + + // Also rename as a group member + await renameGroupMember(oldAvatar, newAvatar, newValue); + const renamePastChatsConfirm = renameChats !== null + ? renameChats + : silent + ? false + : await Popup.show.confirm( + t`Character renamed!`, + `

      ${t`Past chats will still contain the old character name. Would you like to update the character name in previous chats as well?`}

      + ${t`Sprites folder (if any) should be renamed manually.`}`, + ) == POPUP_RESULT.AFFIRMATIVE; + + if (renamePastChatsConfirm) { + await renamePastChats(oldAvatar, newAvatar, newValue); + await reloadCurrentChat(); + toastr.success(t`Character renamed and past chats updated!`, t`Rename Character`); + } else { + toastr.success(t`Character renamed!`, t`Rename Character`); + } + } + else { + throw new Error('Newly renamed character was lost?'); + } + } + else { + throw new Error('Could not rename the character'); + } + } + catch (error) { + // Reloading to prevent data corruption + if (!silent) await Popup.show.text(t`Rename Character`, t`Something went wrong. The page will be reloaded.`); + else toastr.error(t`Something went wrong. The page will be reloaded.`, t`Rename Character`); + + console.log('Renaming character error:', error); + location.reload(); + return false; + } + + return true; +} + +async function renamePastChats(oldAvatar, newAvatar, newName) { + const pastChats = await getPastCharacterChats(); + + for (const { file_name } of pastChats) { + try { + const fileNameWithoutExtension = file_name.replace('.jsonl', ''); + const getChatResponse = await fetch('/api/chats/get', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + ch_name: newName, + file_name: fileNameWithoutExtension, + avatar_url: newAvatar, + }), + cache: 'no-cache', + }); + + if (getChatResponse.ok) { + const currentChat = await getChatResponse.json(); + + for (const message of currentChat) { + if (message.is_user || message.is_system || message.extra?.type == system_message_types.NARRATOR) { + continue; + } + + if (message.name !== undefined) { + message.name = newName; + } + } + + await eventSource.emit(event_types.CHARACTER_RENAMED_IN_PAST_CHAT, currentChat, oldAvatar, newAvatar); + + const saveChatResponse = await fetch('/api/chats/save', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + ch_name: newName, + file_name: fileNameWithoutExtension, + chat: currentChat, + avatar_url: newAvatar, + }), + cache: 'no-cache', + }); + + if (!saveChatResponse.ok) { + throw new Error('Could not save chat'); + } + } + } catch (error) { + toastr.error(t`Past chat could not be updated: ${file_name}`); + console.error(error); + } + } +} + +export function saveChatDebounced() { + const chid = this_chid; + const selectedGroup = selected_group; + + if (chatSaveTimeout) { + console.debug('Clearing chat save timeout'); + clearTimeout(chatSaveTimeout); + chatSaveTimeout = null; + } + + chatSaveTimeout = setTimeout(async () => { + if (selectedGroup !== selected_group) { + console.warn('Chat save timeout triggered, but group changed. Aborting.'); + return; + } + + if (chid !== this_chid) { + console.warn('Chat save timeout triggered, but chid changed. Aborting.'); + return; + } + + console.debug('Chat save timeout triggered'); + await saveChatConditional(); + console.debug('Chat saved'); + }, DEFAULT_SAVE_EDIT_TIMEOUT); +} + +export async function saveChat(chatName, withMetadata, mesId) { + const metadata = { ...chat_metadata, ...(withMetadata || {}) }; + const fileName = chatName ?? characters[this_chid]?.chat; + + if (!fileName && name2 === neutralCharacterName) { + // TODO: Do something for a temporary chat with no character. + return; + } + + if (!fileName) { + console.warn('saveChat called without chat_name and no chat file found'); + return; + } + + characters[this_chid]['date_last_chat'] = Date.now(); + chat.forEach(function (item, i) { + if (item['is_group']) { + toastr.error(t`Trying to save group chat with regular saveChat function. Aborting to prevent corruption.`); + throw new Error('Group chat saved from saveChat'); + } + /* + if (item.is_user) { + //var str = item.mes.replace(`${name1}:`, `${name1}:`); + //chat[i].mes = str; + //chat[i].name = name1; + } else if (i !== chat.length - 1 && chat[i].swipe_id !== undefined) { + // delete chat[i].swipes; + // delete chat[i].swipe_id; + } + */ + }); + + const trimmed_chat = (mesId !== undefined && mesId >= 0 && mesId < chat.length) + ? chat.slice(0, parseInt(mesId) + 1) + : chat; + + var save_chat = [ + { + user_name: name1, + character_name: name2, + create_date: chat_create_date, + chat_metadata: metadata, + }, + ...trimmed_chat, + ]; + return jQuery.ajax({ + type: 'POST', + url: '/api/chats/save', + data: JSON.stringify({ + ch_name: characters[this_chid].name, + file_name: fileName, + chat: save_chat, + avatar_url: characters[this_chid].avatar, + }), + beforeSend: function () { + + }, + cache: false, + dataType: 'json', + contentType: 'application/json', + success: function (data) { }, + error: function (jqXHR, exception) { + toastr.error(t`Check the server connection and reload the page to prevent data loss.`, t`Chat could not be saved`); + console.log(exception); + console.log(jqXHR); + }, + }); +} + +async function read_avatar_load(input) { + if (input.files && input.files[0]) { + if (selected_button == 'create') { + create_save.avatar = input.files; + } + + crop_data = undefined; + const file = input.files[0]; + const fileData = await getBase64Async(file); + + if (!power_user.never_resize_avatars) { + const dlg = new Popup('Set the crop position of the avatar image', POPUP_TYPE.CROP, '', { cropImage: fileData }); + const croppedImage = await dlg.show(); + + if (!croppedImage) { + return; + } + + crop_data = dlg.cropData; + $('#avatar_load_preview').attr('src', String(croppedImage)); + } else { + $('#avatar_load_preview').attr('src', fileData); + } + + if (menu_type == 'create') { + return; + } + + await createOrEditCharacter(); + await delay(DEFAULT_SAVE_EDIT_TIMEOUT); + + const formData = new FormData($('#form_create').get(0)); + await fetch(getThumbnailUrl('avatar', formData.get('avatar_url')), { + method: 'GET', + cache: 'no-cache', + headers: { + 'pragma': 'no-cache', + 'cache-control': 'no-cache', + }, + }); + + $('.mes').each(async function () { + const nameMatch = $(this).attr('ch_name') == formData.get('ch_name'); + if ($(this).attr('is_system') == 'true' && !nameMatch) { + return; + } + if ($(this).attr('is_user') == 'true') { + return; + } + if (nameMatch) { + const previewSrc = $('#avatar_load_preview').attr('src'); + const avatar = $(this).find('.avatar img'); + avatar.attr('src', default_avatar); + await delay(1); + avatar.attr('src', previewSrc); + } + }); + + console.log('Avatar refreshed'); + } +} + +export function getThumbnailUrl(type, file) { + return `/thumbnail?type=${type}&file=${encodeURIComponent(file)}`; +} + +export function buildAvatarList(block, entities, { templateId = 'inline_avatar_template', empty = true, interactable = false, highlightFavs = true } = {}) { + if (empty) { + block.empty(); + } + + for (const entity of entities) { + const id = entity.id; + + // Populate the template + const avatarTemplate = $(`#${templateId} .avatar`).clone(); + + let this_avatar = default_avatar; + if (entity.item.avatar !== undefined && entity.item.avatar != 'none') { + this_avatar = getThumbnailUrl('avatar', entity.item.avatar); + } + + avatarTemplate.attr('data-type', entity.type); + avatarTemplate.attr('data-chid', id); + avatarTemplate.find('img').attr('src', this_avatar).attr('alt', entity.item.name); + avatarTemplate.attr('title', `[Character] ${entity.item.name}\nFile: ${entity.item.avatar}`); + if (highlightFavs) { + avatarTemplate.toggleClass('is_fav', entity.item.fav || entity.item.fav == 'true'); + avatarTemplate.find('.ch_fav').val(entity.item.fav); + } + + // If this is a group, we need to hack slightly. We still want to keep most of the css classes and layout, but use a group avatar instead. + if (entity.type === 'group') { + const grpTemplate = getGroupAvatar(entity.item); + + avatarTemplate.addClass(grpTemplate.attr('class')); + avatarTemplate.empty(); + avatarTemplate.append(grpTemplate.children()); + avatarTemplate.attr({ 'data-grid': id, 'data-chid': null }); + avatarTemplate.attr('title', `[Group] ${entity.item.name}`); + } + else if (entity.type === 'persona') { + avatarTemplate.attr({ 'data-pid': id, 'data-chid': null }); + avatarTemplate.find('img').attr('src', getUserAvatar(entity.item.avatar)); + avatarTemplate.attr('title', `[Persona] ${entity.item.name}\nFile: ${entity.item.avatar}`); + } + + if (interactable) { + avatarTemplate.addClass(INTERACTABLE_CONTROL_CLASS); + avatarTemplate.toggleClass('character_select', entity.type === 'character'); + avatarTemplate.toggleClass('group_select', entity.type === 'group'); + } + + block.append(avatarTemplate); + } +} + +/** + * Loads all the data of a shallow character. + * @param {string|undefined} characterId Array index + * @returns {Promise} Promise that resolves when the character is unshallowed + */ +export async function unshallowCharacter(characterId) { + if (characterId === undefined) { + console.debug('Undefined character cannot be unshallowed'); + return; + } + + /** @type {import('./scripts/char-data.js').v1CharData} */ + const character = characters[characterId]; + if (!character) { + console.debug('Character not found:', characterId); + return; + } + + // Character is not shallow + if (!character.shallow) { + return; + } + + const avatar = character.avatar; + if (!avatar) { + console.debug('Character has no avatar field:', characterId); + return; + } + + await getOneCharacter(avatar); +} + +export async function getChat() { + //console.log('/api/chats/get -- entered for -- ' + characters[this_chid].name); + try { + await unshallowCharacter(this_chid); + + const response = await $.ajax({ + type: 'POST', + url: '/api/chats/get', + data: JSON.stringify({ + ch_name: characters[this_chid].name, + file_name: characters[this_chid].chat, + avatar_url: characters[this_chid].avatar, + }), + dataType: 'json', + contentType: 'application/json', + }); + if (response[0] !== undefined) { + chat.splice(0, chat.length, ...response); + chat_create_date = chat[0]['create_date']; + chat_metadata = chat[0]['chat_metadata'] ?? {}; + + chat.shift(); + } else { + chat_create_date = humanizedDateTime(); + } + await getChatResult(); + eventSource.emit('chatLoaded', { detail: { id: this_chid, character: characters[this_chid] } }); + + // Focus on the textarea if not already focused on a visible text input + setTimeout(function () { + if ($(document.activeElement).is('input:visible, textarea:visible')) { + return; + } + $('#send_textarea').trigger('click').trigger('focus'); + }, 200); + } catch (error) { + await getChatResult(); + console.log(error); + } +} + +async function getChatResult() { + name2 = characters[this_chid].name; + let freshChat = false; + if (chat.length === 0) { + const message = getFirstMessage(); + if (message.mes) { + chat.push(message); + freshChat = true; + } + // Make sure the chat appears on the server + await saveChatConditional(); + } + await loadItemizedPrompts(getCurrentChatId()); + await printMessages(); + select_selected_character(this_chid); + + await eventSource.emit(event_types.CHAT_CHANGED, (getCurrentChatId())); + if (freshChat) await eventSource.emit(event_types.CHAT_CREATED); + + if (chat.length === 1) { + const chat_id = (chat.length - 1); + await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, 'first_message'); + await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, chat_id, 'first_message'); + } +} + +function getFirstMessage() { + const firstMes = characters[this_chid].first_mes || ''; + const alternateGreetings = characters[this_chid]?.data?.alternate_greetings; + + const message = { + name: name2, + is_user: false, + is_system: false, + send_date: getMessageTimeStamp(), + mes: getRegexedString(firstMes, regex_placement.AI_OUTPUT), + extra: {}, + }; + + if (Array.isArray(alternateGreetings) && alternateGreetings.length > 0) { + const swipes = [message.mes, ...(alternateGreetings.map(greeting => getRegexedString(greeting, regex_placement.AI_OUTPUT)))]; + + if (!message.mes) { + swipes.shift(); + message.mes = swipes[0]; + } + + message['swipe_id'] = 0; + message['swipes'] = swipes; + message['swipe_info'] = []; + } + + return message; +} + +export async function openCharacterChat(file_name) { + await clearChat(); + characters[this_chid]['chat'] = file_name; + chat.length = 0; + chat_metadata = {}; + await getChat(); + $('#selected_chat_pole').val(file_name); + await createOrEditCharacter(new CustomEvent('newChat')); +} + +////////// OPTIMZED MAIN API CHANGE FUNCTION //////////// + +export function changeMainAPI() { + const selectedVal = $('#main_api').val(); + //console.log(selectedVal); + const apiElements = { + 'koboldhorde': { + apiStreaming: $('#NULL_SELECTOR'), + apiSettings: $('#kobold_api-settings'), + apiConnector: $('#kobold_horde'), + apiPresets: $('#kobold_api-presets'), + apiRanges: $('#range_block'), + maxContextElem: $('#max_context_block'), + amountGenElem: $('#amount_gen_block'), + }, + 'kobold': { + apiStreaming: $('#streaming_kobold_block'), + apiSettings: $('#kobold_api-settings'), + apiConnector: $('#kobold_api'), + apiPresets: $('#kobold_api-presets'), + apiRanges: $('#range_block'), + maxContextElem: $('#max_context_block'), + amountGenElem: $('#amount_gen_block'), + }, + 'textgenerationwebui': { + apiStreaming: $('#streaming_textgenerationwebui_block'), + apiSettings: $('#textgenerationwebui_api-settings'), + apiConnector: $('#textgenerationwebui_api'), + apiPresets: $('#textgenerationwebui_api-presets'), + apiRanges: $('#range_block_textgenerationwebui'), + maxContextElem: $('#max_context_block'), + amountGenElem: $('#amount_gen_block'), + }, + 'novel': { + apiStreaming: $('#streaming_novel_block'), + apiSettings: $('#novel_api-settings'), + apiConnector: $('#novel_api'), + apiPresets: $('#novel_api-presets'), + apiRanges: $('#range_block_novel'), + maxContextElem: $('#max_context_block'), + amountGenElem: $('#amount_gen_block'), + }, + 'openai': { + apiStreaming: $('#NULL_SELECTOR'), + apiSettings: $('#openai_settings'), + apiConnector: $('#openai_api'), + apiPresets: $('#openai_api-presets'), + apiRanges: $('#range_block_openai'), + maxContextElem: $('#max_context_block'), + amountGenElem: $('#amount_gen_block'), + }, + }; + //console.log('--- apiElements--- '); + //console.log(apiElements); + + //first, disable everything so the old elements stop showing + for (const apiName in apiElements) { + const apiObj = apiElements[apiName]; + //do not hide items to then proceed to immediately show them. + if (selectedVal === apiName) { + continue; + } + apiObj.apiSettings.css('display', 'none'); + apiObj.apiConnector.css('display', 'none'); + apiObj.apiRanges.css('display', 'none'); + apiObj.apiPresets.css('display', 'none'); + apiObj.apiStreaming.css('display', 'none'); + } + + //then, find and enable the active item. + //This is split out of the loop so that different apis can share settings divs + let activeItem = apiElements[selectedVal]; + + activeItem.apiStreaming.css('display', 'block'); + activeItem.apiSettings.css('display', 'block'); + activeItem.apiConnector.css('display', 'block'); + activeItem.apiRanges.css('display', 'block'); + activeItem.apiPresets.css('display', 'block'); + + if (selectedVal === 'openai') { + activeItem.apiPresets.css('display', 'flex'); + } + + if (selectedVal === 'textgenerationwebui' || selectedVal === 'novel') { + console.debug('enabling amount_gen for ooba/novel'); + activeItem.amountGenElem.find('input').prop('disabled', false); + activeItem.amountGenElem.css('opacity', 1.0); + } + + //custom because streaming has been moved up under response tokens, which exists inside common settings block + if (selectedVal === 'novel') { + $('#ai_module_block_novel').css('display', 'block'); + } else { + $('#ai_module_block_novel').css('display', 'none'); + } + + // Hide common settings for OpenAI + console.debug('value?', selectedVal); + if (selectedVal == 'openai') { + console.debug('hiding settings?'); + $('#common-gen-settings-block').css('display', 'none'); + } else { + $('#common-gen-settings-block').css('display', 'block'); + } + + main_api = selectedVal; + setOnlineStatus('no_connection'); + + if (main_api == 'openai' && oai_settings.chat_completion_source == chat_completion_sources.WINDOWAI) { + $('#api_button_openai').trigger('click'); + } + + if (main_api == 'koboldhorde') { + getStatusHorde(); + getHordeModels(true); + } + validateDisabledSamplers(); + setupChatCompletionPromptManager(oai_settings); + forceCharacterEditorTokenize(); +} + +export function setUserName(value, { toastPersonaNameChange = true } = {}) { + name1 = value; + if (name1 === undefined || name1 == '') + name1 = default_user_name; + console.log(`User name changed to ${name1}`); + $('#your_name').text(name1); + if (toastPersonaNameChange && power_user.persona_show_notifications && !isPersonaPanelOpen()) { + toastr.success(t`Your messages will now be sent as ${name1}`, t`Persona Changed`); + } + saveSettingsDebounced(); +} + +async function doOnboarding(avatarId) { + const template = $('#onboarding_template .onboarding'); + let userName = await callGenericPopup(template, POPUP_TYPE.INPUT, currentUser?.name || name1, { rows: 2, wider: true, cancelButton: false }); + + if (userName) { + userName = String(userName).replace('\n', ' '); + setUserName(userName); + console.log(`Binding persona ${avatarId} to name ${userName}`); + power_user.personas[avatarId] = userName; + power_user.persona_descriptions[avatarId] = { + description: '', + position: persona_description_positions.IN_PROMPT, + }; + } +} + +function reloadLoop() { + const MAX_RELOADS = 5; + let reloads = Number(sessionStorage.getItem('reloads') || 0); + if (reloads < MAX_RELOADS) { + reloads++; + sessionStorage.setItem('reloads', String(reloads)); + window.location.reload(); + } +} + +//***************SETTINGS****************// +/////////////////////////////////////////// +export async function getSettings() { + const response = await fetch('/api/settings/get', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({}), + cache: 'no-cache', + }); + + if (!response.ok) { + reloadLoop(); + toastr.error(t`Settings could not be loaded after multiple attempts. Please try again later.`); + throw new Error('Error getting settings'); + } + + const data = await response.json(); + if (data.result != 'file not find' && data.settings) { + settings = JSON.parse(data.settings); + if (settings.username !== undefined && settings.username !== '') { + name1 = settings.username; + $('#your_name').text(name1); + } + + accountStorage.init(settings?.accountStorage); + await setUserControls(data.enable_accounts); + + // Allow subscribers to mutate settings + await eventSource.emit(event_types.SETTINGS_LOADED_BEFORE, settings); + + //Load KoboldAI settings + koboldai_setting_names = data.koboldai_setting_names; + koboldai_settings = data.koboldai_settings; + koboldai_settings.forEach(function (item, i, arr) { + koboldai_settings[i] = JSON.parse(item); + }); + + let arr_holder = {}; + + $('#settings_preset').empty(); + $('#settings_preset').append( + '', + ); //adding in the GUI settings, since it is not loaded dynamically + + koboldai_setting_names.forEach(function (item, i, arr) { + arr_holder[item] = i; + $('#settings_preset').append(``); + //console.log('loading preset #'+i+' -- '+item); + }); + koboldai_setting_names = {}; + koboldai_setting_names = arr_holder; + preset_settings = settings.preset_settings; + + if (preset_settings == 'gui') { + selectKoboldGuiPreset(); + } else { + if (typeof koboldai_setting_names[preset_settings] !== 'undefined') { + $(`#settings_preset option[value=${koboldai_setting_names[preset_settings]}]`) + .attr('selected', 'true'); + } else { + preset_settings = 'gui'; + selectKoboldGuiPreset(); + } + } + + novelai_setting_names = data.novelai_setting_names; + novelai_settings = data.novelai_settings; + novelai_settings.forEach(function (item, i, arr) { + novelai_settings[i] = JSON.parse(item); + }); + arr_holder = {}; + + $('#settings_preset_novel').empty(); + + novelai_setting_names.forEach(function (item, i, arr) { + arr_holder[item] = i; + $('#settings_preset_novel').append(``); + }); + novelai_setting_names = {}; + novelai_setting_names = arr_holder; + + //Load AI model config settings + + amount_gen = settings.amount_gen; + if (settings.max_context !== undefined) + max_context = parseInt(settings.max_context); + + swipes = settings.swipes !== undefined ? !!settings.swipes : true; // enable swipes by default + $('#swipes-checkbox').prop('checked', swipes); /// swipecode + hideSwipeButtons(); + showSwipeButtons(); + + // Kobold + loadKoboldSettings(settings.kai_settings ?? settings); + + // Novel + loadNovelSettings(settings.nai_settings ?? settings); + $(`#settings_preset_novel option[value=${novelai_setting_names[nai_settings.preset_settings_novel]}]`).attr('selected', 'true'); + + // TextGen + loadTextGenSettings(data, settings); + + + // OpenAI + loadOpenAISettings(data, settings.oai_settings ?? settings); + + // Horde + loadHordeSettings(settings); + + // Load power user settings + await loadPowerUserSettings(settings, data); + + // Apply theme toggles from power user settings + applyPowerUserSettings(); + + // Load character tags + loadTagsSettings(settings); + + // Load background + loadBackgroundSettings(settings); + + // Load proxy presets + loadProxyPresets(settings); + + // Allow subscribers to mutate settings + await eventSource.emit(event_types.SETTINGS_LOADED_AFTER, settings); + + // Set context size after loading power user (may override the max value) + $('#max_context').val(max_context); + $('#max_context_counter').val(max_context); + + $('#amount_gen').val(amount_gen); + $('#amount_gen_counter').val(amount_gen); + + //Load which API we are using + if (settings.main_api == undefined) { + settings.main_api = 'kobold'; + } + + if (settings.main_api == 'poe') { + settings.main_api = 'openai'; + } + + main_api = settings.main_api; + $('#main_api').val(main_api); + $('#main_api option[value=' + main_api + ']').attr( + 'selected', + 'true', + ); + changeMainAPI(); + + + //Load User's Name and Avatar + initUserAvatar(settings.user_avatar); + setPersonaDescription(); + + //Load the active character and group + active_character = settings.active_character; + active_group = settings.active_group; + + //Load the API server URL from settings + api_server = settings.api_server; + $('#api_url_text').val(api_server); + + setWorldInfoSettings(settings.world_info_settings ?? settings, data); + + selected_button = settings.selected_button; + + if (data.enable_extensions) { + const enableAutoUpdate = Boolean(data.enable_extensions_auto_update); + const isVersionChanged = settings.currentVersion !== currentVersion; + await loadExtensionSettings(settings, isVersionChanged, enableAutoUpdate); + await eventSource.emit(event_types.EXTENSION_SETTINGS_LOADED); + } + + firstRun = !!settings.firstRun; + + if (firstRun) { + hideLoader(); + await doOnboarding(user_avatar); + firstRun = false; + } + } + await validateDisabledSamplers(); + settingsReady = true; + await eventSource.emit(event_types.SETTINGS_LOADED); +} + +function selectKoboldGuiPreset() { + $('#settings_preset option[value=gui]') + .attr('selected', 'true') + .trigger('change'); +} + +export async function saveSettings(loopCounter = 0) { + if (!settingsReady) { + console.warn('Settings not ready, scheduling another save'); + saveSettingsDebounced(); + return; + } + + const MAX_RETRIES = 3; + if (TempResponseLength.isCustomized()) { + if (loopCounter < MAX_RETRIES) { + console.warn('Response length is currently being overridden, scheduling another save'); + saveSettingsDebounced(++loopCounter); + return; + } + console.error('Response length is currently being overridden, but the save loop has reached the maximum number of retries'); + TempResponseLength.restore(null); + } + + //console.log('Entering settings with name1 = '+name1); + return jQuery.ajax({ + type: 'POST', + url: '/api/settings/save', + data: JSON.stringify({ + firstRun: firstRun, + accountStorage: accountStorage.getState(), + currentVersion: currentVersion, + username: name1, + active_character: active_character, + active_group: active_group, + api_server: api_server, + preset_settings: preset_settings, + user_avatar: user_avatar, + amount_gen: amount_gen, + max_context: max_context, + main_api: main_api, + world_info_settings: getWorldInfoSettings(), + textgenerationwebui_settings: textgen_settings, + swipes: swipes, + horde_settings: horde_settings, + power_user: power_user, + extension_settings: extension_settings, + tags: tags, + tag_map: tag_map, + nai_settings: nai_settings, + kai_settings: kai_settings, + oai_settings: oai_settings, + background: background_settings, + proxies: proxies, + selected_proxy: selected_proxy, + }, null, 4), + beforeSend: function () { }, + cache: false, + dataType: 'json', + contentType: 'application/json', + //processData: false, + success: async function (data) { + eventSource.emit(event_types.SETTINGS_UPDATED); + }, + error: function (jqXHR, exception) { + toastr.error(t`Check the server connection and reload the page to prevent data loss.`, t`Settings could not be saved`); + console.log(exception); + console.log(jqXHR); + }, + }); +} + +/** + * Sets the generation parameters from a preset object. + * @param {{ genamt?: number, max_length?: number }} preset Preset object + */ +export function setGenerationParamsFromPreset(preset) { + const needsUnlock = (preset.max_length ?? max_context) > MAX_CONTEXT_DEFAULT || (preset.genamt ?? amount_gen) > MAX_RESPONSE_DEFAULT; + $('#max_context_unlocked').prop('checked', needsUnlock).trigger('change'); + + if (preset.genamt !== undefined) { + amount_gen = preset.genamt; + $('#amount_gen').val(amount_gen); + $('#amount_gen_counter').val(amount_gen); + } + + if (preset.max_length !== undefined) { + max_context = preset.max_length; + $('#max_context').val(max_context); + $('#max_context_counter').val(max_context); + } +} + +// Common code for message editor done and auto-save +function updateMessage(div) { + const mesBlock = div.closest('.mes_block'); + let text = mesBlock.find('.edit_textarea').val() + ?? mesBlock.find('.mes_text').text(); + const mesElement = div.closest('.mes'); + const mes = chat[mesElement.attr('mesid')]; + + let regexPlacement; + if (mes.is_user) { + regexPlacement = regex_placement.USER_INPUT; + } else if (mes.extra?.type === 'narrator') { + regexPlacement = regex_placement.SLASH_COMMAND; + } else { + regexPlacement = regex_placement.AI_OUTPUT; + } + + // Ignore character override if sent as system + text = getRegexedString( + text, + regexPlacement, + { + characterOverride: mes.extra?.type === 'narrator' ? undefined : mes.name, + isEdit: true, + }, + ); + + + if (power_user.trim_spaces) { + text = text.trim(); + } + + const bias = substituteParams(extractMessageBias(text)); + text = substituteParams(text); + if (bias) { + text = removeMacros(text); + } + mes['mes'] = text; + if (mes['swipe_id'] !== undefined) { + mes['swipes'][mes['swipe_id']] = text; + } + + // editing old messages + if (!mes.extra) { + mes.extra = {}; + } + + if (mes.is_system || mes.is_user || mes.extra.type === system_message_types.NARRATOR) { + mes.extra.bias = bias ?? null; + } else { + mes.extra.bias = null; + } + + chat_metadata['tainted'] = true; + + return { mesBlock, text, mes, bias }; +} + +function openMessageDelete(fromSlashCommand) { + closeMessageEditor(); + hideSwipeButtons(); + if (fromSlashCommand || (!is_send_press) || (selected_group && !is_group_generating)) { + $('#dialogue_del_mes').css('display', 'block'); + $('#send_form').css('display', 'none'); + $('.del_checkbox').each(function () { + $(this).css('display', 'grid'); + $(this).parent().children('.for_checkbox').css('display', 'none'); + }); + } else { + console.debug(` + ERR -- could not enter del mode + this_chid: ${this_chid} + is_send_press: ${is_send_press} + selected_group: ${selected_group} + is_group_generating: ${is_group_generating}`); + } + this_del_mes = -1; + is_delete_mode = true; +} + +function messageEditAuto(div) { + const { mesBlock, text, mes, bias } = updateMessage(div); + + mesBlock.find('.mes_text').val(''); + mesBlock.find('.mes_text').val(messageFormatting( + text, + this_edit_mes_chname, + mes.is_system, + mes.is_user, + this_edit_mes_id, + {}, + false, + )); + mesBlock.find('.mes_bias').empty(); + mesBlock.find('.mes_bias').append(messageFormatting(bias, '', false, false, -1, {}, false)); + saveChatDebounced(); +} + +async function messageEditDone(div) { + let { mesBlock, text, mes, bias } = updateMessage(div); + if (this_edit_mes_id == 0) { + text = substituteParams(text); + } + + await eventSource.emit(event_types.MESSAGE_EDITED, this_edit_mes_id); + text = chat[this_edit_mes_id]?.mes ?? text; + mesBlock.find('.mes_text').empty(); + mesBlock.find('.mes_edit_buttons').css('display', 'none'); + mesBlock.find('.mes_buttons').css('display', ''); + mesBlock.find('.mes_text').append( + messageFormatting( + text, + this_edit_mes_chname, + mes.is_system, + mes.is_user, + this_edit_mes_id, + {}, + false, + ), + ); + mesBlock.find('.mes_bias').empty(); + mesBlock.find('.mes_bias').append(messageFormatting(bias, '', false, false, -1, {}, false)); + appendMediaToMessage(mes, div.closest('.mes')); + addCopyToCodeBlocks(div.closest('.mes')); + + const reasoningEditDone = mesBlock.find('.mes_reasoning_edit_done:visible'); + if (reasoningEditDone.length > 0) { + reasoningEditDone.trigger('click'); + } + + await eventSource.emit(event_types.MESSAGE_UPDATED, this_edit_mes_id); + this_edit_mes_id = undefined; + await saveChatConditional(); +} + +/** + * Fetches the chat content for each chat file from the server and compiles them into a dictionary. + * The function iterates over a provided list of chat metadata and requests the actual chat content + * for each chat, either as an individual chat or a group chat based on the context. + * + * @param {Array} data - An array containing metadata about each chat such as file_name. + * @param {boolean} isGroupChat - A flag indicating if the chat is a group chat. + * @returns {Promise} chat_dict - A dictionary where each key is a file_name and the value is the + * corresponding chat content fetched from the server. + */ +export async function getChatsFromFiles(data, isGroupChat) { + const context = getContext(); + let chat_dict = {}; + let chat_list = Object.values(data).sort((a, b) => a['file_name'].localeCompare(b['file_name'])).reverse(); + + let chat_promise = chat_list.map(({ file_name }) => { + return new Promise(async (res, rej) => { + try { + const endpoint = isGroupChat ? '/api/chats/group/get' : '/api/chats/get'; + const requestBody = isGroupChat + ? JSON.stringify({ id: file_name }) + : JSON.stringify({ + ch_name: characters[context.characterId].name, + file_name: file_name.replace('.jsonl', ''), + avatar_url: characters[context.characterId].avatar, + }); + + const chatResponse = await fetch(endpoint, { + method: 'POST', + headers: getRequestHeaders(), + body: requestBody, + cache: 'no-cache', + }); + + if (!chatResponse.ok) { + return res(); + // continue; + } + + const currentChat = await chatResponse.json(); + if (!isGroupChat) { + // remove the first message, which is metadata, only for individual chats + currentChat.shift(); + } + chat_dict[file_name] = currentChat; + + } catch (error) { + console.error(error); + } + + return res(); + }); + }); + + await Promise.all(chat_promise); + + return chat_dict; +} + +/** + * Fetches the metadata of all past chats related to a specific character based on its avatar URL. + * The function sends a POST request to the server to retrieve all chats for the character. It then + * processes the received data, sorts it by the file name, and returns the sorted data. + * + * @param {null|number} [characterId=null] - When set, the function will use this character id instead of this_chid. + * + * @returns {Promise} - An array containing metadata of all past chats of the character, sorted + * in descending order by file name. Returns an empty array if the fetch request is unsuccessful or the + * response is an object with an `error` property set to `true`. + */ +export async function getPastCharacterChats(characterId = null) { + characterId = characterId ?? this_chid; + if (!characters[characterId]) return []; + + const response = await fetch('/api/characters/chats', { + method: 'POST', + body: JSON.stringify({ avatar_url: characters[characterId].avatar }), + headers: getRequestHeaders(), + }); + + if (!response.ok) { + return []; + } + + const data = await response.json(); + if (typeof data === 'object' && data.error === true) { + return []; + } + + const chats = Object.values(data); + return chats.sort((a, b) => a['file_name'].localeCompare(b['file_name'])).reverse(); +} + +/** + * Helper for `displayPastChats`, to make the same info consistently available for other functions + */ +function getCurrentChatDetails() { + if (!characters[this_chid] && !selected_group) { + return { sessionName: '', group: null, characterName: '', avatarImgURL: '' }; + } + + const group = selected_group ? groups.find(x => x.id === selected_group) : null; + const currentChat = selected_group ? group?.chat_id : characters[this_chid]['chat']; + const displayName = selected_group ? group?.name : characters[this_chid].name; + const avatarImg = selected_group ? group?.avatar_url : getThumbnailUrl('avatar', characters[this_chid]['avatar']); + return { sessionName: currentChat, group: group, characterName: displayName, avatarImgURL: avatarImg }; +} + +/** + * Displays the past chats for a character or a group based on the selected context. + * The function first fetches the chats, processes them, and then displays them in + * the HTML. It also has a built-in search functionality that allows filtering the + * displayed chats based on a search query. + */ +export async function displayPastChats() { + $('#select_chat_div').empty(); + $('#select_chat_search').val('').off('input'); + + const chatDetails = getCurrentChatDetails(); + const currentChat = chatDetails.sessionName; + const displayName = chatDetails.characterName; + const avatarImg = chatDetails.avatarImgURL; + + await displayChats('', currentChat, displayName, avatarImg, selected_group); + + const debouncedDisplay = debounce((searchQuery) => { + displayChats(searchQuery, currentChat, displayName, avatarImg, selected_group); + }); + + // Define the search input listener + $('#select_chat_search').on('input', function () { + const searchQuery = $(this).val(); + debouncedDisplay(searchQuery); + }); + + // UX convenience: Focus the search field when the Manage Chat Files view opens. + setTimeout(function () { + const textSearchElement = $('#select_chat_search'); + textSearchElement.click(); + textSearchElement.focus(); + textSearchElement.select(); // select content (if any) for easy erasing + }, 200); +} + +async function displayChats(searchQuery, currentChat, displayName, avatarImg, selected_group) { + try { + const trimExtension = (fileName) => String(fileName).replace('.jsonl', ''); + + const response = await fetch('/api/chats/search', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + query: searchQuery, + avatar_url: selected_group ? null : characters[this_chid].avatar, + group_id: selected_group || null, + }), + }); + + if (!response.ok) { + throw new Error('Search failed'); + } + + const filteredData = await response.json(); + $('#select_chat_div').empty(); + + filteredData.sort((a, b) => sortMoments(timestampToMoment(a.last_mes), timestampToMoment(b.last_mes))); + + for (const chat of filteredData) { + const isSelected = trimExtension(currentChat) === trimExtension(chat.file_name); + const template = $('#past_chat_template .select_chat_block_wrapper').clone(); + template.find('.select_chat_block').attr('file_name', chat.file_name); + template.find('.avatar img').attr('src', avatarImg); + template.find('.select_chat_block_filename').text(chat.file_name); + template.find('.chat_file_size').text(`(${chat.file_size},`); + template.find('.chat_messages_num').text(`${chat.message_count} 💬)`); + template.find('.select_chat_block_mes').text(chat.preview_message); + template.find('.PastChat_cross').attr('file_name', chat.file_name); + template.find('.chat_messages_date').text(timestampToMoment(chat.last_mes).format('lll')); + + if (isSelected) { + template.find('.select_chat_block').attr('highlight', String(true)); + } + + $('#select_chat_div').append(template); + } + } catch (error) { + console.error('Error loading chats:', error); + toastr.error('Could not load chat data. Try reloading the page.'); + } +} + +export function selectRightMenuWithAnimation(selectedMenuId) { + const displayModes = { + 'rm_group_chats_block': 'flex', + 'rm_api_block': 'grid', + 'rm_characters_block': 'flex', + }; + $('#result_info').toggle(selectedMenuId === 'rm_ch_create_block'); + document.querySelectorAll('#right-nav-panel .right_menu').forEach((menu) => { + $(menu).css('display', 'none'); + + if (selectedMenuId && selectedMenuId.replace('#', '') === menu.id) { + const mode = displayModes[menu.id] ?? 'block'; + $(menu).css('display', mode); + $(menu).css('opacity', 0.0); + $(menu).transition({ + opacity: 1.0, + duration: animation_duration, + easing: animation_easing, + complete: function () { }, + }); + } + }); +} + +export function select_rm_info(type, charId, previousCharId = null) { + if (!type) { + toastr.error(t`Invalid process (no 'type')`); + return; + } + if (type !== 'group_create') { + var displayName = String(charId).replace('.png', ''); + } + + if (type === 'char_delete') { + toastr.warning(t`Character Deleted: ${displayName}`); + } + if (type === 'char_create') { + toastr.success(t`Character Created: ${displayName}`); + } + if (type === 'group_create') { + toastr.success(t`Group Created`); + } + if (type === 'group_delete') { + toastr.warning(t`Group Deleted`); + } + + if (type === 'char_import') { + toastr.success(t`Character Imported: ${displayName}`); + } + + selectRightMenuWithAnimation('rm_characters_block'); + + // Set a timeout so multiple flashes don't overlap + clearTimeout(importFlashTimeout); + importFlashTimeout = setTimeout(function () { + if (type === 'char_import' || type === 'char_create' || type === 'char_import_no_toast') { + // Find the page at which the character is located + const avatarFileName = charId; + const charData = getEntitiesList({ doFilter: true }); + const charIndex = charData.findIndex((x) => x?.item?.avatar?.startsWith(avatarFileName)); + + if (charIndex === -1) { + console.log(`Could not find character ${charId} in the list`); + return; + } + + try { + const perPage = Number(accountStorage.getItem('Characters_PerPage')) || per_page_default; + const page = Math.floor(charIndex / perPage) + 1; + const selector = `#rm_print_characters_block [title*="${avatarFileName}"]`; + $('#rm_print_characters_pagination').pagination('go', page); + + waitUntilCondition(() => document.querySelector(selector) !== null).then(() => { + const element = $(selector).parent(); + + if (element.length === 0) { + console.log(`Could not find element for character ${charId}`); + return; + } + + const scrollOffset = element.offset().top - element.parent().offset().top; + element.parent().scrollTop(scrollOffset); + flashHighlight(element, 5000); + }); + } catch (e) { + console.error(e); + } + } + + if (type === 'group_create') { + // Find the page at which the character is located + const charData = getEntitiesList({ doFilter: true }); + const charIndex = charData.findIndex((x) => String(x?.item?.id) === String(charId)); + + if (charIndex === -1) { + console.log(`Could not find group ${charId} in the list`); + return; + } + + const perPage = Number(accountStorage.getItem('Characters_PerPage')) || per_page_default; + const page = Math.floor(charIndex / perPage) + 1; + $('#rm_print_characters_pagination').pagination('go', page); + const selector = `#rm_print_characters_block [grid="${charId}"]`; + try { + waitUntilCondition(() => document.querySelector(selector) !== null).then(() => { + const element = $(selector); + const scrollOffset = element.offset().top - element.parent().offset().top; + element.parent().scrollTop(scrollOffset); + flashHighlight(element, 5000); + }); + } catch (e) { + console.error(e); + } + } + }, 250); + + if (previousCharId) { + const newId = characters.findIndex((x) => x.avatar == previousCharId); + if (newId >= 0) { + setCharacterId(newId); + } + } +} + +export function select_selected_character(chid) { + //character select + //console.log('select_selected_character() -- starting with input of -- ' + chid + ' (name:' + characters[chid].name + ')'); + select_rm_create(); + setMenuType('character_edit'); + $('#delete_button').css('display', 'flex'); + $('#export_button').css('display', 'flex'); + var display_name = characters[chid].name; + + //create text poles + $('#rm_button_back').css('display', 'none'); + //$("#character_import_button").css("display", "none"); + $('#create_button').attr('value', 'Save'); // what is the use case for this? + $('#dupe_button').show(); + $('#create_button_label').css('display', 'none'); + $('#char_connections_button').show(); + + // Hide the chat scenario button if we're peeking the group member defs + $('#set_chat_scenario').toggle(!selected_group); + + // Don't update the navbar name if we're peeking the group member defs + if (!selected_group) { + $('#rm_button_selected_ch').children('h2').text(display_name); + } + + $('#add_avatar_button').val(''); + + $('#character_popup-button-h3').text(characters[chid].name); + $('#character_name_pole').val(characters[chid].name); + $('#description_textarea').val(characters[chid].description); + $('#character_world').val(characters[chid].data?.extensions?.world || ''); + $('#creator_notes_textarea').val(characters[chid].data?.creator_notes || characters[chid].creatorcomment); + $('#creator_notes_spoiler').html(DOMPurify.sanitize(converter.makeHtml(substituteParams(characters[chid].data?.creator_notes) || characters[chid].creatorcomment), { MESSAGE_SANITIZE: true })); + $('#character_version_textarea').val(characters[chid].data?.character_version || ''); + $('#system_prompt_textarea').val(characters[chid].data?.system_prompt || ''); + $('#post_history_instructions_textarea').val(characters[chid].data?.post_history_instructions || ''); + $('#tags_textarea').val(Array.isArray(characters[chid].data?.tags) ? characters[chid].data.tags.join(', ') : ''); + $('#creator_textarea').val(characters[chid].data?.creator); + $('#character_version_textarea').val(characters[chid].data?.character_version || ''); + $('#personality_textarea').val(characters[chid].personality); + $('#firstmessage_textarea').val(characters[chid].first_mes); + $('#scenario_pole').val(characters[chid].scenario); + $('#depth_prompt_prompt').val(characters[chid].data?.extensions?.depth_prompt?.prompt ?? ''); + $('#depth_prompt_depth').val(characters[chid].data?.extensions?.depth_prompt?.depth ?? depth_prompt_depth_default); + $('#depth_prompt_role').val(characters[chid].data?.extensions?.depth_prompt?.role ?? depth_prompt_role_default); + $('#talkativeness_slider').val(characters[chid].talkativeness || talkativeness_default); + $('#mes_example_textarea').val(characters[chid].mes_example); + $('#selected_chat_pole').val(characters[chid].chat); + $('#create_date_pole').val(characters[chid].create_date); + $('#avatar_url_pole').val(characters[chid].avatar); + $('#chat_import_avatar_url').val(characters[chid].avatar); + $('#chat_import_character_name').val(characters[chid].name); + $('#character_json_data').val(characters[chid].json_data); + let this_avatar = default_avatar; + if (characters[chid].avatar != 'none') { + this_avatar = getThumbnailUrl('avatar', characters[chid].avatar); + } + + updateFavButtonState(characters[chid].fav || characters[chid].fav == 'true'); + + $('#avatar_load_preview').attr('src', this_avatar); + $('#name_div').removeClass('displayBlock'); + $('#name_div').addClass('displayNone'); + $('#renameCharButton').css('display', ''); + $('.open_alternate_greetings').data('chid', chid); + $('#set_character_world').data('chid', chid); + setWorldInfoButtonClass(chid); + checkEmbeddedWorld(chid); + + $('#form_create').attr('actiontype', 'editcharacter'); + $('.form_create_bottom_buttons_block .chat_lorebook_button').show(); + + const externalMediaState = isExternalMediaAllowed(); + $('#character_open_media_overrides').toggle(!selected_group); + $('#character_media_allowed_icon').toggle(externalMediaState); + $('#character_media_forbidden_icon').toggle(!externalMediaState); + + saveSettingsDebounced(); +} + +function select_rm_create() { + setMenuType('create'); + + //console.log('select_rm_Create() -- selected button: '+selected_button); + if (selected_button == 'create') { + if (create_save.avatar != '') { + $('#add_avatar_button').get(0).files = create_save.avatar; + read_avatar_load($('#add_avatar_button').get(0)); + } + } + + selectRightMenuWithAnimation('rm_ch_create_block'); + + $('#set_chat_scenario').hide(); + $('#delete_button_div').css('display', 'none'); + $('#delete_button').css('display', 'none'); + $('#export_button').css('display', 'none'); + $('#create_button_label').css('display', ''); + $('#create_button').attr('value', 'Create'); + $('#dupe_button').hide(); + $('#char_connections_button').hide(); + + //create text poles + $('#rm_button_back').css('display', ''); + $('#character_import_button').css('display', ''); + $('#character_popup-button-h3').text('Create character'); + $('#character_name_pole').val(create_save.name); + $('#description_textarea').val(create_save.description); + $('#character_world').val(create_save.world); + $('#creator_notes_textarea').val(create_save.creator_notes); + $('#creator_notes_spoiler').html(DOMPurify.sanitize(converter.makeHtml(create_save.creator_notes), { MESSAGE_SANITIZE: true })); + $('#post_history_instructions_textarea').val(create_save.post_history_instructions); + $('#system_prompt_textarea').val(create_save.system_prompt); + $('#tags_textarea').val(create_save.tags); + $('#creator_textarea').val(create_save.creator); + $('#character_version_textarea').val(create_save.character_version); + $('#personality_textarea').val(create_save.personality); + $('#firstmessage_textarea').val(create_save.first_message); + $('#talkativeness_slider').val(create_save.talkativeness); + $('#scenario_pole').val(create_save.scenario); + $('#depth_prompt_prompt').val(create_save.depth_prompt_prompt); + $('#depth_prompt_depth').val(create_save.depth_prompt_depth); + $('#depth_prompt_role').val(create_save.depth_prompt_role); + $('#mes_example_textarea').val(create_save.mes_example); + $('#character_json_data').val(''); + $('#avatar_div').css('display', 'flex'); + $('#avatar_load_preview').attr('src', default_avatar); + $('#renameCharButton').css('display', 'none'); + $('#name_div').removeClass('displayNone'); + $('#name_div').addClass('displayBlock'); + $('.open_alternate_greetings').data('chid', -1); + $('#set_character_world').data('chid', -1); + setWorldInfoButtonClass(undefined, !!create_save.world); + updateFavButtonState(false); + checkEmbeddedWorld(); + + $('#form_create').attr('actiontype', 'createcharacter'); + $('.form_create_bottom_buttons_block .chat_lorebook_button').hide(); + $('#character_open_media_overrides').hide(); +} + +function select_rm_characters() { + const doFullRefresh = menu_type === 'characters'; + setMenuType('characters'); + selectRightMenuWithAnimation('rm_characters_block'); + printCharacters(doFullRefresh); +} + +/** + * Sets a prompt injection to insert custom text into any outgoing prompt. For use in UI extensions. + * @param {string} key Prompt injection id. + * @param {string} value Prompt injection value. + * @param {number} position Insertion position. 0 is after story string, 1 is in-chat with custom depth. + * @param {number} depth Insertion depth. 0 represets the last message in context. Expected values up to MAX_INJECTION_DEPTH. + * @param {number} role Extension prompt role. Defaults to SYSTEM. + * @param {boolean} scan Should the prompt be included in the world info scan. + * @param {(function(): Promise|boolean)} filter Filter function to determine if the prompt should be injected. + */ +export function setExtensionPrompt(key, value, position, depth, scan = false, role = extension_prompt_roles.SYSTEM, filter = null) { + extension_prompts[key] = { + value: String(value), + position: Number(position), + depth: Number(depth), + scan: !!scan, + role: Number(role ?? extension_prompt_roles.SYSTEM), + filter: filter, + }; +} + +/** + * Gets a enum value of the extension prompt role by its name. + * @param {string} roleName The name of the extension prompt role. + * @returns {number} The role id of the extension prompt. + */ +export function getExtensionPromptRoleByName(roleName) { + // If the role is already a valid number, return it + if (typeof roleName === 'number' && Object.values(extension_prompt_roles).includes(roleName)) { + return roleName; + } + + switch (roleName) { + case 'system': + return extension_prompt_roles.SYSTEM; + case 'user': + return extension_prompt_roles.USER; + case 'assistant': + return extension_prompt_roles.ASSISTANT; + } + + // Skill issue? + return extension_prompt_roles.SYSTEM; +} + +/** + * Removes all char A/N prompt injections from the chat. + * To clean up when switching from groups to solo and vice versa. + */ +export function removeDepthPrompts() { + for (const key of Object.keys(extension_prompts)) { + if (key.startsWith('DEPTH_PROMPT')) { + delete extension_prompts[key]; + } + } +} + +/** + * Adds or updates the metadata for the currently active chat. + * @param {Object} newValues An object with collection of new values to be added into the metadata. + * @param {boolean} reset Should a metadata be reset by this call. + */ +export function updateChatMetadata(newValues, reset) { + chat_metadata = reset ? { ...newValues } : { ...chat_metadata, ...newValues }; +} + +function updateFavButtonState(state) { + fav_ch_checked = state; + $('#fav_checkbox').val(fav_ch_checked); + $('#favorite_button').toggleClass('fav_on', fav_ch_checked); + $('#favorite_button').toggleClass('fav_off', !fav_ch_checked); +} + +export async function setScenarioOverride() { + if (!selected_group && (this_chid === undefined || !characters[this_chid])) { + console.warn('setScenarioOverride() -- no selected group or character'); + return; + } + + const metadataValue = chat_metadata['scenario'] || ''; + const isGroup = !!selected_group; + + const $template = $(await renderTemplateAsync('scenarioOverride')); + $template.find('[data-group="true"]').toggle(isGroup); + $template.find('[data-character="true"]').toggle(!isGroup); + // TODO: Why does this save on every character input? Save on popup close + $template.find('.chat_scenario').val(metadataValue).on('input', onScenarioOverrideInput); + $template.find('.remove_scenario_override').on('click', onScenarioOverrideRemoveClick); + + await callGenericPopup($template, POPUP_TYPE.TEXT, ''); +} + +function onScenarioOverrideInput() { + const value = String($(this).val()); + chat_metadata['scenario'] = value; + saveMetadataDebounced(); +} + +function onScenarioOverrideRemoveClick() { + $(this).closest('.scenario_override').find('.chat_scenario').val('').trigger('input'); +} + +/** + * Displays a blocking popup with a given text and type. + * @param {JQuery|string|Element} text - Text to display in the popup. + * @param {string} type + * @param {string} inputValue - Value to set the input to. + * @param {PopupOptions} options - Options for the popup. + * @typedef {{okButton?: string, rows?: number, wide?: boolean, wider?: boolean, large?: boolean, allowHorizontalScrolling?: boolean, allowVerticalScrolling?: boolean, cropAspect?: number }} PopupOptions - Options for the popup. + * @returns {Promise} A promise that resolves when the popup is closed. + * @deprecated Use `callGenericPopup` instead. + */ +export function callPopup(text, type, inputValue = '', { okButton, rows, wide, wider, large, allowHorizontalScrolling, allowVerticalScrolling, cropAspect } = {}) { + function getOkButtonText() { + if (['text', 'char_not_selected'].includes(popup_type)) { + $dialoguePopupCancel.css('display', 'none'); + return okButton ?? 'Ok'; + } else if (['delete_extension'].includes(popup_type)) { + return okButton ?? 'Ok'; + } else if (['new_chat', 'confirm'].includes(popup_type)) { + return okButton ?? 'Yes'; + } else if (['input'].includes(popup_type)) { + return okButton ?? t`Save`; + } + return okButton ?? 'Delete'; + } + + dialogueCloseStop = true; + if (type) { + popup_type = type; + } + + const $dialoguePopup = $('#dialogue_popup'); + const $dialoguePopupCancel = $('#dialogue_popup_cancel'); + const $dialoguePopupOk = $('#dialogue_popup_ok'); + const $dialoguePopupInput = $('#dialogue_popup_input'); + const $dialoguePopupText = $('#dialogue_popup_text'); + const $shadowPopup = $('#shadow_popup'); + + $dialoguePopup.toggleClass('wide_dialogue_popup', !!wide) + .toggleClass('wider_dialogue_popup', !!wider) + .toggleClass('large_dialogue_popup', !!large) + .toggleClass('horizontal_scrolling_dialogue_popup', !!allowHorizontalScrolling) + .toggleClass('vertical_scrolling_dialogue_popup', !!allowVerticalScrolling); + + $dialoguePopupCancel.css('display', 'inline-block'); + $dialoguePopupOk.text(getOkButtonText()); + $dialoguePopupInput.toggle(popup_type === 'input').val(inputValue).attr('rows', rows ?? 1); + $dialoguePopupText.empty().append(text); + $shadowPopup.css('display', 'block'); + + if (popup_type == 'input') { + $dialoguePopupInput.trigger('focus'); + } + + $shadowPopup.transition({ + opacity: 1, + duration: animation_duration, + easing: animation_easing, + }); + + return new Promise((resolve) => { + dialogueResolve = resolve; + }); +} + +export function showSwipeButtons() { + if (chat.length === 0) { + return; + } + + if ( + chat[chat.length - 1].is_system || + !swipes || + Number($('.mes:last').attr('mesid')) < 0 || + chat[chat.length - 1].is_user || + chat[chat.length - 1].extra?.image || + (selected_group && is_group_generating) + ) { return; } + + // swipe_id should be set if alternate greetings are added + if (chat.length == 1 && chat[0].swipe_id === undefined) { + return; + } + + //had to add this to make the swipe counter work + //(copied from the onclick functions for swipe buttons.. + //don't know why the array isn't set for non-swipe messsages in Generate or addOneMessage..) + if (chat[chat.length - 1]['swipe_id'] === undefined) { // if there is no swipe-message in the last spot of the chat array + chat[chat.length - 1]['swipe_id'] = 0; // set it to id 0 + chat[chat.length - 1]['swipes'] = []; // empty the array + chat[chat.length - 1]['swipes'][0] = chat[chat.length - 1]['mes']; //assign swipe array with last message from chat + } + + const currentMessage = $('#chat').children().filter(`[mesid="${chat.length - 1}"]`); + const swipeId = chat[chat.length - 1].swipe_id; + const swipeCounterText = formatSwipeCounter((swipeId + 1), chat[chat.length - 1].swipes.length); + const swipeRight = currentMessage.find('.swipe_right'); + const swipeLeft = currentMessage.find('.swipe_left'); + const swipeCounter = currentMessage.find('.swipes-counter'); + + if (swipeId !== undefined && (chat[chat.length - 1].swipes.length > 1 || swipeId > 0)) { + swipeLeft.css('display', 'flex'); + } + //only show right when generate is off, or when next right swipe would not make a generate happen + if (is_send_press === false || chat[chat.length - 1].swipes.length >= swipeId) { + swipeRight.css('display', 'flex').css('opacity', '0.3'); + swipeCounter.css('opacity', '0.3'); + } + if ((chat[chat.length - 1].swipes.length - swipeId) === 1) { + //chevron was moved out of hardcode in HTML to class toggle dependent on last_mes or not + //necessary for 'swipe_right' div in past messages to have no chevron if 'show swipes for all messages' is turned on + swipeRight.css('opacity', '0.7'); + swipeCounter.css('opacity', '0.7'); + } + + //allows for writing individual swipe counters for past messages + const lastSwipeCounter = $('.last_mes .swipes-counter'); + lastSwipeCounter.text(swipeCounterText).show(); +} + +export function hideSwipeButtons() { + chatElement.find('.swipe_right').hide(); + chatElement.find('.last_mes .swipes-counter').hide(); + chatElement.find('.swipe_left').hide(); +} + +/** + * Deletes a swipe from the chat. + * + * @param {number?} swipeId - The ID of the swipe to delete. If not provided, the current swipe will be deleted. + * @returns {Promise|undefined} - The ID of the new swipe after deletion. + */ +export async function deleteSwipe(swipeId = null) { + if (swipeId && (isNaN(swipeId) || swipeId < 0)) { + toastr.warning(t`Invalid swipe ID: ${swipeId + 1}`); + return; + } + + const lastMessage = chat[chat.length - 1]; + if (!lastMessage || !Array.isArray(lastMessage.swipes) || !lastMessage.swipes.length) { + toastr.warning(t`No messages to delete swipes from.`); + return; + } + + if (lastMessage.swipes.length <= 1) { + toastr.warning(t`Can't delete the last swipe.`); + return; + } + + swipeId = swipeId ?? lastMessage.swipe_id; + + if (swipeId < 0 || swipeId >= lastMessage.swipes.length) { + toastr.warning(t`Invalid swipe ID: ${swipeId + 1}`); + return; + } + + lastMessage.swipes.splice(swipeId, 1); + + if (Array.isArray(lastMessage.swipe_info) && lastMessage.swipe_info.length) { + lastMessage.swipe_info.splice(swipeId, 1); + } + + // Select the next swipe, or the one before if it was the last one + const newSwipeId = Math.min(swipeId, lastMessage.swipes.length - 1); + syncSwipeToMes(null, newSwipeId); + + await saveChatConditional(); + await reloadCurrentChat(); + + return newSwipeId; +} + +export async function saveMetadata() { + if (selected_group) { + await editGroup(selected_group, true, false); + } + else { + await saveChatConditional(); + } +} + +export async function saveChatConditional() { + try { + await waitUntilCondition(() => !isChatSaving, DEFAULT_SAVE_EDIT_TIMEOUT, 100); + } catch { + console.warn('Timeout waiting for chat to save'); + return; + } + + try { + if (chatSaveTimeout) { + console.debug('Debounced chat save canceled'); + clearTimeout(chatSaveTimeout); + chatSaveTimeout = null; + } + + isChatSaving = true; + + if (selected_group) { + await saveGroupChat(selected_group, true); + } + else { + await saveChat(); + } + + // Save token and prompts cache to IndexedDB storage + saveTokenCache(); + saveItemizedPrompts(getCurrentChatId()); + } catch (error) { + console.error('Error saving chat', error); + } finally { + isChatSaving = false; + } +} + +/** + * Saves the chat to the server. + * @param {FormData} formData Form data to send to the server. + * @param {EventTarget} eventTarget Event target to trigger the event on. + */ +async function importCharacterChat(formData, eventTarget) { + const headers = getRequestHeaders(); + delete headers['Content-Type']; + const fetchResult = await fetch('/api/chats/import', { + method: 'POST', + body: formData, + headers: headers, + cache: 'no-cache', + }); + + if (fetchResult.ok) { + const data = await fetchResult.json(); + if (data.res) { + await displayPastChats(); + } + } + + if (eventTarget instanceof HTMLInputElement) { + eventTarget.value = ''; + } +} + +function updateViewMessageIds(startFromZero = false) { + const minId = startFromZero ? 0 : getFirstDisplayedMessageId(); + + $('#chat').find('.mes').each(function (index, element) { + $(element).attr('mesid', minId + index); + $(element).find('.mesIDDisplay').text(`#${minId + index}`); + }); + + $('#chat .mes').removeClass('last_mes'); + $('#chat .mes').last().addClass('last_mes'); + + updateEditArrowClasses(); +} + +export function getFirstDisplayedMessageId() { + const allIds = Array.from(document.querySelectorAll('#chat .mes')).map(el => Number(el.getAttribute('mesid'))).filter(x => !isNaN(x)); + const minId = Math.min(...allIds); + return minId; +} + +function updateEditArrowClasses() { + $('#chat .mes .mes_edit_up').removeClass('disabled'); + $('#chat .mes .mes_edit_down').removeClass('disabled'); + + if (this_edit_mes_id !== undefined) { + const down = $(`#chat .mes[mesid="${this_edit_mes_id}"] .mes_edit_down`); + const up = $(`#chat .mes[mesid="${this_edit_mes_id}"] .mes_edit_up`); + const lastId = Number($('#chat .mes').last().attr('mesid')); + const firstId = Number($('#chat .mes').first().attr('mesid')); + + if (lastId == Number(this_edit_mes_id)) { + down.addClass('disabled'); + } + + if (firstId == Number(this_edit_mes_id)) { + up.addClass('disabled'); + } + } +} + +/** + * Closes the message editor. + * @param {'message'|'reasoning'|'all'} what What to close. Default is 'all'. + */ +export function closeMessageEditor(what = 'all') { + if (what === 'message' || what === 'all') { + if (this_edit_mes_id) { + $(`#chat .mes[mesid="${this_edit_mes_id}"] .mes_edit_cancel`).click(); + } + } + if (what === 'reasoning' || what === 'all') { + document.querySelectorAll('.reasoning_edit_textarea').forEach((el) => { + const cancelButton = el.closest('.mes')?.querySelector('.mes_reasoning_edit_cancel'); + if (cancelButton instanceof HTMLElement) { + cancelButton.click(); + } + }); + } +} + +export function setGenerationProgress(progress) { + if (!progress) { + $('#send_textarea').css({ 'background': '', 'transition': '' }); + } + else { + $('#send_textarea').css({ + 'background': `linear-gradient(90deg, #008000d6 ${progress}%, transparent ${progress}%)`, + 'transition': '0.25s ease-in-out', + }); + } +} + +function isHordeGenerationNotAllowed() { + if (main_api == 'koboldhorde' && preset_settings == 'gui') { + toastr.error(t`GUI Settings preset is not supported for Horde. Please select another preset.`); + return true; + } + + return false; +} + +export function cancelTtsPlay() { + if ('speechSynthesis' in window) { + speechSynthesis.cancel(); + } +} + +function updateAlternateGreetingsHintVisibility(root) { + const numberOfGreetings = root.find('.alternate_greetings_list .alternate_greeting').length; + $(root).find('.alternate_grettings_hint').toggle(numberOfGreetings == 0); +} + +function openCharacterWorldPopup() { + const chid = $('#set_character_world').data('chid'); + + if (menu_type != 'create' && chid === undefined) { + toastr.error('Does not have an Id for this character in world select menu.'); + return; + } + + async function onSelectCharacterWorld() { + const value = $('.character_world_info_selector').find('option:selected').val(); + const worldIndex = value !== '' ? Number(value) : NaN; + const name = !isNaN(worldIndex) ? world_names[worldIndex] : ''; + + const previousValue = $('#character_world').val(); + $('#character_world').val(name); + + console.debug('Character world selected:', name); + + if (menu_type == 'create') { + create_save.world = name; + } else { + if (previousValue && !name) { + try { + // Dirty hack to remove embedded lorebook from character JSON data. + const data = JSON.parse(String($('#character_json_data').val())); + + if (data?.data?.character_book) { + data.data.character_book = undefined; + } + + $('#character_json_data').val(JSON.stringify(data)); + toastr.info(t`Embedded lorebook will be removed from this character.`); + } catch { + console.error('Failed to parse character JSON data.'); + } + } + + await createOrEditCharacter(); + } + + setWorldInfoButtonClass(undefined, !!value); + } + + function onExtraWorldInfoChanged() { + const selectedWorlds = $('.character_extra_world_info_selector').val(); + let charLore = world_info.charLore ?? []; + + // TODO: Maybe make this utility function not use the window context? + const fileName = getCharaFilename(chid); + const tempExtraBooks = selectedWorlds.map((index) => world_names[index]).filter((e) => e !== undefined); + + const existingCharIndex = charLore.findIndex((e) => e.name === fileName); + if (existingCharIndex === -1) { + const newCharLoreEntry = { + name: fileName, + extraBooks: tempExtraBooks, + }; + + charLore.push(newCharLoreEntry); + } else if (tempExtraBooks.length === 0) { + charLore.splice(existingCharIndex, 1); + } else { + charLore[existingCharIndex].extraBooks = tempExtraBooks; + } + + Object.assign(world_info, { charLore: charLore }); + saveSettingsDebounced(); + } + + const template = $('#character_world_template .character_world').clone(); + const select = template.find('.character_world_info_selector'); + const extraSelect = template.find('.character_extra_world_info_selector'); + const name = (menu_type == 'create' ? create_save.name : characters[chid]?.data?.name) || 'Nameless'; + const worldId = (menu_type == 'create' ? create_save.world : characters[chid]?.data?.extensions?.world) || ''; + template.find('.character_name').text(name); + + // Not needed on mobile + if (!isMobile()) { + $(extraSelect).select2({ + width: '100%', + placeholder: t`No auxillary Lorebooks set. Click here to select.`, + allowClear: true, + closeOnSelect: false, + }); + } + + // Apped to base dropdown + world_names.forEach((item, i) => { + const option = document.createElement('option'); + option.value = i; + option.innerText = item; + option.selected = item === worldId; + select.append(option); + }); + + // Append to extras dropdown + if (world_names.length > 0) { + extraSelect.empty(); + } + world_names.forEach((item, i) => { + const option = document.createElement('option'); + option.value = i; + option.innerText = item; + + const existingCharLore = world_info.charLore?.find((e) => e.name === getCharaFilename()); + if (existingCharLore) { + option.selected = existingCharLore.extraBooks.includes(item); + } else { + option.selected = false; + } + extraSelect.append(option); + }); + + select.on('change', onSelectCharacterWorld); + extraSelect.on('mousedown change', async function (e) { + // If there's no world names, don't do anything + if (world_names.length === 0) { + e.preventDefault(); + return; + } + + onExtraWorldInfoChanged(); + }); + + callPopup(template, 'text'); +} + +function openAlternateGreetings() { + const chid = $('.open_alternate_greetings').data('chid'); + + if (menu_type != 'create' && chid === undefined) { + toastr.error('Does not have an Id for this character in editor menu.'); + return; + } else { + // If the character does not have alternate greetings, create an empty array + if (characters[chid] && !Array.isArray(characters[chid].data.alternate_greetings)) { + characters[chid].data.alternate_greetings = []; + } + } + + const template = $('#alternate_greetings_template .alternate_grettings').clone(); + const getArray = () => menu_type == 'create' ? create_save.alternate_greetings : characters[chid].data.alternate_greetings; + const popup = new Popup(template, POPUP_TYPE.TEXT, '', { + wide: true, + large: true, + allowVerticalScrolling: true, + onClose: async () => { + if (menu_type !== 'create') { + await createOrEditCharacter(); + } + }, + }); + + for (let index = 0; index < getArray().length; index++) { + addAlternateGreeting(template, getArray()[index], index, getArray, popup); + } + + template.find('.add_alternate_greeting').on('click', function () { + const array = getArray(); + const index = array.length; + array.push(''); + addAlternateGreeting(template, '', index, getArray, popup); + updateAlternateGreetingsHintVisibility(template); + }); + + popup.show(); + updateAlternateGreetingsHintVisibility(template); +} + +/** + * Adds an alternate greeting to the template. + * @param {JQuery} template + * @param {string} greeting + * @param {number} index + * @param {() => any[]} getArray + * @param {Popup} popup + */ +function addAlternateGreeting(template, greeting, index, getArray, popup) { + const greetingBlock = $('#alternate_greeting_form_template .alternate_greeting').clone(); + greetingBlock.find('.alternate_greeting_text').on('input', async function () { + const value = $(this).val(); + const array = getArray(); + array[index] = value; + }).val(greeting); + greetingBlock.find('.greeting_index').text(index + 1); + greetingBlock.find('.delete_alternate_greeting').on('click', async function (event) { + event.preventDefault(); + event.stopPropagation(); + + if (confirm(t`Are you sure you want to delete this alternate greeting?`)) { + const array = getArray(); + array.splice(index, 1); + + // We need to reopen the popup to update the index numbers + await popup.complete(POPUP_RESULT.AFFIRMATIVE); + openAlternateGreetings(); + } + }); + template.find('.alternate_greetings_list').append(greetingBlock); +} + +/** + * Creates or edits a character based on the form data. + * @param {Event} [e] Event that triggered the function call. + */ +async function createOrEditCharacter(e) { + $('#rm_info_avatar').html(''); + const formData = new FormData($('#form_create').get(0)); + formData.set('fav', String(fav_ch_checked)); + const isNewChat = e instanceof CustomEvent && e.type === 'newChat'; + + const rawFile = formData.get('avatar'); + if (rawFile instanceof File) { + const convertedFile = await ensureImageFormatSupported(rawFile); + formData.set('avatar', convertedFile); + } + + const headers = getRequestHeaders(); + delete headers['Content-Type']; + + if ($('#form_create').attr('actiontype') == 'createcharacter') { + if (String($('#character_name_pole').val()).length === 0) { + toastr.error(t`Name is required`); + return; + } + if (is_group_generating || is_send_press) { + toastr.error(t`Cannot create characters while generating. Stop the request and try again.`, t`Creation aborted`); + return; + } + try { + //if the character name text area isn't empty (only posible when creating a new character) + let url = '/api/characters/create'; + + if (crop_data != undefined) { + url += `?crop=${encodeURIComponent(JSON.stringify(crop_data))}`; + } + + formData.delete('alternate_greetings'); + for (const value of create_save.alternate_greetings) { + formData.append('alternate_greetings', value); + } + + formData.append('extensions', JSON.stringify(create_save.extensions)); + + const fetchResult = await fetch(url, { + method: 'POST', + headers: headers, + body: formData, + cache: 'no-cache', + }); + + if (!fetchResult.ok) { + throw new Error('Fetch result is not ok'); + } + + const avatarId = await fetchResult.text(); + + $('#character_cross').trigger('click'); //closes the advanced character editing popup + const fields = [ + { id: '#character_name_pole', callback: value => create_save.name = value }, + { id: '#description_textarea', callback: value => create_save.description = value }, + { id: '#creator_notes_textarea', callback: value => create_save.creator_notes = value }, + { id: '#character_version_textarea', callback: value => create_save.character_version = value }, + { id: '#post_history_instructions_textarea', callback: value => create_save.post_history_instructions = value }, + { id: '#system_prompt_textarea', callback: value => create_save.system_prompt = value }, + { id: '#tags_textarea', callback: value => create_save.tags = value }, + { id: '#creator_textarea', callback: value => create_save.creator = value }, + { id: '#personality_textarea', callback: value => create_save.personality = value }, + { id: '#firstmessage_textarea', callback: value => create_save.first_message = value }, + { id: '#talkativeness_slider', callback: value => create_save.talkativeness = value, defaultValue: talkativeness_default }, + { id: '#scenario_pole', callback: value => create_save.scenario = value }, + { id: '#depth_prompt_prompt', callback: value => create_save.depth_prompt_prompt = value }, + { id: '#depth_prompt_depth', callback: value => create_save.depth_prompt_depth = value, defaultValue: depth_prompt_depth_default }, + { id: '#depth_prompt_role', callback: value => create_save.depth_prompt_role = value, defaultValue: depth_prompt_role_default }, + { id: '#mes_example_textarea', callback: value => create_save.mes_example = value }, + { id: '#character_json_data', callback: () => { } }, + { id: '#alternate_greetings_template', callback: value => create_save.alternate_greetings = value, defaultValue: [] }, + { id: '#character_world', callback: value => create_save.world = value }, + { id: '#_character_extensions_fake', callback: value => create_save.extensions = {} }, + ]; + + fields.forEach(field => { + const fieldValue = field.defaultValue !== undefined ? field.defaultValue : ''; + $(field.id).val(fieldValue); + field.callback && field.callback(fieldValue); + }); + + $('#character_popup-button-h3').text('Create character'); + + create_save.avatar = ''; + + $('#add_avatar_button').replaceWith( + $('#add_avatar_button').val('').clone(true), + ); + + let oldSelectedChar = null; + if (this_chid !== undefined) { + oldSelectedChar = characters[this_chid].avatar; + } + + console.log(`new avatar id: ${avatarId}`); + createTagMapFromList('#tagList', avatarId); + await getCharacters(); + + select_rm_info('char_create', avatarId, oldSelectedChar); + + crop_data = undefined; + + } catch (error) { + console.error('Error creating character', error); + toastr.error(t`Failed to create character`); + } + } else { + try { + let url = '/api/characters/edit'; + + if (crop_data != undefined) { + url += `?crop=${encodeURIComponent(JSON.stringify(crop_data))}`; + } + + formData.delete('alternate_greetings'); + const chid = $('.open_alternate_greetings').data('chid'); + if (characters[chid] && Array.isArray(characters[chid]?.data?.alternate_greetings)) { + for (const value of characters[chid].data.alternate_greetings) { + formData.append('alternate_greetings', value); + } + } + + const fetchResult = await fetch(url, { + method: 'POST', + headers: headers, + body: formData, + cache: 'no-cache', + }); + + if (!fetchResult.ok) { + throw new Error('Fetch result is not ok'); + } + + await getOneCharacter(formData.get('avatar_url')); + favsToHotswap(); // Update fav state + + $('#add_avatar_button').replaceWith( + $('#add_avatar_button').val('').clone(true), + ); + $('#create_button').attr('value', 'Save'); + crop_data = undefined; + await eventSource.emit(event_types.CHARACTER_EDITED, { detail: { id: this_chid, character: characters[this_chid] } }); + + // Recreate the chat if it hasn't been used at least once (i.e. with continue). + const message = getFirstMessage(); + const shouldRegenerateMessage = + !isNewChat && + message.mes && + !selected_group && + !chat_metadata['tainted'] && + (chat.length === 0 || (chat.length === 1 && !chat[0].is_user && !chat[0].is_system)); + + if (shouldRegenerateMessage) { + chat.splice(0, chat.length, message); + const messageId = (chat.length - 1); + await eventSource.emit(event_types.MESSAGE_RECEIVED, messageId, 'first_message'); + await clearChat(); + await printMessages(); + await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, messageId, 'first_message'); + await saveChatConditional(); + } + } catch (error) { + console.log(error); + toastr.error(t`Something went wrong while saving the character, or the image file provided was in an invalid format. Double check that the image is not a webp.`); + } + } +} + +/** + * Formats a counter for a swipe view. + * @param {number} current The current number of items. + * @param {number} total The total number of items. + * @returns {string} The formatted counter. + */ +function formatSwipeCounter(current, total) { + if (isNaN(current) || isNaN(total)) { + return ''; + } + + return `${current}\u200b/\u200b${total}`; +} + +/** + * Handles the swipe to the left event. + * @param {JQuery.Event} _event Event. + * @param {object} params Additional parameters. + * @param {string} [params.source] The source of the swipe event. + * @param {boolean} [params.repeated] Is the swipe event repeated. + */ +function swipe_left(_event, { source, repeated } = {}) { + if (chat.length - 1 === Number(this_edit_mes_id)) { + closeMessageEditor(); + } + if (isStreamingEnabled() && streamingProcessor) { + streamingProcessor.onStopStreaming(); + } + + // Make sure ad-hoc changes to extras are saved before swiping away + syncMesToSwipe(); + + // If the user is holding down the key and we're at the first swipe, don't do anything + if (source === 'keyboard' && repeated && chat[chat.length - 1].swipe_id === 0) { + return; + } + + const swipe_duration = 120; + const swipe_range = '700px'; + chat[chat.length - 1]['swipe_id']--; + + if (chat[chat.length - 1]['swipe_id'] < 0) { + chat[chat.length - 1]['swipe_id'] = chat[chat.length - 1]['swipes'].length - 1; + } + + if (chat[chat.length - 1]['swipe_id'] >= 0) { + /*$(this).parent().children('swipe_right').css('display', 'flex'); + if (chat[chat.length - 1]['swipe_id'] === 0) { + $(this).css('display', 'none'); + }*/ // Just in case + if (!Array.isArray(chat[chat.length - 1]['swipe_info'])) { + chat[chat.length - 1]['swipe_info'] = []; + } + let this_mes_div = $(this).parent(); + let this_mes_block = $(this).parent().children('.mes_block').children('.mes_text'); + const this_mes_div_height = this_mes_div[0].scrollHeight; + this_mes_div.css('height', this_mes_div_height); + const this_mes_block_height = this_mes_block[0].scrollHeight; + chat[chat.length - 1]['mes'] = chat[chat.length - 1]['swipes'][chat[chat.length - 1]['swipe_id']]; + chat[chat.length - 1]['send_date'] = chat[chat.length - 1].swipe_info[chat[chat.length - 1]['swipe_id']]?.send_date || chat[chat.length - 1].send_date; //load the last mes box with the latest generation + chat[chat.length - 1]['extra'] = JSON.parse(JSON.stringify(chat[chat.length - 1].swipe_info[chat[chat.length - 1]['swipe_id']]?.extra || chat[chat.length - 1].extra)); + + if (chat[chat.length - 1].extra) { + // if message has memory attached - remove it to allow regen + if (chat[chat.length - 1].extra.memory) { + delete chat[chat.length - 1].extra.memory; + } + // ditto for display text + if (chat[chat.length - 1].extra.display_text) { + delete chat[chat.length - 1].extra.display_text; + } + } + $(this).parent().children('.mes_block').transition({ + x: swipe_range, + duration: animation_duration > 0 ? swipe_duration : 0, + easing: animation_easing, + queue: false, + complete: async function () { + const is_animation_scroll = ($('#chat').scrollTop() >= ($('#chat').prop('scrollHeight') - $('#chat').outerHeight()) - 10); + //console.log('on left swipe click calling addOneMessage'); + addOneMessage(chat[chat.length - 1], { type: 'swipe' }); + + if (power_user.message_token_count_enabled) { + if (!chat[chat.length - 1].extra) { + chat[chat.length - 1].extra = {}; + } + + const swipeMessage = $('#chat').find(`[mesid="${chat.length - 1}"]`); + const tokenCountText = (chat[chat.length - 1]?.extra?.reasoning || '') + chat[chat.length - 1].mes; + const tokenCount = await getTokenCountAsync(tokenCountText, 0); + chat[chat.length - 1]['extra']['token_count'] = tokenCount; + swipeMessage.find('.tokenCounterDisplay').text(`${tokenCount}t`); + } + + let new_height = this_mes_div_height - (this_mes_block_height - this_mes_block[0].scrollHeight); + if (new_height < 103) new_height = 103; + this_mes_div.animate({ height: new_height + 'px' }, { + duration: 0, //used to be 100 + queue: false, + progress: function () { + // Scroll the chat down as the message expands + + if (is_animation_scroll) $('#chat').scrollTop($('#chat')[0].scrollHeight); + }, + complete: function () { + this_mes_div.css('height', 'auto'); + // Scroll the chat down to the bottom once the animation is complete + if (is_animation_scroll) $('#chat').scrollTop($('#chat')[0].scrollHeight); + }, + }); + $(this).parent().children('.mes_block').transition({ + x: '-' + swipe_range, + duration: 0, + easing: animation_easing, + queue: false, + complete: function () { + $(this).parent().children('.mes_block').transition({ + x: '0px', + duration: animation_duration > 0 ? swipe_duration : 0, + easing: animation_easing, + queue: false, + complete: async function () { + await eventSource.emit(event_types.MESSAGE_SWIPED, (chat.length - 1)); + saveChatDebounced(); + }, + }); + }, + }); + }, + }); + + $(this).parent().children('.avatar').transition({ + x: swipe_range, + duration: animation_duration > 0 ? swipe_duration : 0, + easing: animation_easing, + queue: false, + complete: function () { + $(this).parent().children('.avatar').transition({ + x: '-' + swipe_range, + duration: 0, + easing: animation_easing, + queue: false, + complete: function () { + $(this).parent().children('.avatar').transition({ + x: '0px', + duration: animation_duration > 0 ? swipe_duration : 0, + easing: animation_easing, + queue: false, + complete: function () { + + }, + }); + }, + }); + }, + }); + } + if (chat[chat.length - 1]['swipe_id'] < 0) { + chat[chat.length - 1]['swipe_id'] = 0; + } +} + +/** + * Handles the swipe to the right event. + * @param {JQuery.Event} _event Event. + * @param {object} params Additional parameters. + * @param {string} [params.source] The source of the swipe event. + * @param {boolean} [params.repeated] Is the swipe event repeated. + */ +function swipe_right(_event, { source, repeated } = {}) { + if (chat.length - 1 === Number(this_edit_mes_id)) { + closeMessageEditor(); + } + + if (isHordeGenerationNotAllowed()) { + return unblockGeneration(); + } + + // Make sure ad-hoc changes to extras are saved before swiping away + syncMesToSwipe(); + + const swipe_duration = 200; + const swipe_range = 700; + //console.log(swipe_range); + let run_generate = false; + let run_swipe_right = false; + if (chat[chat.length - 1]['swipe_id'] === undefined) { // if there is no swipe-message in the last spot of the chat array + chat[chat.length - 1]['swipe_id'] = 0; // set it to id 0 + chat[chat.length - 1]['swipes'] = []; // empty the array + chat[chat.length - 1]['swipe_info'] = []; + chat[chat.length - 1]['swipes'][0] = chat[chat.length - 1]['mes']; //assign swipe array with last message from chat + chat[chat.length - 1]['swipe_info'][0] = { + 'send_date': chat[chat.length - 1]['send_date'], + 'gen_started': chat[chat.length - 1]['gen_started'], + 'gen_finished': chat[chat.length - 1]['gen_finished'], + 'extra': JSON.parse(JSON.stringify(chat[chat.length - 1]['extra'])), + }; + //assign swipe info array with last message from chat + } + if (chat.length === 1 && chat[0]['swipe_id'] !== undefined && chat[0]['swipe_id'] === chat[0]['swipes'].length - 1) { // if swipe_right is called on the last alternate greeting, loop back around + chat[0]['swipe_id'] = 0; + } else { + // If the user is holding down the key and we're at the last swipe, don't do anything + if (source === 'keyboard' && repeated && chat[chat.length - 1].swipe_id === chat[chat.length - 1].swipes.length - 1) { + return; + } + chat[chat.length - 1]['swipe_id']++; // make new slot in array + } + if (chat[chat.length - 1].extra) { + // if message has memory attached - remove it to allow regen + if (chat[chat.length - 1].extra.memory) { + delete chat[chat.length - 1].extra.memory; + } + // ditto for display text + if (chat[chat.length - 1].extra.display_text) { + delete chat[chat.length - 1].extra.display_text; + } + } + if (!Array.isArray(chat[chat.length - 1]['swipe_info'])) { + chat[chat.length - 1]['swipe_info'] = []; + } + //console.log(chat[chat.length-1]['swipes']); + if (parseInt(chat[chat.length - 1]['swipe_id']) === chat[chat.length - 1]['swipes'].length && chat.length !== 1) { //if swipe id of last message is the same as the length of the 'swipes' array and not the greeting + delete chat[chat.length - 1].gen_started; + delete chat[chat.length - 1].gen_finished; + run_generate = true; + } else if (parseInt(chat[chat.length - 1]['swipe_id']) < chat[chat.length - 1]['swipes'].length) { //otherwise, if the id is less than the number of swipes + chat[chat.length - 1]['mes'] = chat[chat.length - 1]['swipes'][chat[chat.length - 1]['swipe_id']]; //load the last mes box with the latest generation + chat[chat.length - 1]['send_date'] = chat[chat.length - 1]?.swipe_info[chat[chat.length - 1]['swipe_id']]?.send_date || chat[chat.length - 1]['send_date']; //update send date + chat[chat.length - 1]['extra'] = JSON.parse(JSON.stringify(chat[chat.length - 1].swipe_info[chat[chat.length - 1]['swipe_id']]?.extra || chat[chat.length - 1].extra || [])); + run_swipe_right = true; //then prepare to do normal right swipe to show next message + } + + const currentMessage = $('#chat').children().filter(`[mesid="${chat.length - 1}"]`); + let this_div = currentMessage.find('.swipe_right'); + let this_mes_div = this_div.parent().parent(); + + if (chat[chat.length - 1]['swipe_id'] > chat[chat.length - 1]['swipes'].length) { //if we swipe right while generating (the swipe ID is greater than what we are viewing now) + chat[chat.length - 1]['swipe_id'] = chat[chat.length - 1]['swipes'].length; //show that message slot (will be '...' while generating) + } + if (run_generate) { //hide swipe arrows while generating + this_div.css('display', 'none'); + } + // handles animated transitions when swipe right, specifically height transitions between messages + if (run_generate || run_swipe_right) { + let this_mes_block = this_mes_div.find('.mes_block .mes_text'); + const this_mes_div_height = this_mes_div[0].scrollHeight; + const this_mes_block_height = this_mes_block[0].scrollHeight; + + this_mes_div.children('.swipe_left').css('display', 'flex'); + this_mes_div.children('.mes_block').transition({ // this moves the div back and forth + x: '-' + swipe_range, + duration: animation_duration > 0 ? swipe_duration : 0, + easing: animation_easing, + queue: false, + complete: async function () { + const is_animation_scroll = ($('#chat').scrollTop() >= ($('#chat').prop('scrollHeight') - $('#chat').outerHeight()) - 10); + //console.log(parseInt(chat[chat.length-1]['swipe_id'])); + //console.log(chat[chat.length-1]['swipes'].length); + const swipeMessage = $('#chat').find('[mesid="' + (chat.length - 1) + '"]'); + if (run_generate && parseInt(chat[chat.length - 1]['swipe_id']) === chat[chat.length - 1]['swipes'].length) { + //shows "..." while generating + swipeMessage.find('.mes_text').html('...'); + // resets the timer + swipeMessage.find('.mes_timer').html(''); + swipeMessage.find('.tokenCounterDisplay').text(''); + updateReasoningUI(swipeMessage, { reset: true }); + } else { + //console.log('showing previously generated swipe candidate, or "..."'); + //console.log('onclick right swipe calling addOneMessage'); + addOneMessage(chat[chat.length - 1], { type: 'swipe' }); + + if (power_user.message_token_count_enabled) { + if (!chat[chat.length - 1].extra) { + chat[chat.length - 1].extra = {}; + } + + const tokenCountText = (chat[chat.length - 1]?.extra?.reasoning || '') + chat[chat.length - 1].mes; + const tokenCount = await getTokenCountAsync(tokenCountText, 0); + chat[chat.length - 1]['extra']['token_count'] = tokenCount; + swipeMessage.find('.tokenCounterDisplay').text(`${tokenCount}t`); + } + } + let new_height = this_mes_div_height - (this_mes_block_height - this_mes_block[0].scrollHeight); + if (new_height < 103) new_height = 103; + + + this_mes_div.animate({ height: new_height + 'px' }, { + duration: 0, //used to be 100 + queue: false, + progress: function () { + // Scroll the chat down as the message expands + if (is_animation_scroll) $('#chat').scrollTop($('#chat')[0].scrollHeight); + }, + complete: function () { + this_mes_div.css('height', 'auto'); + // Scroll the chat down to the bottom once the animation is complete + if (is_animation_scroll) $('#chat').scrollTop($('#chat')[0].scrollHeight); + }, + }); + this_mes_div.children('.mes_block').transition({ + x: swipe_range, + duration: 0, + easing: animation_easing, + queue: false, + complete: function () { + this_mes_div.children('.mes_block').transition({ + x: '0px', + duration: animation_duration > 0 ? swipe_duration : 0, + easing: animation_easing, + queue: false, + complete: async function () { + await eventSource.emit(event_types.MESSAGE_SWIPED, (chat.length - 1)); + if (run_generate && !is_send_press && parseInt(chat[chat.length - 1]['swipe_id']) === chat[chat.length - 1]['swipes'].length) { + console.debug('caught here 2'); + is_send_press = true; + await Generate('swipe'); + } else { + if (parseInt(chat[chat.length - 1]['swipe_id']) !== chat[chat.length - 1]['swipes'].length) { + saveChatDebounced(); + } + } + }, + }); + }, + }); + }, + }); + this_mes_div.children('.avatar').transition({ // moves avatar along with swipe + x: '-' + swipe_range, + duration: animation_duration > 0 ? swipe_duration : 0, + easing: animation_easing, + queue: false, + complete: function () { + this_mes_div.children('.avatar').transition({ + x: swipe_range, + duration: 0, + easing: animation_easing, + queue: false, + complete: function () { + this_mes_div.children('.avatar').transition({ + x: '0px', + duration: animation_duration > 0 ? swipe_duration : 0, + easing: animation_easing, + queue: false, + complete: function () { + + }, + }); + }, + }); + }, + }); + } +} + +export const CONNECT_API_MAP = { + // Default APIs not contined inside text gen / chat gen + 'kobold': { + selected: 'kobold', + button: '#api_button', + }, + 'horde': { + selected: 'koboldhorde', + }, + 'novel': { + selected: 'novel', + button: '#api_button_novel', + }, + 'koboldcpp': { + selected: 'textgenerationwebui', + button: '#api_button_textgenerationwebui', + type: textgen_types.KOBOLDCPP, + }, + // KoboldCpp alias + 'kcpp': { + selected: 'textgenerationwebui', + button: '#api_button_textgenerationwebui', + type: textgen_types.KOBOLDCPP, + }, + 'openai': { + selected: 'openai', + button: '#api_button_openai', + source: chat_completion_sources.OPENAI, + }, + // OpenAI alias + 'oai': { + selected: 'openai', + button: '#api_button_openai', + source: chat_completion_sources.OPENAI, + }, + // Google alias + 'google': { + selected: 'openai', + button: '#api_button_openai', + source: chat_completion_sources.MAKERSUITE, + }, + // OpenRouter special naming, to differentiate between chat comp and text comp + 'openrouter': { + selected: 'openai', + button: '#api_button_openai', + source: chat_completion_sources.OPENROUTER, + }, + 'openrouter-text': { + selected: 'textgenerationwebui', + button: '#api_button_textgenerationwebui', + type: textgen_types.OPENROUTER, + }, +}; + +// Collect all unique API names in an array +export const UNIQUE_APIS = [...new Set(Object.values(CONNECT_API_MAP).map(x => x.selected))]; + +// Fill connections map from textgen_types and chat_completion_sources +for (const textGenType of Object.values(textgen_types)) { + if (CONNECT_API_MAP[textGenType]) continue; + CONNECT_API_MAP[textGenType] = { + selected: 'textgenerationwebui', + button: '#api_button_textgenerationwebui', + type: textGenType, + }; +} +for (const chatCompletionSource of Object.values(chat_completion_sources)) { + if (CONNECT_API_MAP[chatCompletionSource]) continue; + CONNECT_API_MAP[chatCompletionSource] = { + selected: 'openai', + button: '#api_button_openai', + source: chatCompletionSource, + }; +} + +async function selectContextCallback(args, name) { + if (!name) { + return power_user.context.preset; + } + + const quiet = isTrueBoolean(args?.quiet); + const contextNames = context_presets.map(preset => preset.name); + const fuse = new Fuse(contextNames); + const result = fuse.search(name); + + if (result.length === 0) { + !quiet && toastr.warning(t`Context template '${name}' not found`); + return ''; + } + + const foundName = result[0].item; + selectContextPreset(foundName, { quiet: quiet }); + return foundName; +} + +async function selectInstructCallback(args, name) { + if (!name) { + return power_user.instruct.enabled || isTrueBoolean(args?.forceGet) ? power_user.instruct.preset : ''; + } + + const quiet = isTrueBoolean(args?.quiet); + const instructNames = instruct_presets.map(preset => preset.name); + const fuse = new Fuse(instructNames); + const result = fuse.search(name); + + if (result.length === 0) { + !quiet && toastr.warning(t`Instruct template '${name}' not found`); + return ''; + } + + const foundName = result[0].item; + selectInstructPreset(foundName, { quiet: quiet }); + return foundName; +} + +async function enableInstructCallback() { + $('#instruct_enabled').prop('checked', true).trigger('input').trigger('change'); + return ''; +} + +async function disableInstructCallback() { + $('#instruct_enabled').prop('checked', false).trigger('input').trigger('change'); + return ''; +} + +/** + * @param {string} text API name + */ +async function connectAPISlash(args, text) { + if (!text.trim()) { + for (const [key, config] of Object.entries(CONNECT_API_MAP)) { + if (config.selected !== main_api) continue; + + if (config.source) { + if (oai_settings.chat_completion_source === config.source) { + return key; + } else { + continue; + } + } + + if (config.type) { + if (textgen_settings.type === config.type) { + return key; + } else { + continue; + } + } + + return key; + } + + console.error('FIXME: The current API is not in the API map'); + return ''; + } + + const apiConfig = CONNECT_API_MAP[text.toLowerCase()]; + if (!apiConfig) { + toastr.error(t`Error: ${text} is not a valid API`); + return ''; + } + + let connectionRequired = false; + + if (main_api !== apiConfig.selected) { + $(`#main_api option[value='${apiConfig.selected || text}']`).prop('selected', true); + $('#main_api').trigger('change'); + connectionRequired = true; + } + + if (apiConfig.source && oai_settings.chat_completion_source !== apiConfig.source) { + $(`#chat_completion_source option[value='${apiConfig.source}']`).prop('selected', true); + $('#chat_completion_source').trigger('change'); + connectionRequired = true; + } + + if (apiConfig.type && textgen_settings.type !== apiConfig.type) { + $(`#textgen_type option[value='${apiConfig.type}']`).prop('selected', true); + $('#textgen_type').trigger('change'); + connectionRequired = true; + } + + if (connectionRequired && apiConfig.button) { + $(apiConfig.button).trigger('click'); + } + + const quiet = isTrueBoolean(args?.quiet); + const toast = quiet ? jQuery() : toastr.info(t`API set to ${text}, trying to connect..`); + + try { + if (connectionRequired) { + await waitUntilCondition(() => online_status !== 'no_connection', 5000, 100); + } + console.log('Connection successful'); + } catch { + console.log('Could not connect after 5 seconds, skipping.'); + } + + toastr.clear(toast); + return text; +} + +/** + * Imports supported files dropped into the app window. + * @param {File[]} files Array of files to process + * @param {Map} [data] Extra data to pass to the import function + * @returns {Promise} + */ +export async function processDroppedFiles(files, data = new Map()) { + const allowedMimeTypes = [ + 'application/json', + 'image/png', + 'application/yaml', + 'application/x-yaml', + 'text/yaml', + 'text/x-yaml', + ]; + + const allowedExtensions = [ + 'charx', + ]; + + const avatarFileNames = []; + for (const file of files) { + const extension = file.name.split('.').pop().toLowerCase(); + if (allowedMimeTypes.some(x => file.type.startsWith(x)) || allowedExtensions.includes(extension)) { + const preservedName = data instanceof Map && data.get(file); + const avatarFileName = await importCharacter(file, { preserveFileName: preservedName }); + if (avatarFileName !== undefined) { + avatarFileNames.push(avatarFileName); + } + } else { + toastr.warning(t`Unsupported file type: ` + file.name); + } + } + + if (avatarFileNames.length > 0) { + await importCharactersTags(avatarFileNames); + selectImportedChar(avatarFileNames[avatarFileNames.length - 1]); + } +} + +/** + * Imports tags for the given characters + * @param {string[]} avatarFileNames character avatar filenames whose tags are to import + */ +async function importCharactersTags(avatarFileNames) { + await getCharacters(); + for (let i = 0; i < avatarFileNames.length; i++) { + if (power_user.tag_import_setting !== tag_import_setting.NONE) { + const importedCharacter = characters.find(character => character.avatar === avatarFileNames[i]); + await importTags(importedCharacter); + } + } +} + +/** + * Selects the given imported char + * @param {string} charId char to select + */ +function selectImportedChar(charId) { + let oldSelectedChar = null; + if (this_chid !== undefined) { + oldSelectedChar = characters[this_chid].avatar; + } + select_rm_info('char_import_no_toast', charId, oldSelectedChar); +} + +/** + * Imports a character from a file. + * @param {File} file File to import + * @param {object} [options] - Options + * @param {string} [options.preserveFileName] Whether to preserve original file name + * @param {Boolean} [options.importTags=false] Whether to import tags + * @returns {Promise} + */ +async function importCharacter(file, { preserveFileName = '', importTags = false } = {}) { + if (is_group_generating || is_send_press) { + toastr.error(t`Cannot import characters while generating. Stop the request and try again.`, t`Import aborted`); + throw new Error('Cannot import character while generating'); + } + + const ext = file.name.match(/\.(\w+)$/); + if (!ext || !(['json', 'png', 'yaml', 'yml', 'charx'].includes(ext[1].toLowerCase()))) { + return; + } + + const format = ext[1].toLowerCase(); + $('#character_import_file_type').val(format); + const formData = new FormData(); + formData.append('avatar', file); + formData.append('file_type', format); + if (preserveFileName) formData.append('preserved_name', preserveFileName); + + const data = await jQuery.ajax({ + type: 'POST', + url: '/api/characters/import', + data: formData, + async: true, + cache: false, + contentType: false, + processData: false, + }); + + if (data.error) { + toastr.error(t`The file is likely invalid or corrupted.`, t`Could not import character`); + return; + } + + if (data.file_name !== undefined) { + $('#character_search_bar').val('').trigger('input'); + + toastr.success(t`Character Created: ${String(data.file_name).replace('.png', '')}`); + let avatarFileName = `${data.file_name}.png`; + if (importTags) { + await importCharactersTags([avatarFileName]); + + selectImportedChar(data.file_name); + } + return avatarFileName; + } +} + +async function importFromURL(items, files) { + for (const item of items) { + if (item.type === 'text/uri-list') { + const uriList = await new Promise((resolve) => { + item.getAsString((uriList) => { resolve(uriList); }); + }); + const uris = uriList.split('\n').filter(uri => uri.trim() !== ''); + try { + for (const uri of uris) { + const request = await fetch(uri); + const data = await request.blob(); + const fileName = request.headers.get('Content-Disposition')?.split('filename=')[1]?.replace(/"/g, '') || uri.split('/').pop() || 'file.png'; + const file = new File([data], fileName, { type: data.type }); + files.push(file); + } + } catch (error) { + console.error('Failed to import from URL', error); + } + } + } +} + +async function doImpersonate(args, prompt) { + const options = prompt?.trim() ? { quiet_prompt: prompt.trim(), quietToLoud: true } : {}; + const shouldAwait = isTrueBoolean(args?.await); + const outerPromise = new Promise((outerResolve) => setTimeout(async () => { + try { + await waitUntilCondition(() => !is_send_press && !is_group_generating, 10000, 100); + } catch { + console.warn('Timeout waiting for generation unlock'); + toastr.warning(t`Cannot run /impersonate command while the reply is being generated.`); + return ''; + } + + // Prevent generate recursion + $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles: true })); + + outerResolve(new Promise(innerResolve => setTimeout(() => innerResolve(Generate('impersonate', options)), 1))); + }, 1)); + + if (shouldAwait) { + const innerPromise = await outerPromise; + await innerPromise; + } + + return ''; +} + +export async function doNewChat({ deleteCurrentChat = false } = {}) { + //Make a new chat for selected character + if ((!selected_group && this_chid == undefined) || menu_type == 'create') { + return; + } + + //Fix it; New chat doesn't create while open create character menu + await clearChat(); + chat.length = 0; + + chat_file_for_del = getCurrentChatDetails()?.sessionName; + + // Make it easier to find in backups + if (deleteCurrentChat) { + await saveChatConditional(); + } + + if (selected_group) { + await createNewGroupChat(selected_group); + if (deleteCurrentChat) await deleteGroupChat(selected_group, chat_file_for_del); + } + else { + //RossAscends: added character name to new chat filenames and replaced Date.now() with humanizedDateTime; + chat_metadata = {}; + characters[this_chid].chat = `${name2} - ${humanizedDateTime()}`; + $('#selected_chat_pole').val(characters[this_chid].chat); + await getChat(); + await createOrEditCharacter(new CustomEvent('newChat')); + if (deleteCurrentChat) await delChat(chat_file_for_del + '.jsonl'); + } + +} + +async function doDeleteChat() { + await displayPastChats(); + let currentChatDeleteButton = $('.select_chat_block[highlight=\'true\']').parent().find('.PastChat_cross'); + $(currentChatDeleteButton).trigger('click'); + await delay(1); + $('#dialogue_popup_ok').trigger('click', { fromSlashCommand: true }); + return ''; +} + +async function doRenameChat(_, chatName) { + if (!chatName) { + toastr.warning(t`Name must be provided as an argument to rename this chat.`); + return ''; + } + + const currentChatName = getCurrentChatId(); + if (!currentChatName) { + toastr.warning(t`No chat selected that can be renamed.`); + return ''; + } + + await renameChat(currentChatName, chatName); + + toastr.success(t`Successfully renamed chat to: ${chatName}`); + return ''; +} + +/** + * Renames the currently selected chat. + * @param {string} oldFileName Old name of the chat (no JSONL extension) + * @param {string} newName New name for the chat (no JSONL extension) + */ +export async function renameChat(oldFileName, newName) { + const body = { + is_group: !!selected_group, + avatar_url: characters[this_chid]?.avatar, + original_file: `${oldFileName}.jsonl`, + renamed_file: `${newName.trim()}.jsonl`, + }; + + try { + showLoader(); + const response = await fetch('/api/chats/rename', { + method: 'POST', + body: JSON.stringify(body), + headers: getRequestHeaders(), + }); + + if (!response.ok) { + throw new Error('Unsuccessful request.'); + } + + const data = await response.json(); + + if (data.error) { + throw new Error('Server returned an error.'); + } + + if (data.sanitizedFileName) { + newName = data.sanitizedFileName; + } + + if (selected_group) { + await renameGroupChat(selected_group, oldFileName, newName); + } + else { + if (characters[this_chid].chat == oldFileName) { + characters[this_chid].chat = newName; + $('#selected_chat_pole').val(characters[this_chid].chat); + await createOrEditCharacter(); + } + } + + await reloadCurrentChat(); + } catch { + hideLoader(); + await delay(500); + await callPopup('An error has occurred. Chat was not renamed.', 'text'); + } finally { + hideLoader(); + } +} + +/** + * /getchatname` slash command + */ +async function doGetChatName() { + return getCurrentChatDetails().sessionName; +} + +const isPwaMode = window.navigator.standalone; +if (isPwaMode) { $('body').addClass('PWA'); } + +function doCharListDisplaySwitch() { + power_user.charListGrid = !power_user.charListGrid; + document.body.classList.toggle('charListGrid', power_user.charListGrid); + saveSettingsDebounced(); +} + +function doCloseChat() { + $('#option_close_chat').trigger('click'); + return ''; +} + +/** + * Function to handle the deletion of a character, given a specific popup type and character ID. + * If popup type equals "del_ch", it will proceed with deletion otherwise it will exit the function. + * It fetches the delete character route, sending necessary parameters, and in case of success, + * it proceeds to delete character from UI and saves settings. + * In case of error during the fetch request, it logs the error details. + * + * @param {string} this_chid - The character ID to be deleted. + * @param {boolean} delete_chats - Whether to delete chats or not. + */ +export async function handleDeleteCharacter(this_chid, delete_chats) { + if (!characters[this_chid]) { + return; + } + + await deleteCharacter(characters[this_chid].avatar, { deleteChats: delete_chats }); +} + +/** + * Deletes a character completely, including associated chats if specified + * + * @param {string|string[]} characterKey - The key (avatar) of the character to be deleted + * @param {Object} [options] - Optional parameters for the deletion + * @param {boolean} [options.deleteChats=true] - Whether to delete associated chats or not + * @return {Promise} - A promise that resolves when the character is successfully deleted + */ +export async function deleteCharacter(characterKey, { deleteChats = true } = {}) { + if (!Array.isArray(characterKey)) { + characterKey = [characterKey]; + } + + for (const key of characterKey) { + const character = characters.find(x => x.avatar == key); + if (!character) { + toastr.warning(t`Character ${key} not found. Skipping deletion.`); + continue; + } + + const chid = characters.indexOf(character); + const pastChats = await getPastCharacterChats(chid); + + const msg = { avatar_url: character.avatar, delete_chats: deleteChats }; + + const response = await fetch('/api/characters/delete', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify(msg), + cache: 'no-cache', + }); + + if (!response.ok) { + toastr.error(`${response.status} ${response.statusText}`, t`Failed to delete character`); + continue; + } + + accountStorage.removeItem(`AlertWI_${character.avatar}`); + accountStorage.removeItem(`AlertRegex_${character.avatar}`); + accountStorage.removeItem(`mediaWarningShown:${character.avatar}`); + delete tag_map[character.avatar]; + select_rm_info('char_delete', character.name); + + if (deleteChats) { + for (const chat of pastChats) { + const name = chat.file_name.replace('.jsonl', ''); + await eventSource.emit(event_types.CHAT_DELETED, name); + } + } + + await eventSource.emit(event_types.CHARACTER_DELETED, { id: chid, character: character }); + } + + await removeCharacterFromUI(); +} + +/** + * Function to delete a character from UI after character deletion API success. + * It manages necessary UI changes such as closing advanced editing popup, unsetting + * character ID, resetting characters array and chat metadata, deselecting character's tab + * panel, removing character name from navigation tabs, clearing chat, fetching updated list of characters. + * It also ensures to save the settings after all the operations. + */ +async function removeCharacterFromUI() { + preserveNeutralChat(); + await clearChat(); + $('#character_cross').trigger('click'); + resetChatState(); + $(document.getElementById('rm_button_selected_ch')).children('h2').text(''); + restoreNeutralChat(); + await getCharacters(); + await printMessages(); + saveSettingsDebounced(); +} + +async function newAssistantChat() { + await clearChat(); + chat.splice(0, chat.length); + chat_metadata = {}; + setCharacterName(neutralCharacterName); + sendSystemMessage(system_message_types.ASSISTANT_NOTE); +} + +function doTogglePanels() { + $('#option_settings').trigger('click'); + return ''; +} + +/** + * Event handler to open a navbar drawer when a drawer open button is clicked. + * Handles click events on .drawer-opener elements. + * Opens the drawer associated with the clicked button according to the data-target attribute. + * @returns {void} + */ +function doDrawerOpenClick() { + const targetDrawerID = $(this).attr('data-target'); + const drawer = $(`#${targetDrawerID}`); + const drawerToggle = drawer.find('.drawer-toggle'); + const drawerWasOpenAlready = drawerToggle.parent().find('.drawer-content').hasClass('openDrawer'); + if (drawerWasOpenAlready || drawer.hasClass('resizing')) { return; } + doNavbarIconClick.call(drawerToggle); +} + +/** + * Event handler to open or close a navbar drawer when a navbar icon is clicked. + * Handles click events on .drawer-toggle elements. + * @returns {void} + */ +function doNavbarIconClick() { + const icon = $(this).find('.drawer-icon'); + const drawer = $(this).parent().find('.drawer-content'); + if (drawer.hasClass('resizing')) { return; } + const drawerWasOpenAlready = $(this).parent().find('.drawer-content').hasClass('openDrawer'); + const targetDrawerID = $(this).parent().find('.drawer-content').attr('id'); + const pinnedDrawerClicked = drawer.hasClass('pinnedOpen'); + + if (!drawerWasOpenAlready) { //to open the drawer + $('.openDrawer').not('.pinnedOpen').addClass('resizing').each((_, el) => { + slideToggle(el, { + ...getSlideToggleOptions(), + onAnimationEnd: function (el) { + el.closest('.drawer-content').classList.remove('resizing'); + }, + }); + }); + $('.openIcon').not('.drawerPinnedOpen').toggleClass('closedIcon openIcon'); + $('.openDrawer').not('.pinnedOpen').toggleClass('closedDrawer openDrawer'); + icon.toggleClass('openIcon closedIcon'); + drawer.toggleClass('openDrawer closedDrawer'); + + //console.log(targetDrawerID); + if (targetDrawerID === 'right-nav-panel') { + $(this).closest('.drawer').find('.drawer-content').addClass('resizing').each((_, el) => { + slideToggle(el, { + ...getSlideToggleOptions(), + elementDisplayStyle: 'flex', + onAnimationEnd: function (el) { + el.closest('.drawer-content').classList.remove('resizing'); + favsToHotswap(); + $('#rm_print_characters_block').trigger('scroll'); + }, + }); + }); + } else { + $(this).closest('.drawer').find('.drawer-content').addClass('resizing').each((_, el) => { + slideToggle(el, { + ...getSlideToggleOptions(), + onAnimationEnd: function (el) { + el.closest('.drawer-content').classList.remove('resizing'); + }, + }); + }); + } + + // Set the height of "autoSetHeight" textareas within the drawer to their scroll height + if (!CSS.supports('field-sizing', 'content')) { + $(this).closest('.drawer').find('.drawer-content textarea.autoSetHeight').each(async function () { + await resetScrollHeight($(this)); + return; + }); + } + + } else if (drawerWasOpenAlready) { //to close manually + icon.toggleClass('closedIcon openIcon'); + + if (pinnedDrawerClicked) { + $(drawer).addClass('resizing').each((_, el) => { + slideToggle(el, { + ...getSlideToggleOptions(), + onAnimationEnd: function (el) { + el.classList.remove('resizing'); + }, + }); + }); + } + else { + $('.openDrawer').not('.pinnedOpen').addClass('resizing').each((_, el) => { + slideToggle(el, { + ...getSlideToggleOptions(), + onAnimationEnd: function (el) { + el.closest('.drawer-content').classList.remove('resizing'); + }, + }); + }); + } + + drawer.toggleClass('closedDrawer openDrawer'); + } +} + +function addDebugFunctions() { + const doBackfill = async () => { + for (const message of chat) { + // System messages are not counted + if (message.is_system) { + continue; + } + + if (!message.extra) { + message.extra = {}; + } + + const tokenCountText = (message?.extra?.reasoning || '') + message.mes; + message.extra.token_count = await getTokenCountAsync(tokenCountText, 0); + } + + await saveChatConditional(); + await reloadCurrentChat(); + }; + + registerDebugFunction('forceOnboarding', 'Force onboarding', 'Forces the onboarding process to restart.', async () => { + firstRun = true; + await saveSettings(); + location.reload(); + }); + + registerDebugFunction('backfillTokenCounts', 'Backfill token counters', + `Recalculates token counts of all messages in the current chat to refresh the counters. + Useful when you switch between models that have different tokenizers. + This is a visual change only. Your chat will be reloaded.`, doBackfill); + + registerDebugFunction('generationTest', 'Send a generation request', 'Generates text using the currently selected API.', async () => { + const text = prompt('Input text:', 'Hello'); + toastr.info('Working on it...'); + const message = await generateRaw(text, null, false, false); + alert(message); + }); + + registerDebugFunction('clearPrompts', 'Delete itemized prompts', 'Deletes all itemized prompts from the local storage.', async () => { + await clearItemizedPrompts(); + toastr.info('Itemized prompts deleted.'); + if (getCurrentChatId()) { + await reloadCurrentChat(); + } + }); + + registerDebugFunction('toggleEventTracing', 'Toggle event tracing', 'Useful to see what triggered a certain event.', () => { + localStorage.setItem('eventTracing', localStorage.getItem('eventTracing') === 'true' ? 'false' : 'true'); + toastr.info('Event tracing is now ' + (localStorage.getItem('eventTracing') === 'true' ? 'enabled' : 'disabled')); + }); + + registerDebugFunction('toggleRegenerateWarning', 'Toggle Ctrl+Enter regeneration confirmation', 'Toggle the warning when regenerating a message with a Ctrl+Enter hotkey.', () => { + accountStorage.setItem('RegenerateWithCtrlEnter', accountStorage.getItem('RegenerateWithCtrlEnter') === 'true' ? 'false' : 'true'); + toastr.info('Regenerate warning is now ' + (accountStorage.getItem('RegenerateWithCtrlEnter') === 'true' ? 'disabled' : 'enabled')); + }); + + registerDebugFunction('copySetup', 'Copy ST setup to clipboard [WIP]', 'Useful data when reporting bugs', async () => { + const getContextContents = getContext(); + const getSettingsContents = settings; + //console.log(getSettingsContents); + const logMessage = ` +\`\`\` +API: ${getSettingsContents.main_api} +API Type: ${getSettingsContents[getSettingsContents.main_api + '_settings'].type} +API server: ${getSettingsContents.api_server} +Model: ${getContextContents.onlineStatus} +Context Template: ${power_user.context.preset} +Instruct Template: ${power_user.instruct.preset} +API Settings: ${JSON.stringify(getSettingsContents[getSettingsContents.main_api + '_settings'], null, 2)} +\`\`\` + `; + + //console.log(getSettingsContents) + //console.log(logMessage); + + try { + await copyText(logMessage); + toastr.info('Your ST API setup data has been copied to the clipboard.'); + } catch (error) { + toastr.error('Failed to copy ST Setup to clipboard:', error); + } + }); +} + +jQuery(async function () { + async function doForceSave() { + await saveSettings(); + await saveChatConditional(); + toastr.success('Chat and settings saved.'); + return ''; + } + + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'dupe', + callback: duplicateCharacter, + helpString: 'Duplicates the currently selected character.', + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'api', + callback: connectAPISlash, + returns: 'the current API', + namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'quiet', + description: 'Suppress the toast message on connection', + typeList: [ARGUMENT_TYPE.BOOLEAN], + defaultValue: 'false', + enumList: commonEnumProviders.boolean('trueFalse')(), + }), + ], + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'API to connect to', + typeList: [ARGUMENT_TYPE.STRING], + enumList: Object.entries(CONNECT_API_MAP).map(([api, { selected }]) => + new SlashCommandEnumValue(api, selected, enumTypes.getBasedOnIndex(UNIQUE_APIS.findIndex(x => x === selected)), + selected[0].toUpperCase() ?? enumIcons.default)), + }), + ], + helpString: ` +
      + Connect to an API. If no argument is provided, it will return the currently connected API. +
      +
      + Available APIs: +
      ${Object.keys(CONNECT_API_MAP).join(', ')}
      +
      + `, + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'impersonate', + callback: doImpersonate, + aliases: ['imp'], + namedArgumentList: [ + new SlashCommandNamedArgument( + 'await', + 'Whether to await for the triggered generation before continuing', + [ARGUMENT_TYPE.BOOLEAN], + false, + false, + 'false', + ), + ], + unnamedArgumentList: [ + new SlashCommandArgument( + 'prompt', [ARGUMENT_TYPE.STRING], false, + ), + ], + helpString: ` +
      + Calls an impersonation response, with an optional additional prompt. +
      +
      + If await=true named argument is passed, the command will wait for the impersonation to end before continuing. +
      +
      + Example: +
        +
      • +
        /impersonate What is the meaning of life?
        +
      • +
      +
      + `, + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'delchat', + callback: doDeleteChat, + helpString: 'Deletes the current chat.', + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'renamechat', + callback: doRenameChat, + unnamedArgumentList: [ + new SlashCommandArgument( + 'new chat name', [ARGUMENT_TYPE.STRING], true, + ), + ], + helpString: 'Renames the current chat.', + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'getchatname', + callback: doGetChatName, + returns: 'chat file name', + helpString: 'Returns the name of the current chat file into the pipe.', + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'closechat', + callback: doCloseChat, + helpString: 'Closes the current chat.', + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'tempchat', + callback: () => { + return new Promise((resolve, reject) => { + const eventCallback = async (chatId) => { + if (chatId) { + return reject('Not in a temporary chat'); + } + await newAssistantChat(); + return resolve(''); + }; + eventSource.once(event_types.CHAT_CHANGED, eventCallback); + doCloseChat(); + setTimeout(() => { + reject('Failed to open temporary chat'); + eventSource.removeListener(event_types.CHAT_CHANGED, eventCallback); + }, debounce_timeout.relaxed); + }); + }, + helpString: 'Opens a temporary chat with Assistant.', + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'panels', + callback: doTogglePanels, + aliases: ['togglepanels'], + helpString: 'Toggle UI panels on/off', + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'forcesave', + callback: doForceSave, + helpString: 'Forces a save of the current chat and settings', + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'instruct', + callback: selectInstructCallback, + returns: 'current template', + namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'quiet', + description: 'Suppress the toast message on template change', + typeList: [ARGUMENT_TYPE.BOOLEAN], + defaultValue: 'false', + enumList: commonEnumProviders.boolean('trueFalse')(), + }), + SlashCommandNamedArgument.fromProps({ + name: 'forceGet', + description: 'Force getting a name even if instruct mode is disabled', + typeList: [ARGUMENT_TYPE.BOOLEAN], + defaultValue: 'false', + enumList: commonEnumProviders.boolean('trueFalse')(), + }), + ], + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'instruct template name', + typeList: [ARGUMENT_TYPE.STRING], + enumProvider: () => instruct_presets.map(preset => new SlashCommandEnumValue(preset.name, null, enumTypes.enum, enumIcons.preset)), + }), + ], + helpString: ` +
      + Selects instruct mode template by name. Enables instruct mode if not already enabled. + Gets the current instruct template if no name is provided and instruct mode is enabled or forceGet=true is passed. +
      +
      + Example: +
        +
      • +
        /instruct creative
        +
      • +
      +
      + `, + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'instruct-on', + callback: enableInstructCallback, + helpString: 'Enables instruct mode.', + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'instruct-off', + callback: disableInstructCallback, + helpString: 'Disables instruct mode', + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'instruct-state', + aliases: ['instruct-toggle'], + helpString: 'Gets the current instruct mode state. If an argument is provided, it will set the instruct mode state.', + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'instruct mode state', + typeList: [ARGUMENT_TYPE.BOOLEAN], + enumList: commonEnumProviders.boolean('trueFalse')(), + }), + ], + callback: async (_args, state) => { + if (!state || typeof state !== 'string') { + return String(power_user.instruct.enabled); + } + + const newState = isTrueBoolean(state); + newState ? enableInstructCallback() : disableInstructCallback(); + return String(power_user.instruct.enabled); + }, + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'context', + callback: selectContextCallback, + returns: 'template name', + namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'quiet', + description: 'Suppress the toast message on template change', + typeList: [ARGUMENT_TYPE.BOOLEAN], + defaultValue: 'false', + enumList: commonEnumProviders.boolean('trueFalse')(), + }), + ], + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'context template name', + typeList: [ARGUMENT_TYPE.STRING], + enumProvider: () => context_presets.map(preset => new SlashCommandEnumValue(preset.name, null, enumTypes.enum, enumIcons.preset)), + }), + ], + helpString: 'Selects context template by name. Gets the current template if no name is provided', + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'chat-manager', + callback: () => { + $('#option_select_chat').trigger('click'); + return ''; + }, + aliases: ['chat-history', 'manage-chats'], + helpString: 'Opens the chat manager for the current character/group.', + })); + + setTimeout(function () { + $('#groupControlsToggle').trigger('click'); + $('#groupCurrentMemberListToggle .inline-drawer-icon').trigger('click'); + }, 200); + + $(document).on('click', '.api_loading', () => cancelStatusCheck('Canceled because connecting was manually canceled')); + + //////////INPUT BAR FOCUS-KEEPING LOGIC///////////// + let S_TAPreviouslyFocused = false; + $('#send_textarea').on('focusin focus click', () => { + S_TAPreviouslyFocused = true; + }); + $('#send_but, #option_regenerate, #option_continue, #mes_continue, #mes_impersonate').on('click', () => { + if (S_TAPreviouslyFocused) { + $('#send_textarea').focus(); + } + }); + $(document).click(event => { + if ($(':focus').attr('id') !== 'send_textarea') { + var validIDs = ['options_button', 'send_but', 'mes_impersonate', 'mes_continue', 'send_textarea', 'option_regenerate', 'option_continue']; + if (!validIDs.includes($(event.target).attr('id'))) { + S_TAPreviouslyFocused = false; + } + } else { + S_TAPreviouslyFocused = true; + } + }); + + ///////////////// + + $('#swipes-checkbox').change(function () { + swipes = !!$('#swipes-checkbox').prop('checked'); + if (swipes) { + //console.log('toggle change calling showswipebtns'); + showSwipeButtons(); + } else { + hideSwipeButtons(); + } + saveSettingsDebounced(); + }); + + ///// SWIPE BUTTON CLICKS /////// + + //limit swiping to only last message clicks + $(document).on('click', '.last_mes .swipe_right', swipe_right); + $(document).on('click', '.last_mes .swipe_left', swipe_left); + + const debouncedCharacterSearch = debounce((searchQuery) => { + entitiesFilter.setFilterData(FILTER_TYPES.SEARCH, searchQuery); + }); + $('#character_search_bar').on('input', function () { + const searchQuery = String($(this).val()); + debouncedCharacterSearch(searchQuery); + }); + + $('#mes_impersonate').on('click', function () { + $('#option_impersonate').trigger('click'); + }); + + $('#mes_continue').on('click', function () { + $('#option_continue').trigger('click'); + }); + + $('#send_but').on('click', function () { + sendTextareaMessage(); + }); + + //menu buttons setup + + $('#rm_button_settings').click(function () { + selected_button = 'settings'; + selectRightMenuWithAnimation('rm_api_block'); + }); + $('#rm_button_characters').click(function () { + selected_button = 'characters'; + select_rm_characters(); + }); + $('#rm_button_back').click(function () { + selected_button = 'characters'; + select_rm_characters(); + }); + $('#rm_button_create').click(function () { + selected_button = 'create'; + select_rm_create(); + }); + $('#rm_button_selected_ch').click(function () { + if (selected_group) { + select_group_chats(selected_group); + } else { + selected_button = 'character_edit'; + select_selected_character(this_chid); + } + $('#character_search_bar').val('').trigger('input'); + }); + + $(document).on('click', '.character_select', async function () { + const id = Number($(this).attr('data-chid')); + await selectCharacterById(id); + }); + + $(document).on('click', '.bogus_folder_select', function () { + const tagId = $(this).attr('tagid'); + console.debug('Bogus folder clicked', tagId); + chooseBogusFolder($(this), tagId); + }); + + const cssAutofit = CSS.supports('field-sizing', 'content'); + if (!cssAutofit) { + /** + * Sets the scroll height of the edit textarea to fit the content. + * @param {HTMLTextAreaElement} e Textarea element to auto-fit + */ + function autoFitEditTextArea(e) { + const scrollTop = chatElement.scrollTop(); + e.style.height = '0px'; + const newHeight = e.scrollHeight + 4; + e.style.height = `${newHeight}px`; + chatElement.scrollTop(scrollTop); + } + const autoFitEditTextAreaDebounced = debounce(autoFitEditTextArea, debounce_timeout.short); + document.addEventListener('input', e => { + if (e.target instanceof HTMLTextAreaElement && e.target.classList.contains('edit_textarea')) { + const scrollbarShown = e.target.clientWidth < e.target.offsetWidth && e.target.offsetHeight >= window.innerHeight * 0.75; + const immediately = (e.target.scrollHeight > e.target.offsetHeight && !scrollbarShown) || e.target.value === ''; + immediately ? autoFitEditTextArea(e.target) : autoFitEditTextAreaDebounced(e.target); + } + }); + } + + const chatElementScroll = document.getElementById('chat'); + const chatScrollHandler = function () { + if (power_user.waifuMode) { + scrollLock = true; + return; + } + + const scrollIsAtBottom = Math.abs(chatElementScroll.scrollHeight - chatElementScroll.clientHeight - chatElementScroll.scrollTop) < 1; + + // Resume autoscroll if the user scrolls to the bottom + if (scrollLock && scrollIsAtBottom) { + scrollLock = false; + } + + // Cancel autoscroll if the user scrolls up + if (!scrollLock && !scrollIsAtBottom) { + scrollLock = true; + } + }; + chatElementScroll.addEventListener('wheel', chatScrollHandler, { passive: true }); + chatElementScroll.addEventListener('touchmove', chatScrollHandler, { passive: true }); + + $(document).on('click', '.mes', function () { + //when a 'delete message' parent div is clicked + // and we are in delete mode and del_checkbox is visible + if (!is_delete_mode || !$(this).children('.del_checkbox').is(':visible')) { + return; + } + $('.mes').children('.del_checkbox').each(function () { + $(this).prop('checked', false); + $(this).parent().removeClass('selected'); + }); + $(this).addClass('selected'); //sets the bg of the mes selected for deletion + var i = Number($(this).attr('mesid')); //checks the message ID in the chat + this_del_mes = i; + //as long as the current message ID is less than the total chat length + while (i < chat.length) { + //sets the bg of the all msgs BELOW the selected .mes + $(`.mes[mesid="${i}"]`).addClass('selected'); + $(`.mes[mesid="${i}"]`).children('.del_checkbox').prop('checked', true); + i++; + } + }); + + $(document).on('click', '.PastChat_cross', function (e) { + e.stopPropagation(); + chat_file_for_del = $(this).attr('file_name'); + console.debug('detected cross click for' + chat_file_for_del); + callPopup('

      Delete the Chat File?

      ', 'del_chat'); + }); + + $('#advanced_div').click(function () { + if (!is_advanced_char_open) { + is_advanced_char_open = true; + $('#character_popup').css({ 'display': 'flex', 'opacity': 0.0 }).addClass('open'); + $('#character_popup').transition({ + opacity: 1.0, + duration: animation_duration, + easing: animation_easing, + }); + } else { + is_advanced_char_open = false; + $('#character_popup').css('display', 'none').removeClass('open'); + } + }); + + $('#character_cross').click(function () { + is_advanced_char_open = false; + $('#character_popup').transition({ + opacity: 0, + duration: animation_duration, + easing: animation_easing, + }); + setTimeout(function () { $('#character_popup').css('display', 'none'); }, animation_duration); + }); + + $('#character_popup_ok').click(function () { + is_advanced_char_open = false; + $('#character_popup').css('display', 'none'); + }); + + $('#dialogue_popup_ok').click(async function (e, customData) { + const fromSlashCommand = customData?.fromSlashCommand || false; + dialogueCloseStop = false; + $('#shadow_popup').transition({ + opacity: 0, + duration: animation_duration, + easing: animation_easing, + }); + setTimeout(function () { + if (dialogueCloseStop) return; + $('#shadow_popup').css('display', 'none'); + $('#dialogue_popup').removeClass('large_dialogue_popup'); + $('#dialogue_popup').removeClass('wide_dialogue_popup'); + }, animation_duration); + + if (popup_type == 'del_chat') { + //close past chat popup + $('#select_chat_cross').trigger('click'); + showLoader(); + if (selected_group) { + await deleteGroupChat(selected_group, chat_file_for_del); + } else { + await delChat(chat_file_for_del); + } + + if (fromSlashCommand) { // When called from `/delchat` command, don't re-open the history view. + $('#options').hide(); // hide option popup menu + hideLoader(); + } else { // Open the history view again after 2 seconds (delay to avoid edge cases for deleting last chat). + setTimeout(function () { + $('#option_select_chat').click(); + $('#options').hide(); // hide option popup menu + hideLoader(); + }, 2000); + } + } + + if (dialogueResolve) { + if (popup_type == 'input') { + dialogueResolve($('#dialogue_popup_input').val()); + $('#dialogue_popup_input').val(''); + + } + else { + dialogueResolve(true); + + } + + dialogueResolve = null; + } + }); + + $('#dialogue_popup_cancel').click(function (e) { + dialogueCloseStop = false; + $('#shadow_popup').transition({ + opacity: 0, + duration: animation_duration, + easing: animation_easing, + }); + setTimeout(function () { + if (dialogueCloseStop) return; + $('#shadow_popup').css('display', 'none'); + $('#dialogue_popup').removeClass('large_dialogue_popup'); + }, animation_duration); + + //$("#shadow_popup").css("opacity:", 0.0); + popup_type = ''; + + if (dialogueResolve) { + dialogueResolve(false); + dialogueResolve = null; + } + + }); + + $('#add_avatar_button').change(function () { + read_avatar_load(this); + }); + + $('#form_create').submit(createOrEditCharacter); + + $('#delete_button').on('click', async function () { + if (this_chid === undefined || !characters[this_chid]) { + toastr.warning('No character selected.'); + return; + } + + let deleteChats = false; + + const confirm = await Popup.show.confirm(t`Delete the character?`, await renderTemplateAsync('deleteConfirm'), { + onClose: () => deleteChats = !!$('#del_char_checkbox').prop('checked'), + }); + if (!confirm) { + return; + } + + await deleteCharacter(characters[this_chid].avatar, { deleteChats: deleteChats }); + }); + + //////// OPTIMIZED ALL CHAR CREATION/EDITING TEXTAREA LISTENERS /////////////// + + $('#character_name_pole').on('input', function () { + if (menu_type == 'create') { + create_save.name = String($('#character_name_pole').val()); + } + }); + + const elementsToUpdate = { + '#description_textarea': function () { create_save.description = String($('#description_textarea').val()); }, + '#creator_notes_textarea': function () { create_save.creator_notes = String($('#creator_notes_textarea').val()); }, + '#character_version_textarea': function () { create_save.character_version = String($('#character_version_textarea').val()); }, + '#system_prompt_textarea': function () { create_save.system_prompt = String($('#system_prompt_textarea').val()); }, + '#post_history_instructions_textarea': function () { create_save.post_history_instructions = String($('#post_history_instructions_textarea').val()); }, + '#creator_textarea': function () { create_save.creator = String($('#creator_textarea').val()); }, + '#tags_textarea': function () { create_save.tags = String($('#tags_textarea').val()); }, + '#personality_textarea': function () { create_save.personality = String($('#personality_textarea').val()); }, + '#scenario_pole': function () { create_save.scenario = String($('#scenario_pole').val()); }, + '#mes_example_textarea': function () { create_save.mes_example = String($('#mes_example_textarea').val()); }, + '#firstmessage_textarea': function () { create_save.first_message = String($('#firstmessage_textarea').val()); }, + '#talkativeness_slider': function () { create_save.talkativeness = Number($('#talkativeness_slider').val()); }, + '#depth_prompt_prompt': function () { create_save.depth_prompt_prompt = String($('#depth_prompt_prompt').val()); }, + '#depth_prompt_depth': function () { create_save.depth_prompt_depth = Number($('#depth_prompt_depth').val()); }, + '#depth_prompt_role': function () { create_save.depth_prompt_role = String($('#depth_prompt_role').val()); }, + }; + + Object.keys(elementsToUpdate).forEach(function (id) { + $(id).on('input', function () { + if (menu_type == 'create') { + elementsToUpdate[id](); + } else { + saveCharacterDebounced(); + } + }); + }); + + $('#favorite_button').on('click', function () { + updateFavButtonState(!fav_ch_checked); + if (menu_type != 'create') { + saveCharacterDebounced(); + } + }); + + /* $("#renameCharButton").on('click', renameCharacter); */ + + $(document).on('click', '.renameChatButton', async function (e) { + e.stopPropagation(); + const oldFileNameFull = $(this).closest('.select_chat_block_wrapper').find('.select_chat_block_filename').text(); + const oldFileName = oldFileNameFull.replace('.jsonl', ''); + + const popupText = await renderTemplateAsync('chatRename'); + const newName = await callPopup(popupText, 'input', oldFileName); + + if (!newName || newName == oldFileName) { + console.log('no new name found, aborting'); + return; + } + + await renameChat(oldFileName, newName); + + await delay(250); + $('#option_select_chat').trigger('click'); + $('#options').hide(); + }); + + $(document).on('click', '.exportChatButton, .exportRawChatButton', async function (e) { + e.stopPropagation(); + const format = $(this).data('format') || 'txt'; + await saveChatConditional(); + const filenamefull = $(this).closest('.select_chat_block_wrapper').find('.select_chat_block_filename').text(); + console.log(`exporting ${filenamefull} in ${format} format`); + + const filename = filenamefull.replace('.jsonl', ''); + const body = { + is_group: !!selected_group, + avatar_url: characters[this_chid]?.avatar, + file: `${filename}.jsonl`, + exportfilename: `${filename}.${format}`, + format: format, + }; + console.log(body); + try { + const response = await fetch('/api/chats/export', { + method: 'POST', + body: JSON.stringify(body), + headers: getRequestHeaders(), + }); + const data = await response.json(); + if (!response.ok) { + // display error message + console.log(data.message); + await delay(250); + toastr.error(`Error: ${data.message}`); + return; + } else { + const mimeType = format == 'txt' ? 'text/plain' : 'application/octet-stream'; + // success, handle response data + console.log(data); + await delay(250); + toastr.success(data.message); + download(data.result, body.exportfilename, mimeType); + } + } catch (error) { + // display error message + console.log(`An error has occurred: ${error.message}`); + await delay(250); + toastr.error(`Error: ${error.message}`); + } + }); + + /////////////////////////////////////////////////////////////////////////////////// + + $('#api_button').click(function (e) { + if ($('#api_url_text').val() != '') { + let value = formatKoboldUrl(String($('#api_url_text').val()).trim()); + + if (!value) { + toastr.error('Please enter a valid URL.'); + return; + } + + $('#api_url_text').val(value); + api_server = value; + startStatusLoading(); + + main_api = 'kobold'; + saveSettingsDebounced(); + getStatusKobold(); + } + }); + + $('#api_button_textgenerationwebui').on('click', async function (e) { + const keys = [ + { id: 'api_key_mancer', secret: SECRET_KEYS.MANCER }, + { id: 'api_key_vllm', secret: SECRET_KEYS.VLLM }, + { id: 'api_key_aphrodite', secret: SECRET_KEYS.APHRODITE }, + { id: 'api_key_tabby', secret: SECRET_KEYS.TABBY }, + { id: 'api_key_togetherai', secret: SECRET_KEYS.TOGETHERAI }, + { id: 'api_key_ooba', secret: SECRET_KEYS.OOBA }, + { id: 'api_key_infermaticai', secret: SECRET_KEYS.INFERMATICAI }, + { id: 'api_key_dreamgen', secret: SECRET_KEYS.DREAMGEN }, + { id: 'api_key_openrouter-tg', secret: SECRET_KEYS.OPENROUTER }, + { id: 'api_key_koboldcpp', secret: SECRET_KEYS.KOBOLDCPP }, + { id: 'api_key_llamacpp', secret: SECRET_KEYS.LLAMACPP }, + { id: 'api_key_featherless', secret: SECRET_KEYS.FEATHERLESS }, + { id: 'api_key_huggingface', secret: SECRET_KEYS.HUGGINGFACE }, + { id: 'api_key_generic', secret: SECRET_KEYS.GENERIC }, + ]; + + for (const key of keys) { + const keyValue = String($(`#${key.id}`).val()).trim(); + if (keyValue.length) { + await writeSecret(key.secret, keyValue); + } + } + + validateTextGenUrl(); + startStatusLoading(); + main_api = 'textgenerationwebui'; + saveSettingsDebounced(); + getStatusTextgen(); + }); + + $('#api_button_novel').on('click', async function (e) { + e.stopPropagation(); + const api_key_novel = String($('#api_key_novel').val()).trim(); + + if (api_key_novel.length) { + await writeSecret(SECRET_KEYS.NOVEL, api_key_novel); + } + + if (!secret_state[SECRET_KEYS.NOVEL]) { + console.log('No secret key saved for NovelAI'); + return; + } + + startStatusLoading(); + // Check near immediately rather than waiting for up to 90s + await getStatusNovel(); + }); + + const button = $('#options_button'); + const menu = $('#options'); + let isOptionsMenuVisible = false; + + function showMenu() { + showBookmarksButtons(); + menu.fadeIn(animation_duration); + optionsPopper.update(); + isOptionsMenuVisible = true; + } + + function hideMenu() { + menu.fadeOut(animation_duration); + optionsPopper.update(); + isOptionsMenuVisible = false; + } + + function isMouseOverButtonOrMenu() { + return menu.is(':hover, :focus-within') || button.is(':hover, :focus'); + } + + button.on('click', function () { + if (isOptionsMenuVisible) { + hideMenu(); + } else { + showMenu(); + } + }); + $(document).on('click', function () { + if (!isOptionsMenuVisible) return; + if (!isMouseOverButtonOrMenu()) { hideMenu(); } + }); + + /* $('#set_chat_scenario').on('click', setScenarioOverride); */ + + ///////////// OPTIMIZED LISTENERS FOR LEFT SIDE OPTIONS POPUP MENU ////////////////////// + $('#options [id]').on('click', async function (event, customData) { + const fromSlashCommand = customData?.fromSlashCommand || false; + var id = $(this).attr('id'); + + // Check whether a custom prompt was provided via custom data (for example through a slash command) + const additionalPrompt = customData?.additionalPrompt?.trim() || undefined; + const buildOrFillAdditionalArgs = (args = {}) => ({ + ...args, + ...(additionalPrompt !== undefined && { quiet_prompt: additionalPrompt, quietToLoud: true }), + }); + + if (id == 'option_select_chat') { + if ((selected_group && !is_group_generating) || (this_chid !== undefined && !is_send_press) || fromSlashCommand) { + await displayPastChats(); + //this is just to avoid the shadow for past chat view when using /delchat + //however, the dialog popup still gets one.. + if (!fromSlashCommand) { + console.log('displaying shadow'); + $('#shadow_select_chat_popup').css('display', 'block'); + $('#shadow_select_chat_popup').css('opacity', 0.0); + $('#shadow_select_chat_popup').transition({ + opacity: 1.0, + duration: animation_duration, + easing: animation_easing, + }); + } + } + } + + else if (id == 'option_start_new_chat') { + if ((selected_group || this_chid !== undefined) && !is_send_press) { + let deleteCurrentChat = false; + const result = await Popup.show.confirm(t`Start new chat?`, await renderTemplateAsync('newChatConfirm'), { + onClose: () => deleteCurrentChat = !!$('#del_chat_checkbox').prop('checked'), + }); + if (!result) { + return; + } + + await doNewChat({ deleteCurrentChat: deleteCurrentChat }); + } + if (!selected_group && this_chid === undefined && !is_send_press) { + await newAssistantChat(); + } + } + + else if (id == 'option_regenerate') { + closeMessageEditor(); + if (is_send_press == false) { + //hideSwipeButtons(); + + if (selected_group) { + regenerateGroup(); + } + else { + is_send_press = true; + Generate('regenerate', buildOrFillAdditionalArgs()); + } + } + } + + else if (id == 'option_impersonate') { + if (is_send_press == false || fromSlashCommand) { + is_send_press = true; + Generate('impersonate', buildOrFillAdditionalArgs()); + } + } + + else if (id == 'option_continue') { + if (this_edit_mes_id) return; // don't proceed if editing a message + + if (is_send_press == false || fromSlashCommand) { + is_send_press = true; + Generate('continue', buildOrFillAdditionalArgs()); + } + } + + else if (id == 'option_delete_mes') { + setTimeout(() => openMessageDelete(fromSlashCommand), animation_duration); + } + + else if (id == 'option_close_chat') { + if (is_send_press == false) { + await clearChat(); + chat.length = 0; + resetSelectedGroup(); + setCharacterId(undefined); + setCharacterName(''); + setActiveCharacter(null); + setActiveGroup(null); + this_edit_mes_id = undefined; + chat_metadata = {}; + selected_button = 'characters'; + $('#rm_button_selected_ch').children('h2').text(''); + select_rm_characters(); + sendSystemMessage(system_message_types.WELCOME); + sendSystemMessage(system_message_types.WELCOME_PROMPT); + await getClientVersion(); + await eventSource.emit(event_types.CHAT_CHANGED, getCurrentChatId()); + } else { + toastr.info('Please stop the message generation first.'); + } + } + + else if (id === 'option_settings') { + //var checkBox = document.getElementById("waifuMode"); + var topBar = document.getElementById('top-bar'); + var topSettingsHolder = document.getElementById('top-settings-holder'); + var divchat = document.getElementById('chat'); + + //if (checkBox.checked) { + if (topBar.style.display === 'none') { + topBar.style.display = ''; // or "inline-block" if that's the original display value + topSettingsHolder.style.display = ''; // or "inline-block" if that's the original display value + + divchat.style.borderRadius = ''; + divchat.style.backgroundColor = ''; + + } else { + + divchat.style.borderRadius = '10px'; // Adjust the value to control the roundness of the corners + divchat.style.backgroundColor = ''; // Set the background color to your preference + + topBar.style.display = 'none'; + topSettingsHolder.style.display = 'none'; + } + //} + } + hideMenu(); + }); + + $('#newChatFromManageScreenButton').on('click', async function () { + await doNewChat({ deleteCurrentChat: false }); + $('#select_chat_cross').trigger('click'); + }); + + ////////////////////////////////////////////////////////////////////////////////////////////// + + //functionality for the cancel delete messages button, reverts to normal display of input form + $('#dialogue_del_mes_cancel').click(function () { + $('#dialogue_del_mes').css('display', 'none'); + $('#send_form').css('display', css_send_form_display); + $('.del_checkbox').each(function () { + $(this).css('display', 'none'); + $(this).parent().children('.for_checkbox').css('display', 'block'); + $(this).parent().removeClass('selected'); + $(this).prop('checked', false); + }); + showSwipeButtons(); + this_del_mes = -1; + is_delete_mode = false; + }); + + //confirms message deletion with the "ok" button + $('#dialogue_del_mes_ok').on('click', async function () { + $('#dialogue_del_mes').css('display', 'none'); + $('#send_form').css('display', css_send_form_display); + $('.del_checkbox').each(function () { + $(this).css('display', 'none'); + $(this).parent().children('.for_checkbox').css('display', 'block'); + $(this).parent().removeClass('selected'); + $(this).prop('checked', false); + }); + + if (this_del_mes >= 0) { + $(`.mes[mesid="${this_del_mes}"]`).nextAll('div').remove(); + $(`.mes[mesid="${this_del_mes}"]`).remove(); + chat.length = this_del_mes; + await saveChatConditional(); + chatElement.scrollTop(chatElement[0].scrollHeight); + await eventSource.emit(event_types.MESSAGE_DELETED, chat.length); + $('#chat .mes').removeClass('last_mes'); + $('#chat .mes').last().addClass('last_mes'); + } else { + console.log('this_del_mes is not >= 0, not deleting'); + } + + showSwipeButtons(); + this_del_mes = -1; + is_delete_mode = false; + }); + + $('#settings_preset').change(function () { + if ($('#settings_preset').find(':selected').val() != 'gui') { + preset_settings = $('#settings_preset').find(':selected').text(); + const preset = koboldai_settings[koboldai_setting_names[preset_settings]]; + loadKoboldSettings(preset); + setGenerationParamsFromPreset(preset); + $('#kobold_api-settings').find('input').prop('disabled', false); + $('#kobold_api-settings').css('opacity', 1.0); + $('#kobold_order') + .css('opacity', 1) + .sortable('enable'); + } else { + //$('.button').disableSelection(); + preset_settings = 'gui'; + + $('#kobold_api-settings').find('input').prop('disabled', true); + $('#kobold_api-settings').css('opacity', 0.5); + + $('#kobold_order') + .css('opacity', 0.5) + .sortable('disable'); + } + saveSettingsDebounced(); + }); + + $('#settings_preset_novel').change(function () { + nai_settings.preset_settings_novel = $('#settings_preset_novel') + .find(':selected') + .text(); + + const preset = novelai_settings[novelai_setting_names[nai_settings.preset_settings_novel]]; + loadNovelPreset(preset); + amount_gen = Number($('#amount_gen').val()); + max_context = Number($('#max_context').val()); + + saveSettingsDebounced(); + }); + + $('#main_api').change(function () { + cancelStatusCheck('Canceled because main api changed'); + changeMainAPI(); + saveSettingsDebounced(); + }); + + ////////////////// OPTIMIZED RANGE SLIDER LISTENERS//////////////// + + var sliderLocked = true; + var sliderTimer; + + $('input[type=\'range\']').on('touchstart', function () { + // Unlock the slider after 300ms + setTimeout(function () { + sliderLocked = false; + $(this).css('background-color', 'var(--SmartThemeQuoteColor)'); + }.bind(this), 300); + }); + + $('input[type=\'range\']').on('touchend', function () { + clearTimeout(sliderTimer); + $(this).css('background-color', ''); + sliderLocked = true; + }); + + $('input[type=\'range\']').on('touchmove', function (event) { + if (sliderLocked) { + event.preventDefault(); + } + }); + + const sliders = [ + { + sliderId: '#amount_gen', + counterId: '#amount_gen_counter', + format: (val) => `${val}`, + setValue: (val) => { amount_gen = Number(val); }, + }, + { + sliderId: '#max_context', + counterId: '#max_context_counter', + format: (val) => `${val}`, + setValue: (val) => { max_context = Number(val); }, + }, + ]; + + sliders.forEach(slider => { + $(document).on('input', slider.sliderId, function () { + const value = $(this).val(); + const formattedValue = slider.format(value); + slider.setValue(value); + $(slider.counterId).val(formattedValue); + saveSettingsDebounced(); + }); + }); + + ////////////////////////////////////////////////////////////// + + $('#select_chat_cross').click(function () { + $('#shadow_select_chat_popup').transition({ + opacity: 0, + duration: animation_duration, + easing: animation_easing, + }); + setTimeout(function () { $('#shadow_select_chat_popup').css('display', 'none'); }, animation_duration); + }); + + $(document).on('pointerup', '.mes_copy', async function () { + if (this_chid !== undefined || selected_group || name2 === neutralCharacterName) { + try { + const messageId = $(this).closest('.mes').attr('mesid'); + const text = chat[messageId]['mes']; + await copyText(text); + toastr.info('Copied!', '', { timeOut: 2000 }); + } catch (err) { + console.error('Failed to copy: ', err); + } + } + }); + + $(document).on('pointerup', '.mes_prompt', async function () { + let mesIdForItemization = $(this).closest('.mes').attr('mesId'); + console.log(`looking for mesID: ${mesIdForItemization}`); + if (itemizedPrompts.length !== undefined && itemizedPrompts.length !== 0) { + await promptItemize(itemizedPrompts, mesIdForItemization); + } + }); + + //******************** + //***Message Editor*** + $(document).on('click', '.mes_edit', async function () { + if (this_chid !== undefined || selected_group || name2 === neutralCharacterName) { + // Previously system messages we're allowed to be edited + /*const message = $(this).closest(".mes"); + + if (message.data("isSystem")) { + return; + }*/ + + let chatScrollPosition = $('#chat').scrollTop(); + if (this_edit_mes_id !== undefined) { + let mes_edited = $(`#chat [mesid="${this_edit_mes_id}"]`).find('.mes_edit_done'); + if (Number(edit_mes_id) == chat.length - 1) { //if the generating swipe (...) + let run_edit = true; + if (chat[edit_mes_id]['swipe_id'] !== undefined) { + if (chat[edit_mes_id]['swipes'].length === chat[edit_mes_id]['swipe_id']) { + run_edit = false; + } + } + if (run_edit) { + hideSwipeButtons(); + } + } + await messageEditDone(mes_edited); + } + $(this).closest('.mes_block').find('.mes_text').empty(); + $(this).closest('.mes_block').find('.mes_buttons').css('display', 'none'); + $(this).closest('.mes_block').find('.mes_edit_buttons').css('display', 'inline-flex'); + var edit_mes_id = $(this).closest('.mes').attr('mesid'); + this_edit_mes_id = edit_mes_id; + + // Also edit reasoning, if it exists + const reasoningEdit = $(this).closest('.mes_block').find('.mes_reasoning_edit:visible'); + if (reasoningEdit.length > 0) { + reasoningEdit.trigger('click'); + } + + var text = chat[edit_mes_id]['mes']; + if (chat[edit_mes_id]['is_user']) { + this_edit_mes_chname = name1; + } else if (chat[edit_mes_id]['force_avatar']) { + this_edit_mes_chname = chat[edit_mes_id]['name']; + } else { + this_edit_mes_chname = name2; + } + if (power_user.trim_spaces) { + text = text.trim(); + } + $(this) + .closest('.mes_block') + .find('.mes_text') + .append( + '', + ); + $('#curEditTextarea').val(text); + let edit_textarea = $(this) + .closest('.mes_block') + .find('.edit_textarea'); + if (!cssAutofit) { + edit_textarea.height(0); + edit_textarea.height(edit_textarea[0].scrollHeight); + } + edit_textarea.focus(); + edit_textarea[0].setSelectionRange( //this sets the cursor at the end of the text + String(edit_textarea.val()).length, + String(edit_textarea.val()).length, + ); + if (Number(this_edit_mes_id) === chat.length - 1) { + $('#chat').scrollTop(chatScrollPosition); + } + + updateEditArrowClasses(); + } + }); + + $(document).on('input', '#curEditTextarea', function () { + if (power_user.auto_save_msg_edits === true) { + messageEditAuto($(this)); + } + }); + + $(document).on('click', '.extraMesButtonsHint', function (e) { + const $hint = $(e.target); + const $buttons = $hint.siblings('.extraMesButtons'); + + $hint.transition({ + opacity: 0, + duration: animation_duration, + easing: animation_easing, + complete: function () { + $hint.hide(); + $buttons + .addClass('visible') + .css({ + opacity: 0, + display: 'flex', + }) + .transition({ + opacity: 1, + duration: animation_duration, + easing: animation_easing, + }); + }, + }); + }); + + $(document).on('click', function (e) { + // Expanded options don't need to be closed + if (power_user.expand_message_actions) { + return; + } + + // Check if the click was outside the relevant elements + if (!$(e.target).closest('.extraMesButtons, .extraMesButtonsHint').length) { + const $visibleButtons = $('.extraMesButtons.visible'); + + if (!$visibleButtons.length) { + return; + } + + const $hiddenHints = $('.extraMesButtonsHint:hidden'); + + // Transition out the .extraMesButtons first + $visibleButtons.transition({ + opacity: 0, + duration: animation_duration, + easing: animation_easing, + complete: function () { + // Hide the .extraMesButtons after the transition + $(this) + .hide() + .removeClass('visible'); + + // Transition the .extraMesButtonsHint back in + $hiddenHints + .show() + .transition({ + opacity: 0.3, + duration: animation_duration, + easing: animation_easing, + complete: function () { + $(this).css('opacity', ''); + }, + }); + }, + }); + } + }); + + $(document).on('click', '.mes_edit_cancel', async function () { + let text = chat[this_edit_mes_id]['mes']; + + $(this).closest('.mes_block').find('.mes_text').empty(); + $(this).closest('.mes_edit_buttons').css('display', 'none'); + $(this).closest('.mes_block').find('.mes_buttons').css('display', ''); + $(this) + .closest('.mes_block') + .find('.mes_text') + .append(messageFormatting( + text, + this_edit_mes_chname, + chat[this_edit_mes_id].is_system, + chat[this_edit_mes_id].is_user, + this_edit_mes_id, + {}, + false, + )); + appendMediaToMessage(chat[this_edit_mes_id], $(this).closest('.mes')); + addCopyToCodeBlocks($(this).closest('.mes')); + + const reasoningEditDone = $(this).closest('.mes_block').find('.mes_reasoning_edit_cancel:visible'); + if (reasoningEditDone.length > 0) { + reasoningEditDone.trigger('click'); + } + + await eventSource.emit(event_types.MESSAGE_UPDATED, this_edit_mes_id); + this_edit_mes_id = undefined; + }); + + $(document).on('click', '.mes_edit_up', async function () { + if (is_send_press || this_edit_mes_id <= 0) { + return; + } + + hideSwipeButtons(); + const targetId = Number(this_edit_mes_id) - 1; + const target = $(`#chat .mes[mesid="${targetId}"]`); + const root = $(this).closest('.mes'); + + if (root.length === 0 || target.length === 0) { + return; + } + + root.insertBefore(target); + + target.attr('mesid', this_edit_mes_id); + root.attr('mesid', targetId); + + const temp = chat[targetId]; + chat[targetId] = chat[this_edit_mes_id]; + chat[this_edit_mes_id] = temp; + + this_edit_mes_id = targetId; + updateViewMessageIds(); + await saveChatConditional(); + showSwipeButtons(); + }); + + $(document).on('click', '.mes_edit_down', async function () { + if (is_send_press || this_edit_mes_id >= chat.length - 1) { + return; + } + + hideSwipeButtons(); + const targetId = Number(this_edit_mes_id) + 1; + const target = $(`#chat .mes[mesid="${targetId}"]`); + const root = $(this).closest('.mes'); + + if (root.length === 0 || target.length === 0) { + return; + } + + root.insertAfter(target); + + target.attr('mesid', this_edit_mes_id); + root.attr('mesid', targetId); + + const temp = chat[targetId]; + chat[targetId] = chat[this_edit_mes_id]; + chat[this_edit_mes_id] = temp; + + this_edit_mes_id = targetId; + updateViewMessageIds(); + await saveChatConditional(); + showSwipeButtons(); + }); + + $(document).on('click', '.mes_edit_copy', async function () { + const confirmation = await callGenericPopup(t`Create a copy of this message?`, POPUP_TYPE.CONFIRM); + if (!confirmation) { + return; + } + + hideSwipeButtons(); + const oldScroll = chatElement[0].scrollTop; + const clone = structuredClone(chat[this_edit_mes_id]); + clone.send_date = Date.now(); + clone.mes = $(this).closest('.mes').find('.edit_textarea').val(); + + if (power_user.trim_spaces) { + clone.mes = clone.mes.trim(); + } + + chat.splice(Number(this_edit_mes_id) + 1, 0, clone); + addOneMessage(clone, { insertAfter: this_edit_mes_id }); + + updateViewMessageIds(); + await saveChatConditional(); + chatElement[0].scrollTop = oldScroll; + showSwipeButtons(); + }); + + $(document).on('click', '.mes_edit_delete', async function (event, customData) { + const fromSlashCommand = customData?.fromSlashCommand || false; + const canDeleteSwipe = (Array.isArray(chat[this_edit_mes_id].swipes) && chat[this_edit_mes_id].swipes.length > 1 && !chat[this_edit_mes_id].is_user && parseInt(this_edit_mes_id) === chat.length - 1); + + let deleteOnlySwipe = false; + if (power_user.confirm_message_delete && fromSlashCommand !== true) { + const result = await callGenericPopup(t`Are you sure you want to delete this message?`, POPUP_TYPE.CONFIRM, null, { + okButton: canDeleteSwipe ? t`Delete Swipe` : t`Delete Message`, + cancelButton: 'Cancel', + customButtons: canDeleteSwipe ? [t`Delete Message`] : null, + }); + if (!result) { + return; + } + deleteOnlySwipe = canDeleteSwipe && result === 1; // Default button, not the custom one + } + + const messageElement = $(this).closest('.mes'); + if (!messageElement) { + return; + } + + if (deleteOnlySwipe) { + const message = chat[this_edit_mes_id]; + const swipe_id = message.swipe_id; + await deleteSwipe(swipe_id); + return; + } + + chat.splice(this_edit_mes_id, 1); + messageElement.remove(); + + let startFromZero = Number(this_edit_mes_id) === 0; + + this_edit_mes_id = undefined; + + updateViewMessageIds(startFromZero); + saveChatDebounced(); + + hideSwipeButtons(); + showSwipeButtons(); + + await eventSource.emit(event_types.MESSAGE_DELETED, chat.length); + }); + + $(document).on('click', '.mes_edit_done', async function () { + await messageEditDone($(this)); + }); + + //Select chat + + //**************************CHARACTER IMPORT EXPORT*************************// + $('#character_import_button').click(function () { + $('#character_import_file').click(); + }); + + $('#character_import_file').on('change', async function (e) { + $('#rm_info_avatar').html(''); + + if (!(e.target instanceof HTMLInputElement)) { + return; + } + + if (!e.target.files.length) { + return; + } + + const avatarFileNames = []; + for (const file of e.target.files) { + const avatarFileName = await importCharacter(file); + if (avatarFileName !== undefined) { + avatarFileNames.push(avatarFileName); + } + } + + if (avatarFileNames.length > 0) { + await importCharactersTags(avatarFileNames); + selectImportedChar(avatarFileNames[avatarFileNames.length - 1]); + } + }); + + $('#export_button').on('click', function () { + isExportPopupOpen = !isExportPopupOpen; + $('#export_format_popup').toggle(isExportPopupOpen); + exportPopper.update(); + }); + + $(document).on('click', '.export_format', async function () { + const format = $(this).data('format'); + + if (!format) { + return; + } + + $('#export_format_popup').hide(); + isExportPopupOpen = false; + exportPopper.update(); + + // Save before exporting + await createOrEditCharacter(); + const body = { format, avatar_url: characters[this_chid].avatar }; + + const response = await fetch('/api/characters/export', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify(body), + }); + + if (response.ok) { + const filename = characters[this_chid].avatar.replace('.png', `.${format}`); + const blob = await response.blob(); + const a = document.createElement('a'); + a.href = URL.createObjectURL(blob); + a.setAttribute('download', filename); + document.body.appendChild(a); + a.click(); + URL.revokeObjectURL(a.href); + document.body.removeChild(a); + } + }); + //**************************CHAT IMPORT EXPORT*************************// + $('#chat_import_button').click(function () { + $('#chat_import_file').click(); + }); + + $('#chat_import_file').on('change', async function (e) { + const file = e.target.files[0]; + + if (!file) { + return; + } + + const ext = file.name.match(/\.(\w+)$/); + if ( + !ext || + (ext[1].toLowerCase() != 'json' && ext[1].toLowerCase() != 'jsonl') + ) { + return; + } + + if (selected_group && file.name.endsWith('.json')) { + toastr.warning('Only SillyTavern\'s own format is supported for group chat imports. Sorry!'); + return; + } + + const format = ext[1].toLowerCase(); + $('#chat_import_file_type').val(format); + + const formData = new FormData($('#form_import_chat').get(0)); + formData.append('user_name', name1); + $('#select_chat_div').html(''); + + if (selected_group) { + await importGroupChat(formData, e.originalEvent.target); + } else { + await importCharacterChat(formData, e.originalEvent.target); + } + }); + + $('#rm_button_group_chats').click(function () { + selected_button = 'group_chats'; + select_group_chats(); + }); + + $('#rm_button_back_from_group').click(function () { + selected_button = 'characters'; + select_rm_characters(); + }); + + $('#dupe_button').click(async function () { + await duplicateCharacter(); + }); + + $(document).on('click', '.mes_stop', function () { + stopGeneration(); + }); + + $(document).on('click', '#form_sheld .stscript_continue', function () { + pauseScriptExecution(); + }); + + $(document).on('click', '#form_sheld .stscript_pause', function () { + pauseScriptExecution(); + }); + + $(document).on('click', '#form_sheld .stscript_stop', function () { + stopScriptExecution(); + }); + + $(document).on('click', '.drawer-opener', doDrawerOpenClick); + + $('.drawer-toggle').on('click', doNavbarIconClick); + + $('html').on('touchstart mousedown', function (e) { + var clickTarget = $(e.target); + + if (isExportPopupOpen + && clickTarget.closest('#export_button').length == 0 + && clickTarget.closest('#export_format_popup').length == 0) { + $('#export_format_popup').hide(); + isExportPopupOpen = false; + exportPopper.update(); + } + + const forbiddenTargets = [ + '#character_cross', + '#avatar-and-name-block', + '#shadow_popup', + '.popup', + '#world_popup', + '.ui-widget', + '.text_pole', + '#toast-container', + '.select2-results', + ]; + for (const id of forbiddenTargets) { + if (clickTarget.closest(id).length > 0) { + return; + } + } + + var targetParentHasOpenDrawer = clickTarget.parents('.openDrawer').length; + if (clickTarget.hasClass('drawer-icon') == false && !clickTarget.hasClass('openDrawer')) { + if ($('.openDrawer').length !== 0) { + if (targetParentHasOpenDrawer === 0) { + //console.log($('.openDrawer').not('.pinnedOpen').length); + $('.openDrawer').not('.pinnedOpen').addClass('resizing').each((_, el) => { + slideToggle(el, { + ...getSlideToggleOptions(), + onAnimationEnd: (el) => { + el.closest('.drawer-content').classList.remove('resizing'); + }, + }); + }); + $('.openIcon').not('.drawerPinnedOpen').toggleClass('closedIcon openIcon'); + $('.openDrawer').not('.pinnedOpen').toggleClass('closedDrawer openDrawer'); + } + } + } + }); + + $(document).on('click', '.inline-drawer-toggle', function (e) { + if ($(e.target).hasClass('text_pole')) { + return; + } + const drawer = $(this).closest('.inline-drawer'); + const icon = drawer.find('.inline-drawer-icon'); + const drawerContent = drawer.find('.inline-drawer-content'); + icon.toggleClass('down up'); + icon.toggleClass('fa-circle-chevron-down fa-circle-chevron-up'); + drawerContent.stop().slideToggle({ + complete: () => { + $(this).css('height', ''); + }, + }); + + // Set the height of "autoSetHeight" textareas within the inline-drawer to their scroll height + if (!CSS.supports('field-sizing', 'content')) { + drawerContent.find('textarea.autoSetHeight').each(async function () { + await resetScrollHeight($(this)); + return; + }); + } + }); + + $(document).on('click', '.inline-drawer-maximize', function () { + const icon = $(this).find('.inline-drawer-icon, .floating_panel_maximize'); + icon.toggleClass('fa-window-maximize fa-window-restore'); + const drawerContent = $(this).closest('.drawer-content'); + drawerContent.toggleClass('maximized'); + const drawerId = drawerContent.attr('id'); + resetMovableStyles(drawerId); + }); + + $(document).on('click', '.mes .avatar', function () { + const messageElement = $(this).closest('.mes'); + const thumbURL = $(this).children('img').attr('src'); + const charsPath = '/characters/'; + const targetAvatarImg = thumbURL.substring(thumbURL.lastIndexOf('=') + 1); + const charname = targetAvatarImg.replace('.png', ''); + const isValidCharacter = characters.some(x => x.avatar === decodeURIComponent(targetAvatarImg)); + + // Remove existing zoomed avatars for characters that are not the clicked character when moving UI is not enabled + if (!power_user.movingUI) { + $('.zoomed_avatar').each(function () { + const currentForChar = $(this).attr('forChar'); + if (currentForChar !== charname && typeof currentForChar !== 'undefined') { + console.debug(`Removing zoomed avatar for character: ${currentForChar}`); + $(this).remove(); + } + }); + } + + const avatarSrc = (isDataURL(thumbURL) || /^\/?img\/(?:.+)/.test(thumbURL)) ? thumbURL : charsPath + targetAvatarImg; + if ($(`.zoomed_avatar[forChar="${charname}"]`).length) { + console.debug('removing container as it already existed'); + $(`.zoomed_avatar[forChar="${charname}"]`).fadeOut(animation_duration, () => { + $(`.zoomed_avatar[forChar="${charname}"]`).remove(); + }); + } else { + console.debug('making new container from template'); + const template = $('#zoomed_avatar_template').html(); + const newElement = $(template); + newElement.attr('forChar', charname); + newElement.attr('id', `zoomFor_${charname}`); + newElement.addClass('draggable'); + newElement.find('.drag-grabber').attr('id', `zoomFor_${charname}header`); + + $('body').append(newElement); + newElement.fadeIn(animation_duration); + const zoomedAvatarImgElement = $(`.zoomed_avatar[forChar="${charname}"] img`); + if (messageElement.attr('is_user') == 'true' || (messageElement.attr('is_system') == 'true' && !isValidCharacter)) { //handle user and system avatars + zoomedAvatarImgElement.attr('src', thumbURL); + zoomedAvatarImgElement.attr('data-izoomify-url', thumbURL); + } else if (messageElement.attr('is_user') == 'false') { //handle char avatars + zoomedAvatarImgElement.attr('src', avatarSrc); + zoomedAvatarImgElement.attr('data-izoomify-url', avatarSrc); + } + loadMovingUIState(); + $(`.zoomed_avatar[forChar="${charname}"]`).css('display', 'flex'); + dragElement(newElement); + + if (power_user.zoomed_avatar_magnification) { + $('.zoomed_avatar_container').izoomify(); + } + + $('.zoomed_avatar, .zoomed_avatar .dragClose').on('click touchend', (e) => { + if (e.target.closest('.dragClose')) { + $(`.zoomed_avatar[forChar="${charname}"]`).fadeOut(animation_duration, () => { + $(`.zoomed_avatar[forChar="${charname}"]`).remove(); + }); + } + }); + + zoomedAvatarImgElement.on('dragstart', (e) => { + console.log('saw drag on avatar!'); + e.preventDefault(); + return false; + }); + } + }); + + document.addEventListener('click', function (e) { + if (!(e.target instanceof HTMLElement)) return; + if (e.target.matches('#OpenAllWIEntries')) { + document.querySelectorAll('#world_popup_entries_list .inline-drawer').forEach((/** @type {HTMLElement} */ drawer) => { + toggleDrawer(drawer, true); + }); + } else if (e.target.matches('#CloseAllWIEntries')) { + document.querySelectorAll('#world_popup_entries_list .inline-drawer').forEach((/** @type {HTMLElement} */ drawer) => { + toggleDrawer(drawer, false); + }); + } + }); + + $(document).on('click', '.open_alternate_greetings', openAlternateGreetings); + /* $('#set_character_world').on('click', openCharacterWorldPopup); */ + + $(document).on('focus', 'input.auto-select, textarea.auto-select', function () { + if (!power_user.enable_auto_select_input) return; + const control = $(this)[0]; + if (control instanceof HTMLInputElement || control instanceof HTMLTextAreaElement) { + control.select(); + console.debug('Auto-selecting content of input control', control); + } + }); + + $(document).keyup(function (e) { + if (e.key === 'Escape') { + const isEditVisible = $('#curEditTextarea').is(':visible') || $('.reasoning_edit_textarea').length > 0; + if (isEditVisible && power_user.auto_save_msg_edits === false) { + closeMessageEditor('all'); + $('#send_textarea').focus(); + return; + } + if (isEditVisible && power_user.auto_save_msg_edits === true) { + $(`#chat .mes[mesid="${this_edit_mes_id}"] .mes_edit_done`).click(); + closeMessageEditor('reasoning'); + $('#send_textarea').focus(); + return; + } + if (!this_edit_mes_id && $('#mes_stop').is(':visible')) { + $('#mes_stop').trigger('click'); + if (chat.length && Array.isArray(chat[chat.length - 1].swipes) && chat[chat.length - 1].swipe_id == chat[chat.length - 1].swipes.length) { + $('.last_mes .swipe_left').trigger('click'); + } + } + } + }); + + $('#char-management-dropdown').on('change', async (e) => { + let target = $(e.target.selectedOptions).attr('id'); + switch (target) { + case 'set_character_world': + openCharacterWorldPopup(); + break; + case 'set_chat_scenario': + await setScenarioOverride(); + break; + case 'renameCharButton': + renameCharacter(); + break; + case 'import_character_info': + await importEmbeddedWorldInfo(); + saveCharacterDebounced(); + break; + case 'character_source': { + const source = getCharacterSource(this_chid); + if (source && isValidUrl(source)) { + const url = new URL(source); + const confirm = await Popup.show.confirm('Open Source', `Do you want to open the link to ${url.hostname} in a new tab?${url}`); + if (confirm) { + window.open(source, '_blank'); + } + } else { + toastr.info('This character doesn\'t seem to have a source.'); + } + } break; + case 'replace_update': { + const confirm = await Popup.show.confirm('Replace Character', '

      Choose a new character card to replace this character with.

      All chats, assets and group memberships will be preserved, but local changes to the character data will be lost.
      Proceed?'); + if (confirm) { + async function uploadReplacementCard(e) { + const file = e.target.files[0]; + + if (!file) { + return; + } + + try { + const chatFile = characters[this_chid]['chat']; + const data = new Map(); + data.set(file, characters[this_chid].avatar); + await processDroppedFiles([file], data); + await openCharacterChat(chatFile); + await fetch(getThumbnailUrl('avatar', characters[this_chid].avatar), { cache: 'no-cache' }); + } catch { + toastr.error('Failed to replace the character card.', 'Something went wrong'); + } + } + $('#character_replace_file').off('change').on('change', uploadReplacementCard).trigger('click'); + } + } break; + case 'import_tags': { + await importTags(characters[this_chid], { importSetting: tag_import_setting.ASK }); + } break; + /*case 'delete_button': + popup_type = "del_ch"; + callPopup(` +

      Delete the character?

      + THIS IS PERMANENT!

      + THIS WILL ALSO DELETE ALL
      + OF THE CHARACTER'S CHAT FILES.

      ` + ); + break;*/ + default: + await eventSource.emit('charManagementDropdown', target); + } + $('#char-management-dropdown').prop('selectedIndex', 0); + }); + + $(window).on('beforeunload', () => { + cancelTtsPlay(); + if (streamingProcessor) { + console.log('Page reloaded. Aborting streaming...'); + streamingProcessor.onStopStreaming(); + } + }); + + + var isManualInput = false; + var valueBeforeManualInput; + + $(document).on('input', '.range-block-counter input, .neo-range-input', function () { + valueBeforeManualInput = $(this).val(); + console.log(valueBeforeManualInput); + }); + + $(document).on('change', '.range-block-counter input, .neo-range-input', function (e) { + e.target.focus(); + e.target.dispatchEvent(new KeyboardEvent('keyup', { bubbles: true })); + }); + + $(document).on('keydown', '.range-block-counter input, .neo-range-input', function (e) { + const masterSelector = '#' + $(this).data('for'); + const masterElement = $(masterSelector); + if (e.key === 'Enter') { + let manualInput = Number($(this).val()); + if (isManualInput) { + //disallow manual inputs outside acceptable range + if (manualInput >= Number($(this).attr('min')) && manualInput <= Number($(this).attr('max'))) { + //if value is ok, assign to slider and update handle text and position + //newSlider.val(manualInput) + //handleSlideEvent.call(newSlider, null, { value: parseFloat(manualInput) }, 'manual'); + valueBeforeManualInput = manualInput; + $(masterElement).val($(this).val()).trigger('input', { forced: true }); + } else { + //if value not ok, warn and reset to last known valid value + toastr.warning(`Invalid value. Must be between ${$(this).attr('min')} and ${$(this).attr('max')}`); + console.log(valueBeforeManualInput); + //newSlider.val(valueBeforeManualInput) + $(this).val(valueBeforeManualInput); + } + } + } + }); + + $(document).on('keyup', '.range-block-counter input, .neo-range-input', function () { + valueBeforeManualInput = $(this).val(); + console.log(valueBeforeManualInput); + isManualInput = true; + }); + + //trigger slider changes when user clicks away + $(document).on('mouseup blur', '.range-block-counter input, .neo-range-input', function () { + const masterSelector = '#' + $(this).data('for'); + const masterElement = $(masterSelector); + let manualInput = Number($(this).val()); + if (isManualInput) { + //if value is between correct range for the slider + if (manualInput >= Number($(this).attr('min')) && manualInput <= Number($(this).attr('max'))) { + valueBeforeManualInput = manualInput; + //set the slider value to input value + $(masterElement).val($(this).val()).trigger('input', { forced: true }); + } else { + //if value not ok, warn and reset to last known valid value + toastr.warning(`Invalid value. Must be between ${$(this).attr('min')} and ${$(this).attr('max')}`); + console.log(valueBeforeManualInput); + $(this).val(valueBeforeManualInput); + } + } + isManualInput = false; + }); + + $('.user_stats_button').on('click', function () { + userStatsHandler(); + }); + + $(document).on('click', '.external_import_button, #external_import_button', async () => { + const html = await renderTemplateAsync('importCharacters'); + + /** @type {string?} */ + const input = await callGenericPopup(html, POPUP_TYPE.INPUT, '', { wider: true, okButton: $('#popup_template').attr('popup-button-import'), rows: 4 }); + + if (!input) { + console.debug('Custom content import cancelled'); + return; + } + + // break input into one input per line + const inputs = input.split('\n').map(x => x.trim()).filter(x => x.length > 0); + + for (const url of inputs) { + let request; + + if (isValidUrl(url)) { + console.debug('Custom content import started for URL: ', url); + request = await fetch('/api/content/importURL', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ url }), + }); + } else { + console.debug('Custom content import started for Char UUID: ', url); + request = await fetch('/api/content/importUUID', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ url }), + }); + } + + if (!request.ok) { + toastr.info(request.statusText, 'Custom content import failed'); + console.error('Custom content import failed', request.status, request.statusText); + return; + } + + const data = await request.blob(); + const customContentType = request.headers.get('X-Custom-Content-Type'); + const fileName = request.headers.get('Content-Disposition').split('filename=')[1].replace(/"/g, ''); + const file = new File([data], fileName, { type: data.type }); + + switch (customContentType) { + case 'character': + await processDroppedFiles([file]); + break; + case 'lorebook': + await importWorldInfo(file); + break; + default: + toastr.warning('Unknown content type'); + console.error('Unknown content type', customContentType); + break; + } + } + }); + + charDragDropHandler = new DragAndDropHandler('body', async (files, event) => { + if (!files.length) { + await importFromURL(event.originalEvent.dataTransfer.items, files); + } + await processDroppedFiles(files); + }, { noAnimation: true }); + + $('#charListGridToggle').on('click', async () => { + doCharListDisplaySwitch(); + }); + + $('#hideCharPanelAvatarButton').on('click', () => { + $('#avatar-and-name-block').slideToggle(); + }); + + $(document).on('mouseup touchend', '#show_more_messages', async function () { + await showMoreMessages(); + }); + + $(document).on('click', '.open_characters_library', async function () { + await getCharacters(); + await eventSource.emit(event_types.OPEN_CHARACTER_LIBRARY); + }); + + // Added here to prevent execution before script.js is loaded and get rid of quirky timeouts + await firstLoadInit(); + + addDebugFunctions(); + + eventSource.on(event_types.CHAT_DELETED, async (name) => { + await deleteItemizedPrompts(name); + }); + eventSource.on(event_types.GROUP_CHAT_DELETED, async (name) => { + await deleteItemizedPrompts(name); + }); + + initCustomSelectedSamplers(); +}); diff --git a/jiuguan2025cc/public/scripts/BulkEditOverlay.js b/jiuguan2025cc/public/scripts/BulkEditOverlay.js new file mode 100644 index 0000000000000000000000000000000000000000..0f39cffd3488ce821f37c8fa28f58f21318a1f12 --- /dev/null +++ b/jiuguan2025cc/public/scripts/BulkEditOverlay.js @@ -0,0 +1,884 @@ +'use strict'; + +import { + characterGroupOverlay, + callPopup, + characters, + event_types, + eventSource, + getCharacters, + getRequestHeaders, + buildAvatarList, + characterToEntity, + printCharactersDebounced, + deleteCharacter, +} from '../script.js'; + +import { favsToHotswap } from './RossAscends-mods.js'; +import { hideLoader, showLoader } from './loader.js'; +import { convertCharacterToPersona } from './personas.js'; +import { createTagInput, getTagKeyForEntity, getTagsList, printTagList, tag_map, compareTagsForSort, removeTagFromMap, importTags, tag_import_setting } from './tags.js'; + +/** + * Static object representing the actions of the + * character context menu override. + */ +class CharacterContextMenu { + /** + * Tag one or more characters, + * opens a popup. + * + * @param {Array} selectedCharacters + */ + static tag = (selectedCharacters) => { + characterGroupOverlay.bulkTagPopupHandler.show(selectedCharacters); + }; + + /** + * Duplicate one or more characters + * + * @param {number} characterId + * @returns {Promise} + */ + static duplicate = async (characterId) => { + const character = CharacterContextMenu.#getCharacter(characterId); + const body = { avatar_url: character.avatar }; + + const result = await fetch('/api/characters/duplicate', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify(body), + }); + + if (!result.ok) { + throw new Error('Character not duplicated'); + } + + const data = await result.json(); + await eventSource.emit(event_types.CHARACTER_DUPLICATED, { oldAvatar: body.avatar_url, newAvatar: data.path }); + }; + + /** + * Favorite a character + * and highlight it. + * + * @param {number} characterId + * @returns {Promise} + */ + static favorite = async (characterId) => { + const character = CharacterContextMenu.#getCharacter(characterId); + const newFavState = !character.data.extensions.fav; + + const data = { + name: character.name, + avatar: character.avatar, + data: { + extensions: { + fav: newFavState, + }, + }, + fav: newFavState, + }; + + const mergeResponse = await fetch('/api/characters/merge-attributes', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify(data), + }); + + if (!mergeResponse.ok) { + mergeResponse.json().then(json => toastr.error(`Character not saved. Error: ${json.message}. Field: ${json.error}`)); + } + + const element = document.getElementById(`CharID${characterId}`); + element.classList.toggle('is_fav'); + }; + + /** + * Convert one or more characters to persona, + * may open a popup for one or more characters. + * + * @param {number} characterId + * @returns {Promise} + */ + static persona = async (characterId) => await convertCharacterToPersona(characterId); + + /** + * Delete one or more characters, + * opens a popup. + * + * @param {string|string[]} characterKey + * @param {boolean} [deleteChats] + * @returns {Promise} + */ + static delete = async (characterKey, deleteChats = false) => { + await deleteCharacter(characterKey, { deleteChats: deleteChats }); + }; + + static #getCharacter = (characterId) => characters[characterId] ?? null; + + /** + * Show the context menu at the given position + * + * @param positionX + * @param positionY + */ + static show = (positionX, positionY) => { + let contextMenu = document.getElementById(BulkEditOverlay.contextMenuId); + contextMenu.style.left = `${positionX}px`; + contextMenu.style.top = `${positionY}px`; + + document.getElementById(BulkEditOverlay.contextMenuId).classList.remove('hidden'); + + // Adjust position if context menu is outside of viewport + const boundingRect = contextMenu.getBoundingClientRect(); + if (boundingRect.right > window.innerWidth) { + contextMenu.style.left = `${positionX - (boundingRect.right - window.innerWidth)}px`; + } + if (boundingRect.bottom > window.innerHeight) { + contextMenu.style.top = `${positionY - (boundingRect.bottom - window.innerHeight)}px`; + } + }; + + /** + * Hide the context menu + */ + static hide = () => document.getElementById(BulkEditOverlay.contextMenuId).classList.add('hidden'); + + /** + * Sets up the context menu for the given overlay + * + * @param characterGroupOverlay + */ + constructor(characterGroupOverlay) { + const contextMenuItems = [ + { id: 'character_context_menu_favorite', callback: characterGroupOverlay.handleContextMenuFavorite }, + { id: 'character_context_menu_duplicate', callback: characterGroupOverlay.handleContextMenuDuplicate }, + { id: 'character_context_menu_delete', callback: characterGroupOverlay.handleContextMenuDelete }, + { id: 'character_context_menu_persona', callback: characterGroupOverlay.handleContextMenuPersona }, + { id: 'character_context_menu_tag', callback: characterGroupOverlay.handleContextMenuTag }, + ]; + + contextMenuItems.forEach(contextMenuItem => document.getElementById(contextMenuItem.id).addEventListener('click', contextMenuItem.callback)); + } +} + +/** + * Represents a tag control not bound to a single character + */ +class BulkTagPopupHandler { + /** + * The characters for this popup + * @type {number[]} + */ + characterIds; + + /** + * A storage of the current mutual tags, as calculated by getMutualTags() + * @type {object[]} + */ + currentMutualTags; + + /** + * Sets up the bulk popup menu handler for the given overlay. + * + * Characters can be passed in with the show() call. + */ + constructor() { } + + /** + * Gets the HTML as a string that is going to be the popup for the bulk tag edit + * + * @returns String containing the html for the popup + */ + #getHtml = () => { + const characterData = JSON.stringify({ characterIds: this.characterIds }); + return `
      +
      +
      +

      Modify tags of ${this.characterIds.length} characters

      + Add or remove the mutual tags of all selected characters. Import all or existing tags for all selected characters. +
      +
      +
      +
      + + +
      +
      +
      +
      + + + + + +
      +
      +
      +
      `; + }; + + /** + * Append and show the tag control + * + * @param {number[]} characterIds - The characters that are shown inside the popup + */ + show(characterIds) { + // shallow copy character ids persistently into this tooltip + this.characterIds = characterIds.slice(); + + if (this.characterIds.length == 0) { + console.log('No characters selected for bulk edit tags.'); + return; + } + + document.body.insertAdjacentHTML('beforeend', this.#getHtml()); + + const entities = this.characterIds.map(id => characterToEntity(characters[id], id)).filter(entity => entity.item !== undefined); + buildAvatarList($('#bulk_tags_avatars_block'), entities); + + // Print the tag list with all mutuable tags, marking them as removable. That is the initial fill + printTagList($('#bulkTagList'), { tags: () => this.getMutualTags(), tagOptions: { removable: true } }); + + // Tag input with resolvable list for the mutual tags to get redrawn, so that newly added tags get sorted correctly + createTagInput('#bulkTagInput', '#bulkTagList', { tags: () => this.getMutualTags(), tagOptions: { removable: true } }); + + document.querySelector('#bulk_tag_popup_reset').addEventListener('click', this.resetTags.bind(this)); + document.querySelector('#bulk_tag_popup_remove_mutual').addEventListener('click', this.removeMutual.bind(this)); + document.querySelector('#bulk_tag_popup_cancel').addEventListener('click', this.hide.bind(this)); + document.querySelector('#bulk_tag_popup_import_all_tags').addEventListener('click', this.importAllTags.bind(this)); + document.querySelector('#bulk_tag_popup_import_existing_tags').addEventListener('click', this.importExistingTags.bind(this)); + } + + /** + * Import existing tags for all selected characters + */ + async importExistingTags() { + for (const characterId of this.characterIds) { + await importTags(characters[characterId], { importSetting: tag_import_setting.ONLY_EXISTING }); + } + + $('#bulkTagList').empty(); + } + + /** + * Import all tags for all selected characters + */ + async importAllTags() { + for (const characterId of this.characterIds) { + await importTags(characters[characterId], { importSetting: tag_import_setting.ALL }); + } + + $('#bulkTagList').empty(); + } + + /** + * Builds a list of all tags that the provided characters have in common. + * + * @returns {Array} A list of mutual tags + */ + getMutualTags() { + if (this.characterIds.length == 0) { + return []; + } + + if (this.characterIds.length === 1) { + // Just use tags of the single character + return getTagsList(getTagKeyForEntity(this.characterIds[0])); + } + + // Find mutual tags for multiple characters + const allTags = this.characterIds.map(cid => getTagsList(getTagKeyForEntity(cid))); + const mutualTags = allTags.reduce((mutual, characterTags) => + mutual.filter(tag => characterTags.some(cTag => cTag.id === tag.id)), + ); + + this.currentMutualTags = mutualTags.sort(compareTagsForSort); + return this.currentMutualTags; + } + + /** + * Hide and remove the tag control + */ + hide() { + let popupElement = document.querySelector('#bulk_tag_shadow_popup'); + if (popupElement) { + document.body.removeChild(popupElement); + } + + // No need to redraw here, all tags actions were redrawn when they happened + } + + /** + * Empty the tag map for the given characters + */ + resetTags() { + for (const characterId of this.characterIds) { + const key = getTagKeyForEntity(characterId); + if (key) tag_map[key] = []; + } + + $('#bulkTagList').empty(); + + printCharactersDebounced(); + } + + /** + * Remove the mutual tags for all given characters + */ + removeMutual() { + const mutualTags = this.getMutualTags(); + + for (const characterId of this.characterIds) { + for (const tag of mutualTags) { + removeTagFromMap(tag.id, characterId); + } + } + + $('#bulkTagList').empty(); + + printCharactersDebounced(); + } +} + +class BulkEditOverlayState { + /** + * + * @type {number} + */ + static browse = 0; + + /** + * + * @type {number} + */ + static select = 1; +} + +/** + * Implement a SingletonPattern, allowing access to the group overlay instance + * from everywhere via (new CharacterGroupOverlay()) + * + * @type BulkEditOverlay + */ +let bulkEditOverlayInstance = null; + +class BulkEditOverlay { + static containerId = 'rm_print_characters_block'; + static contextMenuId = 'character_context_menu'; + static characterClass = 'character_select'; + static groupClass = 'group_select'; + static bogusFolderClass = 'bogus_folder_select'; + static selectModeClass = 'group_overlay_mode_select'; + static selectedClass = 'character_selected'; + static legacySelectedClass = 'bulk_select_checkbox'; + static bulkSelectedCountId = 'bulkSelectedCount'; + + static longPressDelay = 2500; + + #state = BulkEditOverlayState.browse; + #longPress = false; + #stateChangeCallbacks = []; + #selectedCharacters = []; + #bulkTagPopupHandler = new BulkTagPopupHandler(); + + /** + * @typedef {object} LastSelected - An object noting the last selected character and its state. + * @property {number} [characterId] - The character id of the last selected character. + * @property {boolean} [select] - The selected state of the last selected character. true if it was selected, false if it was deselected. + */ + + /** + * @type {LastSelected} - An object noting the last selected character and its state. + */ + lastSelected = { characterId: undefined, select: undefined }; + + /** + * Locks other pointer actions when the context menu is open + * + * @type {boolean} + */ + #contextMenuOpen = false; + + /** + * Whether the next character select should be skipped + * + * @type {boolean} + */ + #cancelNextToggle = false; + + /** + * @type HTMLElement + */ + container = null; + + get state() { + return this.#state; + } + + set state(newState) { + if (this.#state === newState) return; + + eventSource.emit(event_types.CHARACTER_GROUP_OVERLAY_STATE_CHANGE_BEFORE, newState) + .then(() => { + this.#state = newState; + eventSource.emit(event_types.CHARACTER_GROUP_OVERLAY_STATE_CHANGE_AFTER, this.state); + }); + } + + get isLongPress() { + return this.#longPress; + } + + set isLongPress(longPress) { + this.#longPress = longPress; + } + + get stateChangeCallbacks() { + return this.#stateChangeCallbacks; + } + + /** + * + * @returns {number[]} + */ + get selectedCharacters() { + return this.#selectedCharacters; + } + + /** + * The instance of the bulk tag popup handler that handles tagging of all selected characters + * + * @returns {BulkTagPopupHandler} + */ + get bulkTagPopupHandler() { + return this.#bulkTagPopupHandler; + } + + constructor() { + if (bulkEditOverlayInstance instanceof BulkEditOverlay) + return bulkEditOverlayInstance; + + this.container = document.getElementById(BulkEditOverlay.containerId); + + eventSource.on(event_types.CHARACTER_GROUP_OVERLAY_STATE_CHANGE_AFTER, this.handleStateChange); + bulkEditOverlayInstance = Object.freeze(this); + } + + /** + * Set the overlay to browse mode + */ + browseState = () => this.state = BulkEditOverlayState.browse; + + /** + * Set the overlay to select mode + */ + selectState = () => this.state = BulkEditOverlayState.select; + + /** + * Set up a Sortable grid for the loaded page + */ + onPageLoad = () => { + this.browseState(); + + const elements = this.#getEnabledElements(); + elements.forEach(element => element.addEventListener('touchstart', this.handleHold)); + elements.forEach(element => element.addEventListener('mousedown', this.handleHold)); + elements.forEach(element => element.addEventListener('contextmenu', this.handleDefaultContextMenu)); + + elements.forEach(element => element.addEventListener('touchend', this.handleLongPressEnd)); + elements.forEach(element => element.addEventListener('mouseup', this.handleLongPressEnd)); + elements.forEach(element => element.addEventListener('dragend', this.handleLongPressEnd)); + elements.forEach(element => element.addEventListener('touchmove', this.handleLongPressEnd)); + + // Cohee: It only triggers when clicking on a margin between the elements? + // Feel free to fix or remove this, I'm not sure how to. + //this.container.addEventListener('click', this.handleCancelClick); + }; + + /** + * Handle state changes + * + * + */ + handleStateChange = () => { + switch (this.state) { + case BulkEditOverlayState.browse: + this.container.classList.remove(BulkEditOverlay.selectModeClass); + this.#contextMenuOpen = false; + this.#enableClickEventsForCharacters(); + this.#enableClickEventsForGroups(); + this.clearSelectedCharacters(); + this.disableContextMenu(); + this.#disableBulkEditButtonHighlight(); + CharacterContextMenu.hide(); + break; + case BulkEditOverlayState.select: + this.container.classList.add(BulkEditOverlay.selectModeClass); + this.#disableClickEventsForCharacters(); + this.#disableClickEventsForGroups(); + this.enableContextMenu(); + this.#enableBulkEditButtonHighlight(); + break; + } + + this.stateChangeCallbacks.forEach(callback => callback(this.state)); + }; + + /** + * Block the browsers native context menu and + * set a click event to hide the custom context menu. + */ + enableContextMenu = () => { + this.container.addEventListener('contextmenu', this.handleContextMenuShow); + document.addEventListener('click', this.handleContextMenuHide); + }; + + /** + * Remove event listeners, allowing the native browser context + * menu to be opened. + */ + disableContextMenu = () => { + this.container.removeEventListener('contextmenu', this.handleContextMenuShow); + document.removeEventListener('click', this.handleContextMenuHide); + }; + + handleDefaultContextMenu = (event) => { + if (this.isLongPress) { + event.preventDefault(); + event.stopPropagation(); + return false; + } + }; + + /** + * Opens menu on long-press. + * + * @param event - Pointer event + */ + handleHold = (event) => { + if (0 !== event.button && event.type !== 'touchstart') return; + if (this.#contextMenuOpen) { + this.#contextMenuOpen = false; + this.#cancelNextToggle = true; + CharacterContextMenu.hide(); + return; + } + + let cancel = false; + + const cancelHold = (event) => cancel = true; + this.container.addEventListener('mouseup', cancelHold); + this.container.addEventListener('touchend', cancelHold); + + this.isLongPress = true; + + setTimeout(() => { + if (this.isLongPress && !cancel) { + if (this.state === BulkEditOverlayState.browse) { + this.selectState(); + } else if (this.state === BulkEditOverlayState.select) { + this.#contextMenuOpen = true; + CharacterContextMenu.show(...this.#getContextMenuPosition(event)); + } + } + + this.container.removeEventListener('mouseup', cancelHold); + this.container.removeEventListener('touchend', cancelHold); + }, BulkEditOverlay.longPressDelay); + }; + + handleLongPressEnd = (event) => { + this.isLongPress = false; + if (this.#contextMenuOpen) event.stopPropagation(); + }; + + handleCancelClick = () => { + if (false === this.#contextMenuOpen) this.state = BulkEditOverlayState.browse; + this.#contextMenuOpen = false; + }; + + /** + * Returns the position of the mouse/touch location + * + * @param event + * @returns {(boolean|number|*)[]} + */ + #getContextMenuPosition = (event) => [ + event.clientX || event.touches[0].clientX, + event.clientY || event.touches[0].clientY, + ]; + + #stopEventPropagation = (event) => { + if (this.#contextMenuOpen) { + this.handleContextMenuHide(event); + } + event.stopPropagation(); + }; + + #enableClickEventsForGroups = () => this.#getDisabledElements().forEach((element) => element.removeEventListener('click', this.#stopEventPropagation)); + + #disableClickEventsForGroups = () => this.#getDisabledElements().forEach((element) => element.addEventListener('click', this.#stopEventPropagation)); + + #enableClickEventsForCharacters = () => this.#getEnabledElements().forEach(element => element.removeEventListener('click', this.toggleCharacterSelected)); + + #disableClickEventsForCharacters = () => this.#getEnabledElements().forEach(element => element.addEventListener('click', this.toggleCharacterSelected)); + + #enableBulkEditButtonHighlight = () => document.getElementById('bulkEditButton').classList.add('bulk_edit_overlay_active'); + + #disableBulkEditButtonHighlight = () => document.getElementById('bulkEditButton').classList.remove('bulk_edit_overlay_active'); + + #getEnabledElements = () => [...this.container.getElementsByClassName(BulkEditOverlay.characterClass)]; + + #getDisabledElements = () => [...this.container.getElementsByClassName(BulkEditOverlay.groupClass), ...this.container.getElementsByClassName(BulkEditOverlay.bogusFolderClass)]; + + toggleCharacterSelected = event => { + event.stopPropagation(); + + const character = event.currentTarget; + + if (!this.#contextMenuOpen && !this.#cancelNextToggle) { + if (event.shiftKey) { + // Shift click might have selected text that we don't want to. Unselect it. + document.getSelection().removeAllRanges(); + + this.handleShiftClick(character); + } else { + this.toggleSingleCharacter(character); + } + } + + this.#cancelNextToggle = false; + }; + + /** + * When shift click was held down, this function handles the multi select of characters in a single click. + * + * If the last clicked character was deselected, and the current one was deselected too, it will deselect all currently selected characters between those two. + * If the last clicked character was selected, and the current one was selected too, it will select all currently not selected characters between those two. + * If the states do not match, nothing will happen. + * + * @param {HTMLElement} currentCharacter - The html element of the currently toggled character + */ + handleShiftClick = (currentCharacter) => { + const characterId = Number(currentCharacter.getAttribute('data-chid')); + const select = !this.selectedCharacters.includes(characterId); + + if (this.lastSelected.characterId >= 0 && this.lastSelected.select !== undefined) { + // Only if select state and the last select state match we execute the range select + if (select === this.lastSelected.select) { + this.toggleCharactersInRange(currentCharacter, select); + } + } + }; + + /** + * Toggles the selection of a given characters + * + * @param {HTMLElement} character - The html element of a character + * @param {object} param1 - Optional params + * @param {boolean} [param1.markState] - Whether the toggle of this character should be remembered as the last done toggle + */ + toggleSingleCharacter = (character, { markState = true } = {}) => { + const characterId = Number(character.getAttribute('data-chid')); + + const select = !this.selectedCharacters.includes(characterId); + const legacyBulkEditCheckbox = character.querySelector('.' + BulkEditOverlay.legacySelectedClass); + + if (select) { + character.classList.add(BulkEditOverlay.selectedClass); + if (legacyBulkEditCheckbox) legacyBulkEditCheckbox.checked = true; + this.#selectedCharacters.push(characterId); + } else { + character.classList.remove(BulkEditOverlay.selectedClass); + if (legacyBulkEditCheckbox) legacyBulkEditCheckbox.checked = false; + this.#selectedCharacters = this.#selectedCharacters.filter(item => characterId !== item); + } + + this.updateSelectedCount(); + + if (markState) { + this.lastSelected.characterId = characterId; + this.lastSelected.select = select; + } + }; + + /** + * Updates the selected count element with the current count + * + * @param {number} [countOverride] - optional override for a manual number to set + */ + updateSelectedCount = (countOverride = undefined) => { + const count = countOverride ?? this.selectedCharacters.length; + $(`#${BulkEditOverlay.bulkSelectedCountId}`).text(count).attr('title', `${count} characters selected`); + }; + + /** + * Toggles the selection of characters in a given range. + * The range is provided by the given character and the last selected one remembered in the selection state. + * + * @param {HTMLElement} currentCharacter - The html element of the currently toggled character + * @param {boolean} select - true if the characters in the range are to be selected, false if deselected + */ + toggleCharactersInRange = (currentCharacter, select) => { + const currentCharacterId = Number(currentCharacter.getAttribute('data-chid')); + const characters = Array.from(document.querySelectorAll('#' + BulkEditOverlay.containerId + ' .' + BulkEditOverlay.characterClass)); + + const startIndex = characters.findIndex(c => Number(c.getAttribute('data-chid')) === Number(this.lastSelected.characterId)); + const endIndex = characters.findIndex(c => Number(c.getAttribute('data-chid')) === currentCharacterId); + + for (let i = Math.min(startIndex, endIndex); i <= Math.max(startIndex, endIndex); i++) { + const character = characters[i]; + const characterId = Number(character.getAttribute('data-chid')); + const isCharacterSelected = this.selectedCharacters.includes(characterId); + + // Only toggle the character if it wasn't on the state we have are toggling towards. + // Also doing a weird type check, because typescript checker doesn't like the return of 'querySelectorAll'. + if ((select && !isCharacterSelected || !select && isCharacterSelected) && character instanceof HTMLElement) { + this.toggleSingleCharacter(character, { markState: currentCharacterId == characterId }); + } + } + }; + + handleContextMenuShow = (event) => { + event.preventDefault(); + CharacterContextMenu.show(...this.#getContextMenuPosition(event)); + this.#contextMenuOpen = true; + }; + + handleContextMenuHide = (event) => { + let contextMenu = document.getElementById(BulkEditOverlay.contextMenuId); + if (false === contextMenu.contains(event.target)) { + CharacterContextMenu.hide(); + } + }; + + /** + * Concurrently handle character favorite requests. + * + * @returns {Promise} + */ + handleContextMenuFavorite = async () => { + const promises = []; + + for (const characterId of this.selectedCharacters) { + promises.push(CharacterContextMenu.favorite(characterId)); + } + + await Promise.allSettled(promises); + await getCharacters(); + await favsToHotswap(); + this.browseState(); + }; + + /** + * Concurrently handle character duplicate requests. + * + * @returns {Promise} + */ + handleContextMenuDuplicate = () => Promise.all(this.selectedCharacters.map(async characterId => CharacterContextMenu.duplicate(characterId))) + .then(() => getCharacters()) + .then(() => this.browseState()); + + /** + * Sequentially handle all character-to-persona conversions. + * + * @returns {Promise} + */ + handleContextMenuPersona = async () => { + for (const characterId of this.selectedCharacters) { + await CharacterContextMenu.persona(characterId); + } + + this.browseState(); + }; + + /** + * Gets the HTML as a string that is displayed inside the popup for the bulk delete + * + * @param {Array} characterIds - The characters that are shown inside the popup + * @returns String containing the html for the popup content + */ + static #getDeletePopupContentHtml = (characterIds) => { + return ` +

      Delete ${characterIds.length} characters?

      + + + THIS IS PERMANENT! + +
      +
      +
      + +
      `; + }; + + /** + * Request user input before concurrently handle deletion + * requests. + * + * @returns {Promise} + */ + handleContextMenuDelete = () => { + const characterIds = this.selectedCharacters; + const popupContent = BulkEditOverlay.#getDeletePopupContentHtml(characterIds); + const promise = callPopup(popupContent, null) + .then((accept) => { + if (true !== accept) return; + + const deleteChats = document.getElementById('del_char_checkbox').checked ?? false; + + showLoader(); + const toast = toastr.info('We\'re deleting your characters, please wait...', 'Working on it'); + const avatarList = characterIds.map(id => characters[id]?.avatar).filter(a => a); + return CharacterContextMenu.delete(avatarList, deleteChats) + .then(() => this.browseState()) + .finally(() => { + toastr.clear(toast); + hideLoader(); + }); + }); + + // At this moment the popup is already changed in the dom, but not yet closed/resolved. We build the avatar list here + const entities = characterIds.map(id => characterToEntity(characters[id], id)).filter(entity => entity.item !== undefined); + buildAvatarList($('#bulk_delete_avatars_block'), entities); + + return promise; + }; + + /** + * Attaches and opens the tag menu + */ + handleContextMenuTag = () => { + CharacterContextMenu.tag(this.selectedCharacters); + this.browseState(); + }; + + addStateChangeCallback = callback => this.stateChangeCallbacks.push(callback); + + /** + * Clears internal character storage and + * removes visual highlight. + */ + clearSelectedCharacters = () => { + document.querySelectorAll('#' + BulkEditOverlay.containerId + ' .' + BulkEditOverlay.selectedClass) + .forEach(element => element.classList.remove(BulkEditOverlay.selectedClass)); + this.selectedCharacters.length = 0; + }; +} + +export { BulkEditOverlayState, CharacterContextMenu, BulkEditOverlay }; diff --git a/jiuguan2025cc/public/scripts/PromptManager.js b/jiuguan2025cc/public/scripts/PromptManager.js new file mode 100644 index 0000000000000000000000000000000000000000..783fb0c81526304cbb6befcd982a310dd3f958d3 --- /dev/null +++ b/jiuguan2025cc/public/scripts/PromptManager.js @@ -0,0 +1,1973 @@ +'use strict'; + +import { DOMPurify, Popper } from '../lib.js'; + +import { event_types, eventSource, is_send_press, main_api, substituteParams } from '../script.js'; +import { is_group_generating } from './group-chats.js'; +import { Message, TokenHandler } from './openai.js'; +import { power_user } from './power-user.js'; +import { debounce, waitUntilCondition, escapeHtml } from './utils.js'; +import { debounce_timeout } from './constants.js'; +import { renderTemplateAsync } from './templates.js'; +import { Popup } from './popup.js'; +import { t } from './i18n.js'; +import { isMobile } from './RossAscends-mods.js'; + +function debouncePromise(func, delay) { + let timeoutId; + + return (...args) => { + clearTimeout(timeoutId); + + return new Promise((resolve) => { + timeoutId = setTimeout(() => { + const result = func(...args); + resolve(result); + }, delay); + }); + }; +} + +const DEFAULT_DEPTH = 4; + +/** + * @enum {number} + */ +export const INJECTION_POSITION = { + RELATIVE: 0, + ABSOLUTE: 1, +}; + +/** + * Register migrations for the prompt manager when settings are loaded or an Open AI preset is loaded. + */ +const registerPromptManagerMigration = () => { + const migrate = (settings, savePreset = null, presetName = null) => { + if ('Default' === presetName) return; + + if (settings.main_prompt || settings.nsfw_prompt || settings.jailbreak_prompt) { + console.log('Running prompt manager configuration migration'); + if (settings.prompts === undefined || settings.prompts.length === 0) settings.prompts = structuredClone(chatCompletionDefaultPrompts.prompts); + + const findPrompt = (identifier) => settings.prompts.find(prompt => identifier === prompt.identifier); + if (settings.main_prompt) { + findPrompt('main').content = settings.main_prompt; + delete settings.main_prompt; + } + + if (settings.nsfw_prompt) { + findPrompt('nsfw').content = settings.nsfw_prompt; + delete settings.nsfw_prompt; + } + + if (settings.jailbreak_prompt) { + findPrompt('jailbreak').content = settings.jailbreak_prompt; + delete settings.jailbreak_prompt; + } + + if (savePreset && presetName) savePreset(presetName, settings, false); + } + }; + + eventSource.on(event_types.SETTINGS_LOADED_BEFORE, settings => migrate(settings)); + eventSource.on(event_types.OAI_PRESET_CHANGED_BEFORE, event => migrate(event.preset, event.savePreset, event.presetName)); +}; + +/** + * Represents a prompt. + */ +class Prompt { + identifier; role; content; name; system_prompt; position; injection_position; injection_depth; forbid_overrides; extension; + + /** + * Create a new Prompt instance. + * + * @param {Object} param0 - Object containing the properties of the prompt. + * @param {string} param0.identifier - The unique identifier of the prompt. + * @param {string} param0.role - The role associated with the prompt. + * @param {string} param0.content - The content of the prompt. + * @param {string} param0.name - The name of the prompt. + * @param {boolean} param0.system_prompt - Indicates if the prompt is a system prompt. + * @param {string} param0.position - The position of the prompt in the prompt list. + * @param {number} param0.injection_position - The insert position of the prompt. + * @param {number} param0.injection_depth - The depth of the prompt in the chat. + * @param {boolean} param0.forbid_overrides - Indicates if the prompt should not be overridden. + * @param {boolean} param0.extension - Prompt is added by an extension. + */ + constructor({ identifier, role, content, name, system_prompt, position, injection_depth, injection_position, forbid_overrides, extension } = {}) { + this.identifier = identifier; + this.role = role; + this.content = content; + this.name = name; + this.system_prompt = system_prompt; + this.position = position; + this.injection_depth = injection_depth; + this.injection_position = injection_position; + this.forbid_overrides = forbid_overrides; + this.extension = extension ?? false; + } +} + +/** + * Representing a collection of prompts. + */ +export class PromptCollection { + collection = []; + overriddenPrompts = []; + + /** + * Create a new PromptCollection instance. + * + * @param {...Prompt} prompts - An array of Prompt instances. + */ + constructor(...prompts) { + this.add(...prompts); + } + + /** + * Checks if the provided instances are of the Prompt class. + * + * @param {...any} prompts - Instances to check. + * @throws Will throw an error if one or more instances are not of the Prompt class. + */ + checkPromptInstance(...prompts) { + for (let prompt of prompts) { + if (!(prompt instanceof Prompt)) { + throw new Error('Only Prompt instances can be added to PromptCollection'); + } + } + } + + /** + * Adds new Prompt instances to the collection. + * + * @param {...Prompt} prompts - An array of Prompt instances. + */ + add(...prompts) { + this.checkPromptInstance(...prompts); + this.collection.push(...prompts); + } + + /** + * Sets a Prompt instance at a specific position in the collection. + * + * @param {Prompt} prompt - The Prompt instance to set. + * @param {number} position - The position in the collection to set the Prompt instance. + */ + set(prompt, position) { + this.checkPromptInstance(prompt); + this.collection[position] = prompt; + } + + /** + * Retrieves a Prompt instance from the collection by its identifier. + * + * @param {string} identifier - The identifier of the Prompt instance to retrieve. + * @returns {Prompt} The Prompt instance with the provided identifier, or undefined if not found. + */ + get(identifier) { + return this.collection.find(prompt => prompt.identifier === identifier); + } + + /** + * Retrieves the index of a Prompt instance in the collection by its identifier. + * + * @param {string} identifier - The identifier of the Prompt instance to find. + * @returns {number} The index of the Prompt instance in the collection, or -1 if not found. + */ + index(identifier) { + return this.collection.findIndex(prompt => prompt.identifier === identifier); + } + + /** + * Checks if a Prompt instance exists in the collection by its identifier. + * + * @param {string} identifier - The identifier of the Prompt instance to check. + * @returns {boolean} true if the Prompt instance exists in the collection, false otherwise. + */ + has(identifier) { + return this.index(identifier) !== -1; + } + + override(prompt, position) { + this.set(prompt, position); + this.overriddenPrompts.push(prompt.identifier); + } +} + +class PromptManager { + constructor() { + this.systemPrompts = [ + 'main', + 'nsfw', + 'jailbreak', + 'enhanceDefinitions', + ]; + + this.overridablePrompts = [ + 'main', + 'jailbreak', + ]; + + this.overriddenPrompts = []; + + this.configuration = { + version: 1, + prefix: '', + containerIdentifier: '', + listIdentifier: '', + listItemTemplateIdentifier: '', + toggleDisabled: [], + promptOrder: { + strategy: 'global', + dummyId: 100000, + }, + sortableDelay: 30, + warningTokenThreshold: 1500, + dangerTokenThreshold: 500, + defaultPrompts: { + main: '', + nsfw: '', + jailbreak: '', + enhanceDefinitions: '', + }, + }; + + // Chatcompletion configuration object + this.serviceSettings = null; + + // DOM element containing the prompt manager + this.containerElement = null; + + // DOM element containing the prompt list + this.listElement = null; + + // Currently selected character + this.activeCharacter = null; + + // Message collection of the most recent chatcompletion + this.messages = null; + + // The current token handler instance + this.tokenHandler = null; + + // Token usage of last dry run + this.tokenUsage = 0; + + // Error state, contains error message. + this.error = null; + + /** Dry-run for generate, must return a promise */ + this.tryGenerate = async () => { }; + + /** Called to persist the configuration, must return a promise */ + this.saveServiceSettings = () => { }; + + /** Toggle prompt button click */ + this.handleToggle = () => { }; + + /** Prompt name click */ + this.handleInspect = () => { }; + + /** Edit prompt button click */ + this.handleEdit = () => { }; + + /** Detach prompt button click */ + this.handleDetach = () => { }; + + /** Save prompt button click */ + this.handleSavePrompt = () => { }; + + /** Reset prompt button click */ + this.handleResetPrompt = () => { }; + + /** New prompt button click */ + this.handleNewPrompt = () => { }; + + /** Delete prompt button click */ + this.handleDeletePrompt = () => { }; + + /** Append prompt button click */ + this.handleAppendPrompt = () => { }; + + /** Import button click */ + this.handleImport = () => { }; + + /** Full export click */ + this.handleFullExport = () => { }; + + /** Character export click */ + this.handleCharacterExport = () => { }; + + /** Character reset button click*/ + this.handleCharacterReset = () => { }; + + /** Debounced version of render */ + this.renderDebounced = debounce(this.render.bind(this), debounce_timeout.relaxed); + } + + + /** + * Initializes the PromptManager with provided configuration and service settings. + * + * Sets up various handlers for user interactions, event listeners and initial rendering of prompts. + * It is also responsible for preparing prompt edit form buttons, managing popup form close and clear actions. + * + * @param {Object} moduleConfiguration - Configuration object for the PromptManager. + * @param {Object} serviceSettings - Service settings object for the PromptManager. + */ + init(moduleConfiguration, serviceSettings) { + this.configuration = Object.assign(this.configuration, moduleConfiguration); + this.tokenHandler = this.tokenHandler || new TokenHandler(() => { throw new Error('Token handler not set'); }); + this.serviceSettings = serviceSettings; + this.containerElement = document.getElementById(this.configuration.containerIdentifier); + + if ('global' === this.configuration.promptOrder.strategy) this.activeCharacter = { id: this.configuration.promptOrder.dummyId }; + + this.sanitizeServiceSettings(); + + // Enable and disable prompts + this.handleToggle = (event) => { + const promptID = event.target.closest('.' + this.configuration.prefix + 'prompt_manager_prompt').dataset.pmIdentifier; + const promptOrderEntry = this.getPromptOrderEntry(this.activeCharacter, promptID); + const counts = this.tokenHandler.getCounts(); + + counts[promptID] = null; + promptOrderEntry.enabled = !promptOrderEntry.enabled; + this.render(); + this.saveServiceSettings(); + }; + + // Open edit form and load selected prompt + this.handleEdit = (event) => { + this.clearEditForm(); + this.clearInspectForm(); + + const promptID = event.target.closest('.' + this.configuration.prefix + 'prompt_manager_prompt').dataset.pmIdentifier; + const prompt = this.getPromptById(promptID); + + this.loadPromptIntoEditForm(prompt); + + this.showPopup(); + }; + + // Open edit form and load selected prompt + this.handleInspect = (event) => { + this.clearEditForm(); + this.clearInspectForm(); + + const promptID = event.target.closest('.' + this.configuration.prefix + 'prompt_manager_prompt').dataset.pmIdentifier; + if (true === this.messages.hasItemWithIdentifier(promptID)) { + const messages = this.messages.getItemByIdentifier(promptID); + + this.loadMessagesIntoInspectForm(messages); + + this.showPopup('inspect'); + } + }; + + // Detach selected prompt from list form and close edit form + this.handleDetach = (event) => { + if (null === this.activeCharacter) return; + const promptID = event.target.closest('.' + this.configuration.prefix + 'prompt_manager_prompt').dataset.pmIdentifier; + const prompt = this.getPromptById(promptID); + + this.detachPrompt(prompt, this.activeCharacter); + this.hidePopup(); + this.clearEditForm(); + this.render(); + this.saveServiceSettings(); + }; + + // Save prompt edit form to settings and close form. + this.handleSavePrompt = (event) => { + const promptId = event.target.dataset.pmPrompt; + const prompt = this.getPromptById(promptId); + + if (null === prompt) { + const newPrompt = {}; + this.updatePromptWithPromptEditForm(newPrompt); + this.addPrompt(newPrompt, promptId); + } else { + this.updatePromptWithPromptEditForm(prompt); + } + + if ('main' === promptId) this.updateQuickEdit('main', prompt); + if ('nsfw' === promptId) this.updateQuickEdit('nsfw', prompt); + if ('jailbreak' === promptId) this.updateQuickEdit('jailbreak', prompt); + + this.log('Saved prompt: ' + promptId); + + this.hidePopup(); + this.clearEditForm(); + this.render(); + this.saveServiceSettings(); + }; + + // Reset prompt should it be a system prompt + this.handleResetPrompt = (event) => { + const promptId = event.target.dataset.pmPrompt; + const prompt = this.getPromptById(promptId); + + switch (promptId) { + case 'main': + prompt.name = 'Main Prompt'; + prompt.content = this.configuration.defaultPrompts.main; + prompt.forbid_overrides = false; + break; + case 'nsfw': + prompt.name = 'Nsfw Prompt'; + prompt.content = this.configuration.defaultPrompts.nsfw; + break; + case 'jailbreak': + prompt.name = 'Jailbreak Prompt'; + prompt.content = this.configuration.defaultPrompts.jailbreak; + prompt.forbid_overrides = false; + break; + case 'enhanceDefinitions': + prompt.name = 'Enhance Definitions'; + prompt.content = this.configuration.defaultPrompts.enhanceDefinitions; + break; + } + + document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_name').value = prompt.name; + document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_role').value = 'system'; + document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt').value = prompt.content ?? ''; + document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_position').value = prompt.injection_position ?? 0; + document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_depth').value = prompt.injection_depth ?? DEFAULT_DEPTH; + document.getElementById(this.configuration.prefix + 'prompt_manager_depth_block').style.visibility = prompt.injection_position === INJECTION_POSITION.ABSOLUTE ? 'visible' : 'hidden'; + document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_forbid_overrides').checked = prompt.forbid_overrides ?? false; + document.getElementById(this.configuration.prefix + 'prompt_manager_forbid_overrides_block').style.visibility = this.overridablePrompts.includes(prompt.identifier) ? 'visible' : 'hidden'; + document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt').disabled = prompt.marker ?? false; + + if (!this.systemPrompts.includes(promptId)) { + document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_position').removeAttribute('disabled'); + } + }; + + // Append prompt to selected character + this.handleAppendPrompt = (event) => { + const promptID = document.getElementById(this.configuration.prefix + 'prompt_manager_footer_append_prompt').value; + const prompt = this.getPromptById(promptID); + + if (prompt) { + this.appendPrompt(prompt, this.activeCharacter); + this.render(); + this.saveServiceSettings(); + } + }; + + // Delete selected prompt from list form and close edit form + this.handleDeletePrompt = async (event) => { + Popup.show.confirm(t`Are you sure you want to delete this prompt?`, null).then((userChoice) => { + if (!userChoice) return; + const promptID = document.getElementById(this.configuration.prefix + 'prompt_manager_footer_append_prompt').value; + const prompt = this.getPromptById(promptID); + + if (prompt && true === this.isPromptDeletionAllowed(prompt)) { + const promptIndex = this.getPromptIndexById(promptID); + this.serviceSettings.prompts.splice(Number(promptIndex), 1); + + this.log('Deleted prompt: ' + prompt.identifier); + + this.hidePopup(); + this.clearEditForm(); + this.render(); + this.saveServiceSettings(); + } + }); + }; + + // Create new prompt, then save it to settings and close form. + this.handleNewPrompt = (event) => { + const prompt = { + identifier: this.getUuidv4(), + name: '', + role: 'system', + content: '', + }; + + this.loadPromptIntoEditForm(prompt); + this.showPopup(); + }; + + // Export all user prompts + this.handleFullExport = () => { + const prompts = this.serviceSettings.prompts.reduce((userPrompts, prompt) => { + if (false === prompt.system_prompt && false === prompt.marker) userPrompts.push(prompt); + return userPrompts; + }, []); + + let promptOrder = []; + if ('global' === this.configuration.promptOrder.strategy) { + promptOrder = this.getPromptOrderForCharacter({ id: this.configuration.promptOrder.dummyId }); + } else if ('character' === this.configuration.promptOrder.strategy) { + promptOrder = []; + } else { + throw new Error('Prompt order strategy not supported.'); + } + + const exportPrompts = { + prompts: prompts, + prompt_order: promptOrder, + }; + + this.export(exportPrompts, 'full', 'st-prompts'); + }; + + // Export user prompts and order for this character + this.handleCharacterExport = () => { + const characterPrompts = this.getPromptsForCharacter(this.activeCharacter).reduce((userPrompts, prompt) => { + if (false === prompt.system_prompt && !prompt.marker) userPrompts.push(prompt); + return userPrompts; + }, []); + + const characterList = this.getPromptOrderForCharacter(this.activeCharacter); + + const exportPrompts = { + prompts: characterPrompts, + prompt_order: characterList, + }; + + const name = this.activeCharacter.name + '-prompts'; + this.export(exportPrompts, 'character', name); + }; + + // Import prompts for the selected character + this.handleImport = () => { + Popup.show.confirm(t`Existing prompts with the same ID will be overridden. Do you want to proceed?`, null) + .then(userChoice => { + if (!userChoice) return; + + const fileOpener = document.createElement('input'); + fileOpener.type = 'file'; + fileOpener.accept = '.json'; + + fileOpener.addEventListener('change', (event) => { + const file = event.target.files[0]; + if (!file) return; + + const reader = new FileReader(); + + reader.onload = (event) => { + const fileContent = event.target.result; + + try { + const data = JSON.parse(fileContent); + this.import(data); + } catch (err) { + toastr.error(t`An error occurred while importing prompts. More info available in console.`); + console.log('An error occurred while importing prompts'); + console.log(err.toString()); + } + }; + + reader.readAsText(file); + }); + + fileOpener.click(); + }); + }; + + // Restore default state of a characters prompt order + this.handleCharacterReset = () => { + Popup.show.confirm(t`This will reset the prompt order for this character. You will not lose any prompts.`, null) + .then(userChoice => { + if (!userChoice) return; + + this.removePromptOrderForCharacter(this.activeCharacter); + this.addPromptOrderForCharacter(this.activeCharacter, promptManagerDefaultPromptOrder); + + this.render(); + this.saveServiceSettings(); + }); + }; + + // Fill quick edit fields for the first time + if ('global' === this.configuration.promptOrder.strategy) { + const handleQuickEditSave = (event) => { + const promptId = event.target.dataset.pmPrompt; + const prompt = this.getPromptById(promptId); + + prompt.content = event.target.value; + + // Update edit form if present + // @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent + const popupEditFormPrompt = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt'); + if (popupEditFormPrompt.offsetParent) { + popupEditFormPrompt.value = prompt.content; + } + + this.log('Saved prompt: ' + promptId); + this.saveServiceSettings().then(() => this.render()); + }; + + const mainPrompt = this.getPromptById('main'); + const mainElementId = this.updateQuickEdit('main', mainPrompt); + document.getElementById(mainElementId).addEventListener('blur', handleQuickEditSave); + + const nsfwPrompt = this.getPromptById('nsfw'); + const nsfwElementId = this.updateQuickEdit('nsfw', nsfwPrompt); + document.getElementById(nsfwElementId).addEventListener('blur', handleQuickEditSave); + + const jailbreakPrompt = this.getPromptById('jailbreak'); + const jailbreakElementId = this.updateQuickEdit('jailbreak', jailbreakPrompt); + document.getElementById(jailbreakElementId).addEventListener('blur', handleQuickEditSave); + } + + // Re-render when chat history changes. + eventSource.on(event_types.MESSAGE_DELETED, () => this.renderDebounced()); + eventSource.on(event_types.MESSAGE_EDITED, () => this.renderDebounced()); + eventSource.on(event_types.MESSAGE_RECEIVED, () => this.renderDebounced()); + + // Re-render when chatcompletion settings change + eventSource.on(event_types.CHATCOMPLETION_SOURCE_CHANGED, () => this.renderDebounced()); + + eventSource.on(event_types.CHATCOMPLETION_MODEL_CHANGED, () => this.renderDebounced()); + + // Re-render when the character changes. + eventSource.on('chatLoaded', (event) => { + this.handleCharacterSelected(event); + this.saveServiceSettings().then(() => this.renderDebounced()); + }); + + // Re-render when the character gets edited. + eventSource.on(event_types.CHARACTER_EDITED, (event) => { + this.handleCharacterUpdated(event); + this.saveServiceSettings().then(() => this.renderDebounced()); + }); + + // Re-render when the group changes. + eventSource.on('groupSelected', (event) => { + this.handleGroupSelected(event); + this.saveServiceSettings().then(() => this.renderDebounced()); + }); + + // Sanitize settings after character has been deleted. + eventSource.on(event_types.CHARACTER_DELETED, (event) => { + this.handleCharacterDeleted(event); + this.saveServiceSettings().then(() => this.renderDebounced()); + }); + + // Trigger re-render when token settings are changed + document.getElementById('openai_max_context').addEventListener('change', (event) => { + this.serviceSettings.openai_max_context = event.target.value; + if (this.activeCharacter) this.renderDebounced(); + }); + + document.getElementById('openai_max_tokens').addEventListener('change', (event) => { + if (this.activeCharacter) this.renderDebounced(); + }); + + // Prepare prompt edit form buttons + document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_save').addEventListener('click', this.handleSavePrompt); + document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_reset').addEventListener('click', this.handleResetPrompt); + + const closeAndClearPopup = () => { + this.hidePopup(); + this.clearEditForm(); + this.clearInspectForm(); + }; + + // Clear forms on closing the popup + document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_close').addEventListener('click', closeAndClearPopup); + document.getElementById(this.configuration.prefix + 'prompt_manager_popup_close_button').addEventListener('click', closeAndClearPopup); + + // Re-render prompt manager on openai preset change + eventSource.on(event_types.OAI_PRESET_CHANGED_AFTER, () => { + this.sanitizeServiceSettings(); + const mainPrompt = this.getPromptById('main'); + this.updateQuickEdit('main', mainPrompt); + + const nsfwPrompt = this.getPromptById('nsfw'); + this.updateQuickEdit('nsfw', nsfwPrompt); + + const jailbreakPrompt = this.getPromptById('jailbreak'); + this.updateQuickEdit('jailbreak', jailbreakPrompt); + + this.hidePopup(); + this.clearEditForm(); + this.renderDebounced(); + }); + + // Re-render prompt manager on world settings update + eventSource.on(event_types.WORLDINFO_SETTINGS_UPDATED, () => this.renderDebounced()); + + this.log('Initialized'); + } + + /** + * Get the scroll position of the prompt manager + * @returns {number} - Scroll position of the prompt manager + */ + #getScrollPosition() { + return document.getElementById(this.configuration.prefix + 'prompt_manager')?.closest('.scrollableInner')?.scrollTop; + } + + /** + * Set the scroll position of the prompt manager + * @param {number} scrollPosition - The scroll position to set + */ + #setScrollPosition(scrollPosition) { + if (scrollPosition === undefined || scrollPosition === null) return; + document.getElementById(this.configuration.prefix + 'prompt_manager')?.closest('.scrollableInner')?.scrollTo(0, scrollPosition); + } + + /** + * Main rendering function + * + * @param afterTryGenerate - Whether a dry run should be attempted before rendering + */ + render(afterTryGenerate = true) { + if (main_api !== 'openai') return; + + if ('character' === this.configuration.promptOrder.strategy && null === this.activeCharacter) return; + this.error = null; + + waitUntilCondition(() => !is_send_press && !is_group_generating, 1024 * 1024, 100).then(async () => { + if (true === afterTryGenerate) { + // Executed during dry-run for determining context composition + this.profileStart('filling context'); + this.tryGenerate().finally(async () => { + this.profileEnd('filling context'); + this.profileStart('render'); + const scrollPosition = this.#getScrollPosition(); + await this.renderPromptManager(); + await this.renderPromptManagerListItems(); + this.makeDraggable(); + this.#setScrollPosition(scrollPosition); + this.profileEnd('render'); + }); + } else { + // Executed during live communication + this.profileStart('render'); + const scrollPosition = this.#getScrollPosition(); + await this.renderPromptManager(); + await this.renderPromptManagerListItems(); + this.makeDraggable(); + this.#setScrollPosition(scrollPosition); + this.profileEnd('render'); + } + }).catch(() => { + console.log('Timeout while waiting for send press to be false'); + }); + } + + /** + * Update a prompt with the values from the HTML form. + * @param {object} prompt - The prompt to be updated. + * @returns {void} + */ + updatePromptWithPromptEditForm(prompt) { + prompt.name = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_name').value; + prompt.role = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_role').value; + prompt.content = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt').value; + prompt.injection_position = Number(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_position').value); + prompt.injection_depth = Number(document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_depth').value); + prompt.forbid_overrides = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_forbid_overrides').checked; + } + + /** + * Find a prompt by its identifier and update it with the provided object. + * @param {string} identifier - The identifier of the prompt. + * @param {object} updatePrompt - An object with properties to be updated in the prompt. + * @returns {void} + */ + updatePromptByIdentifier(identifier, updatePrompt) { + let prompt = this.serviceSettings.prompts.find((item) => identifier === item.identifier); + if (prompt) prompt = Object.assign(prompt, updatePrompt); + } + + /** + * Iterate over an array of prompts, find each one by its identifier, and update them with the provided data. + * @param {object[]} prompts - An array of prompt updates. + * @returns {void} + */ + updatePrompts(prompts) { + prompts.forEach((update) => { + let prompt = this.getPromptById(update.identifier); + if (prompt) Object.assign(prompt, update); + }); + } + + getTokenHandler() { + return this.tokenHandler; + } + + isPromptDisabledForActiveCharacter(identifier) { + const promptOrderEntry = this.getPromptOrderEntry(this.activeCharacter, identifier); + if (promptOrderEntry) return !promptOrderEntry.enabled; + return false; + } + + /** + * Add a prompt to the current character's prompt list. + * @param {object} prompt - The prompt to be added. + * @param {object} character - The character whose prompt list will be updated. + * @returns {void} + */ + appendPrompt(prompt, character) { + const promptOrder = this.getPromptOrderForCharacter(character); + const index = promptOrder.findIndex(entry => entry.identifier === prompt.identifier); + + if (-1 === index) promptOrder.unshift({ identifier: prompt.identifier, enabled: false }); + } + + /** + * Remove a prompt from the current character's prompt list. + * @param {object} prompt - The prompt to be removed. + * @param {object} character - The character whose prompt list will be updated. + * @returns {void} + */ + // Remove a prompt from the current characters prompt list + detachPrompt(prompt, character) { + const promptOrder = this.getPromptOrderForCharacter(character); + const index = promptOrder.findIndex(entry => entry.identifier === prompt.identifier); + if (-1 === index) return; + promptOrder.splice(index, 1); + } + + /** + * Create a new prompt and add it to the list of prompts. + * @param {object} prompt - The prompt to be added. + * @param {string} identifier - The identifier for the new prompt. + * @returns {void} + */ + addPrompt(prompt, identifier) { + + if (typeof prompt !== 'object' || prompt === null) throw new Error('Object is not a prompt'); + + const newPrompt = { + identifier: identifier, + system_prompt: false, + enabled: false, + marker: false, + ...prompt, + }; + + this.serviceSettings.prompts.push(newPrompt); + } + + /** + * Sanitize the service settings, ensuring each prompt has a unique identifier. + * @returns {void} + */ + sanitizeServiceSettings() { + this.serviceSettings.prompts = this.serviceSettings.prompts ?? []; + this.serviceSettings.prompt_order = this.serviceSettings.prompt_order ?? []; + + if ('global' === this.configuration.promptOrder.strategy) { + const dummyCharacter = { id: this.configuration.promptOrder.dummyId }; + const promptOrder = this.getPromptOrderForCharacter(dummyCharacter); + + if (0 === promptOrder.length) this.addPromptOrderForCharacter(dummyCharacter, promptManagerDefaultPromptOrder); + } + + // Check whether the referenced prompts are present. + this.serviceSettings.prompts.length === 0 + ? this.setPrompts(chatCompletionDefaultPrompts.prompts) + : this.checkForMissingPrompts(this.serviceSettings.prompts); + + // Add identifiers if there are none assigned to a prompt + this.serviceSettings.prompts.forEach(prompt => prompt && (prompt.identifier = prompt.identifier ?? this.getUuidv4())); + + if (this.activeCharacter) { + const promptReferences = this.getPromptOrderForCharacter(this.activeCharacter); + for (let i = promptReferences.length - 1; i >= 0; i--) { + const reference = promptReferences[i]; + if (reference && -1 === this.serviceSettings.prompts.findIndex(prompt => prompt.identifier === reference.identifier)) { + promptReferences.splice(i, 1); + this.log('Removed unused reference: ' + reference.identifier); + } + } + } + } + + /** + * Checks whether entries of a characters prompt order are orphaned + * and if all mandatory system prompts for a character are present. + * + * @param prompts + */ + checkForMissingPrompts(prompts) { + const defaultPromptIdentifiers = chatCompletionDefaultPrompts.prompts.reduce((list, prompt) => { list.push(prompt.identifier); return list; }, []); + + const missingIdentifiers = defaultPromptIdentifiers.filter(identifier => + !prompts.some(prompt => prompt.identifier === identifier), + ); + + missingIdentifiers.forEach(identifier => { + const defaultPrompt = chatCompletionDefaultPrompts.prompts.find(prompt => prompt?.identifier === identifier); + if (defaultPrompt) { + prompts.push(defaultPrompt); + this.log(`Missing system prompt: ${defaultPrompt.identifier}. Added default.`); + } + }); + } + + /** + * Check whether a prompt can be inspected. + * @param {object} prompt - The prompt to check. + * @returns {boolean} True if the prompt is a marker, false otherwise. + */ + isPromptInspectionAllowed(prompt) { + return true; + } + + /** + * Check whether a prompt can be deleted. System prompts cannot be deleted. + * @param {object} prompt - The prompt to check. + * @returns {boolean} True if the prompt can be deleted, false otherwise. + */ + isPromptDeletionAllowed(prompt) { + return false === prompt.system_prompt; + } + + /** + * Check whether a prompt can be edited. + * @param {object} prompt - The prompt to check. + * @returns {boolean} True if the prompt can be edited, false otherwise. + */ + isPromptEditAllowed(prompt) { + const forceEditPrompts = [ + 'charDescription', + 'charPersonality', + 'scenario', + 'personaDescription', + 'worldInfoBefore', + 'worldInfoAfter', + ]; + return forceEditPrompts.includes(prompt.identifier) || !prompt.marker; + } + + /** + * Check whether a prompt can be toggled on or off. + * @param {object} prompt - The prompt to check. + * @returns {boolean} True if the prompt can be deleted, false otherwise. + */ + isPromptToggleAllowed(prompt) { + const forceTogglePrompts = [ + 'charDescription', + 'charPersonality', + 'scenario', + 'personaDescription', + 'worldInfoBefore', + 'worldInfoAfter', + 'main', + 'chatHistory', + 'dialogueExamples', + ]; + return prompt.marker && !forceTogglePrompts.includes(prompt.identifier) ? false : !this.configuration.toggleDisabled.includes(prompt.identifier); + } + + /** + * Handle the deletion of a character by removing their prompt list and nullifying the active character if it was the one deleted. + * @param {object} event - The event object containing the character's ID. + * @returns void + */ + handleCharacterDeleted(event) { + if ('global' === this.configuration.promptOrder.strategy) return; + this.removePromptOrderForCharacter(this.activeCharacter); + if (this.activeCharacter.id === event.detail.id) this.activeCharacter = null; + } + + /** + * Handle the selection of a character by setting them as the active character and setting up their prompt list if necessary. + * @param {object} event - The event object containing the character's ID and character data. + * @returns {void} + */ + handleCharacterSelected(event) { + if ('global' === this.configuration.promptOrder.strategy) { + this.activeCharacter = { id: this.configuration.promptOrder.dummyId }; + } else if ('character' === this.configuration.promptOrder.strategy) { + console.log('FOO'); + this.activeCharacter = { id: event.detail.id, ...event.detail.character }; + const promptOrder = this.getPromptOrderForCharacter(this.activeCharacter); + + // ToDo: These should be passed as parameter or attached to the manager as a set of default options. + // Set default prompts and order for character. + if (0 === promptOrder.length) this.addPromptOrderForCharacter(this.activeCharacter, promptManagerDefaultPromptOrder); + } else { + throw new Error('Unsupported prompt order mode.'); + } + } + + /** + * Set the most recently selected character + * + * @param event + */ + handleCharacterUpdated(event) { + if ('global' === this.configuration.promptOrder.strategy) { + this.activeCharacter = { id: this.configuration.promptOrder.dummyId }; + } else if ('character' === this.configuration.promptOrder.strategy) { + this.activeCharacter = { id: event.detail.id, ...event.detail.character }; + } else { + throw new Error('Prompt order strategy not supported.'); + } + } + + /** + * Set the most recently selected character group + * + * @param event + */ + handleGroupSelected(event) { + if ('global' === this.configuration.promptOrder.strategy) { + this.activeCharacter = { id: this.configuration.promptOrder.dummyId }; + } else if ('character' === this.configuration.promptOrder.strategy) { + const characterDummy = { id: event.detail.id, group: event.detail.group }; + this.activeCharacter = characterDummy; + const promptOrder = this.getPromptOrderForCharacter(characterDummy); + + if (0 === promptOrder.length) this.addPromptOrderForCharacter(characterDummy, promptManagerDefaultPromptOrder); + } else { + throw new Error('Prompt order strategy not supported.'); + } + } + + /** + * Get a list of group characters, regardless of whether they are active or not. + * + * @returns {string[]} + */ + getActiveGroupCharacters() { + // ToDo: Ideally, this should return the actual characters. + return (this.activeCharacter?.group?.members || []).map(member => member && member.substring(0, member.lastIndexOf('.'))); + } + + /** + * Get the prompts for a specific character. Can be filtered to only include enabled prompts. + * @returns {object[]} The prompts for the character. + * @param character + * @param onlyEnabled + */ + getPromptsForCharacter(character, onlyEnabled = false) { + return this.getPromptOrderForCharacter(character) + .map(item => true === onlyEnabled ? (true === item.enabled ? this.getPromptById(item.identifier) : null) : this.getPromptById(item.identifier)) + .filter(prompt => null !== prompt); + } + + /** + * Get the order of prompts for a specific character. If no character is specified or the character doesn't have a prompt list, an empty array is returned. + * @param {object|null} character - The character to get the prompt list for. + * @returns {object[]} The prompt list for the character, or an empty array. + */ + getPromptOrderForCharacter(character) { + return !character ? [] : (this.serviceSettings.prompt_order.find(list => String(list.character_id) === String(character.id))?.order ?? []); + } + + /** + * Set the prompts for the manager. + * @param {object[]} prompts - The prompts to be set. + * @returns {void} + */ + setPrompts(prompts) { + this.serviceSettings.prompts = prompts; + } + + /** + * Remove the prompt list for a specific character. + * @param {object} character - The character whose prompt list will be removed. + * @returns {void} + */ + removePromptOrderForCharacter(character) { + const index = this.serviceSettings.prompt_order.findIndex(list => String(list.character_id) === String(character.id)); + if (-1 !== index) this.serviceSettings.prompt_order.splice(index, 1); + } + + /** + * Adds a new prompt list for a specific character. + * @param {Object} character - Object with at least an `id` property + * @param {Array} promptOrder - Array of prompt objects + */ + addPromptOrderForCharacter(character, promptOrder) { + this.serviceSettings.prompt_order.push({ + character_id: character.id, + order: JSON.parse(JSON.stringify(promptOrder)), + }); + } + + /** + * Searches for a prompt list entry for a given character and identifier. + * @param {Object} character - Character object + * @param {string} identifier - Identifier of the prompt list entry + * @returns {Object|null} The prompt list entry object, or null if not found + */ + getPromptOrderEntry(character, identifier) { + return this.getPromptOrderForCharacter(character).find(entry => entry.identifier === identifier) ?? null; + } + + /** + * Finds and returns a prompt by its identifier. + * @param {string} identifier - Identifier of the prompt + * @returns {Object|null} The prompt object, or null if not found + */ + getPromptById(identifier) { + return this.serviceSettings.prompts.find(item => item && item.identifier === identifier) ?? null; + } + + /** + * Finds and returns the index of a prompt by its identifier. + * @param {string} identifier - Identifier of the prompt + * @returns {number|null} Index of the prompt, or null if not found + */ + getPromptIndexById(identifier) { + return this.serviceSettings.prompts.findIndex(item => item.identifier === identifier) ?? null; + } + + /** + * Enriches a generic object, creating a new prompt object in the process + * + * @param {Object} prompt - Prompt object + * @param original + * @returns {Object} An object with "role" and "content" properties + */ + preparePrompt(prompt, original = null) { + const groupMembers = this.getActiveGroupCharacters(); + const preparedPrompt = new Prompt(prompt); + + if (typeof original === 'string') { + if (0 < groupMembers.length) preparedPrompt.content = substituteParams(prompt.content ?? '', null, null, original, groupMembers.join(', ')); + else preparedPrompt.content = substituteParams(prompt.content, null, null, original); + } else { + if (0 < groupMembers.length) preparedPrompt.content = substituteParams(prompt.content ?? '', null, null, null, groupMembers.join(', ')); + else preparedPrompt.content = substituteParams(prompt.content); + } + + return preparedPrompt; + } + + /** + * Factory function for creating a QuickEdit object associated with a prompt element. + * + * The QuickEdit object provides methods to synchronize an input element's value with a prompt's content + * and handle input events to update the prompt content. + * + */ + createQuickEdit(identifier, title) { + const prompt = this.getPromptById(identifier); + const textareaIdentifier = `${identifier}_prompt_quick_edit_textarea`; + const html = `
      +
      ${title}
      +
      + +
      +
      `; + + const quickEditContainer = document.getElementById('quick-edit-container'); + quickEditContainer.insertAdjacentHTML('afterbegin', html); + + const debouncedSaveServiceSettings = debouncePromise(() => this.saveServiceSettings(), 300); + + const textarea = document.getElementById(textareaIdentifier); + textarea.addEventListener('blur', () => { + prompt.content = textarea.value; + this.updatePromptByIdentifier(identifier, prompt); + debouncedSaveServiceSettings().then(() => this.render()); + }); + + } + + updateQuickEdit(identifier, prompt) { + const elementId = `${identifier}_prompt_quick_edit_textarea`; + const textarea = document.getElementById(elementId); + textarea.value = prompt.content; + + return elementId; + } + + /** + * Checks if a given name is accepted by OpenAi API + * @link https://platform.openai.com/docs/api-reference/chat/create + * + * @param name + * @returns {boolean} + */ + isValidName(name) { + const regex = /^[a-zA-Z0-9_]{1,64}$/; + + return regex.test(name); + } + + sanitizeName(name) { + return name.replace(/[^a-zA-Z0-9_]/g, '_').substring(0, 64); + } + + /** + * Loads a given prompt into the edit form fields. + * @param {Object} prompt - Prompt object with properties 'name', 'role', 'content', and 'system_prompt' + */ + loadPromptIntoEditForm(prompt) { + const nameField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_name'); + const roleField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_role'); + const promptField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt'); + const injectionPositionField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_position'); + const injectionDepthField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_depth'); + const injectionDepthBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_depth_block'); + const forbidOverridesField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_forbid_overrides'); + const forbidOverridesBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_forbid_overrides_block'); + + nameField.value = prompt.name ?? ''; + roleField.value = prompt.role || 'system'; + promptField.value = prompt.content ?? ''; + promptField.disabled = prompt.marker ?? false; + injectionPositionField.value = prompt.injection_position ?? INJECTION_POSITION.RELATIVE; + injectionDepthField.value = prompt.injection_depth ?? DEFAULT_DEPTH; + injectionDepthBlock.style.visibility = prompt.injection_position === INJECTION_POSITION.ABSOLUTE ? 'visible' : 'hidden'; + injectionPositionField.removeAttribute('disabled'); + forbidOverridesField.checked = prompt.forbid_overrides ?? false; + forbidOverridesBlock.style.visibility = this.overridablePrompts.includes(prompt.identifier) ? 'visible' : 'hidden'; + + if (this.systemPrompts.includes(prompt.identifier)) { + injectionPositionField.setAttribute('disabled', 'disabled'); + } + + const resetPromptButton = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_reset'); + if (true === prompt.system_prompt) { + resetPromptButton.style.display = 'block'; + resetPromptButton.dataset.pmPrompt = prompt.identifier; + } else { + resetPromptButton.style.display = 'none'; + } + + injectionPositionField.removeEventListener('change', (e) => this.handleInjectionPositionChange(e)); + injectionPositionField.addEventListener('change', (e) => this.handleInjectionPositionChange(e)); + + const savePromptButton = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_save'); + savePromptButton.dataset.pmPrompt = prompt.identifier; + } + + handleInjectionPositionChange(event) { + const injectionDepthBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_depth_block'); + const injectionPosition = Number(event.target.value); + if (injectionPosition === INJECTION_POSITION.ABSOLUTE) { + injectionDepthBlock.style.visibility = 'visible'; + } else { + injectionDepthBlock.style.visibility = 'hidden'; + } + } + + /** + * Loads a given prompt into the inspect form + * @param {MessageCollection} messages - Prompt object with properties 'name', 'role', 'content', and 'system_prompt' + */ + loadMessagesIntoInspectForm(messages) { + if (!messages) return; + + const createInlineDrawer = (message) => { + const truncatedTitle = message.content.length > 32 ? message.content.slice(0, 32) + '...' : message.content; + const title = message.identifier || truncatedTitle; + const role = message.role; + const content = message.content || 'No Content'; + const tokens = message.getTokens(); + + let drawerHTML = ` +
      +
      + Name: ${escapeHtml(title)}, Role: ${role}, Tokens: ${tokens} +
      +
      +
      ${escapeHtml(content)}
      +
      + `; + + let template = document.createElement('template'); + template.innerHTML = drawerHTML.trim(); + return template.content.firstChild; + }; + + const messageList = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_inspect_list'); + + const messagesCollection = messages instanceof Message ? [messages] : messages.getCollection(); + + if (0 === messagesCollection.length) messageList.innerHTML = 'This marker does not contain any prompts.'; + + messagesCollection.forEach(message => { + messageList.append(createInlineDrawer(message)); + }); + } + + /** + * Clears all input fields in the edit form. + */ + clearEditForm() { + const editArea = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_edit'); + editArea.style.display = 'none'; + + const nameField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_name'); + const roleField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_role'); + const promptField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_prompt'); + const injectionPositionField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_position'); + const injectionDepthField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_injection_depth'); + const injectionDepthBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_depth_block'); + const forbidOverridesField = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_forbid_overrides'); + const forbidOverridesBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_forbid_overrides_block'); + + nameField.value = ''; + roleField.selectedIndex = 0; + promptField.value = ''; + promptField.disabled = false; + injectionPositionField.selectedIndex = 0; + injectionPositionField.removeAttribute('disabled'); + injectionDepthField.value = DEFAULT_DEPTH; + injectionDepthBlock.style.visibility = 'unset'; + forbidOverridesBlock.style.visibility = 'unset'; + forbidOverridesField.checked = false; + + roleField.disabled = false; + } + + clearInspectForm() { + const inspectArea = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_inspect'); + inspectArea.style.display = 'none'; + const messageList = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_entry_form_inspect_list'); + messageList.innerHTML = ''; + } + + /** + * Returns a full list of prompts whose content markers have been substituted. + * @returns {PromptCollection} A PromptCollection object + */ + getPromptCollection() { + const promptOrder = this.getPromptOrderForCharacter(this.activeCharacter); + + const promptCollection = new PromptCollection(); + promptOrder.forEach(entry => { + if (true === entry.enabled) { + const prompt = this.getPromptById(entry.identifier); + if (prompt) promptCollection.add(this.preparePrompt(prompt)); + } else if (!entry.enabled && entry.identifier === 'main') { + // Some extensions require main prompt to be present for relative inserts. + // So we make a GMO-free vegan replacement. + const prompt = structuredClone(this.getPromptById(entry.identifier)); + prompt.content = ''; + if (prompt) promptCollection.add(this.preparePrompt(prompt)); + } + }); + + return promptCollection; + } + + /** + * Setter for messages property + * + * @param {import('./openai.js').MessageCollection} messages + */ + setMessages(messages) { + this.messages = messages; + } + + /** + * Set and process a finished chat completion object + * + * @param {import('./openai.js').ChatCompletion} chatCompletion + */ + setChatCompletion(chatCompletion) { + const messages = chatCompletion.getMessages(); + + this.setMessages(messages); + this.populateTokenCounts(messages); + this.overriddenPrompts = chatCompletion.getOverriddenPrompts(); + } + + /** + * Populates the token handler + * + * @param {import('./openai.js').MessageCollection} messages + */ + populateTokenCounts(messages) { + this.tokenHandler.resetCounts(); + const counts = this.tokenHandler.getCounts(); + messages.getCollection().forEach(message => { + counts[message.identifier] = message.getTokens(); + }); + + this.tokenUsage = this.tokenHandler.getTotal(); + + this.log('Updated token usage with ' + this.tokenUsage); + } + + /** + * Empties, then re-assembles the container containing the prompt list. + */ + async renderPromptManager() { + let selectedPromptIndex = 0; + const existingAppendSelect = document.getElementById(`${this.configuration.prefix}prompt_manager_footer_append_prompt`); + if (existingAppendSelect instanceof HTMLSelectElement) { + selectedPromptIndex = existingAppendSelect.selectedIndex; + } + const promptManagerDiv = this.containerElement; + promptManagerDiv.innerHTML = ''; + + const errorDiv = this.error ? ` +
      + ${DOMPurify.sanitize(this.error)} +
      + ` : ''; + + const totalActiveTokens = this.tokenUsage; + + const headerHtml = await renderTemplateAsync('promptManagerHeader', { error: this.error, errorDiv, prefix: this.configuration.prefix, totalActiveTokens }); + promptManagerDiv.insertAdjacentHTML('beforeend', headerHtml); + + this.listElement = promptManagerDiv.querySelector(`#${this.configuration.prefix}prompt_manager_list`); + + if (null !== this.activeCharacter) { + const prompts = [...this.serviceSettings.prompts] + .filter(prompt => prompt && !prompt?.system_prompt) + .sort((promptA, promptB) => promptA.name.localeCompare(promptB.name)); + const promptsHtml = prompts.reduce((acc, prompt) => acc + ``, ''); + + if (selectedPromptIndex > 0) { + selectedPromptIndex = Math.min(selectedPromptIndex, prompts.length - 1); + } + + if (selectedPromptIndex === -1 && prompts.length) { + selectedPromptIndex = 0; + } + + const rangeBlockDiv = promptManagerDiv.querySelector('.range-block'); + const headerDiv = promptManagerDiv.querySelector('.completion_prompt_manager_header'); + const footerHtml = await renderTemplateAsync('promptManagerFooter', { promptsHtml, prefix: this.configuration.prefix }); + headerDiv.insertAdjacentHTML('afterend', footerHtml); + rangeBlockDiv.querySelector('#prompt-manager-reset-character').addEventListener('click', this.handleCharacterReset); + + const footerDiv = rangeBlockDiv.querySelector(`.${this.configuration.prefix}prompt_manager_footer`); + footerDiv.querySelector('.menu_button:nth-child(2)').addEventListener('click', this.handleAppendPrompt); + footerDiv.querySelector('.caution').addEventListener('click', this.handleDeletePrompt); + footerDiv.querySelector('.menu_button:last-child').addEventListener('click', this.handleNewPrompt); + footerDiv.querySelector('select').selectedIndex = selectedPromptIndex; + + // Add prompt export dialogue and options + + const exportForCharacter = await renderTemplateAsync('promptManagerExportForCharacter'); + const exportPopup = await renderTemplateAsync('promptManagerExportPopup', { isGlobalStrategy: 'global' === this.configuration.promptOrder.strategy, exportForCharacter }); + rangeBlockDiv.insertAdjacentHTML('beforeend', exportPopup); + + // Destroy previous popper instance if it exists + if (this.exportPopper) { + this.exportPopper.destroy(); + } + + this.exportPopper = Popper.createPopper( + document.getElementById('prompt-manager-export'), + document.getElementById('prompt-manager-export-format-popup'), + { placement: 'bottom' }, + ); + + const showExportSelection = () => { + const popup = document.getElementById('prompt-manager-export-format-popup'); + const show = popup.hasAttribute('data-show'); + + if (show) popup.removeAttribute('data-show'); + else popup.setAttribute('data-show', ''); + + this.exportPopper.update(); + }; + + footerDiv.querySelector('#prompt-manager-import').addEventListener('click', this.handleImport); + footerDiv.querySelector('#prompt-manager-export').addEventListener('click', showExportSelection); + rangeBlockDiv.querySelector('.export-promptmanager-prompts-full').addEventListener('click', this.handleFullExport); + rangeBlockDiv.querySelector('.export-promptmanager-prompts-character')?.addEventListener('click', this.handleCharacterExport); + } + } + + /** + * Empties, then re-assembles the prompt list + */ + async renderPromptManagerListItems() { + if (!this.serviceSettings.prompts) return; + + const promptManagerList = this.listElement; + promptManagerList.innerHTML = ''; + + const { prefix } = this.configuration; + + let listItemHtml = await renderTemplateAsync('promptManagerListHeader', { prefix }); + + this.getPromptsForCharacter(this.activeCharacter).forEach(prompt => { + if (!prompt) return; + + const listEntry = this.getPromptOrderEntry(this.activeCharacter, prompt.identifier); + const enabledClass = listEntry.enabled ? '' : `${prefix}prompt_manager_prompt_disabled`; + const draggableClass = `${prefix}prompt_manager_prompt_draggable`; + const markerClass = prompt.marker ? `${prefix}prompt_manager_marker` : ''; + const tokens = this.tokenHandler?.getCounts()[prompt.identifier] ?? 0; + + // Warn the user if the chat history goes below certain token thresholds. + let warningClass = ''; + let warningTitle = ''; + + const tokenBudget = this.serviceSettings.openai_max_context - this.serviceSettings.openai_max_tokens; + if (this.tokenUsage > tokenBudget * 0.8 && + 'chatHistory' === prompt.identifier) { + const warningThreshold = this.configuration.warningTokenThreshold; + const dangerThreshold = this.configuration.dangerTokenThreshold; + + if (tokens <= dangerThreshold) { + warningClass = 'fa-solid tooltip fa-triangle-exclamation text_danger'; + warningTitle = 'Very little of your chat history is being sent, consider deactivating some other prompts.'; + } else if (tokens <= warningThreshold) { + warningClass = 'fa-solid tooltip fa-triangle-exclamation text_warning'; + warningTitle = 'Only a few messages worth chat history are being sent.'; + } + } + + const calculatedTokens = tokens ? tokens : '-'; + + let detachSpanHtml = ''; + if (this.isPromptDeletionAllowed(prompt)) { + detachSpanHtml = ` + + `; + } else { + detachSpanHtml = ''; + } + + let editSpanHtml = ''; + if (this.isPromptEditAllowed(prompt)) { + editSpanHtml = ` + + `; + } else { + editSpanHtml = ''; + } + + let toggleSpanHtml = ''; + if (this.isPromptToggleAllowed(prompt)) { + toggleSpanHtml = ` + + `; + } else { + toggleSpanHtml = ''; + } + + const encodedName = escapeHtml(prompt.name); + const isMarkerPrompt = prompt.marker && prompt.injection_position !== INJECTION_POSITION.ABSOLUTE; + const isSystemPrompt = !prompt.marker && prompt.system_prompt && prompt.injection_position !== INJECTION_POSITION.ABSOLUTE && !prompt.forbid_overrides; + const isImportantPrompt = !prompt.marker && prompt.system_prompt && prompt.injection_position !== INJECTION_POSITION.ABSOLUTE && prompt.forbid_overrides; + const isUserPrompt = !prompt.marker && !prompt.system_prompt && prompt.injection_position !== INJECTION_POSITION.ABSOLUTE; + const isInjectionPrompt = prompt.injection_position === INJECTION_POSITION.ABSOLUTE; + const isOverriddenPrompt = Array.isArray(this.overriddenPrompts) && this.overriddenPrompts.includes(prompt.identifier); + const importantClass = isImportantPrompt ? `${prefix}prompt_manager_important` : ''; + const iconLookup = prompt.role === 'system' && (prompt.marker || prompt.system_prompt) ? '' : prompt.role; + + //add role icons to the right of prompt name + const promptRoles = { + assistant: { roleIcon: 'fa-robot', roleTitle: 'Prompt will be sent as Assistant' }, + user: { roleIcon: 'fa-user', roleTitle: 'Prompt will be sent as User' }, + }; + const roleIcon = promptRoles[iconLookup]?.roleIcon || ''; + const roleTitle = promptRoles[iconLookup]?.roleTitle || ''; + + listItemHtml += ` +
    • + + + ${isMarkerPrompt ? '' : ''} + ${isSystemPrompt ? '' : ''} + ${isImportantPrompt ? '' : ''} + ${isUserPrompt ? '' : ''} + ${isInjectionPrompt ? '' : ''} + ${this.isPromptInspectionAllowed(prompt) ? `${encodedName}` : `${encodedName}`} + ${roleIcon ? `` : ''} + ${isInjectionPrompt ? `@ ${escapeHtml(prompt.injection_depth)}` : ''} + ${isOverriddenPrompt ? '' : ''} + + + + ${detachSpanHtml} + ${editSpanHtml} + ${toggleSpanHtml} + + + + ${calculatedTokens} +
    • + `; + }); + + promptManagerList.insertAdjacentHTML('beforeend', listItemHtml); + + // Now that the new elements are in the DOM, you can add the event listeners. + Array.from(promptManagerList.getElementsByClassName('prompt-manager-detach-action')).forEach(el => { + el.addEventListener('click', this.handleDetach); + }); + + Array.from(promptManagerList.getElementsByClassName('prompt-manager-inspect-action')).forEach(el => { + el.addEventListener('click', this.handleInspect); + }); + + Array.from(promptManagerList.getElementsByClassName('prompt-manager-edit-action')).forEach(el => { + el.addEventListener('click', this.handleEdit); + }); + + Array.from(promptManagerList.querySelectorAll('.prompt-manager-toggle-action')).forEach(el => { + el.addEventListener('click', this.handleToggle); + }); + } + + /** + * Writes the passed data to a json file + * + * @param data + * @param type + * @param name + */ + export(data, type, name = 'export') { + const promptExport = { + version: this.configuration.version, + type: type, + data: data, + }; + + const serializedObject = JSON.stringify(promptExport, null, 4); + const blob = new Blob([serializedObject], { type: 'application/json' }); + const url = URL.createObjectURL(blob); + const downloadLink = document.createElement('a'); + downloadLink.href = url; + + const dateString = this.getFormattedDate(); + downloadLink.download = `${name}-${dateString}.json`; + + downloadLink.click(); + + URL.revokeObjectURL(url); + } + + /** + * Imports a json file with prompts and an optional prompt list for the active character + * + * @param importData + */ + import(importData) { + const mergeKeepNewer = (prompts, newPrompts) => { + let merged = [...prompts, ...newPrompts]; + + let map = new Map(); + for (let obj of merged) { + map.set(obj.identifier, obj); + } + + merged = Array.from(map.values()); + + return merged; + }; + + const controlObj = { + version: 1, + type: '', + data: { + prompts: [], + prompt_order: null, + }, + }; + + if (false === this.validateObject(controlObj, importData)) { + toastr.warning(t`Could not import prompts. Export failed validation.`); + return; + } + + const prompts = mergeKeepNewer(this.serviceSettings.prompts, importData.data.prompts); + + this.setPrompts(prompts); + this.log('Prompt import succeeded'); + + if ('global' === this.configuration.promptOrder.strategy) { + const promptOrder = this.getPromptOrderForCharacter({ id: this.configuration.promptOrder.dummyId }); + Object.assign(promptOrder, importData.data.prompt_order); + this.log('Prompt order import succeeded'); + } else if ('character' === this.configuration.promptOrder.strategy) { + if ('character' === importData.type) { + const promptOrder = this.getPromptOrderForCharacter(this.activeCharacter); + Object.assign(promptOrder, importData.data.prompt_order); + this.log(`Prompt order import for character ${this.activeCharacter.name} succeeded`); + } + } else { + throw new Error('Prompt order strategy not supported.'); + } + + toastr.success(t`Prompt import complete.`); + this.saveServiceSettings().then(() => this.render()); + } + + /** + * Helper function to check whether the structure of object matches controlObj + * + * @param controlObj + * @param object + * @returns {boolean} + */ + validateObject(controlObj, object) { + for (let key in controlObj) { + if (!Object.hasOwn(object, key)) { + if (controlObj[key] === null) continue; + else return false; + } + + if (typeof controlObj[key] === 'object' && controlObj[key] !== null) { + if (typeof object[key] !== 'object') return false; + if (!this.validateObject(controlObj[key], object[key])) return false; + } else { + if (typeof object[key] !== typeof controlObj[key]) return false; + } + } + + return true; + } + + /** + * Get current date as mm/dd/YYYY + * + * @returns {`${string}_${string}_${string}`} + */ + getFormattedDate() { + const date = new Date(); + let month = String(date.getMonth() + 1); + let day = String(date.getDate()); + const year = String(date.getFullYear()); + + if (month.length < 2) month = '0' + month; + if (day.length < 2) day = '0' + day; + + return `${month}_${day}_${year}`; + } + + /** + * Makes the prompt list draggable and handles swapping of two entries in the list. + * @typedef {Object} Entry + * @property {string} identifier + * @returns {void} + */ + makeDraggable() { + $(`#${this.configuration.prefix}prompt_manager_list`).sortable({ + delay: this.configuration.sortableDelay, + handle: isMobile() ? '.drag-handle' : null, + items: `.${this.configuration.prefix}prompt_manager_prompt_draggable`, + update: (event, ui) => { + const promptOrder = this.getPromptOrderForCharacter(this.activeCharacter); + const promptListElement = $(`#${this.configuration.prefix}prompt_manager_list`).sortable('toArray', { attribute: 'data-pm-identifier' }); + const idToObjectMap = new Map(promptOrder.map(prompt => [prompt.identifier, prompt])); + const updatedPromptOrder = promptListElement.map(identifier => idToObjectMap.get(identifier)); + + this.removePromptOrderForCharacter(this.activeCharacter); + this.addPromptOrderForCharacter(this.activeCharacter, updatedPromptOrder); + + this.log(`Prompt order updated for ${this.activeCharacter.name}.`); + + this.saveServiceSettings(); + }, + }); + } + + /** + * Slides down the edit form and adds the class 'openDrawer' to the first element of '#openai_prompt_manager_popup'. + * @returns {void} + */ + showPopup(area = 'edit') { + const areaElement = document.getElementById(this.configuration.prefix + 'prompt_manager_popup_' + area); + areaElement.style.display = 'flex'; + + $('#' + this.configuration.prefix + 'prompt_manager_popup').first() + .slideDown(200, 'swing') + .addClass('openDrawer'); + } + + /** + * Slides up the edit form and removes the class 'openDrawer' from the first element of '#openai_prompt_manager_popup'. + * @returns {void} + */ + hidePopup() { + $('#' + this.configuration.prefix + 'prompt_manager_popup').first() + .slideUp(200, 'swing') + .removeClass('openDrawer'); + } + + /** + * Quick uuid4 implementation + * @returns {string} A string representation of an uuid4 + */ + getUuidv4() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + let r = Math.random() * 16 | 0, + v = c === 'x' ? r : (r & 0x3 | 0x8); + return v.toString(16); + }); + } + + /** + * Write to console with prefix + * + * @param output + */ + log(output) { + if (power_user.console_log_prompts) console.log('[PromptManager] ' + output); + } + + /** + * Start a profiling task + * + * @param identifier + */ + profileStart(identifier) { + if (power_user.console_log_prompts) console.time(identifier); + } + + /** + * End a profiling task + * + * @param identifier + */ + profileEnd(identifier) { + if (power_user.console_log_prompts) { + this.log('Profiling of "' + identifier + '" finished. Result below.'); + console.timeEnd(identifier); + } + } +} + +const chatCompletionDefaultPrompts = { + 'prompts': [ + { + 'name': 'Main Prompt', + 'system_prompt': true, + 'role': 'system', + 'content': 'Write {{char}}\'s next reply in a fictional chat between {{charIfNotGroup}} and {{user}}.', + 'identifier': 'main', + }, + { + 'name': 'Auxiliary Prompt', + 'system_prompt': true, + 'role': 'system', + 'content': '', + 'identifier': 'nsfw', + }, + { + 'identifier': 'dialogueExamples', + 'name': 'Chat Examples', + 'system_prompt': true, + 'marker': true, + }, + { + 'name': 'Post-History Instructions', + 'system_prompt': true, + 'role': 'system', + 'content': '', + 'identifier': 'jailbreak', + }, + { + 'identifier': 'chatHistory', + 'name': 'Chat History', + 'system_prompt': true, + 'marker': true, + }, + { + 'identifier': 'worldInfoAfter', + 'name': 'World Info (after)', + 'system_prompt': true, + 'marker': true, + }, + { + 'identifier': 'worldInfoBefore', + 'name': 'World Info (before)', + 'system_prompt': true, + 'marker': true, + }, + { + 'identifier': 'enhanceDefinitions', + 'role': 'system', + 'name': 'Enhance Definitions', + 'content': 'If you have more knowledge of {{char}}, add to the character\'s lore and personality to enhance them but keep the Character Sheet\'s definitions absolute.', + 'system_prompt': true, + 'marker': false, + }, + { + 'identifier': 'charDescription', + 'name': 'Char Description', + 'system_prompt': true, + 'marker': true, + }, + { + 'identifier': 'charPersonality', + 'name': 'Char Personality', + 'system_prompt': true, + 'marker': true, + }, + { + 'identifier': 'scenario', + 'name': 'Scenario', + 'system_prompt': true, + 'marker': true, + }, + { + 'identifier': 'personaDescription', + 'name': 'Persona Description', + 'system_prompt': true, + 'marker': true, + }, + ], +}; + +const promptManagerDefaultPromptOrders = { + 'prompt_order': [], +}; + +const promptManagerDefaultPromptOrder = [ + { + 'identifier': 'main', + 'enabled': true, + }, + { + 'identifier': 'worldInfoBefore', + 'enabled': true, + }, + { + 'identifier': 'personaDescription', + 'enabled': true, + }, + { + 'identifier': 'charDescription', + 'enabled': true, + }, + { + 'identifier': 'charPersonality', + 'enabled': true, + }, + { + 'identifier': 'scenario', + 'enabled': true, + }, + { + 'identifier': 'enhanceDefinitions', + 'enabled': false, + }, + { + 'identifier': 'nsfw', + 'enabled': true, + }, + { + 'identifier': 'worldInfoAfter', + 'enabled': true, + }, + { + 'identifier': 'dialogueExamples', + 'enabled': true, + }, + { + 'identifier': 'chatHistory', + 'enabled': true, + }, + { + 'identifier': 'jailbreak', + 'enabled': true, + }, +]; + +export { + PromptManager, + registerPromptManagerMigration, + chatCompletionDefaultPrompts, + promptManagerDefaultPromptOrders, + Prompt, +}; diff --git a/jiuguan2025cc/public/scripts/RossAscends-mods.js b/jiuguan2025cc/public/scripts/RossAscends-mods.js new file mode 100644 index 0000000000000000000000000000000000000000..6d4110220b854626604949450d92da5e5f92215e --- /dev/null +++ b/jiuguan2025cc/public/scripts/RossAscends-mods.js @@ -0,0 +1,1320 @@ +import { DOMPurify, Bowser, slideToggle } from '../lib.js'; + +import { + characters, + online_status, + main_api, + api_server, + is_send_press, + max_context, + saveSettingsDebounced, + active_group, + active_character, + setActiveGroup, + setActiveCharacter, + getEntitiesList, + buildAvatarList, + selectCharacterById, + eventSource, + menu_type, + substituteParams, + sendTextareaMessage, + getSlideToggleOptions, +} from '../script.js'; + +import { + power_user, + send_on_enter_options, +} from './power-user.js'; + +import { selected_group, is_group_generating, openGroupById } from './group-chats.js'; +import { getTagKeyForEntity, applyTagsOnCharacterSelect } from './tags.js'; +import { + SECRET_KEYS, + secret_state, +} from './secrets.js'; +import { debounce, getStringHash, isValidUrl } from './utils.js'; +import { chat_completion_sources, oai_settings } from './openai.js'; +import { getTokenCountAsync } from './tokenizers.js'; +import { textgen_types, textgenerationwebui_settings as textgen_settings, getTextGenServer } from './textgen-settings.js'; +import { debounce_timeout } from './constants.js'; + +import { Popup } from './popup.js'; +import { accountStorage } from './util/AccountStorage.js'; +import { getCurrentUserHandle } from './user.js'; + +var RPanelPin = document.getElementById('rm_button_panel_pin'); +var LPanelPin = document.getElementById('lm_button_panel_pin'); +var WIPanelPin = document.getElementById('WI_panel_pin'); + +var RightNavPanel = document.getElementById('right-nav-panel'); +var RightNavDrawerIcon = document.getElementById('rightNavDrawerIcon'); +var LeftNavPanel = document.getElementById('left-nav-panel'); +var LeftNavDrawerIcon = document.getElementById('leftNavDrawerIcon'); +var WorldInfo = document.getElementById('WorldInfo'); +var WIDrawerIcon = document.getElementById('WIDrawerIcon'); + +var SelectedCharacterTab = document.getElementById('rm_button_selected_ch'); + +var connection_made = false; +var retry_delay = 500; +let counterNonce = Date.now(); + +const observerConfig = { childList: true, subtree: true }; +const countTokensDebounced = debounce(RA_CountCharTokens, debounce_timeout.relaxed); +const countTokensShortDebounced = debounce(RA_CountCharTokens, debounce_timeout.short); +const checkStatusDebounced = debounce(RA_checkOnlineStatus, debounce_timeout.short); + +const observer = new MutationObserver(function (mutations) { + mutations.forEach(function (mutation) { + if (!(mutation.target instanceof HTMLElement)) { + return; + } + if (mutation.target.classList.contains('online_status_text')) { + checkStatusDebounced(); + } else if (mutation.target.parentNode === SelectedCharacterTab) { + countTokensShortDebounced(); + } else if (mutation.target.classList.contains('mes_text')) { + for (const element of mutation.target.getElementsByTagName('math')) { + element.childNodes.forEach(function (child) { + if (child.nodeType === Node.TEXT_NODE) { + child.textContent = ''; + } + }); + } + } + }); +}); + +observer.observe(document.documentElement, observerConfig); + + +/** + * Converts generation time from milliseconds to a human-readable format. + * + * The function takes total generation time as an input, then converts it to a format + * of "_ Days, _ Hours, _ Minutes, _ Seconds". If the generation time does not exceed a + * particular measure (like days or hours), that measure will not be included in the output. + * + * @param {number} total_gen_time - The total generation time in milliseconds. + * @returns {string} - A human-readable string that represents the time spent generating characters. + */ +export function humanizeGenTime(total_gen_time) { + + //convert time_spent to humanized format of "_ Hours, _ Minutes, _ Seconds" from milliseconds + let time_spent = total_gen_time || 0; + time_spent = Math.floor(time_spent / 1000); + let seconds = time_spent % 60; + time_spent = Math.floor(time_spent / 60); + let minutes = time_spent % 60; + time_spent = Math.floor(time_spent / 60); + let hours = time_spent % 24; + time_spent = Math.floor(time_spent / 24); + let days = time_spent; + time_spent = ''; + if (days > 0) { time_spent += `${days} Days, `; } + if (hours > 0) { time_spent += `${hours} Hours, `; } + if (minutes > 0) { time_spent += `${minutes} Minutes, `; } + time_spent += `${seconds} Seconds`; + return time_spent; +} + +/** + * DON'T OPTIMIZE, don't change this to a const or let, it needs to be a var. + */ +var parsedUA = null; + +export function getParsedUA() { + if (!parsedUA) { + try { + parsedUA = Bowser.parse(navigator.userAgent); + } catch { + // In case the user agent is an empty string or Bowser can't parse it for some other reason + } + } + + return parsedUA; +} + +/** + * Checks if the device is a mobile device. + * @returns {boolean} - True if the device is a mobile device, false otherwise. + */ +export function isMobile() { + const mobileTypes = ['mobile', 'tablet']; + + return mobileTypes.includes(getParsedUA()?.platform?.type); +} + +export function shouldSendOnEnter() { + if (!power_user) { + return false; + } + + switch (power_user.send_on_enter) { + case send_on_enter_options.DISABLED: + return false; + case send_on_enter_options.AUTO: + return !isMobile(); + case send_on_enter_options.ENABLED: + return true; + } +} + +//RossAscends: Added function to format dates used in files and chat timestamps to a humanized format. +//Mostly I wanted this to be for file names, but couldn't figure out exactly where the filename save code was as everything seemed to be connected. +//Does not break old characters/chats, as the code just uses whatever timestamp exists in the chat. +//New chats made with characters will use this new formatting. +export function humanizedDateTime() { + const now = new Date(Date.now()); + const dt = { + year: now.getFullYear(), month: now.getMonth() + 1, day: now.getDate(), + hour: now.getHours(), minute: now.getMinutes(), second: now.getSeconds(), + }; + for (const key in dt) { + dt[key] = dt[key].toString().padStart(2, '0'); + } + return `${dt.year}-${dt.month}-${dt.day}@${dt.hour}h${dt.minute}m${dt.second}s`; +} + +//this is a common format version to display a timestamp on each chat message +//returns something like: June 19, 2023 2:20pm +export function getMessageTimeStamp() { + const date = Date.now(); + const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; + const d = new Date(date); + const month = months[d.getMonth()]; + const day = d.getDate(); + const year = d.getFullYear(); + let hours = d.getHours(); + const minutes = ('0' + d.getMinutes()).slice(-2); + let meridiem = 'am'; + if (hours >= 12) { + meridiem = 'pm'; + hours -= 12; + } + if (hours === 0) { + hours = 12; + } + const formattedDate = month + ' ' + day + ', ' + year + ' ' + hours + ':' + minutes + meridiem; + return formattedDate; +} + + +// triggers: +$('#rm_button_create').on('click', function () { //when "+New Character" is clicked + $(SelectedCharacterTab).children('h2').html(''); // empty nav's 3rd panel tab +}); +//when any input is made to the create/edit character form textareas +$('#rm_ch_create_block').on('input', function () { countTokensDebounced(); }); +//when any input is made to the advanced editing popup textareas +$('#character_popup').on('input', function () { countTokensDebounced(); }); +//function: +export async function RA_CountCharTokens() { + counterNonce = Date.now(); + const counterNonceLocal = counterNonce; + let total_tokens = 0; + let permanent_tokens = 0; + + const tokenCounters = document.querySelectorAll('[data-token-counter]'); + for (const tokenCounter of tokenCounters) { + if (counterNonceLocal !== counterNonce) { + return; + } + + const counter = $(tokenCounter); + const input = $(document.getElementById(counter.data('token-counter'))); + const isPermanent = counter.data('token-permanent') === true; + const value = String(input.val()); + + if (input.length === 0) { + counter.text('Invalid input reference'); + continue; + } + + if (!value) { + input.data('last-value-hash', ''); + counter.text(0); + continue; + } + + const valueHash = getStringHash(value); + + if (input.data('last-value-hash') === valueHash) { + total_tokens += Number(counter.text()); + permanent_tokens += isPermanent ? Number(counter.text()) : 0; + } else { + // We substitute macro for existing characters, but not for the character being created + const valueToCount = menu_type === 'create' ? value : substituteParams(value); + const tokens = await getTokenCountAsync(valueToCount); + + if (counterNonceLocal !== counterNonce) { + return; + } + + counter.text(tokens); + total_tokens += tokens; + permanent_tokens += isPermanent ? tokens : 0; + input.data('last-value-hash', valueHash); + } + } + + // Warn if total tokens exceeds the limit of half the max context + const tokenLimit = Math.max(((main_api !== 'openai' ? max_context : oai_settings.openai_max_context) / 2), 1024); + const showWarning = (total_tokens > tokenLimit); + $('#result_info_total_tokens').text(total_tokens); + $('#result_info_permanent_tokens').text(permanent_tokens); + $('#result_info_text').toggleClass('neutral_warning', showWarning); + $('#chartokenwarning').toggle(showWarning); +} +/** + * Auto load chat with the last active character or group. + * Fires when active_character is defined and auto_load_chat is true. + * The function first tries to find a character with a specific ID from the global settings. + * If it doesn't exist, it tries to find a group with a specific grid from the global settings. + * If the character list hadn't been loaded yet, it calls itself again after 100ms delay. + * The character or group is selected (clicked) if it is found. + */ +async function RA_autoloadchat() { + if (document.querySelector('#rm_print_characters_block .character_select') !== null) { + // active character is the name, we should look it up in the character list and get the id + if (active_character !== null && active_character !== undefined) { + const active_character_id = characters.findIndex(x => getTagKeyForEntity(x) === active_character); + if (active_character_id !== -1) { + await selectCharacterById(active_character_id); + + // Do a little tomfoolery to spoof the tag selector + const selectedCharElement = $(`#rm_print_characters_block .character_select[chid="${active_character_id}"]`); + applyTagsOnCharacterSelect.call(selectedCharElement); + } else { + setActiveCharacter(null); + saveSettingsDebounced(); + console.warn(`Currently active character with ID ${active_character} not found. Resetting to no active character.`); + } + } + + if (active_group !== null && active_group !== undefined) { + if (active_character) { + console.warn('Active character and active group are both set. Only active character will be loaded. Resetting active group.'); + setActiveGroup(null); + saveSettingsDebounced(); + } else { + const result = await openGroupById(String(active_group)); + if (!result) { + setActiveGroup(null); + saveSettingsDebounced(); + console.warn(`Currently active group with ID ${active_group} not found. Resetting to no active group.`); + } + } + } + + // if the character list hadn't been loaded yet, try again. + } else { setTimeout(RA_autoloadchat, 100); } +} + +export async function favsToHotswap() { + const entities = getEntitiesList({ doFilter: false }); + const container = $('#right-nav-panel .hotswap'); + + // Hard limit is required because even if all hotswaps don't fit the screen, their images would still be loaded + // 25 is roughly calculated as the maximum number of favs that can fit an ultrawide monitor with the default theme + const FAVS_LIMIT = 25; + const favs = entities.filter(x => x.item.fav || x.item.fav == 'true').slice(0, FAVS_LIMIT); + + //helpful instruction message if no characters are favorited + if (favs.length == 0) { + container.html(` ${DOMPurify.sanitize(container.attr('no_favs'))}`); + return; + } + + buildAvatarList(container, favs, { interactable: true, highlightFavs: false }); +} + +//changes input bar and send button display depending on connection status +function RA_checkOnlineStatus() { + if (online_status == 'no_connection') { + const send_textarea = $('#send_textarea'); + send_textarea.attr('placeholder', send_textarea.attr('no_connection_text')); //Input bar placeholder tells users they are not connected + $('#send_form').addClass('no-connection'); + $('#send_but').addClass('displayNone'); //send button is hidden when not connected; + $('#mes_continue').addClass('displayNone'); //continue button is hidden when not connected; + $('#mes_impersonate').addClass('displayNone'); //continue button is hidden when not connected; + $('#API-status-top').removeClass('fa-plug'); + $('#API-status-top').addClass('fa-plug-circle-exclamation redOverlayGlow'); + connection_made = false; + } else { + if (online_status !== undefined && online_status !== 'no_connection') { + const send_textarea = $('#send_textarea'); + send_textarea.attr('placeholder', send_textarea.attr('connected_text')); //on connect, placeholder tells user to type message + $('#send_form').removeClass('no-connection'); + $('#API-status-top').removeClass('fa-plug-circle-exclamation redOverlayGlow'); + $('#API-status-top').addClass('fa-plug'); + connection_made = true; + retry_delay = 100; + + if (!is_send_press && !(selected_group && is_group_generating)) { + $('#send_but').removeClass('displayNone'); //on connect, send button shows + $('#mes_continue').removeClass('displayNone'); //continue button is shown when connected + $('#mes_impersonate').removeClass('displayNone'); //continue button is shown when connected + } + } + } +} +//Auto-connect to API (when set to kobold, API URL exists, and auto_connect is true) + +function RA_autoconnect(PrevApi) { + // secrets.js or script.js not loaded + if (SECRET_KEYS === undefined || online_status === undefined) { + setTimeout(RA_autoconnect, 100); + return; + } + if (online_status === 'no_connection' && power_user.auto_connect) { + switch (main_api) { + case 'kobold': + if (api_server && isValidUrl(api_server)) { + $('#api_button').trigger('click'); + } + break; + case 'novel': + if (secret_state[SECRET_KEYS.NOVEL]) { + $('#api_button_novel').trigger('click'); + } + break; + case 'textgenerationwebui': + if ((textgen_settings.type === textgen_types.MANCER && secret_state[SECRET_KEYS.MANCER]) + || (textgen_settings.type === textgen_types.TOGETHERAI && secret_state[SECRET_KEYS.TOGETHERAI]) + || (textgen_settings.type === textgen_types.INFERMATICAI && secret_state[SECRET_KEYS.INFERMATICAI]) + || (textgen_settings.type === textgen_types.DREAMGEN && secret_state[SECRET_KEYS.DREAMGEN]) + || (textgen_settings.type === textgen_types.OPENROUTER && secret_state[SECRET_KEYS.OPENROUTER]) + || (textgen_settings.type === textgen_types.FEATHERLESS && secret_state[SECRET_KEYS.FEATHERLESS]) + ) { + $('#api_button_textgenerationwebui').trigger('click'); + } + else if (isValidUrl(getTextGenServer())) { + $('#api_button_textgenerationwebui').trigger('click'); + } + break; + case 'openai': + if (((secret_state[SECRET_KEYS.OPENAI] || oai_settings.reverse_proxy) && oai_settings.chat_completion_source == chat_completion_sources.OPENAI) + || ((secret_state[SECRET_KEYS.CLAUDE] || oai_settings.reverse_proxy) && oai_settings.chat_completion_source == chat_completion_sources.CLAUDE) + || ((secret_state[SECRET_KEYS.SCALE] || secret_state[SECRET_KEYS.SCALE_COOKIE]) && oai_settings.chat_completion_source == chat_completion_sources.SCALE) + || (oai_settings.chat_completion_source == chat_completion_sources.WINDOWAI) + || (secret_state[SECRET_KEYS.OPENROUTER] && oai_settings.chat_completion_source == chat_completion_sources.OPENROUTER) + || (secret_state[SECRET_KEYS.AI21] && oai_settings.chat_completion_source == chat_completion_sources.AI21) + || (secret_state[SECRET_KEYS.MAKERSUITE] && oai_settings.chat_completion_source == chat_completion_sources.MAKERSUITE) + || (secret_state[SECRET_KEYS.MISTRALAI] && oai_settings.chat_completion_source == chat_completion_sources.MISTRALAI) + || (secret_state[SECRET_KEYS.COHERE] && oai_settings.chat_completion_source == chat_completion_sources.COHERE) + || (secret_state[SECRET_KEYS.PERPLEXITY] && oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY) + || (secret_state[SECRET_KEYS.GROQ] && oai_settings.chat_completion_source == chat_completion_sources.GROQ) + || (secret_state[SECRET_KEYS.ZEROONEAI] && oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI) + || (secret_state[SECRET_KEYS.BLOCKENTROPY] && oai_settings.chat_completion_source == chat_completion_sources.BLOCKENTROPY) + || (secret_state[SECRET_KEYS.NANOGPT] && oai_settings.chat_completion_source == chat_completion_sources.NANOGPT) + || (secret_state[SECRET_KEYS.DEEPSEEK] && oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK) + || (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM) + ) { + $('#api_button_openai').trigger('click'); + } + break; + } + + if (!connection_made) { + retry_delay = Math.min(retry_delay * 2, 30000); // double retry delay up to to 30 secs + // console.log('connection attempts: ' + RA_AC_retries + ' delay: ' + (retry_delay / 1000) + 's'); + // setTimeout(RA_autoconnect, retry_delay); + } + } +} + +function OpenNavPanels() { + if (!isMobile()) { + //auto-open R nav if locked and previously open + if (accountStorage.getItem('NavLockOn') == 'true' && accountStorage.getItem('NavOpened') == 'true') { + //console.log("RA -- clicking right nav to open"); + $('#rightNavDrawerIcon').click(); + } + + //auto-open L nav if locked and previously open + if (accountStorage.getItem('LNavLockOn') == 'true' && accountStorage.getItem('LNavOpened') == 'true') { + console.debug('RA -- clicking left nav to open'); + $('#leftNavDrawerIcon').click(); + } + + //auto-open WI if locked and previously open + if (accountStorage.getItem('WINavLockOn') == 'true' && accountStorage.getItem('WINavOpened') == 'true') { + console.debug('RA -- clicking WI to open'); + $('#WIDrawerIcon').click(); + } + } +} + +const getUserInputKey = () => getCurrentUserHandle() + '_userInput'; + +function restoreUserInput() { + if (!power_user.restore_user_input) { + console.debug('restoreUserInput disabled'); + return; + } + + const userInput = localStorage.getItem(getUserInputKey()); + if (userInput) { + $('#send_textarea').val(userInput)[0].dispatchEvent(new Event('input', { bubbles: true })); + } +} + +function saveUserInput() { + const userInput = String($('#send_textarea').val()); + localStorage.setItem(getUserInputKey(), userInput); + console.debug('User Input -- ', userInput); +} +const saveUserInputDebounced = debounce(saveUserInput); + +// Make the DIV element draggable: + +export function dragElement(elmnt) { + var isHeaderBeingDragged = false; + var isMouseDown = false; + + var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0; + var height, width, top, left, right, bottom, + maxX, maxY, winHeight, winWidth, + topbar, topBarFirstX, topBarLastY; + + var elmntName = elmnt.attr('id'); + console.debug(`dragElement called for ${elmntName}`); + const elmntNameEscaped = $.escapeSelector(elmntName); + const elmntHeader = $(`#${elmntNameEscaped}header`); + + if (elmntHeader.length) { + elmntHeader.off('mousedown').on('mousedown', (e) => { //listener for drag handle repositioning + isHeaderBeingDragged = true; + isMouseDown = true; + observer.observe(elmnt.get(0), { attributes: true, attributeFilter: ['style'] }); + dragMouseDown(e); + }); + $(elmnt).off('mousedown').on('mousedown', () => { //listener for resize + isMouseDown = true; + observer.observe(elmnt.get(0), { attributes: true, attributeFilter: ['style'] }); + }); + } + + const observer = new MutationObserver((mutations) => { + const target = mutations[0].target; + if (!$(target).is(':visible') //abort if element is invisible + || $(target).hasClass('resizing') //being auto-resized by other JS code + || Number((String(target.height).replace('px', ''))) < 50 //too short + || Number((String(target.width).replace('px', ''))) < 50 //too narrow + || power_user.movingUI === false // if MUI is not turned on + || isMobile() // if it's a mobile screen + ) { + return; + } + + const style = getComputedStyle(target); + height = parseInt(style.height); + width = parseInt(style.width); + top = parseInt(style.top); + left = parseInt(style.left); + right = parseInt(style.right); + bottom = parseInt(style.bottom); + maxX = parseInt(width + left); + maxY = parseInt(height + top); + winWidth = window.innerWidth; + winHeight = window.innerHeight; + + topbar = document.getElementById('top-bar'); + const topbarstyle = getComputedStyle(topbar); + topBarFirstX = parseInt(topbarstyle.marginInline); + topBarLastY = parseInt(topbarstyle.height); + + //prepare an empty poweruser object for the item being altered if we don't have one already + if (!power_user.movingUIState[elmntName]) { + console.debug(`adding config property for ${elmntName}`); + power_user.movingUIState[elmntName] = {}; + } + + //handle resizing + if (!isHeaderBeingDragged && isMouseDown) { //if user is dragging the resize handle (not in header) + let imgHeight, imgWidth, imageAspectRatio; + let containerAspectRatio = height / width; + + //force aspect ratio for zoomed avatars + if ($(elmnt).attr('id').startsWith('zoomFor_')) { + let zoomedAvatarImage = $(elmnt).find('.zoomed_avatar_img'); + imgHeight = zoomedAvatarImage.height(); + imgWidth = zoomedAvatarImage.width(); + imageAspectRatio = imgHeight / imgWidth; + + // Maintain aspect ratio + if (containerAspectRatio !== imageAspectRatio) { + elmnt.css('width', elmnt.width()); + elmnt.css('height', elmnt.width() * imageAspectRatio); + } + + // Prevent resizing offscreen + if (top + elmnt.height() >= winHeight) { + elmnt.css('height', winHeight - top - 1 + 'px'); + elmnt.css('width', (winHeight - top - 1) / imageAspectRatio + 'px'); + } + + if (left + elmnt.width() >= winWidth) { + elmnt.css('width', winWidth - left - 1 + 'px'); + elmnt.css('height', (winWidth - left - 1) * imageAspectRatio + 'px'); + } + } else { //prevent divs that are not zoomedAvatars from resizing offscreen + + if (top + elmnt.height() >= winHeight) { + elmnt.css('height', winHeight - top - 1 + 'px'); + } + + if (left + elmnt.width() >= winWidth) { + elmnt.css('width', winWidth - left - 1 + 'px'); + } + } + + //prevent resizing from top left into the top bar + if (top < topBarLastY && maxX >= topBarFirstX && left <= topBarFirstX) { + elmnt.css('width', width - 1 + 'px'); + } + + //set css to prevent weird resize behavior (does not save) + elmnt.css('left', left); + elmnt.css('top', top); + + //set a listener for mouseup to save new width/height + $(window).off('mouseup').on('mouseup', () => { + console.log(`Saving ${elmntName} Height/Width`); + // check if the height or width actually changed + if (power_user.movingUIState[elmntName].width === elmnt.width() && power_user.movingUIState[elmntName].height === elmnt.height()) { + console.log('no change detected, aborting save'); + return; + } + + power_user.movingUIState[elmntName].width = width; + power_user.movingUIState[elmntName].height = height; + eventSource.emit('resizeUI', elmntName); + saveSettingsDebounced(); + imgHeight = null; + imgWidth = null; + height = null; + width = null; + + containerAspectRatio = null; + imageAspectRatio = null; + $(window).off('mouseup'); + }); + } + + //only record position changes if header is being dragged + power_user.movingUIState[elmntName].top = top; + power_user.movingUIState[elmntName].left = left; + power_user.movingUIState[elmntName].right = right; + power_user.movingUIState[elmntName].bottom = bottom; + power_user.movingUIState[elmntName].margin = 'unset'; + + //handle dragging hit detection to prevent dragging offscreen + if (isHeaderBeingDragged && isMouseDown) { + + if (top <= 0) { + elmnt.css('top', '0px'); + } else if (maxY >= winHeight) { + elmnt.css('top', winHeight - maxY + top - 1 + 'px'); + } + + if (left <= 0) { + elmnt.css('left', '0px'); + } else if (maxX >= winWidth) { + elmnt.css('left', winWidth - maxX + left - 1 + 'px'); + } + } + + // Check if the element header exists and set the reposition listener on the grabber in the header + if (elmntHeader.length) { + elmntHeader.off('mousedown').on('mousedown', (e) => { + dragMouseDown(e); + }); + } else { //if no header, put the listener on the elmnt itself. + elmnt.off('mousedown').on('mousedown', dragMouseDown); + } + }); + + function dragMouseDown(e) { + + if (e) { + isHeaderBeingDragged = true; + e.preventDefault(); + pos3 = e.clientX; //mouse X at click + pos4 = e.clientY; //mouse Y at click + } + $(document).on('mouseup', closeDragElement); + $(document).on('mousemove', elementDrag); + } + + function elementDrag(e) { + if (!power_user.movingUIState[elmntName]) { + power_user.movingUIState[elmntName] = {}; + } + + e = e || window.event; + e.preventDefault(); + + pos1 = pos3 - e.clientX; //X change amt (-1 or 1) + pos2 = pos4 - e.clientY; //Y change amt (-1 or 1) + pos3 = e.clientX; //new mouse X + pos4 = e.clientY; //new mouse Y + + elmnt.attr('data-dragged', 'true'); + + //first set css to computed values to avoid CSS NaN results from 'auto', etc + elmnt.css('left', (elmnt.offset().left) + 'px'); + elmnt.css('top', (elmnt.offset().top) + 'px'); + + //then update element position styles to account for drag changes + elmnt.css('margin', 'unset'); + elmnt.css('left', (elmnt.offset().left - pos1) + 'px'); + elmnt.css('top', (elmnt.offset().top - pos2) + 'px'); + /* elmnt.css('right', ((winWidth - maxX) + 'px')); + elmnt.css('bottom', ((winHeight - maxY) + 'px')); */ + + // Height/Width here are for visuals only, and are not saved to settings. + // This is required because some divs do hot have a set width/height + // and will default to shrink to min value of 100px set in CSS file + elmnt.css('height', height); + elmnt.css('width', width); + return; + } + + function closeDragElement() { + console.debug('drag finished'); + isHeaderBeingDragged = false; + isMouseDown = false; + $(document).off('mouseup', closeDragElement); + $(document).off('mousemove', elementDrag); + $('body').css('overflow', ''); + // Clear the "data-dragged" attribute + elmnt.attr('data-dragged', 'false'); + observer.disconnect(); + console.debug(`Saving ${elmntName} UI position`); + saveSettingsDebounced(); + top = null; + left = null; + right = null; + bottom = null; + maxX = null; + maxY = null; + } +} + +export async function initMovingUI() { + if (!isMobile() && power_user.movingUI === true) { + console.debug('START MOVING UI'); + dragElement($('#sheld')); + dragElement($('#left-nav-panel')); + dragElement($('#right-nav-panel')); + dragElement($('#WorldInfo')); + dragElement($('#floatingPrompt')); + dragElement($('#logprobsViewer')); + dragElement($('#cfgConfig')); + } +} + +/**@type {HTMLTextAreaElement} */ +const sendTextArea = document.querySelector('#send_textarea'); +const chatBlock = document.getElementById('chat'); +const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; + +/** + * this makes the chat input text area resize vertically to match the text size (limited by CSS at 50% window height) + */ +function autoFitSendTextArea() { + const originalScrollBottom = chatBlock.scrollHeight - (chatBlock.scrollTop + chatBlock.offsetHeight); + + sendTextArea.style.height = '1px'; // Reset height to 1px to force recalculation of scrollHeight + const newHeight = sendTextArea.scrollHeight; + sendTextArea.style.height = `${newHeight}px`; + + if (!isFirefox) { + chatBlock.scrollTop = chatBlock.scrollHeight - (chatBlock.offsetHeight + originalScrollBottom); + } +} +export const autoFitSendTextAreaDebounced = debounce(autoFitSendTextArea, debounce_timeout.short); + +// --------------------------------------------------- + +export function initRossMods() { + // initial status check + checkStatusDebounced(); + + if (power_user.auto_load_chat) { + RA_autoloadchat(); + } + + if (power_user.auto_connect) { + RA_autoconnect(); + } + + $('#main_api').change(function () { + var PrevAPI = main_api; + setTimeout(() => RA_autoconnect(PrevAPI), 100); + }); + + $('#api_button').on('click', () => checkStatusDebounced()); + + //toggle pin class when lock toggle clicked + $(RPanelPin).on('click', function () { + accountStorage.setItem('NavLockOn', $(RPanelPin).prop('checked')); + if ($(RPanelPin).prop('checked') == true) { + //console.log('adding pin class to right nav'); + $(RightNavPanel).addClass('pinnedOpen'); + $(RightNavDrawerIcon).addClass('drawerPinnedOpen'); + } else { + //console.log('removing pin class from right nav'); + $(RightNavPanel).removeClass('pinnedOpen'); + $(RightNavDrawerIcon).removeClass('drawerPinnedOpen'); + + if ($(RightNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) { + slideToggle(RightNavPanel, getSlideToggleOptions()); + $(RightNavDrawerIcon).toggleClass('closedIcon openIcon'); + $(RightNavPanel).toggleClass('openDrawer closedDrawer'); + } + } + }); + $(LPanelPin).on('click', function () { + accountStorage.setItem('LNavLockOn', $(LPanelPin).prop('checked')); + if ($(LPanelPin).prop('checked') == true) { + //console.log('adding pin class to Left nav'); + $(LeftNavPanel).addClass('pinnedOpen'); + $(LeftNavDrawerIcon).addClass('drawerPinnedOpen'); + } else { + //console.log('removing pin class from Left nav'); + $(LeftNavPanel).removeClass('pinnedOpen'); + $(LeftNavDrawerIcon).removeClass('drawerPinnedOpen'); + + if ($(LeftNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) { + slideToggle(LeftNavPanel, getSlideToggleOptions()); + $(LeftNavDrawerIcon).toggleClass('closedIcon openIcon'); + $(LeftNavPanel).toggleClass('openDrawer closedDrawer'); + } + } + }); + + $(WIPanelPin).on('click', function () { + accountStorage.setItem('WINavLockOn', $(WIPanelPin).prop('checked')); + if ($(WIPanelPin).prop('checked') == true) { + console.debug('adding pin class to WI'); + $(WorldInfo).addClass('pinnedOpen'); + $(WIDrawerIcon).addClass('drawerPinnedOpen'); + } else { + console.debug('removing pin class from WI'); + $(WorldInfo).removeClass('pinnedOpen'); + $(WIDrawerIcon).removeClass('drawerPinnedOpen'); + + if ($(WorldInfo).hasClass('openDrawer') && $('.openDrawer').length > 1) { + console.debug('closing WI after lock removal'); + slideToggle(WorldInfo, getSlideToggleOptions()); + $(WIDrawerIcon).toggleClass('closedIcon openIcon'); + $(WorldInfo).toggleClass('openDrawer closedDrawer'); + } + } + }); + + // read the state of right Nav Lock and apply to rightnav classlist + $(RPanelPin).prop('checked', accountStorage.getItem('NavLockOn') == 'true'); + if (accountStorage.getItem('NavLockOn') == 'true') { + //console.log('setting pin class via local var'); + $(RightNavPanel).addClass('pinnedOpen'); + $(RightNavDrawerIcon).addClass('drawerPinnedOpen'); + } + if ($(RPanelPin).prop('checked')) { + console.debug('setting pin class via checkbox state'); + $(RightNavPanel).addClass('pinnedOpen'); + $(RightNavDrawerIcon).addClass('drawerPinnedOpen'); + } + // read the state of left Nav Lock and apply to leftnav classlist + $(LPanelPin).prop('checked', accountStorage.getItem('LNavLockOn') === 'true'); + if (accountStorage.getItem('LNavLockOn') == 'true') { + //console.log('setting pin class via local var'); + $(LeftNavPanel).addClass('pinnedOpen'); + $(LeftNavDrawerIcon).addClass('drawerPinnedOpen'); + } + if ($(LPanelPin).prop('checked')) { + console.debug('setting pin class via checkbox state'); + $(LeftNavPanel).addClass('pinnedOpen'); + $(LeftNavDrawerIcon).addClass('drawerPinnedOpen'); + } + + // read the state of left Nav Lock and apply to leftnav classlist + $(WIPanelPin).prop('checked', accountStorage.getItem('WINavLockOn') === 'true'); + if (accountStorage.getItem('WINavLockOn') == 'true') { + //console.log('setting pin class via local var'); + $(WorldInfo).addClass('pinnedOpen'); + $(WIDrawerIcon).addClass('drawerPinnedOpen'); + } + + if ($(WIPanelPin).prop('checked')) { + console.debug('setting pin class via checkbox state'); + $(WorldInfo).addClass('pinnedOpen'); + $(WIDrawerIcon).addClass('drawerPinnedOpen'); + } + + //save state of Right nav being open or closed + $('#rightNavDrawerIcon').on('click', function () { + if (!$('#rightNavDrawerIcon').hasClass('openIcon')) { + accountStorage.setItem('NavOpened', 'true'); + } else { accountStorage.setItem('NavOpened', 'false'); } + }); + + //save state of Left nav being open or closed + $('#leftNavDrawerIcon').on('click', function () { + if (!$('#leftNavDrawerIcon').hasClass('openIcon')) { + accountStorage.setItem('LNavOpened', 'true'); + } else { accountStorage.setItem('LNavOpened', 'false'); } + }); + + //save state of Left nav being open or closed + $('#WorldInfo').on('click', function () { + if (!$('#WorldInfo').hasClass('openIcon')) { + accountStorage.setItem('WINavOpened', 'true'); + } else { accountStorage.setItem('WINavOpened', 'false'); } + }); + + var chatbarInFocus = false; + $('#send_textarea').focus(function () { + chatbarInFocus = true; + }); + + $('#send_textarea').blur(function () { + chatbarInFocus = false; + }); + + setTimeout(() => { + OpenNavPanels(); + }, 300); + + $(SelectedCharacterTab).click(function () { accountStorage.setItem('SelectedNavTab', 'rm_button_selected_ch'); }); + $('#rm_button_characters').click(function () { accountStorage.setItem('SelectedNavTab', 'rm_button_characters'); }); + + // when a char is selected from the list, save them as the auto-load character for next page load + + // when a char is selected from the list, save their name as the auto-load character for next page load + $(document).on('click', '.character_select', function () { + const characterId = $(this).attr('data-chid'); + setActiveCharacter(characterId); + setActiveGroup(null); + saveSettingsDebounced(); + }); + + $(document).on('click', '.group_select', function () { + const groupId = $(this).attr('data-chid') || $(this).attr('data-grid'); + setActiveCharacter(null); + setActiveGroup(groupId); + saveSettingsDebounced(); + }); + + const cssAutofit = CSS.supports('field-sizing', 'content'); + + if (cssAutofit) { + let lastHeight = chatBlock.offsetHeight; + const chatBlockResizeObserver = new ResizeObserver((entries) => { + for (const entry of entries) { + if (entry.target !== chatBlock) { + continue; + } + + const threshold = 1; + const newHeight = chatBlock.offsetHeight; + const deltaHeight = newHeight - lastHeight; + const isScrollAtBottom = Math.abs(chatBlock.scrollHeight - chatBlock.scrollTop - newHeight) <= threshold; + + if (!isScrollAtBottom && Math.abs(deltaHeight) > threshold) { + chatBlock.scrollTop -= deltaHeight; + } + lastHeight = newHeight; + } + }); + + chatBlockResizeObserver.observe(chatBlock); + } + + sendTextArea.addEventListener('input', () => { + saveUserInputDebounced(); + + if (cssAutofit) { + // Unset modifications made with a manual resize + sendTextArea.style.height = 'auto'; + return; + } + + const hasContent = sendTextArea.value !== ''; + const fitsCurrentSize = sendTextArea.scrollHeight <= sendTextArea.offsetHeight; + const isScrollbarShown = sendTextArea.clientWidth < sendTextArea.offsetWidth; + const isHalfScreenHeight = sendTextArea.offsetHeight >= window.innerHeight / 2; + const needsDebounce = hasContent && (fitsCurrentSize || (isScrollbarShown && isHalfScreenHeight)); + if (needsDebounce) autoFitSendTextAreaDebounced(); + else autoFitSendTextArea(); + }); + + restoreUserInput(); + + // Swipe gestures (see: https://www.npmjs.com/package/swiped-events) + document.addEventListener('swiped-left', function (e) { + if (power_user.gestures === false) { + return; + } + if (Popup.util.isPopupOpen()) { + return; + } + if (!$(e.target).closest('#sheld').length) { + return; + } + if ($('#curEditTextarea').length) { + // Don't swipe while in text edit mode + // the ios selection gestures get picked up + // as swipe gestures + return; + } + var SwipeButR = $('.swipe_right:last'); + var SwipeTargetMesClassParent = $(e.target).closest('.last_mes'); + if (SwipeTargetMesClassParent !== null) { + if (SwipeButR.css('display') === 'flex') { + SwipeButR.click(); + } + } + }); + document.addEventListener('swiped-right', function (e) { + if (power_user.gestures === false) { + return; + } + if (Popup.util.isPopupOpen()) { + return; + } + if (!$(e.target).closest('#sheld').length) { + return; + } + if ($('#curEditTextarea').length) { + // Don't swipe while in text edit mode + // the ios selection gestures get picked up + // as swipe gestures + return; + } + var SwipeButL = $('.swipe_left:last'); + var SwipeTargetMesClassParent = $(e.target).closest('.last_mes'); + if (SwipeTargetMesClassParent !== null) { + if (SwipeButL.css('display') === 'flex') { + SwipeButL.click(); + } + } + }); + + + function isInputElementInFocus() { + //return $(document.activeElement).is(":input"); + var focused = $(':focus'); + if (focused.is('input') || focused.is('textarea') || focused.prop('contenteditable') == 'true') { + if (focused.attr('id') === 'send_textarea') { + return false; + } + return true; + } + return false; + } + + function isModifiedKeyboardEvent(event) { + return (event instanceof KeyboardEvent && + event.shiftKey || + event.ctrlKey || + event.altKey || + event.metaKey); + } + + $(document).on('keydown', async function (event) { + await processHotkeys(event.originalEvent); + }); + + const hotkeyTargets = { + 'send_textarea': sendTextArea, + 'dialogue_popup_input': document.querySelector('#dialogue_popup_input'), + }; + + //Additional hotkeys CTRL+ENTER and CTRL+UPARROW + /** + * @param {KeyboardEvent} event + */ + async function processHotkeys(event) { + // Default hotkeys and shortcuts shouldn't work if any popup is currently open + if (Popup.util.isPopupOpen()) { + return; + } + + //Enter to send when send_textarea in focus + if (document.activeElement == hotkeyTargets['send_textarea']) { + const sendOnEnter = shouldSendOnEnter(); + if (!event.shiftKey && !event.ctrlKey && !event.altKey && event.key == 'Enter' && sendOnEnter) { + event.preventDefault(); + sendTextareaMessage(); + return; + } + } + if (document.activeElement == hotkeyTargets['dialogue_popup_input'] && !isMobile()) { + if (!event.shiftKey && !event.ctrlKey && event.key == 'Enter') { + event.preventDefault(); + $('#dialogue_popup_ok').trigger('click'); + return; + } + } + //ctrl+shift+up to scroll to context line + if (event.shiftKey && event.ctrlKey && event.key == 'ArrowUp') { + event.preventDefault(); + let contextLine = $('.lastInContext'); + if (contextLine.length !== 0) { + $('#chat').animate({ + scrollTop: contextLine.offset().top - $('#chat').offset().top + $('#chat').scrollTop(), + }, 300); + } else { toastr.warning('Context line not found, send a message first!'); } + return; + } + //ctrl+shift+down to scroll to bottom of chat + if (event.shiftKey && event.ctrlKey && event.key == 'ArrowDown') { + event.preventDefault(); + $('#chat').animate({ + scrollTop: $('#chat').prop('scrollHeight'), + }, 300); + return; + } + + // Alt+Enter or AltGr+Enter to Continue + if ((event.altKey || (event.altKey && event.ctrlKey)) && event.key == 'Enter') { + if (is_send_press == false) { + console.debug('Continuing with Alt+Enter'); + $('#option_continue').trigger('click'); + return; + } + } + + // Ctrl+Enter for Regeneration Last Response. If editing, accept the edits instead + if (event.ctrlKey && event.key == 'Enter') { + const editMesDone = $('.mes_edit_done:visible'); + const reasoningMesDone = $('.mes_reasoning_edit_done:visible'); + if (editMesDone.length > 0) { + console.debug('Accepting edits with Ctrl+Enter'); + $('#send_textarea').trigger('focus'); + editMesDone.trigger('click'); + return; + } else if (reasoningMesDone.length > 0) { + console.debug('Accepting edits with Ctrl+Enter'); + $('#send_textarea').trigger('focus'); + reasoningMesDone.trigger('click'); + return; + } + else if (is_send_press == false) { + const skipConfirmKey = 'RegenerateWithCtrlEnter'; + const skipConfirm = accountStorage.getItem(skipConfirmKey) === 'true'; + function doRegenerate() { + console.debug('Regenerating with Ctrl+Enter'); + $('#option_regenerate').trigger('click'); + $('#options').hide(); + } + if (skipConfirm) { + doRegenerate(); + } else { + let regenerateWithCtrlEnter = false; + const result = await Popup.show.confirm('Regenerate Message', 'Are you sure you want to regenerate the latest message?', { + customInputs: [{ id: 'regenerateWithCtrlEnter', label: 'Don\'t ask again' }], + onClose: (popup) => { + regenerateWithCtrlEnter = popup.inputResults.get('regenerateWithCtrlEnter') ?? false; + }, + }); + if (!result) { + return; + } + + accountStorage.setItem(skipConfirmKey, String(regenerateWithCtrlEnter)); + doRegenerate(); + } + return; + } else { + console.debug('Ctrl+Enter ignored'); + } + } + + // Helper function to check if nanogallery2's lightbox is active + function isNanogallery2LightboxActive() { + // Check if the body has the 'nGY2On' class, adjust this based on actual behavior + return document.body.classList.contains('nGY2_body_scrollbar'); + } + + if (event.key == 'ArrowLeft') { //swipes left + if ( + !isNanogallery2LightboxActive() && // Check if lightbox is NOT active + $('.swipe_left:last').css('display') === 'flex' && + $('#send_textarea').val() === '' && + $('#character_popup').css('display') === 'none' && + $('#shadow_select_chat_popup').css('display') === 'none' && + !isInputElementInFocus() && + !isModifiedKeyboardEvent(event) + ) { + $('.swipe_left:last').trigger('click', { source: 'keyboard', repeated: event.repeat }); + return; + } + } + if (event.key == 'ArrowRight') { //swipes right + if ( + !isNanogallery2LightboxActive() && // Check if lightbox is NOT active + $('.swipe_right:last').css('display') === 'flex' && + $('#send_textarea').val() === '' && + $('#character_popup').css('display') === 'none' && + $('#shadow_select_chat_popup').css('display') === 'none' && + !isInputElementInFocus() && + !isModifiedKeyboardEvent(event) + ) { + $('.swipe_right:last').trigger('click', { source: 'keyboard', repeated: event.repeat }); + return; + } + } + + + if (event.ctrlKey && event.key == 'ArrowUp') { //edits last USER message if chatbar is empty and focused + if ( + hotkeyTargets['send_textarea'].value === '' && + chatbarInFocus === true && + ($('.swipe_right:last').css('display') === 'flex' || $('.last_mes').attr('is_system') === 'true') && + $('#character_popup').css('display') === 'none' && + $('#shadow_select_chat_popup').css('display') === 'none' + ) { + const isUserMesList = document.querySelectorAll('div[is_user="true"]'); + const lastIsUserMes = isUserMesList[isUserMesList.length - 1]; + const editMes = lastIsUserMes.querySelector('.mes_block .mes_edit'); + if (editMes !== null) { + $(editMes).trigger('click'); + return; + } + } + } + + if (event.key == 'ArrowUp') { //edits last message if chatbar is empty and focused + console.log('got uparrow input'); + if ( + hotkeyTargets['send_textarea'].value === '' && + chatbarInFocus === true && + //$('.swipe_right:last').css('display') === 'flex' && + $('.last_mes .mes_buttons').is(':visible') && + $('#character_popup').css('display') === 'none' && + $('#shadow_select_chat_popup').css('display') === 'none' + ) { + const lastMes = document.querySelector('.last_mes'); + const editMes = lastMes.querySelector('.mes_block .mes_edit'); + if (editMes !== null) { + $(editMes).click(); + return; + } + } + } + + if (event.key == 'Escape') { //closes various panels + //dont override Escape hotkey functions from script.js + //"close edit box" and "cancel stream generation". + if ($('#curEditTextarea').is(':visible') || $('#mes_stop').is(':visible')) { + console.debug('escape key, but deferring to script.js routines'); + return; + } + + if ($('#dialogue_popup').is(':visible')) { + if ($('#dialogue_popup_cancel').is(':visible')) { + $('#dialogue_popup_cancel').trigger('click'); + return; + } else { + $('#dialogue_popup_ok').trigger('click'); + return; + } + } + + if ($('#select_chat_popup').is(':visible')) { + $('#select_chat_cross').trigger('click'); + return; + } + + if ($('#character_popup').is(':visible')) { + $('#character_cross').trigger('click'); + return; + } + + if ($('#dialogue_del_mes_cancel').is(':visible')) { + $('#dialogue_del_mes_cancel').trigger('click'); + return; + } + + if ($('.drawer-content') + .not('#WorldInfo') + .not('#left-nav-panel') + .not('#right-nav-panel') + .not('#floatingPrompt') + .not('#cfgConfig') + .not('#logprobsViewer') + .not('#movingDivs > div') + .is(':visible')) { + let visibleDrawerContent = $('.drawer-content:visible') + .not('#WorldInfo') + .not('#left-nav-panel') + .not('#right-nav-panel') + .not('#floatingPrompt') + .not('#cfgConfig') + .not('#logprobsViewer') + .not('#movingDivs > div'); + $(visibleDrawerContent).parent().find('.drawer-icon').trigger('click'); + return; + } + + if ($('#floatingPrompt').is(':visible')) { + $('#ANClose').trigger('click'); + return; + } + + if ($('#WorldInfo').is(':visible')) { + $('#WIDrawerIcon').trigger('click'); + return; + } + + if ($('#cfgConfig').is(':visible')) { + $('#CFGClose').trigger('click'); + return; + } + + if ($('#logprobsViewer').is(':visible')) { + $('#logprobsViewerClose').trigger('click'); + return; + } + + $('#movingDivs > div').each(function () { + if ($(this).is(':visible')) { + $('#movingDivs > div .floating_panel_close').trigger('click'); + return; + } + }); + + if ($('#left-nav-panel').is(':visible') && + $(LPanelPin).prop('checked') === false) { + $('#leftNavDrawerIcon').trigger('click'); + return; + } + + if ($('#right-nav-panel').is(':visible') && + $(RPanelPin).prop('checked') === false) { + $('#rightNavDrawerIcon').trigger('click'); + return; + } + if ($('.draggable').is(':visible')) { + // Remove the first matched element + $('.draggable:first').remove(); + return; + } + } + + + + + if (event.ctrlKey && /^[1-9]$/.test(event.key)) { + // This will eventually be to trigger quick replies + // event.preventDefault(); + console.log('Ctrl +' + event.key + ' pressed!'); + } + } +} diff --git a/jiuguan2025cc/public/scripts/authors-note.js b/jiuguan2025cc/public/scripts/authors-note.js new file mode 100644 index 0000000000000000000000000000000000000000..6d0aedfb3b5ae8db1f9a9dfcf403db8082448db5 --- /dev/null +++ b/jiuguan2025cc/public/scripts/authors-note.js @@ -0,0 +1,579 @@ +import { + animation_duration, + chat_metadata, + eventSource, + event_types, + extension_prompt_roles, + saveSettingsDebounced, + this_chid, +} from '../script.js'; +import { selected_group } from './group-chats.js'; +import { extension_settings, getContext, saveMetadataDebounced } from './extensions.js'; +import { getCharaFilename, debounce, delay } from './utils.js'; +import { getTokenCountAsync } from './tokenizers.js'; +import { debounce_timeout } from './constants.js'; +import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; +import { SlashCommand } from './slash-commands/SlashCommand.js'; +import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js'; +export { MODULE_NAME as NOTE_MODULE_NAME }; +import { t } from './i18n.js'; + +const MODULE_NAME = '2_floating_prompt'; // <= Deliberate, for sorting lower than memory + +export var shouldWIAddPrompt = false; + +export const metadata_keys = { + prompt: 'note_prompt', + interval: 'note_interval', + depth: 'note_depth', + position: 'note_position', + role: 'note_role', +}; + +const chara_note_position = { + replace: 0, + before: 1, + after: 2, +}; + +function setNoteTextCommand(_, text) { + if (text) { + $('#extension_floating_prompt').val(text).trigger('input'); + toastr.success(t`Author's Note text updated`); + } + return chat_metadata[metadata_keys.prompt]; +} + +function setNoteDepthCommand(_, text) { + if (text) { + const value = Number(text); + + if (Number.isNaN(value)) { + toastr.error(t`Not a valid number`); + return; + } + + $('#extension_floating_depth').val(Math.abs(value)).trigger('input'); + toastr.success(t`Author's Note depth updated`); + } + return chat_metadata[metadata_keys.depth]; +} + +function setNoteIntervalCommand(_, text) { + if (text) { + const value = Number(text); + + if (Number.isNaN(value)) { + toastr.error(t`Not a valid number`); + return; + } + + $('#extension_floating_interval').val(Math.abs(value)).trigger('input'); + toastr.success(t`Author's Note frequency updated`); + } + return chat_metadata[metadata_keys.interval]; +} + +function setNotePositionCommand(_, text) { + const validPositions = { + 'after': 0, + 'scenario': 0, + 'chat': 1, + 'before_scenario': 2, + 'before': 2, + }; + + if (text) { + const position = validPositions[text?.trim()?.toLowerCase()]; + + if (typeof position === 'undefined') { + toastr.error(t`Not a valid position`); + return; + } + + $(`input[name="extension_floating_position"][value="${position}"]`).prop('checked', true).trigger('input'); + toastr.info(t`Author's Note position updated`); + } + return Object.keys(validPositions).find(key => validPositions[key] == chat_metadata[metadata_keys.position]); +} + +function setNoteRoleCommand(_, text) { + const validRoles = { + 'system': 0, + 'user': 1, + 'assistant': 2, + }; + + if (text) { + const role = validRoles[text?.trim()?.toLowerCase()]; + + if (typeof role === 'undefined') { + toastr.error(t`Not a valid role`); + return; + } + + $('#extension_floating_role').val(Math.abs(role)).trigger('input'); + toastr.info(t`Author's Note role updated`); + } + return Object.keys(validRoles).find(key => validRoles[key] == chat_metadata[metadata_keys.role]); +} + +function updateSettings() { + saveSettingsDebounced(); + loadSettings(); + setFloatingPrompt(); +} + +const setMainPromptTokenCounterDebounced = debounce(async (value) => $('#extension_floating_prompt_token_counter').text(await getTokenCountAsync(value)), debounce_timeout.relaxed); +const setCharaPromptTokenCounterDebounced = debounce(async (value) => $('#extension_floating_chara_token_counter').text(await getTokenCountAsync(value)), debounce_timeout.relaxed); +const setDefaultPromptTokenCounterDebounced = debounce(async (value) => $('#extension_floating_default_token_counter').text(await getTokenCountAsync(value)), debounce_timeout.relaxed); + +async function onExtensionFloatingPromptInput() { + chat_metadata[metadata_keys.prompt] = $(this).val(); + setMainPromptTokenCounterDebounced(chat_metadata[metadata_keys.prompt]); + updateSettings(); + saveMetadataDebounced(); +} + +async function onExtensionFloatingIntervalInput() { + chat_metadata[metadata_keys.interval] = Number($(this).val()); + updateSettings(); + saveMetadataDebounced(); +} + +async function onExtensionFloatingDepthInput() { + let value = Number($(this).val()); + + if (value < 0) { + value = Math.abs(value); + $(this).val(value); + } + + chat_metadata[metadata_keys.depth] = value; + updateSettings(); + saveMetadataDebounced(); +} + +async function onExtensionFloatingPositionInput(e) { + chat_metadata[metadata_keys.position] = Number(e.target.value); + updateSettings(); + saveMetadataDebounced(); +} + +async function onDefaultPositionInput(e) { + extension_settings.note.defaultPosition = Number(e.target.value); + saveSettingsDebounced(); +} + +async function onDefaultDepthInput() { + let value = Number($(this).val()); + + if (value < 0) { + value = Math.abs(value); + $(this).val(value); + } + + extension_settings.note.defaultDepth = value; + saveSettingsDebounced(); +} + +async function onDefaultIntervalInput() { + extension_settings.note.defaultInterval = Number($(this).val()); + saveSettingsDebounced(); +} + +function onExtensionFloatingRoleInput(e) { + chat_metadata[metadata_keys.role] = Number(e.target.value); + updateSettings(); +} + +function onExtensionDefaultRoleInput(e) { + extension_settings.note.defaultRole = Number(e.target.value); + saveSettingsDebounced(); +} + +async function onExtensionFloatingCharPositionInput(e) { + const value = e.target.value; + const charaNote = extension_settings.note.chara.find((e) => e.name === getCharaFilename()); + + if (charaNote) { + charaNote.position = Number(value); + updateSettings(); + } +} + +function onExtensionFloatingCharaPromptInput() { + const tempPrompt = $(this).val(); + const avatarName = getCharaFilename(); + let tempCharaNote = { + name: avatarName, + prompt: tempPrompt, + }; + + setCharaPromptTokenCounterDebounced(tempPrompt); + + let existingCharaNoteIndex; + let existingCharaNote; + + if (extension_settings.note.chara) { + existingCharaNoteIndex = extension_settings.note.chara.findIndex((e) => e.name === avatarName); + existingCharaNote = extension_settings.note.chara[existingCharaNoteIndex]; + } + + if (tempPrompt.length === 0 && + extension_settings.note.chara && + existingCharaNote && + !existingCharaNote.useChara + ) { + extension_settings.note.chara.splice(existingCharaNoteIndex, 1); + } + else if (extension_settings.note.chara && existingCharaNote) { + Object.assign(existingCharaNote, tempCharaNote); + } + else if (avatarName && tempPrompt.length > 0) { + if (!extension_settings.note.chara) { + extension_settings.note.chara = []; + } + Object.assign(tempCharaNote, { useChara: false, position: chara_note_position.replace }); + + extension_settings.note.chara.push(tempCharaNote); + } else { + console.log('Character author\'s note error: No avatar name key could be found.'); + toastr.error(t`Something went wrong. Could not save character's author's note.`); + + // Don't save settings if something went wrong + return; + } + + updateSettings(); +} + +function onExtensionFloatingCharaCheckboxChanged() { + const value = !!$(this).prop('checked'); + const charaNote = extension_settings.note.chara.find((e) => e.name === getCharaFilename()); + + if (charaNote) { + charaNote.useChara = value; + + updateSettings(); + } +} + +function onExtensionFloatingDefaultInput() { + extension_settings.note.default = $(this).val(); + setDefaultPromptTokenCounterDebounced(extension_settings.note.default); + updateSettings(); +} + +function loadSettings() { + const DEFAULT_DEPTH = 4; + const DEFAULT_POSITION = 1; + const DEFAULT_INTERVAL = 1; + const DEFAULT_ROLE = extension_prompt_roles.SYSTEM; + + if (extension_settings.note.defaultPosition === undefined) { + extension_settings.note.defaultPosition = DEFAULT_POSITION; + } + + if (extension_settings.note.defaultDepth === undefined) { + extension_settings.note.defaultDepth = DEFAULT_DEPTH; + } + + if (extension_settings.note.defaultInterval === undefined) { + extension_settings.note.defaultInterval = DEFAULT_INTERVAL; + } + + if (extension_settings.note.defaultRole === undefined) { + extension_settings.note.defaultRole = DEFAULT_ROLE; + } + + chat_metadata[metadata_keys.prompt] = chat_metadata[metadata_keys.prompt] ?? extension_settings.note.default ?? ''; + chat_metadata[metadata_keys.interval] = chat_metadata[metadata_keys.interval] ?? extension_settings.note.defaultInterval ?? DEFAULT_INTERVAL; + chat_metadata[metadata_keys.position] = chat_metadata[metadata_keys.position] ?? extension_settings.note.defaultPosition ?? DEFAULT_POSITION; + chat_metadata[metadata_keys.depth] = chat_metadata[metadata_keys.depth] ?? extension_settings.note.defaultDepth ?? DEFAULT_DEPTH; + chat_metadata[metadata_keys.role] = chat_metadata[metadata_keys.role] ?? extension_settings.note.defaultRole ?? DEFAULT_ROLE; + $('#extension_floating_prompt').val(chat_metadata[metadata_keys.prompt]); + $('#extension_floating_interval').val(chat_metadata[metadata_keys.interval]); + $('#extension_floating_allow_wi_scan').prop('checked', extension_settings.note.allowWIScan ?? false); + $('#extension_floating_depth').val(chat_metadata[metadata_keys.depth]); + $('#extension_floating_role').val(chat_metadata[metadata_keys.role]); + $(`input[name="extension_floating_position"][value="${chat_metadata[metadata_keys.position]}"]`).prop('checked', true); + + if (extension_settings.note.chara && getContext().characterId !== undefined) { + const charaNote = extension_settings.note.chara.find((e) => e.name === getCharaFilename()); + + $('#extension_floating_chara').val(charaNote ? charaNote.prompt : ''); + $('#extension_use_floating_chara').prop('checked', charaNote ? charaNote.useChara : false); + $(`input[name="extension_floating_char_position"][value="${charaNote?.position ?? chara_note_position.replace}"]`).prop('checked', true); + } else { + $('#extension_floating_chara').val(''); + $('#extension_use_floating_chara').prop('checked', false); + $(`input[name="extension_floating_char_position"][value="${chara_note_position.replace}"]`).prop('checked', true); + } + + $('#extension_floating_default').val(extension_settings.note.default); + $('#extension_default_depth').val(extension_settings.note.defaultDepth); + $('#extension_default_interval').val(extension_settings.note.defaultInterval); + $('#extension_default_role').val(extension_settings.note.defaultRole); + $(`input[name="extension_default_position"][value="${extension_settings.note.defaultPosition}"]`).prop('checked', true); +} + +export function setFloatingPrompt() { + const context = getContext(); + if (!context.groupId && context.characterId === undefined) { + console.debug('setFloatingPrompt: Not in a chat. Skipping.'); + shouldWIAddPrompt = false; + return; + } + + // take the count of messages + let lastMessageNumber = Array.isArray(context.chat) && context.chat.length ? context.chat.filter(m => m.is_user).length : 0; + + console.debug(` + setFloatingPrompt entered + ------ + lastMessageNumber = ${lastMessageNumber} + metadata_keys.interval = ${chat_metadata[metadata_keys.interval]} + metadata_keys.position = ${chat_metadata[metadata_keys.position]} + metadata_keys.depth = ${chat_metadata[metadata_keys.depth]} + metadata_keys.role = ${chat_metadata[metadata_keys.role]} + ------ + `); + + // interval 1 should be inserted no matter what + if (chat_metadata[metadata_keys.interval] === 1) { + lastMessageNumber = 1; + } + + if (lastMessageNumber <= 0 || chat_metadata[metadata_keys.interval] <= 0) { + context.setExtensionPrompt(MODULE_NAME, ''); + $('#extension_floating_counter').text('(disabled)'); + shouldWIAddPrompt = false; + return; + } + + const messagesTillInsertion = lastMessageNumber >= chat_metadata[metadata_keys.interval] + ? (lastMessageNumber % chat_metadata[metadata_keys.interval]) + : (chat_metadata[metadata_keys.interval] - lastMessageNumber); + const shouldAddPrompt = messagesTillInsertion == 0; + shouldWIAddPrompt = shouldAddPrompt; + + let prompt = shouldAddPrompt ? $('#extension_floating_prompt').val() : ''; + if (shouldAddPrompt && extension_settings.note.chara && getContext().characterId !== undefined) { + const charaNote = extension_settings.note.chara.find((e) => e.name === getCharaFilename()); + + // Only replace with the chara note if the user checked the box + if (charaNote && charaNote.useChara) { + switch (charaNote.position) { + case chara_note_position.before: + prompt = charaNote.prompt + '\n' + prompt; + break; + case chara_note_position.after: + prompt = prompt + '\n' + charaNote.prompt; + break; + default: + prompt = charaNote.prompt; + break; + } + } + } + context.setExtensionPrompt( + MODULE_NAME, + prompt, + chat_metadata[metadata_keys.position], + chat_metadata[metadata_keys.depth], + extension_settings.note.allowWIScan, + chat_metadata[metadata_keys.role], + ); + $('#extension_floating_counter').text(shouldAddPrompt ? '0' : messagesTillInsertion); +} + +function onANMenuItemClick() { + if (!selected_group && this_chid === undefined) { + toastr.warning(t`Select a character before trying to use Author's Note`, '', { timeOut: 2000 }); + return; + } + + //show AN if it's hidden + if ($('#floatingPrompt').css('display') !== 'flex') { + $('#floatingPrompt').addClass('resizing'); + $('#floatingPrompt').css('display', 'flex'); + $('#floatingPrompt').css('opacity', 0.0); + $('#floatingPrompt').transition({ + opacity: 1.0, + duration: animation_duration, + }, async function () { + await delay(50); + $('#floatingPrompt').removeClass('resizing'); + }); + + //auto-open the main AN inline drawer + if ($('#ANBlockToggle') + .siblings('.inline-drawer-content') + .css('display') !== 'block') { + $('#floatingPrompt').addClass('resizing'); + $('#ANBlockToggle').click(); + } + } else { + //hide AN if it's already displayed + $('#floatingPrompt').addClass('resizing'); + $('#floatingPrompt').transition({ + opacity: 0.0, + duration: animation_duration, + }, async function () { + await delay(50); + $('#floatingPrompt').removeClass('resizing'); + }); + setTimeout(function () { + $('#floatingPrompt').hide(); + }, animation_duration); + } + + //duplicate options menu close handler from script.js + //because this listener takes priority + $('#options').stop().fadeOut(animation_duration); +} + +async function onChatChanged() { + loadSettings(); + setFloatingPrompt(); + const context = getContext(); + + // Disable the chara note if in a group + $('#extension_floating_chara').prop('disabled', !!context.groupId); + + const tokenCounter1 = chat_metadata[metadata_keys.prompt] ? await getTokenCountAsync(chat_metadata[metadata_keys.prompt]) : 0; + $('#extension_floating_prompt_token_counter').text(tokenCounter1); + + let tokenCounter2; + if (extension_settings.note.chara && context.characterId !== undefined) { + const charaNote = extension_settings.note.chara.find((e) => e.name === getCharaFilename()); + + if (charaNote) { + tokenCounter2 = await getTokenCountAsync(charaNote.prompt); + } + } + + $('#extension_floating_chara_token_counter').text(tokenCounter2 || 0); + + const tokenCounter3 = extension_settings.note.default ? await getTokenCountAsync(extension_settings.note.default) : 0; + $('#extension_floating_default_token_counter').text(tokenCounter3); +} + +function onAllowWIScanCheckboxChanged() { + extension_settings.note.allowWIScan = !!$(this).prop('checked'); + updateSettings(); +} + +/** + * Inject author's note options and setup event listeners. + */ +// Inserts the extension first since it's statically imported +export function initAuthorsNote() { + $('#extension_floating_prompt').on('input', onExtensionFloatingPromptInput); + $('#extension_floating_interval').on('input', onExtensionFloatingIntervalInput); + $('#extension_floating_depth').on('input', onExtensionFloatingDepthInput); + $('#extension_floating_chara').on('input', onExtensionFloatingCharaPromptInput); + $('#extension_use_floating_chara').on('input', onExtensionFloatingCharaCheckboxChanged); + $('#extension_floating_default').on('input', onExtensionFloatingDefaultInput); + $('#extension_default_depth').on('input', onDefaultDepthInput); + $('#extension_default_interval').on('input', onDefaultIntervalInput); + $('#extension_floating_allow_wi_scan').on('input', onAllowWIScanCheckboxChanged); + $('#extension_floating_role').on('input', onExtensionFloatingRoleInput); + $('#extension_default_role').on('input', onExtensionDefaultRoleInput); + $('input[name="extension_floating_position"]').on('change', onExtensionFloatingPositionInput); + $('input[name="extension_default_position"]').on('change', onDefaultPositionInput); + $('input[name="extension_floating_char_position"]').on('change', onExtensionFloatingCharPositionInput); + $('#ANClose').on('click', function () { + $('#floatingPrompt').transition({ + opacity: 0, + duration: animation_duration, + easing: 'ease-in-out', + }); + setTimeout(function () { $('#floatingPrompt').hide(); }, animation_duration); + }); + $('#option_toggle_AN').on('click', onANMenuItemClick); + + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'note', + callback: setNoteTextCommand, + returns: 'current author\'s note', + unnamedArgumentList: [ + new SlashCommandArgument( + 'text', [ARGUMENT_TYPE.STRING], false, + ), + ], + helpString: ` +
      + Sets an author's note for the currently selected chat if specified and returns the current note. +
      + `, + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'note-depth', + aliases: ['depth'], + callback: setNoteDepthCommand, + returns: 'current author\'s note depth', + unnamedArgumentList: [ + new SlashCommandArgument( + 'number', [ARGUMENT_TYPE.NUMBER], false, + ), + ], + helpString: ` +
      + Sets an author's note depth for in-chat positioning if specified and returns the current depth. +
      + `, + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'note-frequency', + aliases: ['freq', 'note-freq'], + callback: setNoteIntervalCommand, + returns: 'current author\'s note insertion frequency', + namedArgumentList: [], + unnamedArgumentList: [ + new SlashCommandArgument( + 'number', [ARGUMENT_TYPE.NUMBER], false, + ), + ], + helpString: ` +
      + Sets an author's note insertion frequency if specified and returns the current frequency. +
      + `, + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'note-position', + callback: setNotePositionCommand, + aliases: ['pos', 'note-pos'], + returns: 'current author\'s note insertion position', + namedArgumentList: [], + unnamedArgumentList: [ + new SlashCommandArgument( + 'position', [ARGUMENT_TYPE.STRING], false, false, null, ['before', 'after', 'chat'], + ), + ], + helpString: ` +
      + Sets an author's note position if specified and returns the current position. +
      + `, + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'note-role', + callback: setNoteRoleCommand, + returns: 'current author\'s note chat insertion role', + namedArgumentList: [], + unnamedArgumentList: [ + new SlashCommandArgument( + 'role', [ARGUMENT_TYPE.STRING], false, false, null, ['system', 'user', 'assistant'], + ), + ], + helpString: ` +
      + Sets an author's note chat insertion role if specified and returns the current role. +
      + `, + })); + eventSource.on(event_types.CHAT_CHANGED, onChatChanged); +} diff --git a/jiuguan2025cc/public/scripts/autocomplete/AutoComplete.js b/jiuguan2025cc/public/scripts/autocomplete/AutoComplete.js new file mode 100644 index 0000000000000000000000000000000000000000..ba3d427a2b6fa96bceb8d21da53de6bad877053e --- /dev/null +++ b/jiuguan2025cc/public/scripts/autocomplete/AutoComplete.js @@ -0,0 +1,824 @@ +import { power_user } from '../power-user.js'; +import { debounce, escapeRegex } from '../utils.js'; +import { AutoCompleteOption } from './AutoCompleteOption.js'; +import { AutoCompleteFuzzyScore } from './AutoCompleteFuzzyScore.js'; +import { BlankAutoCompleteOption } from './BlankAutoCompleteOption.js'; +// eslint-disable-next-line no-unused-vars +import { AutoCompleteNameResult } from './AutoCompleteNameResult.js'; +import { AutoCompleteSecondaryNameResult } from './AutoCompleteSecondaryNameResult.js'; +import { Popup, getTopmostModalLayer } from '../popup.js'; + +/**@readonly*/ +/**@enum {Number}*/ +export const AUTOCOMPLETE_WIDTH = { + 'INPUT': 0, + 'CHAT': 1, + 'FULL': 2, +}; + +/**@readonly*/ +/**@enum {Number}*/ +export const AUTOCOMPLETE_SELECT_KEY = { + 'TAB': 1, // 2^0 + 'ENTER': 2, // 2^1 +}; + +export class AutoComplete { + /**@type {HTMLTextAreaElement|HTMLInputElement}*/ textarea; + /**@type {boolean}*/ isFloating = false; + /**@type {()=>boolean}*/ checkIfActivate; + /**@type {(text:string, index:number) => Promise}*/ getNameAt; + + /**@type {boolean}*/ isActive = false; + /**@type {boolean}*/ isReplaceable = false; + /**@type {boolean}*/ isShowingDetails = false; + /**@type {boolean}*/ wasForced = false; + /**@type {boolean}*/ isForceHidden = false; + /**@type {boolean}*/ canBeAutoHidden = false; + + /**@type {string}*/ text; + /**@type {AutoCompleteNameResult}*/ parserResult; + /**@type {AutoCompleteSecondaryNameResult}*/ secondaryParserResult; + get effectiveParserResult() { return this.secondaryParserResult ?? this.parserResult; } + /**@type {string}*/ name; + + /**@type {boolean}*/ startQuote; + /**@type {boolean}*/ endQuote; + /**@type {number}*/ selectionStart; + + /**@type {RegExp}*/ fuzzyRegex; + + /**@type {AutoCompleteOption[]}*/ result = []; + /**@type {AutoCompleteOption}*/ selectedItem = null; + + /**@type {HTMLElement}*/ clone; + /**@type {HTMLElement}*/ domWrap; + /**@type {HTMLElement}*/ dom; + /**@type {HTMLElement}*/ detailsWrap; + /**@type {HTMLElement}*/ detailsDom; + + /**@type {function}*/ renderDebounced; + /**@type {function}*/ renderDetailsDebounced; + /**@type {function}*/ updatePositionDebounced; + /**@type {function}*/ updateDetailsPositionDebounced; + /**@type {function}*/ updateFloatingPositionDebounced; + + /**@type {(item:AutoCompleteOption)=>any}*/ onSelect; + + get matchType() { + return power_user.stscript.matching ?? 'fuzzy'; + } + + get autoHide() { + return power_user.stscript.autocomplete.autoHide ?? false; + } + + + + + /** + * @param {HTMLTextAreaElement|HTMLInputElement} textarea The textarea to receive autocomplete. + * @param {() => boolean} checkIfActivate Function should return true only if under the current conditions, autocomplete should display (e.g., for slash commands: autoComplete.text[0] == '/') + * @param {(text: string, index: number) => Promise} getNameAt Function should return (unfiltered, matching against input is done in AutoComplete) information about name options at index in text. + * @param {boolean} isFloating Whether autocomplete should float at the keyboard cursor. + */ + constructor(textarea, checkIfActivate, getNameAt, isFloating = false) { + this.textarea = textarea; + this.checkIfActivate = checkIfActivate; + this.getNameAt = getNameAt; + this.isFloating = isFloating; + + this.domWrap = document.createElement('div'); { + this.domWrap.classList.add('autoComplete-wrap'); + if (isFloating) this.domWrap.classList.add('isFloating'); + } + this.dom = document.createElement('ul'); { + this.dom.classList.add('autoComplete'); + this.domWrap.append(this.dom); + } + this.detailsWrap = document.createElement('div'); { + this.detailsWrap.classList.add('autoComplete-detailsWrap'); + if (isFloating) this.detailsWrap.classList.add('isFloating'); + } + this.detailsDom = document.createElement('div'); { + this.detailsDom.classList.add('autoComplete-details'); + this.detailsWrap.append(this.detailsDom); + } + + this.renderDebounced = debounce(this.render.bind(this), 10); + this.renderDetailsDebounced = debounce(this.renderDetails.bind(this), 10); + this.updatePositionDebounced = debounce(this.updatePosition.bind(this), 10); + this.updateDetailsPositionDebounced = debounce(this.updateDetailsPosition.bind(this), 10); + this.updateFloatingPositionDebounced = debounce(this.updateFloatingPosition.bind(this), 10); + + textarea.addEventListener('input', ()=>{ + this.selectionStart = this.textarea.selectionStart; + if (this.text != this.textarea.value) this.show(true, this.wasForced); + }); + textarea.addEventListener('keydown', (evt)=>this.handleKeyDown(evt)); + textarea.addEventListener('click', ()=>{ + this.selectionStart = this.textarea.selectionStart; + if (this.isActive) this.show(); + }); + textarea.addEventListener('blur', ()=>this.hide()); + if (isFloating) { + textarea.addEventListener('scroll', ()=>this.updateFloatingPositionDebounced()); + } + window.addEventListener('resize', ()=>this.updatePositionDebounced()); + } + + /** + * + * @param {AutoCompleteOption} option + */ + makeItem(option) { + const li = option.renderItem(); + // gotta listen to pointerdown (happens before textarea-blur) + li.addEventListener('pointerdown', (evt)=>{ + evt.preventDefault(); + this.selectedItem = this.result.find(it=>it.name == li.getAttribute('data-name')); + this.select(); + }); + return li; + } + + + /** + * + * @param {AutoCompleteOption} item + */ + updateName(item) { + const chars = Array.from(item.dom.querySelector('.name').children); + switch (this.matchType) { + case 'strict': { + chars.forEach((it, idx)=>{ + if (idx + item.nameOffset < item.name.length) { + it.classList.add('matched'); + } else { + it.classList.remove('matched'); + } + }); + break; + } + case 'includes': { + const start = item.name.toLowerCase().search(this.name); + chars.forEach((it, idx)=>{ + if (idx + item.nameOffset < start) { + it.classList.remove('matched'); + } else if (idx + item.nameOffset < start + item.name.length) { + it.classList.add('matched'); + } else { + it.classList.remove('matched'); + } + }); + break; + } + case 'fuzzy': { + item.name.replace(this.fuzzyRegex, (_, ...parts)=>{ + parts.splice(-2, 2); + if (parts.length == 2) { + chars.forEach(c=>c.classList.remove('matched')); + } else { + let cIdx = item.nameOffset; + parts.forEach((it, idx)=>{ + if (it === null || it.length == 0) return ''; + if (idx % 2 == 1) { + chars.slice(cIdx, cIdx + it.length).forEach(c=>c.classList.add('matched')); + } else { + chars.slice(cIdx, cIdx + it.length).forEach(c=>c.classList.remove('matched')); + } + cIdx += it.length; + }); + } + return ''; + }); + } + } + return item; + } + + /** + * Calculate score for the fuzzy match. + * @param {AutoCompleteOption} option + * @returns The option. + */ + fuzzyScore(option) { + // might have been matched by the options matchProvider function instead + if (!this.fuzzyRegex.test(option.name)) { + option.score = new AutoCompleteFuzzyScore(Number.MAX_SAFE_INTEGER, -1); + return option; + } + const parts = this.fuzzyRegex.exec(option.name).slice(1, -1); + let start = null; + let consecutive = []; + let current = ''; + let offset = 0; + parts.forEach((part, idx) => { + if (idx % 2 == 0) { + if (part.length > 0) { + if (current.length > 0) { + consecutive.push(current); + } + current = ''; + } + } else { + if (start === null) { + start = offset; + } + current += part; + } + offset += part.length; + }); + if (current.length > 0) { + consecutive.push(current); + } + consecutive.sort((a,b)=>b.length - a.length); + option.score = new AutoCompleteFuzzyScore(start, consecutive[0]?.length ?? 0); + return option; + } + + /** + * Compare two auto complete options by their fuzzy score. + * @param {AutoCompleteOption} a + * @param {AutoCompleteOption} b + */ + fuzzyScoreCompare(a, b) { + if (a.score.start < b.score.start) return -1; + if (a.score.start > b.score.start) return 1; + if (a.score.longestConsecutive > b.score.longestConsecutive) return -1; + if (a.score.longestConsecutive < b.score.longestConsecutive) return 1; + return a.name.localeCompare(b.name); + } + + basicAutoHideCheck() { + // auto hide only if at least one char has been typed after the name + space + return this.textarea.selectionStart > this.parserResult.start + + this.parserResult.name.length + + (this.startQuote ? 1 : 0) + + (this.endQuote ? 1 : 0) + + 1 + ; + } + + /** + * Show the autocomplete. + * @param {boolean} isInput Whether triggered by input. + * @param {boolean} isForced Whether force-showing (ctrl+space). + * @param {boolean} isSelect Whether an autocomplete option was just selected. + */ + async show(isInput = false, isForced = false, isSelect = false) { + //TODO check if isInput and isForced are both required + this.text = this.textarea.value; + this.isReplaceable = false; + + if (document.activeElement != this.textarea) { + // only show with textarea in focus + return this.hide(); + } + if (!this.checkIfActivate()) { + // only show if provider wants to + return this.hide(); + } + + // disable force-hide if trigger was forced + if (isForced) this.isForceHidden = false; + + // request provider to get name result (potentially "incomplete", i.e. not an actual existing name) for + // cursor position + this.parserResult = await this.getNameAt(this.text, this.textarea.selectionStart); + this.secondaryParserResult = null; + + if (!this.parserResult) { + // don't show if no name result found, e.g., cursor's area is not a command + return this.hide(); + } + + // need to know if name can be inside quotes, and then check if quotes are already there + if (this.parserResult.canBeQuoted) { + this.startQuote = this.text[this.parserResult.start] == '"'; + this.endQuote = this.startQuote && this.text[this.parserResult.start + this.parserResult.name.length + 1] == '"'; + } else { + this.startQuote = false; + this.endQuote = false; + } + + // use lowercase name for matching + this.name = this.parserResult.name.toLowerCase() ?? ''; + + const isCursorInNamePart = this.textarea.selectionStart >= this.parserResult.start && this.textarea.selectionStart <= this.parserResult.start + this.parserResult.name.length + (this.startQuote ? 1 : 0); + if (isForced || isInput) { + // if forced (ctrl+space) or user input... + if (isCursorInNamePart) { + // ...and cursor is somewhere in the name part (including right behind the final char) + // -> show autocomplete for the (partial if cursor in the middle) name + this.name = this.name.slice(0, this.textarea.selectionStart - (this.parserResult.start) - (this.startQuote ? 1 : 0)); + this.parserResult.name = this.name; + this.isReplaceable = true; + this.isForceHidden = false; + this.canBeAutoHidden = false; + } else { + this.isReplaceable = false; + this.canBeAutoHidden = this.basicAutoHideCheck(); + } + } else { + // if not forced and no user input -> just show details + this.isReplaceable = false; + this.canBeAutoHidden = this.basicAutoHideCheck(); + } + + if (isForced || isInput || isSelect) { + // is forced or user input or just selected autocomplete option... + if (!isCursorInNamePart) { + // ...and cursor is not somwehere in the main name part -> check for secondary options (e.g., named arguments) + const result = this.parserResult.getSecondaryNameAt(this.text, this.textarea.selectionStart, isSelect); + if (result && (isForced || result.isRequired)) { + this.secondaryParserResult = result; + this.name = this.secondaryParserResult.name; + this.isReplaceable = isForced || this.secondaryParserResult.isRequired; + this.isForceHidden = false; + this.canBeAutoHidden = false; + } else { + this.isReplaceable = false; + this.canBeAutoHidden = this.basicAutoHideCheck(); + } + } + } + + if (this.matchType == 'fuzzy') { + // only build the fuzzy regex if match type is set to fuzzy + this.fuzzyRegex = new RegExp(`^(.*?)${this.name.split('').map(char=>`(${escapeRegex(char)})`).join('(.*?)')}(.*?)$`, 'i'); + } + + //TODO maybe move the matchers somewhere else; a single match function? matchType is available as property + const matchers = { + 'strict': (name) => name.toLowerCase().startsWith(this.name), + 'includes': (name) => name.toLowerCase().includes(this.name), + 'fuzzy': (name) => this.fuzzyRegex.test(name), + }; + + this.result = this.effectiveParserResult.optionList + // filter the list of options by the partial name according to the matching type + .filter(it => this.isReplaceable || it.name == '' ? (it.matchProvider ? it.matchProvider(this.name) : matchers[this.matchType](it.name)) : it.name.toLowerCase() == this.name) + // remove aliases + .filter((it,idx,list) => list.findIndex(opt=>opt.value == it.value) == idx); + + if (this.result.length == 0 && this.effectiveParserResult != this.parserResult && isForced) { + // no matching secondary results and forced trigger -> show current command details + this.secondaryParserResult = null; + this.result = [this.effectiveParserResult.optionList.find(it=>it.name == this.effectiveParserResult.name)]; + this.name = this.effectiveParserResult.name; + this.fuzzyRegex = /(.*)(.*)(.*)/; + } + + this.result = this.result + // update remaining options + .map(option => { + // build element + option.dom = this.makeItem(option); + // update replacer and add quotes if necessary + const optionName = option.valueProvider ? option.valueProvider(this.name) : option.name; + if (this.effectiveParserResult.canBeQuoted) { + option.replacer = optionName.includes(' ') || this.startQuote || this.endQuote ? `"${optionName.replace(/"/g, '\\"')}"` : `${optionName}`; + } else { + option.replacer = optionName; + } + // calculate fuzzy score if matching is fuzzy + if (this.matchType == 'fuzzy') this.fuzzyScore(option); + // update the name to highlight the matched chars + this.updateName(option); + return option; + }) + // sort by fuzzy score or alphabetical + .toSorted(this.matchType == 'fuzzy' ? this.fuzzyScoreCompare : (a, b) => a.name.localeCompare(b.name)) + ; + + + + if (this.isForceHidden) { + // hidden with escape + return this.hide(); + } + if (this.autoHide && this.canBeAutoHidden && !isForced && this.effectiveParserResult == this.parserResult && this.result.length == 1) { + // auto hide user setting enabled and somewhere after name part and would usually show command details + return this.hide(); + } + if (this.result.length == 0) { + if (!isInput) { + // no result and no input? hide autocomplete + return this.hide(); + } + if (this.effectiveParserResult instanceof AutoCompleteSecondaryNameResult && !this.effectiveParserResult.forceMatch) { + // no result and matching is no forced? hide autocomplete + return this.hide(); + } + // otherwise add "no match" notice + const option = new BlankAutoCompleteOption( + this.name.length ? + this.effectiveParserResult.makeNoMatchText() + : this.effectiveParserResult.makeNoOptionsText() + , + ); + this.result.push(option); + } else if (this.result.length == 1 && this.effectiveParserResult && this.effectiveParserResult != this.secondaryParserResult && this.result[0].name == this.effectiveParserResult.name) { + // only one result that is exactly the current value? just show hint, no autocomplete + this.isReplaceable = false; + this.isShowingDetails = false; + } else if (!this.isReplaceable && this.result.length > 1) { + return this.hide(); + } + this.selectedItem = this.result[0]; + this.isActive = true; + this.wasForced = isForced; + this.renderDebounced(); + } + + /** + * Hide autocomplete. + */ + hide() { + this.domWrap?.remove(); + this.detailsWrap?.remove(); + this.isActive = false; + this.isShowingDetails = false; + this.wasForced = false; + } + + + + /** + * Create updated DOM. + */ + render() { + if (!this.isActive) return this.domWrap.remove(); + if (this.isReplaceable) { + this.dom.innerHTML = ''; + const frag = document.createDocumentFragment(); + for (const item of this.result) { + if (item == this.selectedItem) { + item.dom.classList.add('selected'); + } else { + item.dom.classList.remove('selected'); + } + if (!item.isSelectable) { + item.dom.classList.add('not-selectable'); + } + frag.append(item.dom); + } + this.dom.append(frag); + this.updatePosition(); + this.getLayer().append(this.domWrap); + } else { + this.domWrap.remove(); + } + this.renderDetailsDebounced(); + } + + /** + * Create updated DOM for details. + */ + renderDetails() { + if (!this.isActive) return this.detailsWrap.remove(); + if (!this.isShowingDetails && this.isReplaceable) return this.detailsWrap.remove(); + this.detailsDom.innerHTML = ''; + this.detailsDom.append(this.selectedItem?.renderDetails() ?? 'NO ITEM'); + this.getLayer().append(this.detailsWrap); + this.updateDetailsPositionDebounced(); + } + + /** + * @returns {HTMLElement} closest ancestor dialog or body + */ + getLayer() { + return this.textarea.closest('dialog, body'); + } + + + + /** + * Update position of DOM. + */ + updatePosition() { + if (this.isFloating) { + this.updateFloatingPosition(); + } else { + const rect = {}; + rect[AUTOCOMPLETE_WIDTH.INPUT] = this.textarea.getBoundingClientRect(); + rect[AUTOCOMPLETE_WIDTH.CHAT] = document.querySelector('#sheld').getBoundingClientRect(); + rect[AUTOCOMPLETE_WIDTH.FULL] = this.getLayer().getBoundingClientRect(); + this.domWrap.style.setProperty('--bottom', `${window.innerHeight - rect[AUTOCOMPLETE_WIDTH.INPUT].top}px`); + this.dom.style.setProperty('--bottom', `${window.innerHeight - rect[AUTOCOMPLETE_WIDTH.INPUT].top}px`); + this.domWrap.style.bottom = `${window.innerHeight - rect[AUTOCOMPLETE_WIDTH.INPUT].top}px`; + if (this.isShowingDetails) { + this.domWrap.style.setProperty('--leftOffset', '1vw'); + this.domWrap.style.setProperty('--leftOffset', `max(1vw, ${rect[power_user.stscript.autocomplete.width.left].left}px)`); + this.domWrap.style.setProperty('--rightOffset', `calc(100vw - min(${rect[power_user.stscript.autocomplete.width.right].right}px, ${this.isShowingDetails ? 74 : 0}vw)`); + } else { + this.domWrap.style.setProperty('--leftOffset', `max(1vw, ${rect[power_user.stscript.autocomplete.width.left].left}px)`); + this.domWrap.style.setProperty('--rightOffset', `calc(100vw - min(99vw, ${rect[power_user.stscript.autocomplete.width.right].right}px)`); + } + } + this.updateDetailsPosition(); + } + + /** + * Update position of details DOM. + */ + updateDetailsPosition() { + if (this.isShowingDetails || !this.isReplaceable) { + if (this.isFloating) { + this.updateFloatingDetailsPosition(); + } else { + const rect = {}; + rect[AUTOCOMPLETE_WIDTH.INPUT] = this.textarea.getBoundingClientRect(); + rect[AUTOCOMPLETE_WIDTH.CHAT] = document.querySelector('#sheld').getBoundingClientRect(); + rect[AUTOCOMPLETE_WIDTH.FULL] = this.getLayer().getBoundingClientRect(); + if (this.isReplaceable) { + this.detailsWrap.classList.remove('full'); + const selRect = this.selectedItem.dom.children[0].getBoundingClientRect(); + this.detailsWrap.style.setProperty('--targetOffset', `${selRect.top}`); + this.detailsWrap.style.setProperty('--rightOffset', '1vw'); + this.detailsWrap.style.setProperty('--bottomOffset', `calc(100vh - ${rect[AUTOCOMPLETE_WIDTH.INPUT].top}px)`); + this.detailsWrap.style.setProperty('--leftOffset', `calc(100vw - ${this.domWrap.style.getPropertyValue('--rightOffset')}`); + } else { + this.detailsWrap.classList.add('full'); + this.detailsWrap.style.setProperty('--targetOffset', `${rect[AUTOCOMPLETE_WIDTH.INPUT].top}`); + this.detailsWrap.style.setProperty('--bottomOffset', `calc(100vh - ${rect[AUTOCOMPLETE_WIDTH.INPUT].top}px)`); + this.detailsWrap.style.setProperty('--leftOffset', `${rect[power_user.stscript.autocomplete.width.left].left}px`); + this.detailsWrap.style.setProperty('--rightOffset', `calc(100vw - ${rect[power_user.stscript.autocomplete.width.right].right}px)`); + } + } + } + } + + + /** + * Update position of floating autocomplete. + */ + updateFloatingPosition() { + const location = this.getCursorPosition(); + const rect = this.textarea.getBoundingClientRect(); + const layerRect = this.getLayer().getBoundingClientRect(); + // cursor is out of view -> hide + if (location.bottom < rect.top || location.top > rect.bottom || location.left < rect.left || location.left > rect.right) { + return this.hide(); + } + const left = Math.max(rect.left, location.left) - layerRect.left; + this.domWrap.style.setProperty('--targetOffset', `${left}`); + if (location.top <= window.innerHeight / 2) { + // if cursor is in lower half of window, show list above line + this.domWrap.style.top = `${location.bottom - layerRect.top}px`; + this.domWrap.style.bottom = 'auto'; + this.domWrap.style.maxHeight = `calc(${location.bottom - layerRect.top}px - ${this.textarea.closest('dialog') ? '0' : '1vh'})`; + } else { + // if cursor is in upper half of window, show list below line + this.domWrap.style.top = 'auto'; + this.domWrap.style.bottom = `calc(${layerRect.height}px - ${location.top - layerRect.top}px)`; + this.domWrap.style.maxHeight = `calc(${location.top - layerRect.top}px - ${this.textarea.closest('dialog') ? '0' : '1vh'})`; + } + } + + updateFloatingDetailsPosition(location = null) { + if (!location) location = this.getCursorPosition(); + const rect = this.textarea.getBoundingClientRect(); + const layerRect = this.getLayer().getBoundingClientRect(); + if (location.bottom < rect.top || location.top > rect.bottom || location.left < rect.left || location.left > rect.right) { + return this.hide(); + } + const left = Math.max(rect.left, location.left) - layerRect.left; + this.detailsWrap.style.setProperty('--targetOffset', `${left}`); + if (this.isReplaceable) { + this.detailsWrap.classList.remove('full'); + if (left < window.innerWidth / 4) { + // if cursor is in left part of screen, show details on right of list + this.detailsWrap.classList.add('right'); + this.detailsWrap.classList.remove('left'); + } else { + // if cursor is in right part of screen, show details on left of list + this.detailsWrap.classList.remove('right'); + this.detailsWrap.classList.add('left'); + } + } else { + this.detailsWrap.classList.remove('left'); + this.detailsWrap.classList.remove('right'); + this.detailsWrap.classList.add('full'); + } + if (location.top <= window.innerHeight / 2) { + // if cursor is in lower half of window, show list above line + this.detailsWrap.style.top = `${location.bottom - layerRect.top}px`; + this.detailsWrap.style.bottom = 'auto'; + this.detailsWrap.style.maxHeight = `calc(${location.bottom - layerRect.top}px - ${this.textarea.closest('dialog') ? '0' : '1vh'})`; + } else { + // if cursor is in upper half of window, show list below line + this.detailsWrap.style.top = 'auto'; + this.detailsWrap.style.bottom = `calc(${layerRect.height}px - ${location.top - layerRect.top}px)`; + this.detailsWrap.style.maxHeight = `calc(${location.top - layerRect.top}px - ${this.textarea.closest('dialog') ? '0' : '1vh'})`; + } + } + + /** + * Calculate (keyboard) cursor coordinates within textarea. + * @returns {{left:number, top:number, bottom:number}} + */ + getCursorPosition() { + const inputRect = this.textarea.getBoundingClientRect(); + const style = window.getComputedStyle(this.textarea); + if (!this.clone) { + this.clone = document.createElement('div'); + for (const key of style) { + this.clone.style[key] = style[key]; + } + this.clone.style.position = 'fixed'; + this.clone.style.visibility = 'hidden'; + document.body.append(this.clone); + const mo = new MutationObserver(muts=>{ + if (muts.find(it=>Array.from(it.removedNodes).includes(this.textarea))) { + this.clone.remove(); + } + }); + mo.observe(this.textarea.parentElement, { childList:true }); + } + this.clone.style.height = `${inputRect.height}px`; + this.clone.style.left = `${inputRect.left}px`; + this.clone.style.top = `${inputRect.top}px`; + this.clone.style.whiteSpace = style.whiteSpace; + this.clone.style.tabSize = style.tabSize; + const text = this.textarea.value; + const before = text.slice(0, this.textarea.selectionStart); + this.clone.textContent = before; + const locator = document.createElement('span'); + locator.textContent = text[this.textarea.selectionStart]; + this.clone.append(locator); + this.clone.append(text.slice(this.textarea.selectionStart + 1)); + this.clone.scrollTop = this.textarea.scrollTop; + this.clone.scrollLeft = this.textarea.scrollLeft; + const locatorRect = locator.getBoundingClientRect(); + const location = { + left: locatorRect.left, + top: locatorRect.top, + bottom: locatorRect.bottom, + }; + return location; + } + + + /** + * Toggle details view alongside autocomplete list. + */ + toggleDetails() { + this.isShowingDetails = !this.isShowingDetails; + this.renderDetailsDebounced(); + this.updatePosition(); + } + + + /** + * Select an item for autocomplete and put text into textarea. + */ + async select() { + if (this.isReplaceable && this.selectedItem.value !== null) { + this.textarea.value = `${this.text.slice(0, this.effectiveParserResult.start)}${this.selectedItem.replacer}${this.text.slice(this.effectiveParserResult.start + this.effectiveParserResult.name.length + (this.startQuote ? 1 : 0) + (this.endQuote ? 1 : 0))}`; + this.textarea.selectionStart = this.effectiveParserResult.start + this.selectedItem.replacer.length; + this.textarea.selectionEnd = this.textarea.selectionStart; + this.show(false, false, true); + } else { + const selectionStart = this.textarea.selectionStart; + const selectionEnd = this.textarea.selectionDirection; + this.textarea.selectionStart = selectionStart; + this.textarea.selectionDirection = selectionEnd; + } + this.wasForced = false; + this.textarea.dispatchEvent(new Event('input', { bubbles:true })); + this.onSelect?.(this.selectedItem); + } + + + /** + * Mark the item at newIdx in the autocomplete list as selected. + * @param {number} newIdx + */ + selectItemAtIndex(newIdx) { + this.selectedItem.dom.classList.remove('selected'); + this.selectedItem = this.result[newIdx]; + this.selectedItem.dom.classList.add('selected'); + const rect = this.selectedItem.dom.children[0].getBoundingClientRect(); + const rectParent = this.dom.getBoundingClientRect(); + if (rect.top < rectParent.top || rect.bottom > rectParent.bottom ) { + this.dom.scrollTop += rect.top < rectParent.top ? rect.top - rectParent.top : rect.bottom - rectParent.bottom; + } + this.renderDetailsDebounced(); + } + + /** + * Handle keyboard events. + * @param {KeyboardEvent} evt The event. + */ + async handleKeyDown(evt) { + // autocomplete is shown and cursor at end of current command name (or inside name and typed or forced) + if (this.isActive && this.isReplaceable) { + // actions in the list + switch (evt.key) { + case 'ArrowUp': { + // select previous item + if (evt.ctrlKey || evt.altKey || evt.shiftKey) return; + evt.preventDefault(); + evt.stopPropagation(); + const idx = this.result.indexOf(this.selectedItem); + let newIdx; + if (idx == 0) newIdx = this.result.length - 1; + else newIdx = idx - 1; + this.selectItemAtIndex(newIdx); + return; + } + case 'ArrowDown': { + // select next item + if (evt.ctrlKey || evt.altKey || evt.shiftKey) return; + evt.preventDefault(); + evt.stopPropagation(); + const idx = this.result.indexOf(this.selectedItem); + const newIdx = (idx + 1) % this.result.length; + this.selectItemAtIndex(newIdx); + return; + } + case 'Enter': { + // pick the selected item to autocomplete + if ((power_user.stscript.autocomplete.select & AUTOCOMPLETE_SELECT_KEY.ENTER) != AUTOCOMPLETE_SELECT_KEY.ENTER) break; + if (evt.ctrlKey || evt.altKey || evt.shiftKey || this.selectedItem.value == '') break; + if (this.selectedItem.name == this.name) break; + if (!this.selectedItem.isSelectable) break; + evt.preventDefault(); + evt.stopImmediatePropagation(); + this.select(); + return; + } + case 'Tab': { + // pick the selected item to autocomplete + if ((power_user.stscript.autocomplete.select & AUTOCOMPLETE_SELECT_KEY.TAB) != AUTOCOMPLETE_SELECT_KEY.TAB) break; + if (evt.ctrlKey || evt.altKey || evt.shiftKey || this.selectedItem.value == '') break; + evt.preventDefault(); + evt.stopImmediatePropagation(); + if (!this.selectedItem.isSelectable) break; + this.select(); + return; + } + } + } + // details are shown, cursor can be anywhere + if (this.isActive) { + switch (evt.key) { + case 'Escape': { + // close autocomplete + if (evt.ctrlKey || evt.altKey || evt.shiftKey) return; + evt.preventDefault(); + evt.stopPropagation(); + this.isForceHidden = true; + this.wasForced = false; + this.hide(); + return; + } + case 'Enter': { + // hide autocomplete on enter (send, execute, ...) + if (!evt.shiftKey) { + this.hide(); + return; + } + break; + } + } + } + // autocomplete shown or not, cursor anywhere + switch (evt.key) { + // The first is a non-breaking space, the second is a regular space. + case ' ': + case ' ': { + if (evt.ctrlKey || evt.altKey) { + if (this.isActive && this.isReplaceable) { + // ctrl-space to toggle details for selected item + this.toggleDetails(); + } else { + // ctrl-space to force show autocomplete + this.show(false, true); + } + evt.preventDefault(); + evt.stopPropagation(); + return; + } + break; + } + } + if (['Control', 'Shift', 'Alt'].includes(evt.key)) { + // ignore keydown on modifier keys + return; + } + // await keyup to see if cursor position or text has changed + const oldText = this.textarea.value; + await new Promise(resolve=>{ + window.addEventListener('keyup', resolve, { once:true }); + }); + if (this.selectionStart != this.textarea.selectionStart) { + this.selectionStart = this.textarea.selectionStart; + this.show(this.isReplaceable || oldText != this.textarea.value); + } else if (this.isActive) { + this.text != this.textarea.value && this.show(this.isReplaceable); + } + } +} diff --git a/jiuguan2025cc/public/scripts/autocomplete/AutoCompleteFuzzyScore.js b/jiuguan2025cc/public/scripts/autocomplete/AutoCompleteFuzzyScore.js new file mode 100644 index 0000000000000000000000000000000000000000..550fbe6a2785ae5be73af0210c6dd35b95748949 --- /dev/null +++ b/jiuguan2025cc/public/scripts/autocomplete/AutoCompleteFuzzyScore.js @@ -0,0 +1,16 @@ + + + +export class AutoCompleteFuzzyScore { + /**@type {number}*/ start; + /**@type {number}*/ longestConsecutive; + + /** + * @param {number} start + * @param {number} longestConsecutive + */ + constructor(start, longestConsecutive) { + this.start = start; + this.longestConsecutive = longestConsecutive; + } +} diff --git a/jiuguan2025cc/public/scripts/autocomplete/AutoCompleteNameResult.js b/jiuguan2025cc/public/scripts/autocomplete/AutoCompleteNameResult.js new file mode 100644 index 0000000000000000000000000000000000000000..f048d6383bd0a89d1e0431501987e00625155c0d --- /dev/null +++ b/jiuguan2025cc/public/scripts/autocomplete/AutoCompleteNameResult.js @@ -0,0 +1,17 @@ +import { AutoCompleteNameResultBase } from './AutoCompleteNameResultBase.js'; +import { AutoCompleteSecondaryNameResult } from './AutoCompleteSecondaryNameResult.js'; + + + +export class AutoCompleteNameResult extends AutoCompleteNameResultBase { + /** + * + * @param {string} text The whole text + * @param {number} index Cursor index within text + * @param {boolean} isSelect Whether autocomplete was triggered by selecting an autocomplete option + * @returns {AutoCompleteSecondaryNameResult} + */ + getSecondaryNameAt(text, index, isSelect) { + return null; + } +} diff --git a/jiuguan2025cc/public/scripts/autocomplete/AutoCompleteNameResultBase.js b/jiuguan2025cc/public/scripts/autocomplete/AutoCompleteNameResultBase.js new file mode 100644 index 0000000000000000000000000000000000000000..150ee68c5c25c6767d83e1c07bb431d8a3690794 --- /dev/null +++ b/jiuguan2025cc/public/scripts/autocomplete/AutoCompleteNameResultBase.js @@ -0,0 +1,31 @@ +import { SlashCommandNamedArgumentAutoCompleteOption } from '../slash-commands/SlashCommandNamedArgumentAutoCompleteOption.js'; +import { AutoCompleteOption } from './AutoCompleteOption.js'; + + + +export class AutoCompleteNameResultBase { + /**@type {string} */ name; + /**@type {number} */ start; + /**@type {AutoCompleteOption[]} */ optionList = []; + /**@type {boolean} */ canBeQuoted = false; + /**@type {()=>string} */ makeNoMatchText = ()=>`No matches found for "${this.name}"`; + /**@type {()=>string} */ makeNoOptionsText = ()=>'No options'; + + + /** + * @param {string} name Name (potentially partial) of the name at the requested index. + * @param {number} start Index where the name starts. + * @param {AutoCompleteOption[]} optionList A list of autocomplete options found in the current scope. + * @param {boolean} canBeQuoted Whether the name can be inside quotes. + * @param {()=>string} makeNoMatchText Function that returns text to show when no matches where found. + * @param {()=>string} makeNoOptionsText Function that returns text to show when no options are available to match against. + */ + constructor(name, start, optionList = [], canBeQuoted = false, makeNoMatchText = null, makeNoOptionsText = null) { + this.name = name; + this.start = start; + this.optionList = optionList; + this.canBeQuoted = canBeQuoted; + this.noMatchText = makeNoMatchText ?? this.makeNoMatchText; + this.noOptionstext = makeNoOptionsText ?? this.makeNoOptionsText; + } +} diff --git a/jiuguan2025cc/public/scripts/autocomplete/AutoCompleteOption.js b/jiuguan2025cc/public/scripts/autocomplete/AutoCompleteOption.js new file mode 100644 index 0000000000000000000000000000000000000000..24822750b86fb52a72c67fddb208d525db2e675b --- /dev/null +++ b/jiuguan2025cc/public/scripts/autocomplete/AutoCompleteOption.js @@ -0,0 +1,224 @@ +import { SlashCommand } from '../slash-commands/SlashCommand.js'; +import { AutoCompleteFuzzyScore } from './AutoCompleteFuzzyScore.js'; + + + +export class AutoCompleteOption { + /**@type {string}*/ name; + /**@type {string}*/ typeIcon; + /**@type {string}*/ type; + /**@type {number}*/ nameOffset = 0; + /**@type {AutoCompleteFuzzyScore}*/ score; + /**@type {string}*/ replacer; + /**@type {HTMLElement}*/ dom; + /**@type {(input:string)=>boolean}*/ matchProvider; + /**@type {(input:string)=>string}*/ valueProvider; + /**@type {boolean}*/ makeSelectable = false; + + + /** + * Used as a comparison value when removing duplicates (e.g., when a SlashCommand has aliases). + * @type {any} + * */ + get value() { + return this.name; + } + + get isSelectable() { + return this.makeSelectable || !this.valueProvider; + } + + + /** + * @param {string} name + */ + constructor(name, typeIcon = ' ', type = '', matchProvider = null, valueProvider = null, makeSelectable = false) { + this.name = name; + this.typeIcon = typeIcon; + this.type = type; + this.matchProvider = matchProvider; + this.valueProvider = valueProvider; + this.makeSelectable = makeSelectable; + } + + + makeItem(key, typeIcon, noSlash, namedArguments = [], unnamedArguments = [], returnType = 'void', helpString = '', aliasList = []) { + const li = document.createElement('li'); { + li.classList.add('item'); + const type = document.createElement('span'); { + type.classList.add('type'); + type.classList.add('monospace'); + type.textContent = typeIcon; + li.append(type); + } + const specs = document.createElement('span'); { + specs.classList.add('specs'); + const name = document.createElement('span'); { + name.classList.add('name'); + name.classList.add('monospace'); + name.textContent = noSlash ? '' : '/'; + key.split('').forEach(char=>{ + const span = document.createElement('span'); { + span.textContent = char; + name.append(span); + } + }); + specs.append(name); + } + const body = document.createElement('span'); { + body.classList.add('body'); + const args = document.createElement('span'); { + args.classList.add('arguments'); + for (const arg of namedArguments) { + const argItem = document.createElement('span'); { + argItem.classList.add('argument'); + argItem.classList.add('namedArgument'); + if (!arg.isRequired || (arg.defaultValue ?? false)) argItem.classList.add('optional'); + if (arg.acceptsMultiple) argItem.classList.add('multiple'); + const name = document.createElement('span'); { + name.classList.add('argument-name'); + name.textContent = arg.name; + argItem.append(name); + } + if (arg.enumList.length > 0) { + const enums = document.createElement('span'); { + enums.classList.add('argument-enums'); + for (const e of arg.enumList) { + const enumItem = document.createElement('span'); { + enumItem.classList.add('argument-enum'); + enumItem.textContent = e; + enums.append(enumItem); + } + } + argItem.append(enums); + } + } else { + const types = document.createElement('span'); { + types.classList.add('argument-types'); + for (const t of arg.typeList) { + const type = document.createElement('span'); { + type.classList.add('argument-type'); + type.textContent = t; + types.append(type); + } + } + argItem.append(types); + } + } + args.append(argItem); + } + } + for (const arg of unnamedArguments) { + const argItem = document.createElement('span'); { + argItem.classList.add('argument'); + argItem.classList.add('unnamedArgument'); + if (!arg.isRequired || (arg.defaultValue ?? false)) argItem.classList.add('optional'); + if (arg.acceptsMultiple) argItem.classList.add('multiple'); + if (arg.enumList.length > 0) { + const enums = document.createElement('span'); { + enums.classList.add('argument-enums'); + for (const e of arg.enumList) { + const enumItem = document.createElement('span'); { + enumItem.classList.add('argument-enum'); + enumItem.textContent = e; + enums.append(enumItem); + } + } + argItem.append(enums); + } + } else { + const types = document.createElement('span'); { + types.classList.add('argument-types'); + for (const t of arg.typeList) { + const type = document.createElement('span'); { + type.classList.add('argument-type'); + type.textContent = t; + types.append(type); + } + } + argItem.append(types); + } + } + args.append(argItem); + } + } + body.append(args); + } + const returns = document.createElement('span'); { + returns.classList.add('returns'); + returns.textContent = returnType ?? 'void'; + // body.append(returns); + } + specs.append(body); + } + li.append(specs); + } + const stopgap = document.createElement('span'); { + stopgap.classList.add('stopgap'); + stopgap.textContent = ''; + li.append(stopgap); + } + const help = document.createElement('span'); { + help.classList.add('help'); + const content = document.createElement('span'); { + content.classList.add('helpContent'); + content.innerHTML = helpString; + const text = content.textContent; + content.innerHTML = ''; + content.textContent = text; + help.append(content); + } + li.append(help); + } + if (aliasList.length > 0) { + const aliases = document.createElement('span'); { + aliases.classList.add('aliases'); + aliases.append(' (alias: '); + for (const aliasName of aliasList) { + const alias = document.createElement('span'); { + alias.classList.add('monospace'); + alias.textContent = `/${aliasName}`; + aliases.append(alias); + } + } + aliases.append(')'); + // li.append(aliases); + } + } + } + return li; + } + + + /** + * @returns {HTMLElement} + */ + renderItem() { + // throw new Error(`${this.constructor.name}.renderItem() is not implemented`); + let li; + li = this.makeItem(this.name, this.typeIcon, true); + li.setAttribute('data-name', this.name); + li.setAttribute('data-option-type', this.type); + return li; + } + + + /** + * @returns {DocumentFragment} + */ + renderDetails() { + // throw new Error(`${this.constructor.name}.renderDetails() is not implemented`); + const frag = document.createDocumentFragment(); + const specs = document.createElement('div'); { + specs.classList.add('specs'); + const name = document.createElement('div'); { + name.classList.add('name'); + name.classList.add('monospace'); + name.textContent = this.name; + specs.append(name); + } + frag.append(specs); + } + return frag; + } +} diff --git a/jiuguan2025cc/public/scripts/autocomplete/AutoCompleteSecondaryNameResult.js b/jiuguan2025cc/public/scripts/autocomplete/AutoCompleteSecondaryNameResult.js new file mode 100644 index 0000000000000000000000000000000000000000..e0e65fc7c5d66b456fcc4c9df152b94903071e6c --- /dev/null +++ b/jiuguan2025cc/public/scripts/autocomplete/AutoCompleteSecondaryNameResult.js @@ -0,0 +1,6 @@ +import { AutoCompleteNameResultBase } from './AutoCompleteNameResultBase.js'; + +export class AutoCompleteSecondaryNameResult extends AutoCompleteNameResultBase { + /**@type {boolean}*/ isRequired = false; + /**@type {boolean}*/ forceMatch = true; +} diff --git a/jiuguan2025cc/public/scripts/autocomplete/BlankAutoCompleteOption.js b/jiuguan2025cc/public/scripts/autocomplete/BlankAutoCompleteOption.js new file mode 100644 index 0000000000000000000000000000000000000000..12b1da95b27e21e5d7fd9a6095759b97678d5ceb --- /dev/null +++ b/jiuguan2025cc/public/scripts/autocomplete/BlankAutoCompleteOption.js @@ -0,0 +1,29 @@ +import { AutoCompleteOption } from './AutoCompleteOption.js'; + +export class BlankAutoCompleteOption extends AutoCompleteOption { + /** + * @param {string} name + */ + constructor(name) { + super(name); + this.dom = this.renderItem(); + } + + get value() { return null; } + + + renderItem() { + const li = document.createElement('li'); { + li.classList.add('item'); + li.classList.add('blank'); + li.textContent = this.name; + } + return li; + } + + + renderDetails() { + const frag = document.createDocumentFragment(); + return frag; + } +} diff --git a/jiuguan2025cc/public/scripts/autocomplete/MacroAutoCompleteOption.js b/jiuguan2025cc/public/scripts/autocomplete/MacroAutoCompleteOption.js new file mode 100644 index 0000000000000000000000000000000000000000..c871108872bee0e6ef500dae5b4e7eb533e23a25 --- /dev/null +++ b/jiuguan2025cc/public/scripts/autocomplete/MacroAutoCompleteOption.js @@ -0,0 +1,44 @@ +import { AutoCompleteOption } from './AutoCompleteOption.js'; + +export class MacroAutoCompleteOption extends AutoCompleteOption { + /**@type {string}*/ fullName; + /**@type {string}*/ description; + + + constructor(name, fullName, description) { + super(name, '{}'); + this.fullName = fullName; + this.description = description; + this.nameOffset = 2; + } + + + renderItem() { + let li; + li = this.makeItem(`${this.fullName}`, '{}', true, [], [], null, this.description); + li.setAttribute('data-name', this.name); + li.setAttribute('data-option-type', 'macro'); + return li; + } + + + renderDetails() { + const frag = document.createDocumentFragment(); + const specs = document.createElement('div'); { + specs.classList.add('specs'); + const name = document.createElement('div'); { + name.classList.add('name'); + name.classList.add('monospace'); + name.textContent = this.fullName; + specs.append(name); + } + frag.append(specs); + } + const help = document.createElement('span'); { + help.classList.add('help'); + help.innerHTML = this.description; + frag.append(help); + } + return frag; + } +} diff --git a/jiuguan2025cc/public/scripts/backgrounds.js b/jiuguan2025cc/public/scripts/backgrounds.js new file mode 100644 index 0000000000000000000000000000000000000000..3deef929ab8607083bf1658f119f5a8fae820031 --- /dev/null +++ b/jiuguan2025cc/public/scripts/backgrounds.js @@ -0,0 +1,546 @@ +import { Fuse } from '../lib.js'; + +import { callPopup, chat_metadata, eventSource, event_types, generateQuietPrompt, getCurrentChatId, getRequestHeaders, getThumbnailUrl, saveSettingsDebounced } from '../script.js'; +import { saveMetadataDebounced } from './extensions.js'; +import { SlashCommand } from './slash-commands/SlashCommand.js'; +import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; +import { flashHighlight, stringFormat } from './utils.js'; + +const BG_METADATA_KEY = 'custom_background'; +const LIST_METADATA_KEY = 'chat_backgrounds'; + +export let background_settings = { + name: '__transparent.png', + url: generateUrlParameter('__transparent.png', false), + fitting: 'classic', +}; + +export function loadBackgroundSettings(settings) { + let backgroundSettings = settings.background; + if (!backgroundSettings || !backgroundSettings.name || !backgroundSettings.url) { + backgroundSettings = background_settings; + } + if (!backgroundSettings.fitting) { + backgroundSettings.fitting = 'classic'; + } + setBackground(backgroundSettings.name, backgroundSettings.url); + setFittingClass(backgroundSettings.fitting); + $('#background_fitting').val(backgroundSettings.fitting); +} + +/** + * Sets the background for the current chat and adds it to the list of custom backgrounds. + * @param {{url: string, path:string}} backgroundInfo + */ +function forceSetBackground(backgroundInfo) { + saveBackgroundMetadata(backgroundInfo.url); + setCustomBackground(); + + const list = chat_metadata[LIST_METADATA_KEY] || []; + const bg = backgroundInfo.path; + list.push(bg); + chat_metadata[LIST_METADATA_KEY] = list; + saveMetadataDebounced(); + getChatBackgroundsList(); + highlightNewBackground(bg); + highlightLockedBackground(); +} + +async function onChatChanged() { + if (hasCustomBackground()) { + setCustomBackground(); + } + else { + unsetCustomBackground(); + } + + getChatBackgroundsList(); + highlightLockedBackground(); +} + +function getChatBackgroundsList() { + const list = chat_metadata[LIST_METADATA_KEY]; + const listEmpty = !Array.isArray(list) || list.length === 0; + + $('#bg_custom_content').empty(); + $('#bg_chat_hint').toggle(listEmpty); + + if (listEmpty) { + return; + } + + for (const bg of list) { + const template = getBackgroundFromTemplate(bg, true); + $('#bg_custom_content').append(template); + } +} + +function getBackgroundPath(fileUrl) { + return `backgrounds/${fileUrl}`; +} + +function highlightLockedBackground() { + $('.bg_example').removeClass('locked'); + + const lockedBackground = chat_metadata[BG_METADATA_KEY]; + + if (!lockedBackground) { + return; + } + + $('.bg_example').each(function () { + const url = $(this).data('url'); + if (url === lockedBackground) { + $(this).addClass('locked'); + } + }); +} + +/** + * Locks the background for the current chat + * @param {Event} e Click event + * @returns {string} Empty string + */ +function onLockBackgroundClick(e) { + e?.stopPropagation(); + + const chatName = getCurrentChatId(); + + if (!chatName) { + toastr.warning('Select a chat to lock the background for it'); + return ''; + } + + const relativeBgImage = getUrlParameter(this) ?? background_settings.url; + + saveBackgroundMetadata(relativeBgImage); + setCustomBackground(); + highlightLockedBackground(); + return ''; +} + +/** + * Locks the background for the current chat + * @param {Event} e Click event + * @returns {string} Empty string + */ +function onUnlockBackgroundClick(e) { + e?.stopPropagation(); + removeBackgroundMetadata(); + unsetCustomBackground(); + highlightLockedBackground(); + return ''; +} + +function hasCustomBackground() { + return chat_metadata[BG_METADATA_KEY]; +} + +function saveBackgroundMetadata(file) { + chat_metadata[BG_METADATA_KEY] = file; + saveMetadataDebounced(); +} + +function removeBackgroundMetadata() { + delete chat_metadata[BG_METADATA_KEY]; + saveMetadataDebounced(); +} + +function setCustomBackground() { + const file = chat_metadata[BG_METADATA_KEY]; + + // bg already set + if (document.getElementById('bg_custom').style.backgroundImage == file) { + return; + } + + $('#bg_custom').css('background-image', file); +} + +function unsetCustomBackground() { + $('#bg_custom').css('background-image', 'none'); +} + +function onSelectBackgroundClick() { + const isCustom = $(this).attr('custom') === 'true'; + const relativeBgImage = getUrlParameter(this); + + // if clicked on upload button + if (!relativeBgImage) { + return; + } + + // Automatically lock the background if it's custom or other background is locked + if (hasCustomBackground() || isCustom) { + saveBackgroundMetadata(relativeBgImage); + setCustomBackground(); + highlightLockedBackground(); + } + highlightLockedBackground(); + + const customBg = window.getComputedStyle(document.getElementById('bg_custom')).backgroundImage; + + // Custom background is set. Do not override the layer below + if (customBg !== 'none') { + return; + } + + const bgFile = $(this).attr('bgfile'); + const backgroundUrl = getBackgroundPath(bgFile); + + // Fetching to browser memory to reduce flicker + fetch(backgroundUrl).then(() => { + setBackground(bgFile, relativeBgImage); + }).catch(() => { + console.log('Background could not be set: ' + backgroundUrl); + }); +} + +async function onCopyToSystemBackgroundClick(e) { + e.stopPropagation(); + const bgNames = await getNewBackgroundName(this); + + if (!bgNames) { + return; + } + + const bgFile = await fetch(bgNames.oldBg); + + if (!bgFile.ok) { + toastr.warning('Failed to copy background'); + return; + } + + const blob = await bgFile.blob(); + const file = new File([blob], bgNames.newBg); + const formData = new FormData(); + formData.set('avatar', file); + + uploadBackground(formData); + + const list = chat_metadata[LIST_METADATA_KEY] || []; + const index = list.indexOf(bgNames.oldBg); + list.splice(index, 1); + saveMetadataDebounced(); + getChatBackgroundsList(); +} + +/** + * Gets the new background name from the user. + * @param {Element} referenceElement + * @returns {Promise<{oldBg: string, newBg: string}>} + * */ +async function getNewBackgroundName(referenceElement) { + const exampleBlock = $(referenceElement).closest('.bg_example'); + const isCustom = exampleBlock.attr('custom') === 'true'; + const oldBg = exampleBlock.attr('bgfile'); + + if (!oldBg) { + console.debug('no bgfile'); + return; + } + + const fileExtension = oldBg.split('.').pop(); + const fileNameBase = isCustom ? oldBg.split('/').pop() : oldBg; + const oldBgExtensionless = fileNameBase.replace(`.${fileExtension}`, ''); + const newBgExtensionless = await callPopup('

      Enter new background name:

      ', 'input', oldBgExtensionless); + + if (!newBgExtensionless) { + console.debug('no new_bg_extensionless'); + return; + } + + const newBg = `${newBgExtensionless}.${fileExtension}`; + + if (oldBgExtensionless === newBgExtensionless) { + console.debug('new_bg === old_bg'); + return; + } + + return { oldBg, newBg }; +} + +async function onRenameBackgroundClick(e) { + e.stopPropagation(); + + const bgNames = await getNewBackgroundName(this); + + if (!bgNames) { + return; + } + + const data = { old_bg: bgNames.oldBg, new_bg: bgNames.newBg }; + const response = await fetch('/api/backgrounds/rename', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify(data), + cache: 'no-cache', + }); + + if (response.ok) { + await getBackgrounds(); + highlightNewBackground(bgNames.newBg); + } else { + toastr.warning('Failed to rename background'); + } +} + +async function onDeleteBackgroundClick(e) { + e.stopPropagation(); + const bgToDelete = $(this).closest('.bg_example'); + const url = bgToDelete.data('url'); + const isCustom = bgToDelete.attr('custom') === 'true'; + const confirm = await callPopup('

      Delete the background?

      ', 'confirm'); + const bg = bgToDelete.attr('bgfile'); + + if (confirm) { + // If it's not custom, it's a built-in background. Delete it from the server + if (!isCustom) { + delBackground(bg); + } else { + const list = chat_metadata[LIST_METADATA_KEY] || []; + const index = list.indexOf(bg); + list.splice(index, 1); + } + + const siblingSelector = '.bg_example:not(#form_bg_download)'; + const nextBg = bgToDelete.next(siblingSelector); + const prevBg = bgToDelete.prev(siblingSelector); + const anyBg = $(siblingSelector); + + if (nextBg.length > 0) { + nextBg.trigger('click'); + } else if (prevBg.length > 0) { + prevBg.trigger('click'); + } else { + $(anyBg[Math.floor(Math.random() * anyBg.length)]).trigger('click'); + } + + bgToDelete.remove(); + + if (url === chat_metadata[BG_METADATA_KEY]) { + removeBackgroundMetadata(); + unsetCustomBackground(); + highlightLockedBackground(); + } + + if (isCustom) { + getChatBackgroundsList(); + saveMetadataDebounced(); + } + } +} + +const autoBgPrompt = 'Ignore previous instructions and choose a location ONLY from the provided list that is the most suitable for the current scene. Do not output any other text:\n{0}'; + +async function autoBackgroundCommand() { + /** @type {HTMLElement[]} */ + const bgTitles = Array.from(document.querySelectorAll('#bg_menu_content .BGSampleTitle')); + const options = bgTitles.map(x => ({ element: x, text: x.innerText.trim() })).filter(x => x.text.length > 0); + if (options.length == 0) { + toastr.warning('No backgrounds to choose from. Please upload some images to the "backgrounds" folder.'); + return ''; + } + + const list = options.map(option => `- ${option.text}`).join('\n'); + const prompt = stringFormat(autoBgPrompt, list); + const reply = await generateQuietPrompt(prompt, false, false); + const fuse = new Fuse(options, { keys: ['text'] }); + const bestMatch = fuse.search(reply, { limit: 1 }); + + if (bestMatch.length == 0) { + for (const option of options) { + if (String(reply).toLowerCase().includes(option.text.toLowerCase())) { + console.debug('Fallback choosing background:', option); + option.element.click(); + return ''; + } + } + + toastr.warning('No match found. Please try again.'); + return ''; + } + + console.debug('Automatically choosing background:', bestMatch); + bestMatch[0].item.element.click(); + return ''; +} + +export async function getBackgrounds() { + const response = await fetch('/api/backgrounds/all', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + '': '', + }), + }); + if (response.ok) { + const getData = await response.json(); + //background = getData; + //console.log(getData.length); + $('#bg_menu_content').children('div').remove(); + for (const bg of getData) { + const template = getBackgroundFromTemplate(bg, false); + $('#bg_menu_content').append(template); + } + } +} + +/** + * Gets the CSS URL of the background + * @param {Element} block + * @returns {string} URL of the background + */ +function getUrlParameter(block) { + return $(block).closest('.bg_example').data('url'); +} + +function generateUrlParameter(bg, isCustom) { + return isCustom ? `url("${encodeURI(bg)}")` : `url("${getBackgroundPath(bg)}")`; +} + +/** + * Instantiates a background template + * @param {string} bg Path to background + * @param {boolean} isCustom Whether the background is custom + * @returns {JQuery} Background template + */ +function getBackgroundFromTemplate(bg, isCustom) { + const template = $('#background_template .bg_example').clone(); + const thumbPath = isCustom ? bg : getThumbnailUrl('bg', bg); + const url = generateUrlParameter(bg, isCustom); + const title = isCustom ? bg.split('/').pop() : bg; + const friendlyTitle = title.slice(0, title.lastIndexOf('.')); + template.attr('title', title); + template.attr('bgfile', bg); + template.attr('custom', String(isCustom)); + template.data('url', url); + template.css('background-image', `url('${thumbPath}')`); + template.find('.BGSampleTitle').text(friendlyTitle); + return template; +} + +async function setBackground(bg, url) { + $('#bg1').css('background-image', url); + background_settings.name = bg; + background_settings.url = url; + saveSettingsDebounced(); +} + +async function delBackground(bg) { + await fetch('/api/backgrounds/delete', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + bg: bg, + }), + }); +} + +function onBackgroundUploadSelected() { + const form = $('#form_bg_download').get(0); + + if (!(form instanceof HTMLFormElement)) { + console.error('form_bg_download is not a form'); + return; + } + + const formData = new FormData(form); + uploadBackground(formData); + form.reset(); +} + +/** + * Uploads a background to the server + * @param {FormData} formData + */ +function uploadBackground(formData) { + jQuery.ajax({ + type: 'POST', + url: '/api/backgrounds/upload', + data: formData, + beforeSend: function () { + }, + cache: false, + contentType: false, + processData: false, + success: async function (bg) { + setBackground(bg, generateUrlParameter(bg, false)); + await getBackgrounds(); + highlightNewBackground(bg); + }, + error: function (jqXHR, exception) { + console.log(exception); + console.log(jqXHR); + }, + }); +} + +/** + * @param {string} bg + */ +function highlightNewBackground(bg) { + const newBg = $(`.bg_example[bgfile="${bg}"]`); + const scrollOffset = newBg.offset().top - newBg.parent().offset().top; + $('#Backgrounds').scrollTop(scrollOffset); + flashHighlight(newBg); +} + +/** + * Sets the fitting class for the background element + * @param {string} fitting Fitting type + */ +function setFittingClass(fitting) { + const backgrounds = $('#bg1, #bg_custom'); + for (const option of ['cover', 'contain', 'stretch', 'center']) { + backgrounds.toggleClass(option, option === fitting); + } + background_settings.fitting = fitting; +} + +function onBackgroundFilterInput() { + const filterValue = String($(this).val()).toLowerCase(); + $('#bg_menu_content > div').each(function () { + const $bgContent = $(this); + if ($bgContent.attr('title').toLowerCase().includes(filterValue)) { + $bgContent.show(); + } else { + $bgContent.hide(); + } + }); +} + +export function initBackgrounds() { + eventSource.on(event_types.CHAT_CHANGED, onChatChanged); + eventSource.on(event_types.FORCE_SET_BACKGROUND, forceSetBackground); + $(document).on('click', '.bg_example', onSelectBackgroundClick); + $(document).on('click', '.bg_example_lock', onLockBackgroundClick); + $(document).on('click', '.bg_example_unlock', onUnlockBackgroundClick); + $(document).on('click', '.bg_example_edit', onRenameBackgroundClick); + $(document).on('click', '.bg_example_cross', onDeleteBackgroundClick); + $(document).on('click', '.bg_example_copy', onCopyToSystemBackgroundClick); + $('#auto_background').on('click', autoBackgroundCommand); + $('#add_bg_button').on('change', onBackgroundUploadSelected); + $('#bg-filter').on('input', onBackgroundFilterInput); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'lockbg', + callback: () => onLockBackgroundClick(new CustomEvent('click')), + aliases: ['bglock'], + helpString: 'Locks a background for the currently selected chat', + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'unlockbg', + callback: () => onUnlockBackgroundClick(new CustomEvent('click')), + aliases: ['bgunlock'], + helpString: 'Unlocks a background for the currently selected chat', + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'autobg', + callback: autoBackgroundCommand, + aliases: ['bgauto'], + helpString: 'Automatically changes the background based on the chat context using the AI request prompt', + })); + + $('#background_fitting').on('input', function () { + background_settings.fitting = String($(this).val()); + setFittingClass(background_settings.fitting); + saveSettingsDebounced(); + }); +} diff --git a/jiuguan2025cc/public/scripts/bookmarks.js b/jiuguan2025cc/public/scripts/bookmarks.js new file mode 100644 index 0000000000000000000000000000000000000000..61baf34a44ab27a07ea518e5db520b1966111935 --- /dev/null +++ b/jiuguan2025cc/public/scripts/bookmarks.js @@ -0,0 +1,647 @@ +import { + characters, + saveChat, + system_messages, + system_message_types, + this_chid, + openCharacterChat, + chat_metadata, + getRequestHeaders, + getThumbnailUrl, + getCharacters, + chat, + saveChatConditional, + saveItemizedPrompts, +} from '../script.js'; +import { humanizedDateTime, getMessageTimeStamp } from './RossAscends-mods.js'; +import { + getGroupPastChats, + group_activation_strategy, + groups, + openGroupById, + openGroupChat, + saveGroupBookmarkChat, + selected_group, +} from './group-chats.js'; +import { hideLoader, showLoader } from './loader.js'; +import { getLastMessageId } from './macros.js'; +import { Popup } from './popup.js'; +import { SlashCommand } from './slash-commands/SlashCommand.js'; +import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js'; +import { commonEnumProviders } from './slash-commands/SlashCommandCommonEnumsProvider.js'; +import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; +import { createTagMapFromList } from './tags.js'; +import { renderTemplateAsync } from './templates.js'; +import { t } from './i18n.js'; + +import { + getUniqueName, + isTrueBoolean, +} from './utils.js'; + +const bookmarkNameToken = 'Checkpoint #'; + +async function getExistingChatNames() { + if (selected_group) { + const data = await getGroupPastChats(selected_group); + return data.map(x => x.file_name); + } else { + const response = await fetch('/api/characters/chats', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ avatar_url: characters[this_chid].avatar }), + }); + + if (response.ok) { + const data = await response.json(); + return Object.values(data).map(x => x.file_name.replace('.jsonl', '')); + } + } +} + +async function getBookmarkName({ isReplace = false, forceName = null } = {}) { + const chatNames = await getExistingChatNames(); + + const body = await renderTemplateAsync('createCheckpoint', { isReplace: isReplace }); + let name = forceName ?? await Popup.show.input('Create Checkpoint', body); + // Special handling for confirmed empty input (=> auto-generate name) + if (name === '') { + for (let i = chatNames.length; i < 1000; i++) { + name = bookmarkNameToken + i; + if (!chatNames.includes(name)) { + break; + } + } + } + if (!name) { + return null; + } + + return `${name} - ${humanizedDateTime()}`; +} + +function getMainChatName() { + if (chat_metadata) { + if (chat_metadata['main_chat']) { + return chat_metadata['main_chat']; + } + // groups didn't support bookmarks before chat metadata was introduced + else if (selected_group) { + return null; + } + else if (characters[this_chid].chat && characters[this_chid].chat.includes(bookmarkNameToken)) { + const tokenIndex = characters[this_chid].chat.lastIndexOf(bookmarkNameToken); + chat_metadata['main_chat'] = characters[this_chid].chat.substring(0, tokenIndex).trim(); + return chat_metadata['main_chat']; + } + } + return null; +} + +export function showBookmarksButtons() { + try { + if (selected_group) { + $('#option_convert_to_group').hide(); + } else { + $('#option_convert_to_group').show(); + } + + if (chat_metadata['main_chat']) { + // In bookmark chat + $('#option_back_to_main').show(); + $('#option_new_bookmark').show(); + } else if (!selected_group && !characters[this_chid].chat) { + // No chat recorded on character + $('#option_back_to_main').hide(); + $('#option_new_bookmark').hide(); + } else { + // In main chat + $('#option_back_to_main').hide(); + $('#option_new_bookmark').show(); + } + } + catch { + $('#option_back_to_main').hide(); + $('#option_new_bookmark').hide(); + $('#option_convert_to_group').hide(); + } +} + +async function saveBookmarkMenu() { + if (!chat.length) { + toastr.warning('The chat is empty.', 'Checkpoint creation failed'); + return; + } + + return await createNewBookmark(chat.length - 1); +} + +// Export is used by Timelines extension. Do not remove. +export async function createBranch(mesId) { + if (!chat.length) { + toastr.warning('The chat is empty.', 'Branch creation failed'); + return; + } + + if (mesId < 0 || mesId >= chat.length) { + toastr.warning('Invalid message ID.', 'Branch creation failed'); + return; + } + + const lastMes = chat[mesId]; + const mainChat = selected_group ? groups?.find(x => x.id == selected_group)?.chat_id : characters[this_chid].chat; + const newMetadata = { main_chat: mainChat }; + let name = `Branch #${mesId} - ${humanizedDateTime()}`; + + if (selected_group) { + await saveGroupBookmarkChat(selected_group, name, newMetadata, mesId); + } else { + await saveChat(name, newMetadata, mesId); + } + // append to branches list if it exists + // otherwise create it + if (typeof lastMes.extra !== 'object') { + lastMes.extra = {}; + } + if (typeof lastMes.extra['branches'] !== 'object') { + lastMes.extra['branches'] = []; + } + lastMes.extra['branches'].push(name); + return name; +} + +/** + * Creates a new bookmark for a message. + * + * @param {number} mesId - The ID of the message. + * @param {Object} [options={}] - Optional parameters. + * @param {string?} [options.forceName=null] - The name to force for the bookmark. + * @returns {Promise} - A promise that resolves to the bookmark name when the bookmark is created. + */ +export async function createNewBookmark(mesId, { forceName = null } = {}) { + if (this_chid === undefined && !selected_group) { + toastr.info('No character selected.', 'Create Checkpoint'); + return null; + } + if (!chat.length) { + toastr.warning('The chat is empty.', 'Create Checkpoint'); + return null; + } + if (!chat[mesId]) { + toastr.warning('Invalid message ID.', 'Create Checkpoint'); + return null; + } + + const lastMes = chat[mesId]; + + if (typeof lastMes.extra !== 'object') { + lastMes.extra = {}; + } + + const isReplace = lastMes.extra.bookmark_link; + + let name = await getBookmarkName({ isReplace: isReplace, forceName: forceName }); + if (!name) { + return null; + } + + const mainChat = selected_group ? groups?.find(x => x.id == selected_group)?.chat_id : characters[this_chid].chat; + const newMetadata = { main_chat: mainChat }; + await saveItemizedPrompts(name); + + if (selected_group) { + await saveGroupBookmarkChat(selected_group, name, newMetadata, mesId); + } else { + await saveChat(name, newMetadata, mesId); + } + + lastMes.extra['bookmark_link'] = name; + + const mes = $(`.mes[mesid="${mesId}"]`); + updateBookmarkDisplay(mes, name); + + await saveChatConditional(); + toastr.success('Click the flag icon next to the message to open the checkpoint chat.', 'Create Checkpoint', { timeOut: 10000 }); + return name; +} + + +/** + * Updates the display of the bookmark on a chat message. + * @param {JQuery} mes - The message element + * @param {string?} [newBookmarkLink=null] - The new bookmark link (optional) + */ +export function updateBookmarkDisplay(mes, newBookmarkLink = null) { + newBookmarkLink && mes.attr('bookmark_link', newBookmarkLink); + const bookmarkFlag = mes.find('.mes_bookmark'); + bookmarkFlag.attr('title', `Checkpoint\n${mes.attr('bookmark_link')}\n\n${bookmarkFlag.data('tooltip')}`); +} + +async function backToMainChat() { + const mainChatName = getMainChatName(); + const allChats = await getExistingChatNames(); + + if (allChats.includes(mainChatName)) { + if (selected_group) { + await openGroupChat(selected_group, mainChatName); + } else { + await openCharacterChat(mainChatName); + } + return mainChatName; + } + + return null; +} + +export async function convertSoloToGroupChat() { + if (selected_group) { + console.log('Already in group. No need for conversion'); + return; + } + + if (this_chid === undefined) { + console.log('Need to have a character selected'); + return; + } + + const confirm = await Popup.show.confirm(t`Convert to group chat`, t`Are you sure you want to convert this chat to a group chat?` + '
      ' + t`This cannot be reverted.`); + if (!confirm) { + return; + } + + const character = characters[this_chid]; + + // Populate group required fields + const name = getUniqueName(`Group: ${character.name}`, y => groups.findIndex(x => x.name === y) !== -1); + const avatar = getThumbnailUrl('avatar', character.avatar); + const chatName = humanizedDateTime(); + const chats = [chatName]; + const members = [character.avatar]; + const activationStrategy = group_activation_strategy.NATURAL; + const allowSelfResponses = false; + const favChecked = character.fav || character.fav == 'true'; + /** @type {any} */ + const metadata = Object.assign({}, chat_metadata); + delete metadata.main_chat; + + const createGroupResponse = await fetch('/api/groups/create', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + name: name, + members: members, + avatar_url: avatar, + allow_self_responses: activationStrategy, + activation_strategy: allowSelfResponses, + disabled_members: [], + chat_metadata: metadata, + fav: favChecked, + chat_id: chatName, + chats: chats, + }), + }); + + if (!createGroupResponse.ok) { + console.error('Group creation unsuccessful'); + return; + } + + const group = await createGroupResponse.json(); + + // Convert tags list and assign to group + createTagMapFromList('#tagList', group.id); + + // Update chars list + await getCharacters(); + + // Convert chat to group format + const groupChat = chat.slice(); + const genIdFirst = Date.now(); + + for (let index = 0; index < groupChat.length; index++) { + const message = groupChat[index]; + + // Save group-chat marker + if (index == 0) { + message.is_group = true; + } + + // Skip messages we don't care about + if (message.is_user || message.is_system || message.extra?.type === system_message_types.NARRATOR || message.force_avatar !== undefined) { + continue; + } + + // Set force fields for solo character + message.name = character.name; + message.original_avatar = character.avatar; + message.force_avatar = getThumbnailUrl('avatar', character.avatar); + + // Allow regens of a single message in group + if (typeof message.extra !== 'object') { + message.extra = { gen_id: genIdFirst + index }; + } + } + + // Save group chat + const createChatResponse = await fetch('/api/chats/group/save', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ id: chatName, chat: groupChat }), + }); + + if (!createChatResponse.ok) { + console.error('Group chat creation unsuccessful'); + toastr.error('Group chat creation unsuccessful'); + return; + } + + // Click on the freshly selected group to open it + await openGroupById(group.id); + + toastr.success('The chat has been successfully converted!'); +} + +/** + * Creates a new branch from the message with the given ID + * @param {number} mesId Message ID + * @returns {Promise} Branch file name + */ +export async function branchChat(mesId) { + if (this_chid === undefined && !selected_group) { + toastr.info('No character selected.', 'Create Branch'); + return null; + } + + const fileName = await createBranch(mesId); + await saveItemizedPrompts(fileName); + + if (selected_group) { + await openGroupChat(selected_group, fileName); + } else { + await openCharacterChat(fileName); + } + + return fileName; +} + +function registerBookmarksSlashCommands() { + /** + * Validates a message ID. (Is a number, exists as a message) + * + * @param {number} mesId - The message ID to validate. + * @param {string} context - The context of the slash command. Will be used as the title of any toasts. + * @returns {boolean} - Returns true if the message ID is valid, otherwise false. + */ + function validateMessageId(mesId, context) { + if (isNaN(mesId)) { + toastr.warning('Invalid message ID was provided', context); + return false; + } + if (!chat[mesId]) { + toastr.warning(`Message for id ${mesId} not found`, context); + return false; + } + return true; + } + + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'branch-create', + returns: 'Name of the new branch', + callback: async (args, text) => { + const mesId = Number(args.mesId ?? text ?? getLastMessageId()); + if (!validateMessageId(mesId, 'Create Branch')) return ''; + + const branchName = await branchChat(mesId); + return branchName ?? ''; + }, + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'Message ID', + typeList: [ARGUMENT_TYPE.NUMBER], + enumProvider: commonEnumProviders.messages(), + }), + ], + helpString: ` +
      + Create a new branch from the selected message. If no message id is provided, will use the last message. +
      +
      + Creating a branch will automatically choose a name for the branch.
      + After creating the branch, the branch chat will be automatically opened. +
      +
      + Use Checkpoints and /checkpoint-create instead if you do not want to jump to the new chat. +
      `, + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'checkpoint-create', + returns: 'Name of the new checkpoint', + callback: async (args, text) => { + const mesId = Number(args.mesId ?? getLastMessageId()); + if (!validateMessageId(mesId, 'Create Checkpoint')) return ''; + + if (typeof text !== 'string') { + toastr.warning('Checkpoint name must be a string or empty', 'Create Checkpoint'); + return ''; + } + + const checkPointName = await createNewBookmark(mesId, { forceName: text }); + return checkPointName ?? ''; + }, + namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'mesId', + description: 'Message ID', + typeList: [ARGUMENT_TYPE.NUMBER], + enumProvider: commonEnumProviders.messages(), + }), + ], + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'Checkpoint name', + typeList: [ARGUMENT_TYPE.STRING], + }), + ], + helpString: ` +
      + Create a new checkpoint for the selected message with the provided name. If no message id is provided, will use the last message.
      + Leave the checkpoint name empty to auto-generate one. +
      +
      + A created checkpoint will be permanently linked with the message.
      + If a checkpoint already exists, the link to it will be overwritten.
      + After creating the checkpoint, the checkpoint chat can be opened with the checkpoint flag, + using the /go command with the checkpoint name or the /checkpoint-go command on the message. +
      +
      + Use Branches and /branch-create instead if you do want to jump to the new chat. +
      +
      + Example: +
        +
      • +
        /checkpoint-create mes={{lastCharMessage}} Checkpoint for char reply | /setvar key=rememberCheckpoint {{pipe}}
        + Will create a new checkpoint to the latest message of the current character, and save it as a local variable for future use. +
      • +
      +
      `, + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'checkpoint-go', + returns: 'Name of the checkpoint', + callback: async (args, text) => { + const mesId = Number(args.mesId ?? text ?? getLastMessageId()); + if (!validateMessageId(mesId, 'Open Checkpoint')) return ''; + + const checkPointName = chat[mesId].extra?.bookmark_link; + if (!checkPointName) { + toastr.warning('No checkpoint is linked to the selected message', 'Open Checkpoint'); + return ''; + } + + if (selected_group) { + await openGroupChat(selected_group, checkPointName); + } else { + await openCharacterChat(checkPointName); + } + + return checkPointName; + }, + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'Message ID', + typeList: [ARGUMENT_TYPE.NUMBER], + enumProvider: commonEnumProviders.messages(), + }), + ], + helpString: ` +
      + Open the checkpoint linked to the selected message. If no message id is provided, will use the last message. +
      +
      + Use /checkpoint-get if you want to make sure that the selected message has a checkpoint. +
      `, + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'checkpoint-exit', + returns: 'The name of the chat exited to. Returns an empty string if not in a checkpoint chat.', + callback: async () => { + const mainChat = await backToMainChat(); + return mainChat ?? ''; + }, + helpString: 'Exit the checkpoint chat.
      If not in a checkpoint chat, returns empty string.', + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'checkpoint-parent', + returns: 'Name of the parent chat for this checkpoint', + callback: async () => { + const mainChatName = getMainChatName(); + return mainChatName ?? ''; + }, + helpString: 'Get the name of the parent chat for this checkpoint.
      If not in a checkpoint chat, returns empty string.', + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'checkpoint-get', + returns: 'Name of the chat', + callback: async (args, text) => { + const mesId = Number(args.mesId ?? text ?? getLastMessageId()); + if (!validateMessageId(mesId, 'Get Checkpoint')) return ''; + + const checkPointName = chat[mesId].extra?.bookmark_link; + return checkPointName ?? ''; + }, + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'Message ID', + typeList: [ARGUMENT_TYPE.NUMBER], + enumProvider: commonEnumProviders.messages(), + }), + ], + helpString: ` +
      + Get the name of the checkpoint linked to the selected message. If no message id is provided, will use the last message.
      + If no checkpoint is linked, the result will be empty. +
      `, + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'checkpoint-list', + returns: 'JSON array of all existing checkpoints in this chat, as an array', + /** @param {{links?: string}} args @returns {Promise} */ + callback: async (args, _) => { + const result = Object.entries(chat) + .filter(([_, message]) => message.extra?.bookmark_link) + .map(([mesId, message]) => isTrueBoolean(args.links) ? message.extra.bookmark_link : Number(mesId)); + return JSON.stringify(result); + }, + namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'links', + description: 'Get a list of all links / chat names of the checkpoints, instead of the message ids', + typeList: [ARGUMENT_TYPE.BOOLEAN], + enumList: commonEnumProviders.boolean('trueFalse')(), + defaultValue: 'false', + }), + ], + helpString: ` +
      + List all existing checkpoints in this chat. +
      +
      + Returns a list of all message ids that have a checkpoint, or all checkpoint links if links is set to true.
      + The value will be a JSON array. +
      `, + })); +} + +export function initBookmarks() { + $('#option_new_bookmark').on('click', saveBookmarkMenu); + $('#option_back_to_main').on('click', backToMainChat); + $('#option_convert_to_group').on('click', convertSoloToGroupChat); + + $(document).on('click', '.select_chat_block, .mes_bookmark', async function (e) { + // If shift is held down, we are not following the bookmark, but creating a new one + const mes = $(this).closest('.mes'); + if (e.shiftKey && mes.length) { + const selectedMesId = mes.attr('mesid'); + await createNewBookmark(Number(selectedMesId)); + return; + } + + const fileName = $(this).hasClass('mes_bookmark') + ? $(this).closest('.mes').attr('bookmark_link') + : $(this).attr('file_name').replace('.jsonl', ''); + + if (!fileName) { + return; + } + + try { + showLoader(); + if (selected_group) { + await openGroupChat(selected_group, fileName); + } else { + await openCharacterChat(fileName); + } + } finally { + await hideLoader(); + } + + $('#shadow_select_chat_popup').css('display', 'none'); + }); + + $(document).on('click', '.mes_create_bookmark', async function () { + const mesId = $(this).closest('.mes').attr('mesid'); + if (mesId !== undefined) { + await createNewBookmark(Number(mesId)); + } + }); + + $(document).on('click', '.mes_create_branch', async function () { + const mesId = $(this).closest('.mes').attr('mesid'); + if (mesId !== undefined) { + await branchChat(Number(mesId)); + } + }); + + registerBookmarksSlashCommands(); +} diff --git a/jiuguan2025cc/public/scripts/browser-fixes.js b/jiuguan2025cc/public/scripts/browser-fixes.js new file mode 100644 index 0000000000000000000000000000000000000000..01bb25d26e988793ad03283ee6bed782b5f6c774 --- /dev/null +++ b/jiuguan2025cc/public/scripts/browser-fixes.js @@ -0,0 +1,86 @@ +import { getParsedUA, isMobile } from './RossAscends-mods.js'; + +const isFirefox = () => /firefox/i.test(navigator.userAgent); + +function sanitizeInlineQuotationOnCopy() { + // STRG+C, STRG+V on firefox leads to duplicate double quotes when inline quotation elements are copied. + // To work around this, take the selection and transform to before calling toString(). + document.addEventListener('copy', function (event) { + if (document.activeElement instanceof HTMLInputElement || document.activeElement instanceof HTMLTextAreaElement) { + return; + } + + const selection = window.getSelection(); + if (!selection.anchorNode?.parentElement.closest('.mes_text')) { + return; + } + + const range = selection.getRangeAt(0).cloneContents(); + const tempDOM = document.createDocumentFragment(); + + /** + * Process a node, transforming elements to elements and preserving children. + * @param {Node} node Input node + * @returns {Node} Processed node + */ + function processNode(node) { + if (node.nodeType === Node.ELEMENT_NODE && node.nodeName.toLowerCase() === 'q') { + // Transform to , preserve children + const span = document.createElement('span'); + + [...node.childNodes].forEach(child => { + const processedChild = processNode(child); + span.appendChild(processedChild); + }); + + return span; + } else { + // Nested structures containing elements are unlikely + return node.cloneNode(true); + } + } + + [...range.childNodes].forEach(child => { + const processedChild = processNode(child); + tempDOM.appendChild(processedChild); + }); + + const newRange = document.createRange(); + newRange.selectNodeContents(tempDOM); + + event.preventDefault(); + event.clipboardData.setData('text/plain', newRange.toString()); + }); +} + +function addSafariPatch() { + const userAgent = getParsedUA(); + console.debug('User Agent', userAgent); + const isMobileSafari = /iPad|iPhone|iPod/.test(navigator.platform) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1); + const isDesktopSafari = userAgent?.browser?.name === 'Safari' && userAgent?.platform?.type === 'desktop'; + const isIOS = userAgent?.os?.name === 'iOS'; + + if (isIOS || isMobileSafari || isDesktopSafari) { + document.body.classList.add('safari'); + } +} + +function applyBrowserFixes() { + if (isFirefox()) { + sanitizeInlineQuotationOnCopy(); + } + + if (isMobile()) { + const fixFunkyPositioning = () => { + console.debug('[Mobile] Device viewport change detected.'); + document.documentElement.style.position = 'fixed'; + requestAnimationFrame(() => document.documentElement.style.position = ''); + }; + window.addEventListener('resize', fixFunkyPositioning); + window.addEventListener('orientationchange', fixFunkyPositioning); + } + + addSafariPatch(); +} + +export { isFirefox, applyBrowserFixes }; diff --git a/jiuguan2025cc/public/scripts/bulk-edit.js b/jiuguan2025cc/public/scripts/bulk-edit.js new file mode 100644 index 0000000000000000000000000000000000000000..8159a9662b56f18ca95ac3704141ca63a01e74f7 --- /dev/null +++ b/jiuguan2025cc/public/scripts/bulk-edit.js @@ -0,0 +1,124 @@ +import { characterGroupOverlay } from '../script.js'; +import { BulkEditOverlay, BulkEditOverlayState } from './BulkEditOverlay.js'; + + +let is_bulk_edit = false; + +const enableBulkEdit = () => { + enableBulkSelect(); + characterGroupOverlay.selectState(); + // show the bulk edit option buttons + $('.bulkEditOptionElement').show(); + is_bulk_edit = true; + characterGroupOverlay.updateSelectedCount(0); +}; + +const disableBulkEdit = () => { + disableBulkSelect(); + characterGroupOverlay.browseState(); + // hide the bulk edit option buttons + $('.bulkEditOptionElement').hide(); + is_bulk_edit = false; + characterGroupOverlay.updateSelectedCount(0); +}; + +const toggleBulkEditMode = (isBulkEdit) => { + if (isBulkEdit) { + disableBulkEdit(); + } else { + enableBulkEdit(); + } +}; + +/** + * Toggles bulk edit mode on/off when the edit button is clicked. + */ +function onEditButtonClick() { + console.log('Edit button clicked'); + toggleBulkEditMode(is_bulk_edit); +} + +/** + * Toggles the select state of all characters in bulk edit mode to selected. If all are selected, they'll be deselected. + */ +function onSelectAllButtonClick() { + console.log('Bulk select all button clicked'); + const characters = Array.from(document.querySelectorAll('#' + BulkEditOverlay.containerId + ' .' + BulkEditOverlay.characterClass)); + let atLeastOneSelected = false; + for (const character of characters) { + const checked = $(character).find('.bulk_select_checkbox:checked').length > 0; + if (!checked && character instanceof HTMLElement) { + characterGroupOverlay.toggleSingleCharacter(character); + atLeastOneSelected = true; + } + } + + if (!atLeastOneSelected) { + // If none was selected, trigger click on all to deselect all of them + for(const character of characters) { + const checked = $(character).find('.bulk_select_checkbox:checked') ?? false; + if (checked && character instanceof HTMLElement) { + characterGroupOverlay.toggleSingleCharacter(character); + } + } + } +} + +/** + * Deletes all characters that have been selected via the bulk checkboxes. + */ +async function onDeleteButtonClick() { + console.log('Delete button clicked'); + + // We just let the button trigger the context menu delete option + await characterGroupOverlay.handleContextMenuDelete(); +} + +/** + * Enables bulk selection by adding a checkbox next to each character. + */ +function enableBulkSelect() { + $('#rm_print_characters_block .character_select').each((i, el) => { + // Prevent checkbox from adding multiple times (because of stage change callback) + if ($(el).find('.bulk_select_checkbox').length > 0) { + return; + } + const checkbox = $(''); + checkbox.on('change', () => { + // Do something when the checkbox is changed + }); + $(el).prepend(checkbox); + }); + $('#rm_print_characters_block.group_overlay_mode_select .bogus_folder_select, #rm_print_characters_block.group_overlay_mode_select .group_select') + .addClass('disabled'); + + $('#rm_print_characters_block').addClass('bulk_select'); + // We also need to disable the default click event for the character_select divs + $(document).on('click', '.bulk_select_checkbox', function (event) { + event.stopImmediatePropagation(); + }); +} + +/** + * Disables bulk selection by removing the checkboxes. + */ +function disableBulkSelect() { + $('.bulk_select_checkbox').remove(); + $('#rm_print_characters_block.group_overlay_mode_select .bogus_folder_select, #rm_print_characters_block.group_overlay_mode_select .group_select') + .removeClass('disabled'); + $('#rm_print_characters_block').removeClass('bulk_select'); +} + +/** + * Entry point that runs on page load. + */ +export function initBulkEdit() { + characterGroupOverlay.addStateChangeCallback((state) => { + if (state === BulkEditOverlayState.select) enableBulkEdit(); + if (state === BulkEditOverlayState.browse) disableBulkEdit(); + }); + + $('#bulkEditButton').on('click', onEditButtonClick); + $('#bulkSelectAllButton').on('click', onSelectAllButtonClick); + $('#bulkDeleteButton').on('click', onDeleteButtonClick); +} diff --git a/jiuguan2025cc/public/scripts/cfg-scale.js b/jiuguan2025cc/public/scripts/cfg-scale.js new file mode 100644 index 0000000000000000000000000000000000000000..ff15d4f8c187675d435472007fde10e9dcbc7123 --- /dev/null +++ b/jiuguan2025cc/public/scripts/cfg-scale.js @@ -0,0 +1,498 @@ +import { + chat_metadata, + substituteParams, + this_chid, + eventSource, + event_types, + saveSettingsDebounced, + animation_duration, +} from '../script.js'; +import { extension_settings, saveMetadataDebounced } from './extensions.js'; +import { selected_group } from './group-chats.js'; +import { getCharaFilename, delay } from './utils.js'; +import { power_user } from './power-user.js'; + +const extensionName = 'cfg'; +const defaultSettings = { + global: { + 'guidance_scale': 1, + 'negative_prompt': '', + }, + chara: [], +}; +const settingType = { + guidance_scale: 0, + negative_prompt: 1, + positive_prompt: 2, +}; + +// Used for character and chat CFG values +function updateSettings() { + saveSettingsDebounced(); + loadSettings(); +} + +function setCharCfg(tempValue, setting) { + const avatarName = getCharaFilename(); + + // Assign temp object + let tempCharaCfg = { + name: avatarName, + }; + + switch (setting) { + case settingType.guidance_scale: + tempCharaCfg['guidance_scale'] = Number(tempValue); + break; + case settingType.negative_prompt: + tempCharaCfg['negative_prompt'] = tempValue; + break; + case settingType.positive_prompt: + tempCharaCfg['positive_prompt'] = tempValue; + break; + default: + return false; + } + + let existingCharaCfgIndex; + let existingCharaCfg; + + if (extension_settings.cfg.chara) { + existingCharaCfgIndex = extension_settings.cfg.chara.findIndex((e) => e.name === avatarName); + existingCharaCfg = extension_settings.cfg.chara[existingCharaCfgIndex]; + } + + if (extension_settings.cfg.chara && existingCharaCfg) { + const tempAssign = Object.assign(existingCharaCfg, tempCharaCfg); + + // If both values are default, remove the entry + if (!existingCharaCfg.useChara && + (tempAssign.guidance_scale ?? 1.00) === 1.00 && + (tempAssign.negative_prompt?.length ?? 0) === 0 && + (tempAssign.positive_prompt?.length ?? 0) === 0) { + extension_settings.cfg.chara.splice(existingCharaCfgIndex, 1); + } + } else if (avatarName && tempValue.length > 0) { + if (!extension_settings.cfg.chara) { + extension_settings.cfg.chara = []; + } + + extension_settings.cfg.chara.push(tempCharaCfg); + } else { + console.debug('Character CFG error: No avatar name key could be found.'); + + // Don't save settings if something went wrong + return false; + } + + updateSettings(); + + return true; +} + +function setChatCfg(tempValue, setting) { + switch (setting) { + case settingType.guidance_scale: + chat_metadata[metadataKeys.guidance_scale] = tempValue; + break; + case settingType.negative_prompt: + chat_metadata[metadataKeys.negative_prompt] = tempValue; + break; + case settingType.positive_prompt: + chat_metadata[metadataKeys.positive_prompt] = tempValue; + break; + default: + return false; + } + + saveMetadataDebounced(); + + return true; +} + +// TODO: Only change CFG when character is selected +function onCfgMenuItemClick() { + if (!selected_group && this_chid === undefined) { + toastr.warning('Select a character before trying to configure CFG', '', { timeOut: 2000 }); + return; + } + + //show CFG config if it's hidden + if ($('#cfgConfig').css('display') !== 'flex') { + $('#cfgConfig').addClass('resizing'); + $('#cfgConfig').css('display', 'flex'); + $('#cfgConfig').css('opacity', 0.0); + $('#cfgConfig').transition({ + opacity: 1.0, + duration: animation_duration, + }, async function () { + await delay(50); + $('#cfgConfig').removeClass('resizing'); + }); + + //auto-open the main AN inline drawer + if ($('#CFGBlockToggle') + .siblings('.inline-drawer-content') + .css('display') !== 'block') { + $('#floatingPrompt').addClass('resizing'); + $('#CFGBlockToggle').click(); + } + } else { + //hide AN if it's already displayed + $('#cfgConfig').addClass('resizing'); + $('#cfgConfig').transition({ + opacity: 0.0, + duration: animation_duration, + }, async function () { + await delay(50); + $('#cfgConfig').removeClass('resizing'); + }); + setTimeout(function () { + $('#cfgConfig').hide(); + }, animation_duration); + + } + //duplicate options menu close handler from script.js + //because this listener takes priority + $('#options').stop().fadeOut(animation_duration); +} + +async function onChatChanged() { + loadSettings(); + await modifyCharaHtml(); +} + +// Rearrange the panel if a group chat is present +async function modifyCharaHtml() { + if (selected_group) { + $('#chara_cfg_container').hide(); + $('#groupchat_cfg_use_chara_container').show(); + } else { + $('#chara_cfg_container').show(); + $('#groupchat_cfg_use_chara_container').hide(); + // TODO: Remove chat checkbox here + } +} + +// Reloads chat-specific settings +function loadSettings() { + // Set chat CFG if it exists + $('#chat_cfg_guidance_scale').val(chat_metadata[metadataKeys.guidance_scale] ?? 1.0.toFixed(2)); + $('#chat_cfg_guidance_scale_counter').val(chat_metadata[metadataKeys.guidance_scale]?.toFixed(2) ?? 1.0.toFixed(2)); + $('#chat_cfg_negative_prompt').val(chat_metadata[metadataKeys.negative_prompt] ?? ''); + $('#chat_cfg_positive_prompt').val(chat_metadata[metadataKeys.positive_prompt] ?? ''); + $('#groupchat_cfg_use_chara').prop('checked', chat_metadata[metadataKeys.groupchat_individual_chars] ?? false); + if (chat_metadata[metadataKeys.prompt_combine]?.length > 0) { + chat_metadata[metadataKeys.prompt_combine].forEach((element) => { + $(`input[name="cfg_prompt_combine"][value="${element}"]`) + .prop('checked', true); + }); + } + + // Display the negative separator in quotes if not quoted already + let promptSeparatorDisplay = []; + const promptSeparator = chat_metadata[metadataKeys.prompt_separator]; + if (promptSeparator) { + promptSeparatorDisplay.push(promptSeparator); + if (!promptSeparator.startsWith('"')) { + promptSeparatorDisplay.unshift('"'); + } + + if (!promptSeparator.endsWith('"')) { + promptSeparatorDisplay.push('"'); + } + } + + $('#cfg_prompt_separator').val(promptSeparatorDisplay.length === 0 ? '' : promptSeparatorDisplay.join('')); + + $('#cfg_prompt_insertion_depth').val(chat_metadata[metadataKeys.prompt_insertion_depth] ?? 1); + + // Set character CFG if it exists + if (!selected_group) { + const charaCfg = extension_settings.cfg.chara.find((e) => e.name === getCharaFilename()); + $('#chara_cfg_guidance_scale').val(charaCfg?.guidance_scale ?? 1.00); + $('#chara_cfg_guidance_scale_counter').val(charaCfg?.guidance_scale?.toFixed(2) ?? 1.0.toFixed(2)); + $('#chara_cfg_negative_prompt').val(charaCfg?.negative_prompt ?? ''); + $('#chara_cfg_positive_prompt').val(charaCfg?.positive_prompt ?? ''); + } +} + +// Load initial extension settings +async function initialLoadSettings() { + // Create the settings if they don't exist + extension_settings[extensionName] = extension_settings[extensionName] || {}; + if (Object.keys(extension_settings[extensionName]).length === 0) { + Object.assign(extension_settings[extensionName], defaultSettings); + saveSettingsDebounced(); + } + + // Set global CFG values on load + $('#global_cfg_guidance_scale').val(extension_settings.cfg.global.guidance_scale); + $('#global_cfg_guidance_scale_counter').val(extension_settings.cfg.global.guidance_scale.toFixed(2)); + $('#global_cfg_negative_prompt').val(extension_settings.cfg.global.negative_prompt); + $('#global_cfg_positive_prompt').val(extension_settings.cfg.global.positive_prompt); +} + +function migrateSettings() { + let performSettingsSave = false; + let performMetaSave = false; + + if (power_user.guidance_scale) { + extension_settings.cfg.global.guidance_scale = power_user.guidance_scale; + delete power_user['guidance_scale']; + performSettingsSave = true; + } + + if (power_user.negative_prompt) { + extension_settings.cfg.global.negative_prompt = power_user.negative_prompt; + delete power_user['negative_prompt']; + performSettingsSave = true; + } + + if (chat_metadata['cfg_negative_combine']) { + chat_metadata[metadataKeys.prompt_combine] = chat_metadata['cfg_negative_combine']; + chat_metadata['cfg_negative_combine'] = undefined; + performMetaSave = true; + } + + if (chat_metadata['cfg_negative_insertion_depth']) { + chat_metadata[metadataKeys.prompt_insertion_depth] = chat_metadata['cfg_negative_insertion_depth']; + chat_metadata['cfg_negative_insertion_depth'] = undefined; + performMetaSave = true; + } + + if (chat_metadata['cfg_negative_separator']) { + chat_metadata[metadataKeys.prompt_separator] = chat_metadata['cfg_negative_separator']; + chat_metadata['cfg_negative_separator'] = undefined; + performMetaSave = true; + } + + if (performSettingsSave) { + saveSettingsDebounced(); + } + + if (performMetaSave) { + saveMetadataDebounced(); + } +} + +// This function is called when the extension is loaded +export function initCfg() { + $('#CFGClose').on('click', function () { + $('#cfgConfig').transition({ + opacity: 0, + duration: animation_duration, + easing: 'ease-in-out', + }); + setTimeout(function () { $('#cfgConfig').hide(); }, animation_duration); + }); + + $('#chat_cfg_guidance_scale').on('input', function () { + const numberValue = Number($(this).val()); + const success = setChatCfg(numberValue, settingType.guidance_scale); + if (success) { + $('#chat_cfg_guidance_scale_counter').val(numberValue.toFixed(2)); + } + }); + + $('#chat_cfg_negative_prompt').on('input', function () { + setChatCfg($(this).val(), settingType.negative_prompt); + }); + + $('#chat_cfg_positive_prompt').on('input', function () { + setChatCfg($(this).val(), settingType.positive_prompt); + }); + + $('#chara_cfg_guidance_scale').on('input', function () { + const value = $(this).val(); + const success = setCharCfg(value, settingType.guidance_scale); + if (success) { + $('#chara_cfg_guidance_scale_counter').val(Number(value).toFixed(2)); + } + }); + + $('#chara_cfg_negative_prompt').on('input', function () { + setCharCfg($(this).val(), settingType.negative_prompt); + }); + + $('#chara_cfg_positive_prompt').on('input', function () { + setCharCfg($(this).val(), settingType.positive_prompt); + }); + + $('#global_cfg_guidance_scale').on('input', function () { + extension_settings.cfg.global.guidance_scale = Number($(this).val()); + $('#global_cfg_guidance_scale_counter').val(extension_settings.cfg.global.guidance_scale.toFixed(2)); + saveSettingsDebounced(); + }); + + $('#global_cfg_negative_prompt').on('input', function () { + extension_settings.cfg.global.negative_prompt = $(this).val(); + saveSettingsDebounced(); + }); + + $('#global_cfg_positive_prompt').on('input', function () { + extension_settings.cfg.global.positive_prompt = $(this).val(); + saveSettingsDebounced(); + }); + + $('input[name="cfg_prompt_combine"]').on('input', function () { + const values = $('#cfgConfig').find('input[name="cfg_prompt_combine"]') + .filter(':checked') + .map(function () { return Number($(this).val()); }) + .get() + .filter((e) => !Number.isNaN(e)) || []; + + chat_metadata[metadataKeys.prompt_combine] = values; + saveMetadataDebounced(); + }); + + $('#cfg_prompt_insertion_depth').on('input', function () { + chat_metadata[metadataKeys.prompt_insertion_depth] = Number($(this).val()); + saveMetadataDebounced(); + }); + + $('#cfg_prompt_separator').on('input', function () { + chat_metadata[metadataKeys.prompt_separator] = $(this).val(); + saveMetadataDebounced(); + }); + + $('#groupchat_cfg_use_chara').on('input', function () { + const checked = !!$(this).prop('checked'); + chat_metadata[metadataKeys.groupchat_individual_chars] = checked; + + if (checked) { + toastr.info('You can edit character CFG values in their respective character chats.'); + } + + saveMetadataDebounced(); + }); + + initialLoadSettings(); + + if (extension_settings.cfg) { + migrateSettings(); + } + + $('#option_toggle_CFG').on('click', onCfgMenuItemClick); + + // Hook events + eventSource.on(event_types.CHAT_CHANGED, async () => { + await onChatChanged(); + }); +} + +export const cfgType = { + chat: 0, + chara: 1, + global: 2, +}; + +export const metadataKeys = { + guidance_scale: 'cfg_guidance_scale', + negative_prompt: 'cfg_negative_prompt', + positive_prompt: 'cfg_positive_prompt', + prompt_combine: 'cfg_prompt_combine', + groupchat_individual_chars: 'cfg_groupchat_individual_chars', + prompt_insertion_depth: 'cfg_prompt_insertion_depth', + prompt_separator: 'cfg_prompt_separator', +}; + +// Gets the CFG guidance scale +// If the guidance scale is 1, ignore the CFG prompt(s) since it won't be used anyways +export function getGuidanceScale() { + if (!extension_settings.cfg) { + console.warn('CFG extension is not enabled. Skipping CFG guidance.'); + return; + } + + const charaCfg = extension_settings.cfg.chara?.find((e) => e.name === getCharaFilename(this_chid)); + const chatGuidanceScale = chat_metadata[metadataKeys.guidance_scale]; + const groupchatCharOverride = chat_metadata[metadataKeys.groupchat_individual_chars] ?? false; + + if (chatGuidanceScale && chatGuidanceScale !== 1 && !groupchatCharOverride) { + return { + type: cfgType.chat, + value: chatGuidanceScale, + }; + } + + if ((!selected_group && charaCfg || groupchatCharOverride) && charaCfg?.guidance_scale !== 1) { + return { + type: cfgType.chara, + value: charaCfg.guidance_scale, + }; + } + + if (extension_settings.cfg.global && extension_settings.cfg.global?.guidance_scale !== 1) { + return { + type: cfgType.global, + value: extension_settings.cfg.global.guidance_scale, + }; + } +} + +/** + * Gets the CFG prompt separator. + * @returns {string} The CFG prompt separator + */ +function getCustomSeparator() { + const defaultSeparator = '\n'; + + try { + if (chat_metadata[metadataKeys.prompt_separator]) { + return JSON.parse(chat_metadata[metadataKeys.prompt_separator]); + } + + return defaultSeparator; + } catch { + console.warn('Invalid JSON detected for prompt separator. Using default separator.'); + return defaultSeparator; + } +} + +/** + * Gets the CFG prompt based on the guidance scale. + * @param {{type: number, value: number}} guidanceScale The CFG guidance scale + * @param {boolean} isNegative Whether to get the negative prompt + * @param {boolean} quiet Whether to suppress console output + * @returns {{value: string, depth: number}} The CFG prompt and insertion depth + */ +export function getCfgPrompt(guidanceScale, isNegative, quiet = false) { + let splitCfgPrompt = []; + + const cfgPromptCombine = chat_metadata[metadataKeys.prompt_combine] ?? []; + if (guidanceScale.type === cfgType.chat || cfgPromptCombine.includes(cfgType.chat)) { + splitCfgPrompt.unshift( + substituteParams( + chat_metadata[isNegative ? metadataKeys.negative_prompt : metadataKeys.positive_prompt], + ), + ); + } + + const charaCfg = extension_settings.cfg.chara?.find((e) => e.name === getCharaFilename(this_chid)); + if (guidanceScale.type === cfgType.chara || cfgPromptCombine.includes(cfgType.chara)) { + splitCfgPrompt.unshift( + substituteParams( + isNegative ? charaCfg.negative_prompt : charaCfg.positive_prompt, + ), + ); + } + + if (guidanceScale.type === cfgType.global || cfgPromptCombine.includes(cfgType.global)) { + splitCfgPrompt.unshift( + substituteParams( + isNegative ? extension_settings.cfg.global.negative_prompt : extension_settings.cfg.global.positive_prompt, + ), + ); + } + + const customSeparator = getCustomSeparator(); + const combinedCfgPrompt = splitCfgPrompt.filter((e) => e.length > 0).join(customSeparator); + const insertionDepth = chat_metadata[metadataKeys.prompt_insertion_depth] ?? 1; + !quiet && console.log(`Setting CFG with guidance scale: ${guidanceScale.value}, negatives: ${combinedCfgPrompt}`); + + return { + value: combinedCfgPrompt, + depth: insertionDepth, + }; +} diff --git a/jiuguan2025cc/public/scripts/char-data.js b/jiuguan2025cc/public/scripts/char-data.js new file mode 100644 index 0000000000000000000000000000000000000000..51e85722ca9d4d998aab4ec97e582d9aece231c1 --- /dev/null +++ b/jiuguan2025cc/public/scripts/char-data.js @@ -0,0 +1,118 @@ +/** + * @typedef {object} v2DataWorldInfoEntry + * @property {string[]} keys - An array of primary keys associated with the entry. + * @property {string[]} secondary_keys - An array of secondary keys associated with the entry (optional). + * @property {string} comment - A human-readable description or explanation for the entry. + * @property {string} content - The main content or data associated with the entry. + * @property {boolean} constant - Indicates if the entry's content is fixed and unchangeable. + * @property {boolean} selective - Indicates if the entry's inclusion is controlled by specific conditions. + * @property {number} insertion_order - Defines the order in which the entry is inserted during processing. + * @property {boolean} enabled - Controls whether the entry is currently active and used. + * @property {string} position - Specifies the location or context where the entry applies. + * @property {v2DataWorldInfoEntryExtensionInfos} extensions - An object containing additional details for extensions associated with the entry. + * @property {number} id - A unique identifier assigned to the entry. + */ +/** + * @typedef {object} v2DataWorldInfoEntryExtensionInfos + * @property {number} position - The order in which the extension is applied relative to other extensions. + * @property {boolean} exclude_recursion - Prevents the extension from being applied recursively. + * @property {number} probability - The chance (between 0 and 1) of the extension being applied. + * @property {boolean} useProbability - Determines if the `probability` property is used. + * @property {number} depth - The maximum level of nesting allowed for recursive application of the extension. + * @property {number} selectiveLogic - Defines the logic used to determine if the extension is applied selectively. + * @property {string} group - A category or grouping for the extension. + * @property {boolean} group_override - Overrides any existing group assignment for the extension. + * @property {number} group_weight - A value used for prioritizing extensions within the same group. + * @property {boolean} prevent_recursion - Completely disallows recursive application of the extension. + * @property {boolean} delay_until_recursion - Will only be checked during recursion. + * @property {number} scan_depth - The maximum depth to search for matches when applying the extension. + * @property {boolean} match_whole_words - Specifies if only entire words should be matched during extension application. + * @property {boolean} use_group_scoring - Indicates if group weight is considered when selecting extensions. + * @property {boolean} case_sensitive - Controls whether case sensitivity is applied during matching for the extension. + * @property {string} automation_id - An identifier used for automation purposes related to the extension. + * @property {number} role - The specific function or purpose of the extension. + * @property {boolean} vectorized - Indicates if the extension is optimized for vectorized processing. + * @property {number} display_index - The order in which the extension should be displayed for user interfaces. + */ + +/** + * @typedef {object} v2WorldInfoBook + * @property {string} name - the name of the book + * @property {v2DataWorldInfoEntry[]} entries - the entries of the book + */ + +/** + * @typedef {object} v2CharData + * @property {string} name - The character's name. + * @property {string} description - A brief description of the character. + * @property {string} character_version - The character's data version. + * @property {string} personality - A short summary of the character's personality traits. + * @property {string} scenario - A description of the character's background or setting. + * @property {string} first_mes - The character's opening message in a conversation. + * @property {string} mes_example - An example message demonstrating the character's conversation style. + * @property {string} creator_notes - Internal notes or comments left by the character's creator. + * @property {string[]} tags - A list of keywords or labels associated with the character. + * @property {string} system_prompt - The system prompt used to interact with the character. + * @property {string} post_history_instructions - Instructions for handling the character's conversation history. + * @property {string} creator - The name of the person who created the character. + * @property {string[]} alternate_greetings - Additional greeting messages the character can use. + * @property {v2WorldInfoBook} character_book - Data about the character's world or story (if applicable). + * @property {v2CharDataExtensionInfos} extensions - Additional details specific to the character. + */ +/** + * @typedef {object} v2CharDataExtensionInfos + * @property {number} talkativeness - A numerical value indicating the character's propensity to talk. + * @property {boolean} fav - A flag indicating whether the character is a favorite. + * @property {string} world - The fictional world or setting where the character exists (if applicable). + * @property {object} depth_prompt - Prompts used to explore the character's depth and complexity. + * @property {number} depth_prompt.depth - The level of detail or nuance targeted by the prompt. + * @property {string} depth_prompt.prompt - The actual prompt text used for deeper character interaction. + * @property {"system" | "user" | "assistant"} depth_prompt.role - The role the character takes on during the prompted interaction (system, user, or assistant). + * @property {RegexScriptData[]} regex_scripts - Custom regex scripts for the character. + * // Non-standard extensions added by external tools + * @property {string} [pygmalion_id] - The unique identifier assigned to the character by the Pygmalion.chat. + * @property {string} [github_repo] - The gitHub repository associated with the character. + * @property {string} [source_url] - The source URL associated with the character. + * @property {{full_path: string}} [chub] - The Chub-specific data associated with the character. + * @property {{source: string[]}} [risuai] - The RisuAI-specific data associated with the character. + * @property {{positive: string, negative: string}} [sd_character_prompt] - SD-specific data associated with the character. + */ + +/** +* @typedef {object} RegexScriptData +* @property {string} id - UUID of the script +* @property {string} scriptName - The name of the script +* @property {string} findRegex - The regex to find +* @property {string} replaceString - The string to replace +* @property {string[]} trimStrings - The strings to trim +* @property {number[]} placement - The placement of the script +* @property {boolean} disabled - Whether the script is disabled +* @property {boolean} markdownOnly - Whether the script only applies to Markdown +* @property {boolean} promptOnly - Whether the script only applies to prompts +* @property {boolean} runOnEdit - Whether the script runs on edit +* @property {number} substituteRegex - Whether the regex should be substituted +* @property {number} minDepth - The minimum depth +* @property {number} maxDepth - The maximum depth +*/ + +/** + * @typedef {object} v1CharData + * @property {string} name - the name of the character + * @property {string} description - the description of the character + * @property {string} personality - a short personality description of the character + * @property {string} scenario - a scenario description of the character + * @property {string} first_mes - the first message in the conversation + * @property {string} mes_example - the example message in the conversation + * @property {string} creatorcomment - creator's notes of the character + * @property {string[]} tags - the tags of the character + * @property {number} talkativeness - talkativeness + * @property {boolean|string} fav - fav + * @property {string} create_date - create_date + * @property {v2CharData} data - v2 data extension + * // Non-standard extensions added by the ST server (not part of the original data) + * @property {string} chat - name of the current chat file chat + * @property {string} avatar - file name of the avatar image (acts as a unique identifier) + * @property {string} json_data - the full raw JSON data of the character + * @property {boolean?} shallow - if the data is shallow (lazy-loaded) + */ +export default 0;// now this file is a module diff --git a/jiuguan2025cc/public/scripts/chat-templates.js b/jiuguan2025cc/public/scripts/chat-templates.js new file mode 100644 index 0000000000000000000000000000000000000000..5c3ad7cf1e5adbb01901afdaeff2d98fc6c40691 --- /dev/null +++ b/jiuguan2025cc/public/scripts/chat-templates.js @@ -0,0 +1,107 @@ +// the hash can be obtained from command line e.g. via: MODEL=path_to_model; python -c "import json, hashlib, sys; print(hashlib.sha256(json.load(open('"$MODEL"/tokenizer_config.json'))['chat_template'].encode()).hexdigest())" +// note that chat templates must be trimmed to match the llama.cpp metadata value +const hash_derivations = { + // Meta + 'e10ca381b1ccc5cf9db52e371f3b6651576caee0a630b452e2816b2d404d4b65': + // Meta-Llama-3.1-8B-Instruct + // Meta-Llama-3.1-70B-Instruct + 'Llama 3 Instruct' + , + '5816fce10444e03c2e9ee1ef8a4a1ea61ae7e69e438613f3b17b69d0426223a4': + // Llama-3.2-1B-Instruct + // Llama-3.2-3B-Instruct + 'Llama 3 Instruct' + , + '73e87b1667d87ab7d7b579107f01151b29ce7f3ccdd1018fdc397e78be76219d': + // Nemotron 70B + 'Llama 3 Instruct' + , + + // Mistral + // Mistral Reference: https://github.com/mistralai/mistral-common + 'e16746b40344d6c5b5265988e0328a0bf7277be86f1c335156eae07e29c82826': + // Mistral-Small-Instruct-2409 + // Mistral-Large-Instruct-2407 + 'Mistral V2 & V3' + , + '3c4ad5fa60dd8c7ccdf82fa4225864c903e107728fcaf859fa6052cb80c92ee9': + // Mistral-Large-Instruct-2411 + 'Mistral V7' // https://huggingface.co./mistralai/Mistral-Large-Instruct-2411 + , + 'e4676cb56dffea7782fd3e2b577cfaf1e123537e6ef49b3ec7caa6c095c62272': + // Mistral-Nemo-Instruct-2407 + 'Mistral V3-Tekken' + , + '26a59556925c987317ce5291811ba3b7f32ec4c647c400c6cc7e3a9993007ba7': + // Mistral-7B-Instruct-v0.3 + 'Mistral V2 & V3' + , + + // Gemma + 'ecd6ae513fe103f0eb62e8ab5bfa8d0fe45c1074fa398b089c93a7e70c15cfd6': + // gemma-2-9b-it + // gemma-2-27b-it + 'Gemma 2' + , + '87fa45af6cdc3d6a9e4dd34a0a6848eceaa73a35dcfe976bd2946a5822a38bf3': + // gemma-2-2b-it + 'Gemma 2' + , + '7de1c58e208eda46e9c7f86397df37ec49883aeece39fb961e0a6b24088dd3c4': + // gemma-3 + 'Gemma 2' + , + + // Cohere + '3b54f5c219ae1caa5c0bb2cdc7c001863ca6807cf888e4240e8739fa7eb9e02e': + // command-r-08-2024 + 'Command R' + , + + // Tulu + 'ac7498a36a719da630e99d48e6ebc4409de85a77556c2b6159eeb735bcbd11df': + // Tulu-3-8B + // Tulu-3-70B + 'Tulu' + , + + // DeepSeek V2.5 + '54d400beedcd17f464e10063e0577f6f798fa896266a912d8a366f8a2fcc0bca': + 'DeepSeek-V2.5' + , + + // DeepSeek R1 + 'b6835114b7303ddd78919a82e4d9f7d8c26ed0d7dfc36beeb12d524f6144eab1': + 'DeepSeek-V2.5' + , +}; + +const substr_derivations = { + '<|im_start|>': 'ChatML', // qwen2.5, ... +}; + +const parse_derivation = derivation => (typeof derivation === 'string') ? { + 'context': derivation, + 'instruct': derivation, +} : derivation; + +export async function deriveTemplatesFromChatTemplate(chat_template, hash) { + if (chat_template.trim() === '') { + console.log('Missing chat template.'); + return null; + } + + if (hash in hash_derivations) { + return parse_derivation(hash_derivations[hash]); + } + + // heuristics + for (const [substr, derivation] of Object.entries(substr_derivations) ) { + if (chat_template.includes(substr)) { + return parse_derivation(derivation); + } + } + + console.warn(`Unknown chat template hash: ${hash} for [${chat_template}]`); + return null; +} diff --git a/jiuguan2025cc/public/scripts/chats.js b/jiuguan2025cc/public/scripts/chats.js new file mode 100644 index 0000000000000000000000000000000000000000..a6094b7f72f1943244e6792106bb5fa38fe6a9f9 --- /dev/null +++ b/jiuguan2025cc/public/scripts/chats.js @@ -0,0 +1,1639 @@ +// Move chat functions here from script.js (eventually) + +import { Popper, css } from '../lib.js'; +import { + addCopyToCodeBlocks, + appendMediaToMessage, + characters, + chat, + eventSource, + event_types, + getCurrentChatId, + getRequestHeaders, + hideSwipeButtons, + name1, + name2, + reloadCurrentChat, + saveChatDebounced, + saveSettingsDebounced, + showSwipeButtons, + this_chid, + saveChatConditional, + chat_metadata, + neutralCharacterName, + updateChatMetadata, + system_message_types, +} from '../script.js'; +import { selected_group } from './group-chats.js'; +import { power_user } from './power-user.js'; +import { + extractTextFromHTML, + extractTextFromMarkdown, + extractTextFromPDF, + extractTextFromEpub, + getBase64Async, + getStringHash, + humanFileSize, + saveBase64AsFile, + extractTextFromOffice, + download, +} from './utils.js'; +import { extension_settings, renderExtensionTemplateAsync, saveMetadataDebounced } from './extensions.js'; +import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js'; +import { ScraperManager } from './scrapers.js'; +import { DragAndDropHandler } from './dragdrop.js'; +import { renderTemplateAsync } from './templates.js'; +import { t } from './i18n.js'; +import { humanizedDateTime } from './RossAscends-mods.js'; +import { accountStorage } from './util/AccountStorage.js'; + +/** + * @typedef {Object} FileAttachment + * @property {string} url File URL + * @property {number} size File size + * @property {string} name File name + * @property {number} created Timestamp + * @property {string} [text] File text + */ + +/** + * @typedef {function} ConverterFunction + * @param {File} file File object + * @returns {Promise} Converted file text + */ + +const fileSizeLimit = 1024 * 1024 * 100; // 100 MB +const ATTACHMENT_SOURCE = { + GLOBAL: 'global', + CHARACTER: 'character', + CHAT: 'chat', +}; + +/** + * @type {Record} File converters + */ +const converters = { + 'application/pdf': extractTextFromPDF, + 'text/html': extractTextFromHTML, + 'text/markdown': extractTextFromMarkdown, + 'application/epub+zip': extractTextFromEpub, + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': extractTextFromOffice, + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': extractTextFromOffice, + 'application/vnd.openxmlformats-officedocument.presentationml.presentation': extractTextFromOffice, + 'application/vnd.oasis.opendocument.text': extractTextFromOffice, + 'application/vnd.oasis.opendocument.presentation': extractTextFromOffice, + 'application/vnd.oasis.opendocument.spreadsheet': extractTextFromOffice, +}; + +/** + * Finds a matching key in the converters object. + * @param {string} type MIME type + * @returns {string} Matching key + */ +function findConverterKey(type) { + return Object.keys(converters).find((key) => { + // Match exact type + if (type === key) { + return true; + } + + // Match wildcards + if (key.endsWith('*')) { + return type.startsWith(key.substring(0, key.length - 1)); + } + + return false; + }); +} + +/** + * Determines if the file type has a converter function. + * @param {string} type MIME type + * @returns {boolean} True if the file type is convertible, false otherwise. + */ +function isConvertible(type) { + return Boolean(findConverterKey(type)); +} + +/** + * Gets the converter function for a file type. + * @param {string} type MIME type + * @returns {ConverterFunction} Converter function + */ +function getConverter(type) { + const key = findConverterKey(type); + return key && converters[key]; +} + +/** + * Mark a range of messages as hidden ("is_system") or not. + * @param {number} start Starting message ID + * @param {number} end Ending message ID (inclusive) + * @param {boolean} unhide If true, unhide the messages instead. + * @param {string} nameFitler Optional name filter + * @returns {Promise} + */ +export async function hideChatMessageRange(start, end, unhide, nameFitler = null) { + if (isNaN(start)) return; + if (!end) end = start; + const hide = !unhide; + + for (let messageId = start; messageId <= end; messageId++) { + const message = chat[messageId]; + if (!message) continue; + if (nameFitler && message.name !== nameFitler) continue; + + message.is_system = hide; + + // Also toggle "hidden" state for all visible messages + const messageBlock = $(`.mes[mesid="${messageId}"]`); + if (!messageBlock.length) continue; + messageBlock.attr('is_system', String(hide)); + } + + // Reload swipes. Useful when a last message is hidden. + hideSwipeButtons(); + showSwipeButtons(); + + saveChatDebounced(); +} + +/** + * Mark message as hidden (system message). + * @deprecated Use hideChatMessageRange. + * @param {number} messageId Message ID + * @param {JQuery} _messageBlock Unused + * @returns {Promise} + */ +export async function hideChatMessage(messageId, _messageBlock) { + return hideChatMessageRange(messageId, messageId, false); +} + +/** + * Mark message as visible (non-system message). + * @deprecated Use hideChatMessageRange. + * @param {number} messageId Message ID + * @param {JQuery} _messageBlock Unused + * @returns {Promise} + */ +export async function unhideChatMessage(messageId, _messageBlock) { + return hideChatMessageRange(messageId, messageId, true); +} + +/** + * Adds a file attachment to the message. + * @param {object} message Message object + * @returns {Promise} A promise that resolves when file is uploaded. + */ +export async function populateFileAttachment(message, inputId = 'file_form_input') { + try { + if (!message) return; + if (!message.extra) message.extra = {}; + const fileInput = document.getElementById(inputId); + if (!(fileInput instanceof HTMLInputElement)) return; + const file = fileInput.files[0]; + if (!file) return; + + const slug = getStringHash(file.name); + const fileNamePrefix = `${Date.now()}_${slug}`; + const fileBase64 = await getBase64Async(file); + let base64Data = fileBase64.split(',')[1]; + + // If file is image + if (file.type.startsWith('image/')) { + const extension = file.type.split('/')[1]; + const imageUrl = await saveBase64AsFile(base64Data, name2, fileNamePrefix, extension); + message.extra.image = imageUrl; + message.extra.inline_image = true; + } else { + const uniqueFileName = `${fileNamePrefix}.txt`; + + if (isConvertible(file.type)) { + try { + const converter = getConverter(file.type); + const fileText = await converter(file); + base64Data = window.btoa(unescape(encodeURIComponent(fileText))); + } catch (error) { + toastr.error(String(error), t`Could not convert file`); + console.error('Could not convert file', error); + } + } + + const fileUrl = await uploadFileAttachment(uniqueFileName, base64Data); + + if (!fileUrl) { + return; + } + + message.extra.file = { + url: fileUrl, + size: file.size, + name: file.name, + created: Date.now(), + }; + } + + } catch (error) { + console.error('Could not upload file', error); + } finally { + $('#file_form').trigger('reset'); + } +} + +/** + * Uploads file to the server. + * @param {string} fileName + * @param {string} base64Data + * @returns {Promise} File URL + */ +export async function uploadFileAttachment(fileName, base64Data) { + try { + const result = await fetch('/api/files/upload', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + name: fileName, + data: base64Data, + }), + }); + + if (!result.ok) { + const error = await result.text(); + throw new Error(error); + } + + const responseData = await result.json(); + return responseData.path; + } catch (error) { + toastr.error(String(error), t`Could not upload file`); + console.error('Could not upload file', error); + } +} + +/** + * Downloads file from the server. + * @param {string} url File URL + * @returns {Promise} File text + */ +export async function getFileAttachment(url) { + try { + const result = await fetch(url, { + method: 'GET', + cache: 'force-cache', + headers: getRequestHeaders(), + }); + + if (!result.ok) { + const error = await result.text(); + throw new Error(error); + } + + const text = await result.text(); + return text; + } catch (error) { + toastr.error(error, t`Could not download file`); + console.error('Could not download file', error); + } +} + +/** + * Validates file to make sure it is not binary or not image. + * @param {File} file File object + * @returns {Promise} True if file is valid, false otherwise. + */ +async function validateFile(file) { + const fileText = await file.text(); + const isImage = file.type.startsWith('image/'); + const isBinary = /^[\x00-\x08\x0E-\x1F\x7F-\xFF]*$/.test(fileText); + + if (!isImage && file.size > fileSizeLimit) { + toastr.error(t`File is too big. Maximum size is ${humanFileSize(fileSizeLimit)}.`); + return false; + } + + // If file is binary + if (isBinary && !isImage && !isConvertible(file.type)) { + toastr.error(t`Binary files are not supported. Select a text file or image.`); + return false; + } + + return true; +} + +export function hasPendingFileAttachment() { + const fileInput = document.getElementById('file_form_input'); + if (!(fileInput instanceof HTMLInputElement)) return false; + const file = fileInput.files[0]; + return !!file; +} + +/** + * Displays file information in the message sending form. + * @param {File} file File object + * @returns {Promise} + */ +async function onFileAttach(file) { + if (!file) return; + + const isValid = await validateFile(file); + + // If file is binary + if (!isValid) { + $('#file_form').trigger('reset'); + return; + } + + $('#file_form .file_name').text(file.name); + $('#file_form .file_size').text(humanFileSize(file.size)); + $('#file_form').removeClass('displayNone'); + + // Reset form on chat change + eventSource.once(event_types.CHAT_CHANGED, () => { + $('#file_form').trigger('reset'); + }); +} + +/** + * Deletes file from message. + * @param {number} messageId Message ID + */ +async function deleteMessageFile(messageId) { + const confirm = await callGenericPopup('Are you sure you want to delete this file?', POPUP_TYPE.CONFIRM); + + if (confirm !== POPUP_RESULT.AFFIRMATIVE) { + console.debug('Delete file cancelled'); + return; + } + + const message = chat[messageId]; + + if (!message?.extra?.file) { + console.debug('Message has no file'); + return; + } + + const url = message.extra.file.url; + + delete message.extra.file; + $(`.mes[mesid="${messageId}"] .mes_file_container`).remove(); + await saveChatConditional(); + await deleteFileFromServer(url); +} + + +/** + * Opens file from message in a modal. + * @param {number} messageId Message ID + */ +async function viewMessageFile(messageId) { + const messageFile = chat[messageId]?.extra?.file; + + if (!messageFile) { + console.debug('Message has no file or it is empty'); + return; + } + + await openFilePopup(messageFile); +} + +/** + * Inserts a file embed into the message. + * @param {number} messageId + * @param {JQuery} messageBlock + * @returns {Promise} + */ +function embedMessageFile(messageId, messageBlock) { + const message = chat[messageId]; + + if (!message) { + console.warn('Failed to find message with id', messageId); + return; + } + + $('#embed_file_input') + .off('change') + .on('change', parseAndUploadEmbed) + .trigger('click'); + + async function parseAndUploadEmbed(e) { + const file = e.target.files[0]; + if (!file) return; + + const isValid = await validateFile(file); + + if (!isValid) { + $('#file_form').trigger('reset'); + return; + } + + await populateFileAttachment(message, 'embed_file_input'); + await eventSource.emit(event_types.MESSAGE_FILE_EMBEDDED, messageId); + appendMediaToMessage(message, messageBlock); + await saveChatConditional(); + } +} + +/** + * Appends file content to the message text. + * @param {object} message Message object + * @param {string} messageText Message text + * @returns {Promise} Message text with file content appended. + */ +export async function appendFileContent(message, messageText) { + if (message.extra?.file) { + const fileText = message.extra.file.text || (await getFileAttachment(message.extra.file.url)); + + if (fileText) { + const fileWrapped = `${fileText}\n\n`; + message.extra.fileLength = fileWrapped.length; + messageText = fileWrapped + messageText; + } + } + return messageText; +} + +/** + * Replaces style tags in the message text with custom tags with encoded content. + * @param {string} text + * @returns {string} Encoded message text + * @copyright https://github.com/kwaroran/risuAI + */ +export function encodeStyleTags(text) { + const styleRegex = /`; + } catch (error) { + return `CSS ERROR: ${error}`; + } + }); +} + +async function openExternalMediaOverridesDialog() { + const entityId = getCurrentEntityId(); + + if (!entityId) { + toastr.info(t`No character or group selected`); + return; + } + + const template = $(await renderTemplateAsync('forbidMedia')); + template.find('.forbid_media_global_state_forbidden').toggle(power_user.forbid_external_media); + template.find('.forbid_media_global_state_allowed').toggle(!power_user.forbid_external_media); + + if (power_user.external_media_allowed_overrides.includes(entityId)) { + template.find('#forbid_media_override_allowed').prop('checked', true); + } + else if (power_user.external_media_forbidden_overrides.includes(entityId)) { + template.find('#forbid_media_override_forbidden').prop('checked', true); + } + else { + template.find('#forbid_media_override_global').prop('checked', true); + } + + callGenericPopup(template, POPUP_TYPE.TEXT, '', { wide: false, large: false }); +} + +export function getCurrentEntityId() { + if (selected_group) { + return String(selected_group); + } + + return characters[this_chid]?.avatar ?? null; +} + +export function isExternalMediaAllowed() { + const entityId = getCurrentEntityId(); + if (!entityId) { + return !power_user.forbid_external_media; + } + + if (power_user.external_media_allowed_overrides.includes(entityId)) { + return true; + } + + if (power_user.external_media_forbidden_overrides.includes(entityId)) { + return false; + } + + return !power_user.forbid_external_media; +} + +async function enlargeMessageImage() { + const mesBlock = $(this).closest('.mes'); + const mesId = mesBlock.attr('mesid'); + const message = chat[mesId]; + const imgSrc = message?.extra?.image; + const title = message?.extra?.title; + + if (!imgSrc) { + return; + } + + const img = document.createElement('img'); + img.classList.add('img_enlarged'); + img.src = imgSrc; + const imgHolder = document.createElement('div'); + imgHolder.classList.add('img_enlarged_holder'); + imgHolder.append(img); + const imgContainer = $('
      '); + imgContainer.prepend(imgHolder); + imgContainer.addClass('img_enlarged_container'); + + const codeTitle = imgContainer.find('.img_enlarged_title'); + codeTitle.addClass('txt').text(title); + const titleEmpty = !title || title.trim().length === 0; + imgContainer.find('pre').toggle(!titleEmpty); + addCopyToCodeBlocks(imgContainer); + + const popup = new Popup(imgContainer, POPUP_TYPE.DISPLAY, '', { large: true, transparent: true }); + + popup.dlg.style.width = 'unset'; + popup.dlg.style.height = 'unset'; + + img.addEventListener('click', event => { + const shouldZoom = !img.classList.contains('zoomed'); + img.classList.toggle('zoomed', shouldZoom); + event.stopPropagation(); + }); + codeTitle[0]?.addEventListener('click', event => { + event.stopPropagation(); + }); + + popup.dlg.addEventListener('click', event => { + popup.completeCancelled(); + }); + + await popup.show(); +} + +async function deleteMessageImage() { + const value = await callGenericPopup('

      Delete image from message?
      This action can\'t be undone.

      ', POPUP_TYPE.TEXT, '', { + okButton: t`Delete one`, + customButtons: [ + { + text: t`Delete all`, + appendAtEnd: true, + result: POPUP_RESULT.CUSTOM1, + }, + { + text: t`Cancel`, + appendAtEnd: true, + result: POPUP_RESULT.CANCELLED, + }, + ], + }); + + if (!value) { + return; + } + + const mesBlock = $(this).closest('.mes'); + const mesId = mesBlock.attr('mesid'); + const message = chat[mesId]; + + let isLastImage = true; + + if (Array.isArray(message.extra.image_swipes)) { + const indexOf = message.extra.image_swipes.indexOf(message.extra.image); + if (indexOf > -1) { + message.extra.image_swipes.splice(indexOf, 1); + isLastImage = message.extra.image_swipes.length === 0; + if (!isLastImage) { + const newIndex = Math.min(indexOf, message.extra.image_swipes.length - 1); + message.extra.image = message.extra.image_swipes[newIndex]; + } + } + } + + if (isLastImage || value === POPUP_RESULT.CUSTOM1) { + delete message.extra.image; + delete message.extra.inline_image; + delete message.extra.title; + delete message.extra.append_title; + delete message.extra.image_swipes; + mesBlock.find('.mes_img_container').removeClass('img_extra'); + mesBlock.find('.mes_img').attr('src', ''); + } else { + appendMediaToMessage(message, mesBlock); + } + + await saveChatConditional(); +} + +/** + * Deletes file from the server. + * @param {string} url Path to the file on the server + * @param {boolean} [silent=false] If true, do not show error messages + * @returns {Promise} True if file was deleted, false otherwise. + */ +async function deleteFileFromServer(url, silent = false) { + try { + const result = await fetch('/api/files/delete', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ path: url }), + }); + + if (!result.ok && !silent) { + const error = await result.text(); + throw new Error(error); + } + + await eventSource.emit(event_types.FILE_ATTACHMENT_DELETED, url); + return true; + } catch (error) { + toastr.error(String(error), t`Could not delete file`); + console.error('Could not delete file', error); + return false; + } +} + +/** + * Opens file attachment in a modal. + * @param {FileAttachment} attachment File attachment + */ +async function openFilePopup(attachment) { + const fileText = attachment.text || (await getFileAttachment(attachment.url)); + + const modalTemplate = $('
      '); + modalTemplate.find('code').addClass('txt').text(fileText); + modalTemplate.addClass('file_modal').addClass('textarea_compact').addClass('fontsize90p'); + addCopyToCodeBlocks(modalTemplate); + + callGenericPopup(modalTemplate, POPUP_TYPE.TEXT, '', { wide: true, large: true }); +} + +/** + * Edit a file attachment in a notepad-like modal. + * @param {FileAttachment} attachment Attachment to edit + * @param {string} source Attachment source + * @param {function} callback Callback function + */ +async function editAttachment(attachment, source, callback) { + const originalFileText = attachment.text || (await getFileAttachment(attachment.url)); + const template = $(await renderExtensionTemplateAsync('attachments', 'notepad')); + + let editedFileText = originalFileText; + template.find('[name="notepadFileContent"]').val(editedFileText).on('input', function () { + editedFileText = String($(this).val()); + }); + + let editedFileName = attachment.name; + template.find('[name="notepadFileName"]').val(editedFileName).on('input', function () { + editedFileName = String($(this).val()); + }); + + const result = await callGenericPopup(template, POPUP_TYPE.CONFIRM, '', { wide: true, large: true, okButton: 'Save', cancelButton: 'Cancel' }); + + if (result !== POPUP_RESULT.AFFIRMATIVE) { + return; + } + + if (editedFileText === originalFileText && editedFileName === attachment.name) { + return; + } + + const nullCallback = () => { }; + await deleteAttachment(attachment, source, nullCallback, false); + const file = new File([editedFileText], editedFileName, { type: 'text/plain' }); + await uploadFileAttachmentToServer(file, source); + + callback(); +} + +/** + * Downloads an attachment to the user's device. + * @param {FileAttachment} attachment Attachment to download + */ +async function downloadAttachment(attachment) { + const fileText = attachment.text || (await getFileAttachment(attachment.url)); + const blob = new Blob([fileText], { type: 'text/plain' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = attachment.name; + a.click(); + URL.revokeObjectURL(url); +} + +/** + * Removes an attachment from the disabled list. + * @param {FileAttachment} attachment Attachment to enable + * @param {function} callback Success callback + */ +function enableAttachment(attachment, callback) { + ensureAttachmentsExist(); + extension_settings.disabled_attachments = extension_settings.disabled_attachments.filter(url => url !== attachment.url); + saveSettingsDebounced(); + callback(); +} + +/** + * Adds an attachment to the disabled list. + * @param {FileAttachment} attachment Attachment to disable + * @param {function} callback Success callback + */ +function disableAttachment(attachment, callback) { + ensureAttachmentsExist(); + extension_settings.disabled_attachments.push(attachment.url); + saveSettingsDebounced(); + callback(); +} + +/** + * Moves a file attachment to a different source. + * @param {FileAttachment} attachment Attachment to moves + * @param {string} source Source of the attachment + * @param {function} callback Success callback + * @returns {Promise} A promise that resolves when the attachment is moved. + */ +async function moveAttachment(attachment, source, callback) { + let selectedTarget = source; + const targets = getAvailableTargets(); + const template = $(await renderExtensionTemplateAsync('attachments', 'move-attachment', { name: attachment.name, targets })); + template.find('.moveAttachmentTarget').val(source).on('input', function () { + selectedTarget = String($(this).val()); + }); + + const result = await callGenericPopup(template, POPUP_TYPE.CONFIRM, '', { wide: false, large: false, okButton: 'Move', cancelButton: 'Cancel' }); + + if (result !== POPUP_RESULT.AFFIRMATIVE) { + console.debug('Move attachment cancelled'); + return; + } + + if (selectedTarget === source) { + console.debug('Move attachment cancelled: same source and target'); + return; + } + + const content = await getFileAttachment(attachment.url); + const file = new File([content], attachment.name, { type: 'text/plain' }); + await deleteAttachment(attachment, source, () => { }, false); + await uploadFileAttachmentToServer(file, selectedTarget); + callback(); +} + +/** + * Deletes an attachment from the server and the chat. + * @param {FileAttachment} attachment Attachment to delete + * @param {string} source Source of the attachment + * @param {function} callback Callback function + * @param {boolean} [confirm=true] If true, show a confirmation dialog + * @returns {Promise} A promise that resolves when the attachment is deleted. + */ +export async function deleteAttachment(attachment, source, callback, confirm = true) { + if (confirm) { + const result = await callGenericPopup('Are you sure you want to delete this attachment?', POPUP_TYPE.CONFIRM); + + if (result !== POPUP_RESULT.AFFIRMATIVE) { + return; + } + } + + ensureAttachmentsExist(); + + switch (source) { + case 'global': + extension_settings.attachments = extension_settings.attachments.filter((a) => a.url !== attachment.url); + saveSettingsDebounced(); + break; + case 'chat': + chat_metadata.attachments = chat_metadata.attachments.filter((a) => a.url !== attachment.url); + saveMetadataDebounced(); + break; + case 'character': + extension_settings.character_attachments[characters[this_chid]?.avatar] = extension_settings.character_attachments[characters[this_chid]?.avatar].filter((a) => a.url !== attachment.url); + break; + } + + if (Array.isArray(extension_settings.disabled_attachments) && extension_settings.disabled_attachments.includes(attachment.url)) { + extension_settings.disabled_attachments = extension_settings.disabled_attachments.filter(url => url !== attachment.url); + saveSettingsDebounced(); + } + + const silent = confirm === false; + await deleteFileFromServer(attachment.url, silent); + callback(); +} + +/** + * Determines if the attachment is disabled. + * @param {FileAttachment} attachment Attachment to check + * @returns {boolean} True if attachment is disabled, false otherwise. + */ +function isAttachmentDisabled(attachment) { + return extension_settings.disabled_attachments.some(url => url === attachment?.url); +} + +/** + * Opens the attachment manager. + */ +async function openAttachmentManager() { + /** + * Renders a list of attachments. + * @param {FileAttachment[]} attachments List of attachments + * @param {string} source Source of the attachments + */ + async function renderList(attachments, source) { + /** + * Sorts attachments by sortField and sortOrder. + * @param {FileAttachment} a First attachment + * @param {FileAttachment} b Second attachment + * @returns {number} Sort order + */ + function sortFn(a, b) { + const sortValueA = a[sortField]; + const sortValueB = b[sortField]; + if (typeof sortValueA === 'string' && typeof sortValueB === 'string') { + return sortValueA.localeCompare(sortValueB) * (sortOrder === 'asc' ? 1 : -1); + } + return (sortValueA - sortValueB) * (sortOrder === 'asc' ? 1 : -1); + } + + /** + * Filters attachments by name. + * @param {FileAttachment} a Attachment + * @returns {boolean} True if attachment matches the filter, false otherwise. + */ + function filterFn(a) { + if (!filterString) { + return true; + } + + return a.name.toLowerCase().includes(filterString.toLowerCase()); + } + const sources = { + [ATTACHMENT_SOURCE.GLOBAL]: '.globalAttachmentsList', + [ATTACHMENT_SOURCE.CHARACTER]: '.characterAttachmentsList', + [ATTACHMENT_SOURCE.CHAT]: '.chatAttachmentsList', + }; + + const selected = template + .find(sources[source]) + .find('.attachmentListItemCheckbox:checked') + .map((_, el) => $(el).closest('.attachmentListItem').attr('data-attachment-url')) + .get(); + + template.find(sources[source]).empty(); + + // Sort attachments by sortField and sortOrder, and apply filter + const sortedAttachmentList = attachments.slice().filter(filterFn).sort(sortFn); + + for (const attachment of sortedAttachmentList) { + const isDisabled = isAttachmentDisabled(attachment); + const attachmentTemplate = template.find('.attachmentListItemTemplate .attachmentListItem').clone(); + attachmentTemplate.toggleClass('disabled', isDisabled); + attachmentTemplate.attr('data-attachment-url', attachment.url); + attachmentTemplate.attr('data-attachment-source', source); + attachmentTemplate.find('.attachmentFileIcon').attr('title', attachment.url); + attachmentTemplate.find('.attachmentListItemName').text(attachment.name); + attachmentTemplate.find('.attachmentListItemSize').text(humanFileSize(attachment.size)); + attachmentTemplate.find('.attachmentListItemCreated').text(new Date(attachment.created).toLocaleString()); + attachmentTemplate.find('.viewAttachmentButton').on('click', () => openFilePopup(attachment)); + attachmentTemplate.find('.editAttachmentButton').on('click', () => editAttachment(attachment, source, renderAttachments)); + attachmentTemplate.find('.deleteAttachmentButton').on('click', () => deleteAttachment(attachment, source, renderAttachments)); + attachmentTemplate.find('.downloadAttachmentButton').on('click', () => downloadAttachment(attachment)); + attachmentTemplate.find('.moveAttachmentButton').on('click', () => moveAttachment(attachment, source, renderAttachments)); + attachmentTemplate.find('.enableAttachmentButton').toggle(isDisabled).on('click', () => enableAttachment(attachment, renderAttachments)); + attachmentTemplate.find('.disableAttachmentButton').toggle(!isDisabled).on('click', () => disableAttachment(attachment, renderAttachments)); + template.find(sources[source]).append(attachmentTemplate); + + if (selected.includes(attachment.url)) { + attachmentTemplate.find('.attachmentListItemCheckbox').prop('checked', true); + } + } + } + + /** + * Renders buttons for the attachment manager. + */ + async function renderButtons() { + const sources = { + [ATTACHMENT_SOURCE.GLOBAL]: '.globalAttachmentsTitle', + [ATTACHMENT_SOURCE.CHARACTER]: '.characterAttachmentsTitle', + [ATTACHMENT_SOURCE.CHAT]: '.chatAttachmentsTitle', + }; + + const modal = template.find('.actionButtonsModal').hide(); + const scrapers = ScraperManager.getDataBankScrapers(); + + for (const scraper of scrapers) { + const isAvailable = await ScraperManager.isScraperAvailable(scraper.id); + if (!isAvailable) { + continue; + } + + const buttonTemplate = template.find('.actionButtonTemplate .actionButton').clone(); + if (scraper.iconAvailable) { + buttonTemplate.find('.actionButtonIcon').addClass(scraper.iconClass); + buttonTemplate.find('.actionButtonImg').remove(); + } else { + buttonTemplate.find('.actionButtonImg').attr('src', scraper.iconClass); + buttonTemplate.find('.actionButtonIcon').remove(); + } + buttonTemplate.find('.actionButtonText').text(scraper.name); + buttonTemplate.attr('title', scraper.description); + buttonTemplate.on('click', () => { + const target = modal.attr('data-attachment-manager-target'); + runScraper(scraper.id, target, renderAttachments); + }); + modal.append(buttonTemplate); + } + + const modalButtonData = Object.entries(sources).map(entry => { + const [source, selector] = entry; + const button = template.find(selector).find('.openActionModalButton').get(0); + + if (!button) { + return; + } + + const bodyListener = (e) => { + if (modal.is(':visible') && (!$(e.target).closest('.openActionModalButton').length)) { + modal.hide(); + } + + // Replay a click if the modal was already open by another button + if ($(e.target).closest('.openActionModalButton').length && !modal.is(':visible')) { + modal.show(); + } + }; + document.body.addEventListener('click', bodyListener); + + const popper = Popper.createPopper(button, modal.get(0), { placement: 'bottom-end' }); + button.addEventListener('click', () => { + modal.attr('data-attachment-manager-target', source); + modal.toggle(); + popper.update(); + }); + + return [popper, bodyListener]; + }).filter(Boolean); + + return () => { + modalButtonData.forEach(p => { + const [popper, bodyListener] = p; + popper.destroy(); + document.body.removeEventListener('click', bodyListener); + }); + modal.remove(); + }; + } + + async function renderAttachments() { + /** @type {FileAttachment[]} */ + const globalAttachments = extension_settings.attachments ?? []; + /** @type {FileAttachment[]} */ + const chatAttachments = chat_metadata.attachments ?? []; + /** @type {FileAttachment[]} */ + const characterAttachments = extension_settings.character_attachments?.[characters[this_chid]?.avatar] ?? []; + + await renderList(globalAttachments, ATTACHMENT_SOURCE.GLOBAL); + await renderList(chatAttachments, ATTACHMENT_SOURCE.CHAT); + await renderList(characterAttachments, ATTACHMENT_SOURCE.CHARACTER); + + const isNotCharacter = this_chid === undefined || selected_group; + const isNotInChat = getCurrentChatId() === undefined; + template.find('.characterAttachmentsBlock').toggle(!isNotCharacter); + template.find('.chatAttachmentsBlock').toggle(!isNotInChat); + + const characterName = characters[this_chid]?.name || 'Anonymous'; + template.find('.characterAttachmentsName').text(characterName); + + const chatName = getCurrentChatId() || 'Unnamed chat'; + template.find('.chatAttachmentsName').text(chatName); + } + + const dragDropHandler = new DragAndDropHandler('.popup', async (files, event) => { + let selectedTarget = ATTACHMENT_SOURCE.GLOBAL; + const targets = getAvailableTargets(); + + const targetSelectTemplate = $(await renderExtensionTemplateAsync('attachments', 'files-dropped', { count: files.length, targets: targets })); + targetSelectTemplate.find('.droppedFilesTarget').on('input', function () { + selectedTarget = String($(this).val()); + }); + const result = await callGenericPopup(targetSelectTemplate, POPUP_TYPE.CONFIRM, '', { wide: false, large: false, okButton: 'Upload', cancelButton: 'Cancel' }); + if (result !== POPUP_RESULT.AFFIRMATIVE) { + console.log('File upload cancelled'); + return; + } + for (const file of files) { + await uploadFileAttachmentToServer(file, selectedTarget); + } + renderAttachments(); + }); + + let sortField = accountStorage.getItem('DataBank_sortField') || 'created'; + let sortOrder = accountStorage.getItem('DataBank_sortOrder') || 'desc'; + let filterString = ''; + + const template = $(await renderExtensionTemplateAsync('attachments', 'manager', {})); + + template.find('.attachmentSearch').on('input', function () { + filterString = String($(this).val()); + renderAttachments(); + }); + template.find('.attachmentSort').on('change', function () { + if (!(this instanceof HTMLSelectElement) || this.selectedOptions.length === 0) { + return; + } + + sortField = this.selectedOptions[0].dataset.sortField; + sortOrder = this.selectedOptions[0].dataset.sortOrder; + accountStorage.setItem('DataBank_sortField', sortField); + accountStorage.setItem('DataBank_sortOrder', sortOrder); + renderAttachments(); + }); + function handleBulkAction(action) { + return async () => { + const selectedAttachments = document.querySelectorAll('.attachmentListItemCheckboxContainer .attachmentListItemCheckbox:checked'); + + if (selectedAttachments.length === 0) { + toastr.info(t`No attachments selected.`, t`Data Bank`); + return; + } + + if (action.confirmMessage) { + const confirm = await callGenericPopup(action.confirmMessage, POPUP_TYPE.CONFIRM); + if (confirm !== POPUP_RESULT.AFFIRMATIVE) { + return; + } + } + + const includeDisabled = true; + const attachments = getDataBankAttachments(includeDisabled); + selectedAttachments.forEach(async (checkbox) => { + const listItem = checkbox.closest('.attachmentListItem'); + if (!(listItem instanceof HTMLElement)) { + return; + } + const url = listItem.dataset.attachmentUrl; + const source = listItem.dataset.attachmentSource; + const attachment = attachments.find(a => a.url === url); + if (!attachment) { + return; + } + await action.perform(attachment, source); + }); + + document.querySelectorAll('.attachmentListItemCheckbox, .attachmentsBulkEditCheckbox').forEach(checkbox => { + if (checkbox instanceof HTMLInputElement) { + checkbox.checked = false; + } + }); + + await renderAttachments(); + }; + } + + template.find('.bulkActionDisable').on('click', handleBulkAction({ + perform: (attachment) => disableAttachment(attachment, () => { }), + })); + + template.find('.bulkActionEnable').on('click', handleBulkAction({ + perform: (attachment) => enableAttachment(attachment, () => { }), + })); + + template.find('.bulkActionDelete').on('click', handleBulkAction({ + confirmMessage: 'Are you sure you want to delete the selected attachments?', + perform: async (attachment, source) => await deleteAttachment(attachment, source, () => { }, false), + })); + + template.find('.bulkActionSelectAll').on('click', () => { + $('.attachmentListItemCheckbox:visible').each((_, checkbox) => { + if (checkbox instanceof HTMLInputElement) { + checkbox.checked = true; + } + }); + }); + template.find('.bulkActionSelectNone').on('click', () => { + $('.attachmentListItemCheckbox:visible').each((_, checkbox) => { + if (checkbox instanceof HTMLInputElement) { + checkbox.checked = false; + } + }); + }); + + const cleanupFn = await renderButtons(); + await verifyAttachments(); + await renderAttachments(); + await callGenericPopup(template, POPUP_TYPE.TEXT, '', { wide: true, large: true, okButton: 'Close', allowVerticalScrolling: true }); + + cleanupFn(); + dragDropHandler.destroy(); +} + +/** + * Gets a list of available targets for attachments. + * @returns {string[]} List of available targets + */ +function getAvailableTargets() { + const targets = Object.values(ATTACHMENT_SOURCE); + + const isNotCharacter = this_chid === undefined || selected_group; + const isNotInChat = getCurrentChatId() === undefined; + + if (isNotCharacter) { + targets.splice(targets.indexOf(ATTACHMENT_SOURCE.CHARACTER), 1); + } + + if (isNotInChat) { + targets.splice(targets.indexOf(ATTACHMENT_SOURCE.CHAT), 1); + } + + return targets; +} + +/** + * Runs a known scraper on a source and saves the result as an attachment. + * @param {string} scraperId Id of the scraper + * @param {string} target Target for the attachment + * @param {function} callback Callback function + * @returns {Promise} A promise that resolves when the source is scraped. + */ +async function runScraper(scraperId, target, callback) { + try { + console.log(`Running scraper ${scraperId} for ${target}`); + const files = await ScraperManager.runDataBankScraper(scraperId); + + if (!Array.isArray(files)) { + console.warn('Scraping returned nothing'); + return; + } + + if (files.length === 0) { + console.warn('Scraping returned no files'); + toastr.info(t`No files were scraped.`, t`Data Bank`); + return; + } + + for (const file of files) { + await uploadFileAttachmentToServer(file, target); + } + + toastr.success(t`Scraped ${files.length} files from ${scraperId} to ${target}.`, t`Data Bank`); + callback(); + } + catch (error) { + console.error('Scraping failed', error); + toastr.error(t`Check browser console for details.`, t`Scraping failed`); + } +} + +/** + * Uploads a file attachment to the server. + * @param {File} file File to upload + * @param {string} target Target for the attachment + * @returns {Promise} Path to the uploaded file + */ +export async function uploadFileAttachmentToServer(file, target) { + const isValid = await validateFile(file); + + if (!isValid) { + return; + } + + let base64Data = await getBase64Async(file); + const slug = getStringHash(file.name); + const uniqueFileName = `${Date.now()}_${slug}.txt`; + + if (isConvertible(file.type)) { + try { + const converter = getConverter(file.type); + const fileText = await converter(file); + base64Data = window.btoa(unescape(encodeURIComponent(fileText))); + } catch (error) { + toastr.error(String(error), t`Could not convert file`); + console.error('Could not convert file', error); + } + } else { + const fileText = await file.text(); + base64Data = window.btoa(unescape(encodeURIComponent(fileText))); + } + + const fileUrl = await uploadFileAttachment(uniqueFileName, base64Data); + const convertedSize = Math.round(base64Data.length * 0.75); + + if (!fileUrl) { + return; + } + + const attachment = { + url: fileUrl, + size: convertedSize, + name: file.name, + created: Date.now(), + }; + + ensureAttachmentsExist(); + + switch (target) { + case ATTACHMENT_SOURCE.GLOBAL: + extension_settings.attachments.push(attachment); + saveSettingsDebounced(); + break; + case ATTACHMENT_SOURCE.CHAT: + chat_metadata.attachments.push(attachment); + saveMetadataDebounced(); + break; + case ATTACHMENT_SOURCE.CHARACTER: + extension_settings.character_attachments[characters[this_chid]?.avatar].push(attachment); + saveSettingsDebounced(); + break; + } + + return fileUrl; +} + +function ensureAttachmentsExist() { + if (!Array.isArray(extension_settings.disabled_attachments)) { + extension_settings.disabled_attachments = []; + } + + if (!Array.isArray(extension_settings.attachments)) { + extension_settings.attachments = []; + } + + if (!Array.isArray(chat_metadata.attachments)) { + chat_metadata.attachments = []; + } + + if (this_chid !== undefined && characters[this_chid]) { + if (!extension_settings.character_attachments) { + extension_settings.character_attachments = {}; + } + + if (!Array.isArray(extension_settings.character_attachments[characters[this_chid].avatar])) { + extension_settings.character_attachments[characters[this_chid].avatar] = []; + } + } +} + +/** + * Gets all currently available attachments. Ignores disabled attachments by default. + * @param {boolean} [includeDisabled=false] If true, include disabled attachments + * @returns {FileAttachment[]} List of attachments + */ +export function getDataBankAttachments(includeDisabled = false) { + ensureAttachmentsExist(); + const globalAttachments = extension_settings.attachments ?? []; + const chatAttachments = chat_metadata.attachments ?? []; + const characterAttachments = extension_settings.character_attachments?.[characters[this_chid]?.avatar] ?? []; + + return [...globalAttachments, ...chatAttachments, ...characterAttachments].filter(x => includeDisabled || !isAttachmentDisabled(x)); +} + +/** + * Gets all attachments for a specific source. Includes disabled attachments by default. + * @param {string} source Attachment source + * @param {boolean} [includeDisabled=true] If true, include disabled attachments + * @returns {FileAttachment[]} List of attachments + */ +export function getDataBankAttachmentsForSource(source, includeDisabled = true) { + ensureAttachmentsExist(); + + function getBySource() { + switch (source) { + case ATTACHMENT_SOURCE.GLOBAL: + return extension_settings.attachments ?? []; + case ATTACHMENT_SOURCE.CHAT: + return chat_metadata.attachments ?? []; + case ATTACHMENT_SOURCE.CHARACTER: + return extension_settings.character_attachments?.[characters[this_chid]?.avatar] ?? []; + } + + return []; + } + + return getBySource().filter(x => includeDisabled || !isAttachmentDisabled(x)); +} + +/** + * Verifies all attachments in the Data Bank. + * @returns {Promise} A promise that resolves when attachments are verified. + */ +async function verifyAttachments() { + for (const source of Object.values(ATTACHMENT_SOURCE)) { + await verifyAttachmentsForSource(source); + } +} + +/** + * Verifies all attachments for a specific source. + * @param {string} source Attachment source + * @returns {Promise} A promise that resolves when attachments are verified. + */ +async function verifyAttachmentsForSource(source) { + try { + const attachments = getDataBankAttachmentsForSource(source); + const urls = attachments.map(a => a.url); + const response = await fetch('/api/files/verify', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ urls }), + }); + + if (!response.ok) { + const error = await response.text(); + throw new Error(error); + } + + const verifiedUrls = await response.json(); + for (const attachment of attachments) { + if (verifiedUrls[attachment.url] === false) { + console.log('Deleting orphaned attachment', attachment); + await deleteAttachment(attachment, source, () => { }, false); + } + } + } catch (error) { + console.error('Attachment verification failed', error); + } +} + +const NEUTRAL_CHAT_KEY = 'neutralChat'; + +export function preserveNeutralChat() { + if (this_chid !== undefined || selected_group || name2 !== neutralCharacterName) { + return; + } + + sessionStorage.setItem(NEUTRAL_CHAT_KEY, JSON.stringify({ chat, chat_metadata })); +} + +export function restoreNeutralChat() { + if (this_chid !== undefined || selected_group || name2 !== neutralCharacterName) { + return; + } + + const neutralChat = sessionStorage.getItem(NEUTRAL_CHAT_KEY); + if (!neutralChat) { + return; + } + + const { chat: neutralChatData, chat_metadata: neutralChatMetadata } = JSON.parse(neutralChat); + chat.splice(0, chat.length, ...neutralChatData); + updateChatMetadata(neutralChatMetadata, true); + sessionStorage.removeItem(NEUTRAL_CHAT_KEY); +} + +/** + * Registers a file converter function. + * @param {string} mimeType MIME type + * @param {ConverterFunction} converter Function to convert file + * @returns {void} + */ +export function registerFileConverter(mimeType, converter) { + if (typeof mimeType !== 'string' || typeof converter !== 'function') { + console.error('Invalid converter registration'); + return; + } + + if (Object.keys(converters).includes(mimeType)) { + console.error('Converter already registered'); + return; + } + + converters[mimeType] = converter; +} + +jQuery(function () { + $(document).on('click', '.mes_hide', async function () { + const messageBlock = $(this).closest('.mes'); + const messageId = Number(messageBlock.attr('mesid')); + await hideChatMessageRange(messageId, messageId, false); + }); + + $(document).on('click', '.mes_unhide', async function () { + const messageBlock = $(this).closest('.mes'); + const messageId = Number(messageBlock.attr('mesid')); + await hideChatMessageRange(messageId, messageId, true); + }); + + $(document).on('click', '.mes_file_delete', async function () { + const messageBlock = $(this).closest('.mes'); + const messageId = Number(messageBlock.attr('mesid')); + await deleteMessageFile(messageId); + }); + + $(document).on('click', '.mes_file_open', async function () { + const messageBlock = $(this).closest('.mes'); + const messageId = Number(messageBlock.attr('mesid')); + await viewMessageFile(messageId); + }); + + $(document).on('click', '.assistant_note_export', async function () { + const chatToSave = [ + { + user_name: name1, + character_name: name2, + chat_metadata: chat_metadata, + }, + ...chat.filter(x => x?.extra?.type !== system_message_types.ASSISTANT_NOTE), + ]; + + download(chatToSave.map((m) => JSON.stringify(m)).join('\n'), `Assistant - ${humanizedDateTime()}.jsonl`, 'application/json'); + }); + + // Do not change. #attachFile is added by extension. + $(document).on('click', '#attachFile', function () { + $('#file_form_input').trigger('click'); + }); + + // Do not change. #manageAttachments is added by extension. + $(document).on('click', '#manageAttachments', function () { + openAttachmentManager(); + }); + + $(document).on('click', '.mes_embed', function () { + const messageBlock = $(this).closest('.mes'); + const messageId = Number(messageBlock.attr('mesid')); + embedMessageFile(messageId, messageBlock); + }); + + $(document).on('click', '.editor_maximize', async function () { + const broId = $(this).attr('data-for'); + const bro = $(`#${broId}`); + const contentEditable = bro.is('[contenteditable]'); + const withTab = $(this).attr('data-tab'); + + if (!bro.length) { + console.error('Could not find editor with id', broId); + return; + } + + const wrapper = document.createElement('div'); + wrapper.classList.add('height100p', 'wide100p', 'flex-container'); + wrapper.classList.add('flexFlowColumn', 'justifyCenter', 'alignitemscenter'); + const textarea = document.createElement('textarea'); + textarea.dataset.for = broId; + textarea.value = String(contentEditable ? bro[0].innerText : bro.val()); + textarea.classList.add('height100p', 'wide100p', 'maximized_textarea'); + bro.hasClass('monospace') && textarea.classList.add('monospace'); + bro.hasClass('mdHotkeys') && textarea.classList.add('mdHotkeys'); + textarea.addEventListener('input', function () { + if (contentEditable) { + bro[0].innerText = textarea.value; + bro.trigger('input'); + } else { + bro.val(textarea.value).trigger('input'); + } + }); + wrapper.appendChild(textarea); + + if (withTab) { + textarea.addEventListener('keydown', (evt) => { + if (evt.key == 'Tab' && !evt.shiftKey && !evt.ctrlKey && !evt.altKey) { + evt.preventDefault(); + const start = textarea.selectionStart; + const end = textarea.selectionEnd; + if (end - start > 0 && textarea.value.substring(start, end).includes('\n')) { + const lineStart = textarea.value.lastIndexOf('\n', start); + const count = textarea.value.substring(lineStart, end).split('\n').length - 1; + textarea.value = `${textarea.value.substring(0, lineStart)}${textarea.value.substring(lineStart, end).replace(/\n/g, '\n\t')}${textarea.value.substring(end)}`; + textarea.selectionStart = start + 1; + textarea.selectionEnd = end + count; + } else { + textarea.value = `${textarea.value.substring(0, start)}\t${textarea.value.substring(end)}`; + textarea.selectionStart = start + 1; + textarea.selectionEnd = end + 1; + } + } else if (evt.key == 'Tab' && evt.shiftKey && !evt.ctrlKey && !evt.altKey) { + evt.preventDefault(); + const start = textarea.selectionStart; + const end = textarea.selectionEnd; + const lineStart = textarea.value.lastIndexOf('\n', start); + const count = textarea.value.substring(lineStart, end).split('\n\t').length - 1; + textarea.value = `${textarea.value.substring(0, lineStart)}${textarea.value.substring(lineStart, end).replace(/\n\t/g, '\n')}${textarea.value.substring(end)}`; + textarea.selectionStart = start - 1; + textarea.selectionEnd = end - count; + } + }); + } + + await callGenericPopup(wrapper, POPUP_TYPE.TEXT, '', { wide: true, large: true }); + }); + + $(document).on('click', 'body.documentstyle .mes .mes_text', function () { + if (window.getSelection().toString()) return; + if ($('.edit_textarea').length) return; + $(this).closest('.mes').find('.mes_edit').trigger('click'); + }); + + $(document).on('click', '.open_media_overrides', openExternalMediaOverridesDialog); + $(document).on('input', '#forbid_media_override_allowed', function () { + const entityId = getCurrentEntityId(); + if (!entityId) return; + power_user.external_media_allowed_overrides.push(entityId); + power_user.external_media_forbidden_overrides = power_user.external_media_forbidden_overrides.filter((v) => v !== entityId); + saveSettingsDebounced(); + reloadCurrentChat(); + }); + $(document).on('input', '#forbid_media_override_forbidden', function () { + const entityId = getCurrentEntityId(); + if (!entityId) return; + power_user.external_media_forbidden_overrides.push(entityId); + power_user.external_media_allowed_overrides = power_user.external_media_allowed_overrides.filter((v) => v !== entityId); + saveSettingsDebounced(); + reloadCurrentChat(); + }); + $(document).on('input', '#forbid_media_override_global', function () { + const entityId = getCurrentEntityId(); + if (!entityId) return; + power_user.external_media_allowed_overrides = power_user.external_media_allowed_overrides.filter((v) => v !== entityId); + power_user.external_media_forbidden_overrides = power_user.external_media_forbidden_overrides.filter((v) => v !== entityId); + saveSettingsDebounced(); + reloadCurrentChat(); + }); + + $(document).on('click', '.mes_img_enlarge', enlargeMessageImage); + $(document).on('click', '.mes_img_delete', deleteMessageImage); + + $('#file_form_input').on('change', async () => { + const fileInput = document.getElementById('file_form_input'); + if (!(fileInput instanceof HTMLInputElement)) return; + const file = fileInput.files[0]; + await onFileAttach(file); + }); + $('#file_form').on('reset', function () { + $('#file_form').addClass('displayNone'); + }); + + document.getElementById('send_textarea').addEventListener('paste', async function (event) { + if (event.clipboardData.files.length === 0) { + return; + } + + event.preventDefault(); + event.stopPropagation(); + + const fileInput = document.getElementById('file_form_input'); + if (!(fileInput instanceof HTMLInputElement)) return; + + // Workaround for Firefox: Use a DataTransfer object to indirectly set fileInput.files + const dataTransfer = new DataTransfer(); + for (let i = 0; i < event.clipboardData.files.length; i++) { + dataTransfer.items.add(event.clipboardData.files[i]); + } + + fileInput.files = dataTransfer.files; + await onFileAttach(fileInput.files[0]); + }); +}); diff --git a/jiuguan2025cc/public/scripts/constants.js b/jiuguan2025cc/public/scripts/constants.js new file mode 100644 index 0000000000000000000000000000000000000000..f95a8e146e3cd7ded7ce8c2c42163ed4172a6288 --- /dev/null +++ b/jiuguan2025cc/public/scripts/constants.js @@ -0,0 +1,16 @@ +/** + * Common debounce timeout values to use with `debounce` calls. + * @enum {number} + */ +export const debounce_timeout = { + /** [100 ms] For ultra-fast responses, typically for keypresses or executions that might happen multiple times in a loop or recursion. */ + quick: 100, + /** [200 ms] Slightly slower than quick, but still very responsive. */ + short: 200, + /** [300 ms] Default time for general use, good balance between responsiveness and performance. */ + standard: 300, + /** [1.000 ms] For situations where the function triggers more intensive tasks. */ + relaxed: 1000, + /** [5 sec] For delayed tasks, like auto-saving or completing batch operations that need a significant pause. */ + extended: 5000, +}; diff --git a/jiuguan2025cc/public/scripts/custom-request.js b/jiuguan2025cc/public/scripts/custom-request.js new file mode 100644 index 0000000000000000000000000000000000000000..ca47b975bf9ab356b9f13e24eaa98713d6ffb828 --- /dev/null +++ b/jiuguan2025cc/public/scripts/custom-request.js @@ -0,0 +1,189 @@ +import { getPresetManager } from './preset-manager.js'; +import { extractMessageFromData, getGenerateUrl, getRequestHeaders } from '../script.js'; +import { getTextGenServer } from './textgen-settings.js'; + +// #region Type Definitions +/** + * @typedef {Object} TextCompletionRequestBase + * @property {string} prompt - The text prompt for completion + * @property {number} max_tokens - Maximum number of tokens to generate + * @property {string} [model] - Optional model name + * @property {string} api_type - Type of API to use + * @property {string} [api_server] - Optional API server URL + * @property {number} [temperature] - Optional temperature parameter + */ + +/** @typedef {Record & TextCompletionRequestBase} TextCompletionRequest */ + +/** + * @typedef {Object} TextCompletionPayloadBase + * @property {string} prompt - The text prompt for completion + * @property {number} max_tokens - Maximum number of tokens to generate + * @property {number} max_new_tokens - Alias for max_tokens + * @property {string} [model] - Optional model name + * @property {string} api_type - Type of API to use + * @property {string} api_server - API server URL + * @property {number} [temperature] - Optional temperature parameter + */ + +/** @typedef {Record & TextCompletionPayloadBase} TextCompletionPayload */ + +/** + * @typedef {Object} ChatCompletionMessage + * @property {string} role - The role of the message author (e.g., "user", "assistant", "system") + * @property {string} content - The content of the message + */ + +/** + * @typedef {Object} ChatCompletionPayloadBase + * @property {ChatCompletionMessage[]} messages - Array of chat messages + * @property {string} [model] - Optional model name to use for completion + * @property {string} chat_completion_source - Source provider for chat completion + * @property {number} max_tokens - Maximum number of tokens to generate + * @property {number} [temperature] - Optional temperature parameter for response randomness + */ + +/** @typedef {Record & ChatCompletionPayloadBase} ChatCompletionPayload */ +// #endregion + +/** + * Creates & sends a text completion request. Streaming is not supported. + */ +export class TextCompletionService { + static TYPE = 'textgenerationwebui'; + + /** + * @param {TextCompletionRequest} custom + * @returns {TextCompletionPayload} + */ + static createRequestData({ prompt, max_tokens, model, api_type, api_server, temperature, ...props }) { + return { + ...props, + prompt, + max_tokens, + max_new_tokens: max_tokens, + model, + api_type, + api_server: api_server ?? getTextGenServer(api_type), + temperature, + stream: false, + }; + } + + /** + * Sends a text completion request to the specified server + * @param {TextCompletionPayload} data Request data + * @param {boolean?} extractData Extract message from the response. Default true + * @returns {Promise} Extracted data or the raw response + * @throws {Error} + */ + static async sendRequest(data, extractData = true) { + const response = await fetch(getGenerateUrl(this.TYPE), { + method: 'POST', + headers: getRequestHeaders(), + cache: 'no-cache', + body: JSON.stringify(data), + signal: new AbortController().signal, + }); + + const json = await response.json(); + if (!response.ok || json.error) { + throw json; + } + + return extractData ? extractMessageFromData(json, this.TYPE) : json; + } + + /** + * @param {string} presetName + * @param {TextCompletionRequest} custom + * @param {boolean?} extractData Extract message from the response. Default true + * @returns {Promise} Extracted data or the raw response + * @throws {Error} + */ + static async sendRequestWithPreset(presetName, custom, extractData = true) { + const presetManager = getPresetManager(this.TYPE); + if (!presetManager) { + throw new Error('Preset manager not found'); + } + + const preset = presetManager.getCompletionPresetByName(presetName); + if (!preset) { + throw new Error('Preset not found'); + } + + const data = this.createRequestData({ ...preset, ...custom }); + + return await this.sendRequest(data, extractData); + } +} + +/** + * Creates & sends a chat completion request. Streaming is not supported. + */ +export class ChatCompletionService { + static TYPE = 'openai'; + + /** + * @param {ChatCompletionPayload} custom + * @returns {ChatCompletionPayload} + */ + static createRequestData({ messages, model, chat_completion_source, max_tokens, temperature, ...props }) { + return { + ...props, + messages, + model, + chat_completion_source, + max_tokens, + temperature, + stream: false, + }; + } + + /** + * Sends a chat completion request + * @param {ChatCompletionPayload} data Request data + * @param {boolean?} extractData Extract message from the response. Default true + * @returns {Promise} Extracted data or the raw response + * @throws {Error} + */ + static async sendRequest(data, extractData = true) { + const response = await fetch('/api/backends/chat-completions/generate', { + method: 'POST', + headers: getRequestHeaders(), + cache: 'no-cache', + body: JSON.stringify(data), + signal: new AbortController().signal, + }); + + const json = await response.json(); + if (!response.ok || json.error) { + throw json; + } + + return extractData ? extractMessageFromData(json, this.TYPE) : json; + } + + /** + * @param {string} presetName + * @param {ChatCompletionPayload} custom + * @param {boolean} extractData Extract message from the response. Default true + * @returns {Promise} Extracted data or the raw response + * @throws {Error} + */ + static async sendRequestWithPreset(presetName, custom, extractData = true) { + const presetManager = getPresetManager(this.TYPE); + if (!presetManager) { + throw new Error('Preset manager not found'); + } + + const preset = presetManager.getCompletionPresetByName(presetName); + if (!preset) { + throw new Error('Preset not found'); + } + + const data = this.createRequestData({ ...preset, ...custom }); + + return await this.sendRequest(data, extractData); + } +} diff --git a/jiuguan2025cc/public/scripts/dragdrop.js b/jiuguan2025cc/public/scripts/dragdrop.js new file mode 100644 index 0000000000000000000000000000000000000000..c73e9e245ba08d1cc53150e44e3819a11e1dec0f --- /dev/null +++ b/jiuguan2025cc/public/scripts/dragdrop.js @@ -0,0 +1,107 @@ +import { debounce_timeout } from './constants.js'; + +/** + * Drag and drop handler + * + * Can be used on any element, enabling drag&drop styling and callback on drop. + */ +export class DragAndDropHandler { + /** @private @type {JQuery.Selector} */ selector; + /** @private @type {(files: File[], event:JQuery.DropEvent) => void} */ onDropCallback; + /** @private @type {NodeJS.Timeout} Remark: Not actually NodeJS timeout, but it's close */ dragLeaveTimeout; + + /** @private @type {boolean} */ noAnimation; + + /** + * Create a DragAndDropHandler + * @param {JQuery.Selector} selector - The CSS selector for the elements to enable drag and drop + * @param {(files: File[], event:JQuery.DropEvent) => void} onDropCallback - The callback function to handle the drop event + */ + constructor(selector, onDropCallback, { noAnimation = false } = {}) { + this.selector = selector; + this.onDropCallback = onDropCallback; + this.dragLeaveTimeout = null; + + this.noAnimation = noAnimation; + + this.init(); + } + + /** + * Destroy the drag and drop functionality + */ + destroy() { + if (this.selector === 'body') { + $(document.body).off('dragover', this.handleDragOver.bind(this)); + $(document.body).off('dragleave', this.handleDragLeave.bind(this)); + $(document.body).off('drop', this.handleDrop.bind(this)); + } else { + $(document.body).off('dragover', this.selector, this.handleDragOver.bind(this)); + $(document.body).off('dragleave', this.selector, this.handleDragLeave.bind(this)); + $(document.body).off('drop', this.selector, this.handleDrop.bind(this)); + } + + $(this.selector).remove('drop_target no_animation'); + } + + /** + * Initialize the drag and drop functionality + * Automatically called on construction + * @private + */ + init() { + if (this.selector === 'body') { + $(document.body).on('dragover', this.handleDragOver.bind(this)); + $(document.body).on('dragleave', this.handleDragLeave.bind(this)); + $(document.body).on('drop', this.handleDrop.bind(this)); + } else { + $(document.body).on('dragover', this.selector, this.handleDragOver.bind(this)); + $(document.body).on('dragleave', this.selector, this.handleDragLeave.bind(this)); + $(document.body).on('drop', this.selector, this.handleDrop.bind(this)); + } + + $(this.selector).addClass('drop_target'); + if (this.noAnimation) $(this.selector).addClass('no_animation'); + } + + /** + * @param {JQuery.DragOverEvent} event - The dragover event + * @private + */ + handleDragOver(event) { + event.preventDefault(); + event.stopPropagation(); + clearTimeout(this.dragLeaveTimeout); + $(this.selector).addClass('drop_target dragover'); + if (this.noAnimation) $(this.selector).addClass('no_animation'); + } + + /** + * @param {JQuery.DragLeaveEvent} event - The dragleave event + * @private + */ + handleDragLeave(event) { + event.preventDefault(); + event.stopPropagation(); + + // Debounce the removal of the class, so it doesn't "flicker" on dragging over + clearTimeout(this.dragLeaveTimeout); + this.dragLeaveTimeout = setTimeout(() => { + $(this.selector).removeClass('dragover'); + }, debounce_timeout.quick); + } + + /** + * @param {JQuery.DropEvent} event - The drop event + * @private + */ + handleDrop(event) { + event.preventDefault(); + event.stopPropagation(); + clearTimeout(this.dragLeaveTimeout); + $(this.selector).removeClass('dragover'); + + const files = Array.from(event.originalEvent.dataTransfer.files); + this.onDropCallback(files, event); + } +} diff --git a/jiuguan2025cc/public/scripts/dynamic-styles.js b/jiuguan2025cc/public/scripts/dynamic-styles.js new file mode 100644 index 0000000000000000000000000000000000000000..ad9a8fbd1bd16238e60d5b77b2b4aae0b77e871d --- /dev/null +++ b/jiuguan2025cc/public/scripts/dynamic-styles.js @@ -0,0 +1,162 @@ +/** @type {CSSStyleSheet} */ +let dynamicStyleSheet = null; +/** @type {CSSStyleSheet} */ +let dynamicExtensionStyleSheet = null; + +/** + * An observer that will check if any new stylesheets are added to the head + * @type {MutationObserver} + */ +const observer = new MutationObserver(mutations => { + mutations.forEach(mutation => { + if (mutation.type !== 'childList') return; + + mutation.addedNodes.forEach(node => { + if (node instanceof HTMLLinkElement && node.tagName === 'LINK' && node.rel === 'stylesheet') { + node.addEventListener('load', () => { + try { + applyDynamicFocusStyles(node.sheet); + } catch (e) { + console.warn('Failed to process new stylesheet:', e); + } + }); + } + }); + }); +}); + +/** + * Generates dynamic focus styles based on the given stylesheet, taking its hover styles as reference + * + * @param {CSSStyleSheet} styleSheet - The stylesheet to process + * @param {object} [options] - Optional configuration options + * @param {boolean} [options.fromExtension=false] - Indicates if the styles are from an extension + */ +function applyDynamicFocusStyles(styleSheet, { fromExtension = false } = {}) { + /** @type {{baseSelector: string, rule: CSSStyleRule}[]} */ + const hoverRules = []; + /** @type {Set} */ + const focusRules = new Set(); + + const PLACEHOLDER = ':__PLACEHOLDER__'; + + /** + * Processes the CSS rules and separates selectors for hover and focus + * @param {CSSRuleList} rules - The CSS rules to process + */ + function processRules(rules) { + Array.from(rules).forEach(rule => { + if (rule instanceof CSSImportRule) { + // Make sure that @import rules are processed recursively + processImportedStylesheet(rule.styleSheet); + } else if (rule instanceof CSSStyleRule) { + // Separate multiple selectors on a rule + const selectors = rule.selectorText.split(',').map(s => s.trim()); + + // We collect all hover and focus rules to be able to later decide which hover rules don't have a matching focus rule + selectors.forEach(selector => { + const isHover = selector.includes(':hover'), isFocus = selector.includes(':focus'); + if (isHover && isFocus) { + // We currently do nothing here. Rules containing both hover and focus are very specific and should never be automatically touched + } + else if (isHover) { + const baseSelector = selector.replace(':hover', PLACEHOLDER).trim(); + hoverRules.push({ baseSelector, rule }); + } else if (isFocus) { + // We need to make sure that we remember all existing :focus, :focus-within and :focus-visible rules + const baseSelector = selector.replace(':focus-within', PLACEHOLDER).replace(':focus-visible', PLACEHOLDER).replace(':focus', PLACEHOLDER).trim(); + focusRules.add(baseSelector); + } + }); + } else if (rule instanceof CSSMediaRule || rule instanceof CSSSupportsRule) { + // Recursively process nested rules + processRules(rule.cssRules); + } + }); + } + + /** + * Processes the CSS rules of an imported stylesheet recursively + * @param {CSSStyleSheet} sheet - The imported stylesheet to process + */ + function processImportedStylesheet(sheet) { + if (sheet && sheet.cssRules) { + processRules(sheet.cssRules); + } + } + + processRules(styleSheet.cssRules); + + /** @type {CSSStyleSheet} */ + let targetStyleSheet = null; + + // Now finally create the dynamic focus rules + hoverRules.forEach(({ baseSelector, rule }) => { + if (!focusRules.has(baseSelector)) { + // Only initialize the dynamic stylesheet if needed + targetStyleSheet ??= getDynamicStyleSheet({ fromExtension }); + + // The closest keyboard-equivalent to :hover styling is utilizing the :focus-visible rule from modern browsers. + // It let's the browser decide whether a focus highlighting is expected and makes sense. + // So we take all :hover rules that don't have a manually defined focus rule yet, and create their + // :focus-visible counterpart, which will make the styling work the same for keyboard and mouse. + // If something like :focus-within or a more specific selector like `.blah:has(:focus-visible)` for elements inside, + // it should be manually defined in CSS. + const focusSelector = rule.selectorText.replace(/:hover/g, ':focus-visible'); + const focusRule = `${focusSelector} { ${rule.style.cssText} }`; + + try { + targetStyleSheet.insertRule(focusRule, targetStyleSheet.cssRules.length); + } catch (e) { + console.warn('Failed to insert focus rule:', e); + } + } + }); +} + +/** + * Retrieves the stylesheet that should be used for dynamic rules + * + * @param {object} options - The options object + * @param {boolean} [options.fromExtension=false] - Indicates whether the rules are coming from extensions + * @return {CSSStyleSheet} The dynamic stylesheet + */ +function getDynamicStyleSheet({ fromExtension = false } = {}) { + if (fromExtension) { + if (!dynamicExtensionStyleSheet) { + const styleSheetElement = document.createElement('style'); + styleSheetElement.setAttribute('id', 'dynamic-extension-styles'); + document.head.appendChild(styleSheetElement); + dynamicExtensionStyleSheet = styleSheetElement.sheet; + } + return dynamicExtensionStyleSheet; + } else { + if (!dynamicStyleSheet) { + const styleSheetElement = document.createElement('style'); + styleSheetElement.setAttribute('id', 'dynamic-styles'); + document.head.appendChild(styleSheetElement); + dynamicStyleSheet = styleSheetElement.sheet; + } + return dynamicStyleSheet; + } +} + +/** + * Initializes dynamic styles for ST + */ +export function initDynamicStyles() { + // Start observing the head for any new added stylesheets + observer.observe(document.head, { + childList: true, + subtree: true, + }); + + // Process all stylesheets on initial load + Array.from(document.styleSheets).forEach(sheet => { + try { + applyDynamicFocusStyles(sheet, { fromExtension: sheet.href?.toLowerCase().includes('scripts/extensions') == true }); + } catch (e) { + console.warn('Failed to process stylesheet on initial load:', e); + } + }); +} diff --git a/jiuguan2025cc/public/scripts/extensions-slashcommands.js b/jiuguan2025cc/public/scripts/extensions-slashcommands.js new file mode 100644 index 0000000000000000000000000000000000000000..f86919823ea091e46197e35044fbe072eb7f74ab --- /dev/null +++ b/jiuguan2025cc/public/scripts/extensions-slashcommands.js @@ -0,0 +1,320 @@ +import { disableExtension, enableExtension, extension_settings, extensionNames } from './extensions.js'; +import { SlashCommand } from './slash-commands/SlashCommand.js'; +import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js'; +import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js'; +import { commonEnumProviders } from './slash-commands/SlashCommandCommonEnumsProvider.js'; +import { enumTypes, SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js'; +import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; +import { equalsIgnoreCaseAndAccents, isFalseBoolean, isTrueBoolean } from './utils.js'; + +/** + * @param {'enable' | 'disable' | 'toggle'} action - The action to perform on the extension + * @returns {(args: {[key: string]: string | SlashCommandClosure}, extensionName: string | SlashCommandClosure) => Promise} + */ +function getExtensionActionCallback(action) { + return async (args, extensionName) => { + if (args?.reload instanceof SlashCommandClosure) throw new Error('\'reload\' argument cannot be a closure.'); + if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); + if (!extensionName) { + toastr.warning(`Extension name must be provided as an argument to ${action} this extension.`); + return ''; + } + + const reload = !isFalseBoolean(args?.reload); + const internalExtensionName = findExtension(extensionName); + if (!internalExtensionName) { + toastr.warning(`Extension ${extensionName} does not exist.`); + return ''; + } + + const isEnabled = !extension_settings.disabledExtensions.includes(internalExtensionName); + + if (action === 'enable' && isEnabled) { + toastr.info(`Extension ${extensionName} is already enabled.`); + return internalExtensionName; + } + + if (action === 'disable' && !isEnabled) { + toastr.info(`Extension ${extensionName} is already disabled.`); + return internalExtensionName; + } + + if (action === 'toggle') { + action = isEnabled ? 'disable' : 'enable'; + } + + if (reload) { + toastr.info(`${action.charAt(0).toUpperCase() + action.slice(1)}ing extension ${extensionName} and reloading...`); + + // Clear input, so it doesn't stay because the command didn't "finish", + // and wait for a bit to both show the toast and let the clear bubble through. + $('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles: true })); + await new Promise(resolve => setTimeout(resolve, 100)); + } + + if (action === 'enable') { + await enableExtension(internalExtensionName, reload); + } else { + await disableExtension(internalExtensionName, reload); + } + + toastr.success(`Extension ${extensionName} ${action}d.`); + + + console.info(`Extension ${action}ed: ${extensionName}`); + if (!reload) { + console.info('Reload not requested, so page needs to be reloaded manually for changes to take effect.'); + } + + return internalExtensionName; + }; +} + +/** + * Finds an extension by name, allowing omission of the "third-party/" prefix. + * + * @param {string} name - The name of the extension to find + * @returns {string?} - The matched extension name or undefined if not found + */ +function findExtension(name) { + return extensionNames.find(extName => { + return equalsIgnoreCaseAndAccents(extName, name) || equalsIgnoreCaseAndAccents(extName, `third-party/${name}`); + }); +} + +/** + * Provides an array of SlashCommandEnumValue objects based on the extension names. + * Each object contains the name of the extension and a description indicating if it is a third-party extension. + * + * @returns {SlashCommandEnumValue[]} An array of SlashCommandEnumValue objects + */ +const extensionNamesEnumProvider = () => extensionNames.map(name => { + const isThirdParty = name.startsWith('third-party/'); + if (isThirdParty) name = name.slice('third-party/'.length); + + const description = isThirdParty ? 'third party extension' : null; + + return new SlashCommandEnumValue(name, description, !isThirdParty ? enumTypes.name : enumTypes.enum); +}); + +export function registerExtensionSlashCommands() { + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'extension-enable', + callback: getExtensionActionCallback('enable'), + returns: 'The internal extension name', + namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'reload', + description: 'Whether to reload the page after enabling the extension', + typeList: [ARGUMENT_TYPE.BOOLEAN], + defaultValue: 'true', + enumList: commonEnumProviders.boolean('trueFalse')(), + }), + ], + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'Extension name', + typeList: [ARGUMENT_TYPE.STRING], + isRequired: true, + enumProvider: extensionNamesEnumProvider, + forceEnum: true, + }), + ], + helpString: ` +
      + Enables a specified extension. +
      +
      + By default, the page will be reloaded automatically, stopping any further commands.
      + If reload=false named argument is passed, the page will not be reloaded, and the extension will stay disabled until refreshed. + The page either needs to be refreshed, or /reload-page has to be called. +
      +
      + Example: +
        +
      • +
        /extension-enable Summarize
        +
      • +
      +
      + `, + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'extension-disable', + callback: getExtensionActionCallback('disable'), + returns: 'The internal extension name', + namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'reload', + description: 'Whether to reload the page after disabling the extension', + typeList: [ARGUMENT_TYPE.BOOLEAN], + defaultValue: 'true', + enumList: commonEnumProviders.boolean('trueFalse')(), + }), + ], + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'Extension name', + typeList: [ARGUMENT_TYPE.STRING], + isRequired: true, + enumProvider: extensionNamesEnumProvider, + forceEnum: true, + }), + ], + helpString: ` +
      + Disables a specified extension. +
      +
      + By default, the page will be reloaded automatically, stopping any further commands.
      + If reload=false named argument is passed, the page will not be reloaded, and the extension will stay enabled until refreshed. + The page either needs to be refreshed, or /reload-page has to be called. +
      +
      + Example: +
        +
      • +
        /extension-disable Summarize
        +
      • +
      +
      + `, + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'extension-toggle', + callback: async (args, extensionName) => { + if (args?.state instanceof SlashCommandClosure) throw new Error('\'state\' argument cannot be a closure.'); + if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); + + const action = isTrueBoolean(args?.state) ? 'enable' : + isFalseBoolean(args?.state) ? 'disable' : + 'toggle'; + + return await getExtensionActionCallback(action)(args, extensionName); + }, + returns: 'The internal extension name', + namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'reload', + description: 'Whether to reload the page after toggling the extension', + typeList: [ARGUMENT_TYPE.BOOLEAN], + defaultValue: 'true', + enumList: commonEnumProviders.boolean('trueFalse')(), + }), + SlashCommandNamedArgument.fromProps({ + name: 'state', + description: 'Explicitly set the state of the extension (true to enable, false to disable). If not provided, the state will be toggled to the opposite of the current state.', + typeList: [ARGUMENT_TYPE.BOOLEAN], + enumList: commonEnumProviders.boolean('trueFalse')(), + }), + ], + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'Extension name', + typeList: [ARGUMENT_TYPE.STRING], + isRequired: true, + enumProvider: extensionNamesEnumProvider, + forceEnum: true, + }), + ], + helpString: ` +
      + Toggles the state of a specified extension. +
      +
      + By default, the page will be reloaded automatically, stopping any further commands.
      + If reload=false named argument is passed, the page will not be reloaded, and the extension will stay in its current state until refreshed. + The page either needs to be refreshed, or /reload-page has to be called. +
      +
      + Example: +
        +
      • +
        /extension-toggle Summarize
        +
      • +
      • +
        /extension-toggle Summarize state=true
        +
      • +
      +
      + `, + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'extension-state', + callback: async (_, extensionName) => { + if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); + const internalExtensionName = findExtension(extensionName); + if (!internalExtensionName) { + toastr.warning(`Extension ${extensionName} does not exist.`); + return ''; + } + + const isEnabled = !extension_settings.disabledExtensions.includes(internalExtensionName); + return String(isEnabled); + }, + returns: 'The state of the extension, whether it is enabled.', + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'Extension name', + typeList: [ARGUMENT_TYPE.STRING], + isRequired: true, + enumProvider: extensionNamesEnumProvider, + forceEnum: true, + }), + ], + helpString: ` +
      + Returns the state of a specified extension (true if enabled, false if disabled). +
      +
      + Example: +
        +
      • +
        /extension-state Summarize
        +
      • +
      +
      + `, + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'extension-exists', + aliases: ['extension-installed'], + callback: async (_, extensionName) => { + if (typeof extensionName !== 'string') throw new Error('Extension name must be a string. Closures or arrays are not allowed.'); + const exists = findExtension(extensionName) !== undefined; + return exists ? 'true' : 'false'; + }, + returns: 'Whether the extension exists and is installed.', + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'Extension name', + typeList: [ARGUMENT_TYPE.STRING], + isRequired: true, + enumProvider: extensionNamesEnumProvider, + }), + ], + helpString: ` +
      + Checks if a specified extension exists. +
      +
      + Example: +
        +
      • +
        /extension-exists SillyTavern-LALib
        +
      • +
      +
      + `, + })); + + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'reload-page', + callback: async () => { + toastr.info('Reloading the page...'); + location.reload(); + return ''; + }, + helpString: 'Reloads the current page. All further commands will not be processed.', + })); +} diff --git a/jiuguan2025cc/public/scripts/extensions.js b/jiuguan2025cc/public/scripts/extensions.js new file mode 100644 index 0000000000000000000000000000000000000000..ff70819d54d9beb8dd8c1ae89c9b4a5a47c670e3 --- /dev/null +++ b/jiuguan2025cc/public/scripts/extensions.js @@ -0,0 +1,1417 @@ +import { DOMPurify, Popper } from '../lib.js'; + +import { eventSource, event_types, saveSettings, saveSettingsDebounced, getRequestHeaders, animation_duration } from '../script.js'; +import { showLoader } from './loader.js'; +import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js'; +import { renderTemplate, renderTemplateAsync } from './templates.js'; +import { delay, isSubsetOf, sanitizeSelector, setValueByPath } from './utils.js'; +import { getContext } from './st-context.js'; +import { isAdmin } from './user.js'; +import { addLocaleData, getCurrentLocale, t } from './i18n.js'; +import { debounce_timeout } from './constants.js'; +import { accountStorage } from './util/AccountStorage.js'; + +export { + getContext, + getApiUrl, +}; + +/** @type {string[]} */ +export let extensionNames = []; + +/** + * Holds the type of each extension. + * Don't use this directly, use getExtensionType instead! + * @type {Record} + */ +export let extensionTypes = {}; + +/** + * A list of active modules provided by the Extras API. + * @type {string[]} + */ +export let modules = []; + +/** + * A set of active extensions. + * @type {Set} + */ +let activeExtensions = new Set(); + +const getApiUrl = () => extension_settings.apiUrl; +const sortManifestsByOrder = (a, b) => parseInt(a.loading_order) - parseInt(b.loading_order) || String(a.display_name).localeCompare(String(b.display_name)); +const sortManifestsByName = (a, b) => String(a.display_name).localeCompare(String(b.display_name)) || parseInt(a.loading_order) - parseInt(b.loading_order); +let connectedToApi = false; + +/** + * Holds manifest data for each extension. + * @type {Record} + */ +let manifests = {}; + +/** + * Default URL for the Extras API. + */ +const defaultUrl = 'http://localhost:5100'; + +let requiresReload = false; +let stateChanged = false; +let saveMetadataTimeout = null; + +export function saveMetadataDebounced() { + const context = getContext(); + const groupId = context.groupId; + const characterId = context.characterId; + + if (saveMetadataTimeout) { + clearTimeout(saveMetadataTimeout); + } + + saveMetadataTimeout = setTimeout(async () => { + const newContext = getContext(); + + if (groupId !== newContext.groupId) { + console.warn('Group changed, not saving metadata'); + return; + } + + if (characterId !== newContext.characterId) { + console.warn('Character changed, not saving metadata'); + return; + } + + console.debug('Saving metadata...'); + await newContext.saveMetadata(); + console.debug('Saved metadata...'); + }, debounce_timeout.relaxed); +} + +/** + * Provides an ability for extensions to render HTML templates synchronously. + * Templates sanitation and localization is forced. + * @param {string} extensionName Extension name + * @param {string} templateId Template ID + * @param {object} templateData Additional data to pass to the template + * @returns {string} Rendered HTML + * + * @deprecated Use renderExtensionTemplateAsync instead. + */ +export function renderExtensionTemplate(extensionName, templateId, templateData = {}, sanitize = true, localize = true) { + return renderTemplate(`scripts/extensions/${extensionName}/${templateId}.html`, templateData, sanitize, localize, true); +} + +/** + * Provides an ability for extensions to render HTML templates asynchronously. + * Templates sanitation and localization is forced. + * @param {string} extensionName Extension name + * @param {string} templateId Template ID + * @param {object} templateData Additional data to pass to the template + * @returns {Promise} Rendered HTML + */ +export function renderExtensionTemplateAsync(extensionName, templateId, templateData = {}, sanitize = true, localize = true) { + return renderTemplateAsync(`scripts/extensions/${extensionName}/${templateId}.html`, templateData, sanitize, localize, true); +} + +// Disables parallel updates +export class ModuleWorkerWrapper { + constructor(callback) { + this.isBusy = false; + this.callback = callback; + } + + // Called by the extension + async update(...args) { + // Don't touch me I'm busy... + if (this.isBusy) { + return; + } + + // I'm free. Let's update! + try { + this.isBusy = true; + await this.callback(...args); + } + finally { + this.isBusy = false; + } + } +} + +export const extension_settings = { + apiUrl: defaultUrl, + apiKey: '', + autoConnect: false, + notifyUpdates: false, + disabledExtensions: [], + expressionOverrides: [], + memory: {}, + note: { + default: '', + chara: [], + wiAddition: [], + }, + caption: { + refine_mode: false, + }, + expressions: { + /** @type {number} see `EXPRESSION_API` */ + api: undefined, + /** @type {string[]} */ + custom: [], + showDefault: false, + translate: false, + /** @type {string} */ + fallback_expression: undefined, + /** @type {string} */ + llmPrompt: undefined, + allowMultiple: true, + rerollIfSame: false, + }, + connectionManager: { + selectedProfile: '', + /** @type {import('./extensions/connection-manager/index.js').ConnectionProfile[]} */ + profiles: [], + }, + dice: {}, + /** @type {import('./char-data.js').RegexScriptData[]} */ + regex: [], + character_allowed_regex: [], + tts: {}, + sd: { + prompts: {}, + character_prompts: {}, + character_negative_prompts: {}, + }, + chromadb: {}, + translate: {}, + objective: {}, + quickReply: {}, + randomizer: { + controls: [], + fluctuation: 0.1, + enabled: false, + }, + speech_recognition: {}, + rvc: {}, + hypebot: {}, + vectors: {}, + variables: { + global: {}, + }, + /** + * @type {import('./chats.js').FileAttachment[]} + */ + attachments: [], + /** + * @type {Record} + */ + character_attachments: {}, + /** + * @type {string[]} + */ + disabled_attachments: [], + gallery: { + /** @type {{[characterKey: string]: string}} */ + folders: {}, + /** @type {string} */ + sort: 'dateAsc', + }, +}; + +function showHideExtensionsMenu() { + // Get the number of menu items that are not hidden + const hasMenuItems = $('#extensionsMenu').children().filter((_, child) => $(child).css('display') !== 'none').length > 0; + + // We have menu items, so we can stop checking + if (hasMenuItems) { + clearInterval(menuInterval); + } + + // Show or hide the menu button + $('#extensionsMenuButton').toggle(hasMenuItems); +} + +// Periodically check for new extensions +const menuInterval = setInterval(showHideExtensionsMenu, 1000); + +/** + * Gets the type of an extension based on its external ID. + * @param {string} externalId External ID of the extension (excluding or including the leading 'third-party/') + * @returns {string} Type of the extension (global, local, system, or empty string if not found) + */ +function getExtensionType(externalId) { + const id = Object.keys(extensionTypes).find(id => id === externalId || (id.startsWith('third-party') && id.endsWith(externalId))); + return id ? extensionTypes[id] : ''; +} + +/** + * Performs a fetch of the Extras API. + * @param {string|URL} endpoint Extras API endpoint + * @param {RequestInit} args Request arguments + * @returns {Promise} Response from the fetch + */ +export async function doExtrasFetch(endpoint, args = {}) { + if (!args) { + args = {}; + } + + if (!args.method) { + Object.assign(args, { method: 'GET' }); + } + + if (!args.headers) { + args.headers = {}; + } + + if (extension_settings.apiKey) { + Object.assign(args.headers, { + 'Authorization': `Bearer ${extension_settings.apiKey}`, + }); + } + + return await fetch(endpoint, args); +} + +/** + * Discovers extensions from the API. + * @returns {Promise<{name: string, type: string}[]>} + */ +async function discoverExtensions() { + try { + const response = await fetch('/api/extensions/discover'); + + if (response.ok) { + const extensions = await response.json(); + return extensions; + } + else { + return []; + } + } + catch (err) { + console.error(err); + return []; + } +} + +function onDisableExtensionClick() { + const name = $(this).data('name'); + disableExtension(name, false); +} + +function onEnableExtensionClick() { + const name = $(this).data('name'); + enableExtension(name, false); +} + +/** + * Enables an extension by name. + * @param {string} name Extension name + * @param {boolean} [reload=true] If true, reload the page after enabling the extension + */ +export async function enableExtension(name, reload = true) { + extension_settings.disabledExtensions = extension_settings.disabledExtensions.filter(x => x !== name); + stateChanged = true; + await saveSettings(); + if (reload) { + location.reload(); + } else { + requiresReload = true; + } +} + +/** + * Disables an extension by name. + * @param {string} name Extension name + * @param {boolean} [reload=true] If true, reload the page after disabling the extension + */ +export async function disableExtension(name, reload = true) { + extension_settings.disabledExtensions.push(name); + stateChanged = true; + await saveSettings(); + if (reload) { + location.reload(); + } else { + requiresReload = true; + } +} + +/** + * Loads manifest.json files for extensions. + * @param {string[]} names Array of extension names + * @returns {Promise>} Object with extension names as keys and their manifests as values + */ +async function getManifests(names) { + const obj = {}; + const promises = []; + + for (const name of names) { + const promise = new Promise((resolve, reject) => { + fetch(`/scripts/extensions/${name}/manifest.json`).then(async response => { + if (response.ok) { + const json = await response.json(); + obj[name] = json; + resolve(); + } else { + reject(); + } + }).catch(err => { + reject(); + console.log('Could not load manifest.json for ' + name, err); + }); + }); + + promises.push(promise); + } + + await Promise.allSettled(promises); + return obj; +} + +/** + * Tries to activate all available extensions that are not already active. + * @returns {Promise} + */ +async function activateExtensions() { + const extensions = Object.entries(manifests).sort((a, b) => sortManifestsByOrder(a[1], b[1])); + const promises = []; + + for (let entry of extensions) { + const name = entry[0]; + const manifest = entry[1]; + + if (activeExtensions.has(name)) { + continue; + } + + const meetsModuleRequirements = !Array.isArray(manifest.requires) || isSubsetOf(modules, manifest.requires); + const isDisabled = extension_settings.disabledExtensions.includes(name); + + if (meetsModuleRequirements && !isDisabled) { + try { + console.debug('Activating extension', name); + const promise = addExtensionLocale(name, manifest).finally(() => Promise.all([addExtensionScript(name, manifest), addExtensionStyle(name, manifest)])); + await promise + .then(() => activeExtensions.add(name)) + .catch(err => console.log('Could not activate extension', name, err)); + promises.push(promise); + } + catch (error) { + console.error('Could not activate extension', name); + console.error(error); + } + } + } + + await Promise.allSettled(promises); +} + +async function connectClickHandler() { + const baseUrl = String($('#extensions_url').val()); + extension_settings.apiUrl = baseUrl; + const testApiKey = $('#extensions_api_key').val(); + extension_settings.apiKey = String(testApiKey); + saveSettingsDebounced(); + await connectToApi(baseUrl); +} + +function autoConnectInputHandler() { + const value = $(this).prop('checked'); + extension_settings.autoConnect = !!value; + + if (value && !connectedToApi) { + $('#extensions_connect').trigger('click'); + } + + saveSettingsDebounced(); +} + +async function addExtensionsButtonAndMenu() { + const buttonHTML = await renderTemplateAsync('wandButton'); + const extensionsMenuHTML = await renderTemplateAsync('wandMenu'); + + $(document.body).append(extensionsMenuHTML); + $('#leftSendForm').append(buttonHTML); + + const button = $('#extensionsMenuButton'); + const dropdown = $('#extensionsMenu'); + let isDropdownVisible = false; + + let popper = Popper.createPopper(button.get(0), dropdown.get(0), { + placement: 'top-start', + }); + + $(button).on('click', function () { + if (isDropdownVisible) { + dropdown.fadeOut(animation_duration); + isDropdownVisible = false; + } else { + dropdown.fadeIn(animation_duration); + isDropdownVisible = true; + } + popper.update(); + }); + + $('html').on('click', function (e) { + if (!isDropdownVisible) return; + const clickTarget = $(e.target); + const noCloseTargets = ['#sd_gen', '#extensionsMenuButton', '#roll_dice']; + if (!noCloseTargets.some(id => clickTarget.closest(id).length > 0)) { + dropdown.fadeOut(animation_duration); + isDropdownVisible = false; + } + }); +} + +function notifyUpdatesInputHandler() { + extension_settings.notifyUpdates = !!$('#extensions_notify_updates').prop('checked'); + saveSettingsDebounced(); + + if (extension_settings.notifyUpdates) { + checkForExtensionUpdates(true); + } +} + +/** + * Connects to the Extras API. + * @param {string} baseUrl Extras API base URL + * @returns {Promise} + */ +async function connectToApi(baseUrl) { + if (!baseUrl) { + return; + } + + const url = new URL(baseUrl); + url.pathname = '/api/modules'; + + try { + const getExtensionsResult = await doExtrasFetch(url); + + if (getExtensionsResult.ok) { + const data = await getExtensionsResult.json(); + modules = data.modules; + await activateExtensions(); + await eventSource.emit(event_types.EXTRAS_CONNECTED, modules); + } + + updateStatus(getExtensionsResult.ok); + } + catch { + updateStatus(false); + } +} + +/** + * Updates the status of Extras API connection. + * @param {boolean} success Whether the connection was successful + */ +function updateStatus(success) { + connectedToApi = success; + const _text = success ? t`Connected to API` : t`Could not connect to API`; + const _class = success ? 'success' : 'failure'; + $('#extensions_status').text(_text); + $('#extensions_status').attr('class', _class); +} + +/** + * Adds a CSS file for an extension. + * @param {string} name Extension name + * @param {object} manifest Extension manifest + * @returns {Promise} When the CSS is loaded + */ +function addExtensionStyle(name, manifest) { + if (!manifest.css) { + return Promise.resolve(); + } + + return new Promise((resolve, reject) => { + const url = `/scripts/extensions/${name}/${manifest.css}`; + const id = sanitizeSelector(`${name}-css`); + + if ($(`link[id="${id}"]`).length === 0) { + const link = document.createElement('link'); + link.id = id; + link.rel = 'stylesheet'; + link.type = 'text/css'; + link.href = url; + link.onload = function () { + resolve(); + }; + link.onerror = function (e) { + reject(e); + }; + document.head.appendChild(link); + } + }); +} + +/** + * Loads a JS file for an extension. + * @param {string} name Extension name + * @param {object} manifest Extension manifest + * @returns {Promise} When the script is loaded + */ +function addExtensionScript(name, manifest) { + if (!manifest.js) { + return Promise.resolve(); + } + + return new Promise((resolve, reject) => { + const url = `/scripts/extensions/${name}/${manifest.js}`; + const id = sanitizeSelector(`${name}-js`); + let ready = false; + + if ($(`script[id="${id}"]`).length === 0) { + const script = document.createElement('script'); + script.id = id; + script.type = 'module'; + script.src = url; + script.async = true; + script.onerror = function (err) { + reject(err); + }; + script.onload = function () { + if (!ready) { + ready = true; + resolve(); + } + }; + document.body.appendChild(script); + } + }); +} + +/** + * Adds a localization data for an extension. + * @param {string} name Extension name + * @param {object} manifest Manifest object + */ +function addExtensionLocale(name, manifest) { + // No i18n data in the manifest + if (!manifest.i18n || typeof manifest.i18n !== 'object') { + return Promise.resolve(); + } + + const currentLocale = getCurrentLocale(); + const localeFile = manifest.i18n[currentLocale]; + + // Manifest doesn't provide a locale file for the current locale + if (!localeFile) { + return Promise.resolve(); + } + + return fetch(`/scripts/extensions/${name}/${localeFile}`) + .then(async response => { + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + const data = await response.json(); + + if (data && typeof data === 'object') { + addLocaleData(currentLocale, data); + } + }) + .catch(err => { + console.log('Could not load extension locale data for ' + name, err); + }); +} + +/** + * Generates HTML string for displaying an extension in the UI. + * + * @param {string} name - The name of the extension. + * @param {object} manifest - The manifest of the extension. + * @param {boolean} isActive - Whether the extension is active or not. + * @param {boolean} isDisabled - Whether the extension is disabled or not. + * @param {boolean} isExternal - Whether the extension is external or not. + * @param {string} checkboxClass - The class for the checkbox HTML element. + * @return {string} - The HTML string that represents the extension. + */ +function generateExtensionHtml(name, manifest, isActive, isDisabled, isExternal, checkboxClass) { + function getExtensionIcon() { + const type = getExtensionType(name); + switch (type) { + case 'global': + return ''; + case 'local': + return ''; + case 'system': + return ''; + default: + return ''; + } + } + + const isUserAdmin = isAdmin(); + const extensionIcon = getExtensionIcon(); + const displayName = manifest.display_name; + const displayVersion = manifest.version || ''; + const externalId = name.replace('third-party', ''); + let originHtml = ''; + if (isExternal) { + originHtml = ''; + } + + let toggleElement = isActive || isDisabled ? + '` : + ``; + + let deleteButton = isExternal ? `` : ''; + let updateButton = isExternal ? `` : ''; + let moveButton = isExternal && isUserAdmin ? `` : ''; + let modulesInfo = ''; + + if (isActive && Array.isArray(manifest.optional)) { + const optional = new Set(manifest.optional); + modules.forEach(x => optional.delete(x)); + if (optional.size > 0) { + const optionalString = DOMPurify.sanitize([...optional].join(', ')); + modulesInfo = '
      ' + t`Optional modules:` + ` ${optionalString}
      `; + } + } else if (!isDisabled) { // Neither active nor disabled + const requirements = new Set(manifest.requires); + modules.forEach(x => requirements.delete(x)); + if (requirements.size > 0) { + const requirementsString = DOMPurify.sanitize([...requirements].join(', ')); + modulesInfo = `
      Missing modules: ${requirementsString}
      `; + } + } + + // if external, wrap the name in a link to the repo + + let extensionHtml = ` +
      `; + + return extensionHtml; +} + +/** + * Gets extension data and generates the corresponding HTML for displaying the extension. + * + * @param {Array} extension - An array where the first element is the extension name and the second element is the extension manifest. + * @return {object} - An object with 'isExternal' indicating whether the extension is external, and 'extensionHtml' for the extension's HTML string. + */ +function getExtensionData(extension) { + const name = extension[0]; + const manifest = extension[1]; + const isActive = activeExtensions.has(name); + const isDisabled = extension_settings.disabledExtensions.includes(name); + const isExternal = name.startsWith('third-party'); + + const checkboxClass = isDisabled ? 'checkbox_disabled' : ''; + + const extensionHtml = generateExtensionHtml(name, manifest, isActive, isDisabled, isExternal, checkboxClass); + + return { isExternal, extensionHtml }; +} + + +/** + * Gets the module information to be displayed. + * + * @return {string} - The HTML string for the module information. + */ +function getModuleInformation() { + let moduleInfo = modules.length ? `

      ${DOMPurify.sanitize(modules.join(', '))}

      ` : '

      ' + t`Not connected to the API!` + '

      '; + return ` +

      ` + t`Modules provided by your Extras API:` + `

      + ${moduleInfo} + `; +} + +/** + * Generates the HTML strings for all extensions and displays them in a popup. + */ +async function showExtensionsDetails() { + const abortController = new AbortController(); + let popupPromise; + try { + // If we are updating an extension, the "old" popup is still active. We should close that. + let initialScrollTop = 0; + const oldPopup = Popup.util.popups.find(popup => popup.content.querySelector('.extensions_info')); + if (oldPopup) { + initialScrollTop = oldPopup.content.scrollTop; + await oldPopup.completeCancelled(); + } + const htmlDefault = $('

      ' + t`Built-in Extensions:` + '

      '); + const htmlExternal = $('

      ' + t`Installed Extensions:` + '

      '); + const htmlLoading = $(`
      + + ` + t`Loading third-party extensions... Please wait...` + ` +
      `); + + htmlExternal.append(htmlLoading); + + const sortOrderKey = 'extensions_sortByName'; + const sortByName = accountStorage.getItem(sortOrderKey) === 'true'; + const sortFn = sortByName ? sortManifestsByName : sortManifestsByOrder; + const extensions = Object.entries(manifests).sort((a, b) => sortFn(a[1], b[1])).map(getExtensionData); + + extensions.forEach(value => { + const { isExternal, extensionHtml } = value; + const container = isExternal ? htmlExternal : htmlDefault; + container.append(extensionHtml); + }); + + const html = $('
      ') + .addClass('extensions_info') + .append(htmlDefault) + .append(htmlExternal) + .append(getModuleInformation()); + + /** @type {import('./popup.js').CustomPopupButton} */ + const updateAllButton = { + text: t`Update all`, + action: async () => { + requiresReload = true; + await autoUpdateExtensions(true); + await popup.complete(POPUP_RESULT.AFFIRMATIVE); + }, + }; + + /** @type {import('./popup.js').CustomPopupButton} */ + const sortOrderButton = { + text: sortByName ? t`Sort: Display Name` : t`Sort: Loading Order`, + action: async () => { + abortController.abort(); + accountStorage.setItem(sortOrderKey, sortByName ? 'false' : 'true'); + await showExtensionsDetails(); + }, + }; + + let waitingForSave = false; + + const popup = new Popup(html, POPUP_TYPE.TEXT, '', { + okButton: t`Close`, + wide: true, + large: true, + customButtons: [sortOrderButton, updateAllButton], + allowVerticalScrolling: true, + onClosing: async () => { + if (waitingForSave) { + return false; + } + if (stateChanged) { + waitingForSave = true; + const toast = toastr.info(t`The page will be reloaded shortly...`, t`Extensions state changed`); + await saveSettings(); + toastr.clear(toast); + waitingForSave = false; + requiresReload = true; + } + return true; + }, + }); + popupPromise = popup.show(); + popup.content.scrollTop = initialScrollTop; + checkForUpdatesManual(sortFn, abortController.signal).finally(() => htmlLoading.remove()); + } catch (error) { + toastr.error(t`Error loading extensions. See browser console for details.`); + console.error(error); + } + if (popupPromise) { + await popupPromise; + abortController.abort(); + } + if (requiresReload) { + showLoader(); + location.reload(); + } +} + +/** + * Handles the click event for the update button of an extension. + * This function makes a POST request to '/api/extensions/update' with the extension's name. + * If the extension is already up to date, it displays a success message. + * If the extension is not up to date, it updates the extension and displays a success message with the new commit hash. + */ +async function onUpdateClick() { + const isCurrentUserAdmin = isAdmin(); + const extensionName = $(this).data('name'); + const isGlobal = getExtensionType(extensionName) === 'global'; + if (isGlobal && !isCurrentUserAdmin) { + toastr.error(t`You don't have permission to update global extensions.`); + return; + } + + const icon = $(this).find('i'); + icon.addClass('fa-spin'); + await updateExtension(extensionName, false); + // updateExtension eats the error, but we can at least stop the spinner + icon.removeClass('fa-spin'); +} + +/** + * Updates a third-party extension via the API. + * @param {string} extensionName Extension folder name + * @param {boolean} quiet If true, don't show a success message + */ +async function updateExtension(extensionName, quiet) { + try { + const response = await fetch('/api/extensions/update', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + extensionName, + global: getExtensionType(extensionName) === 'global', + }), + }); + + if (!response.ok) { + const text = await response.text(); + toastr.error(text || response.statusText, t`Extension update failed`, { timeOut: 5000 }); + console.error('Extension update failed', response.status, response.statusText, text); + return; + } + + const data = await response.json(); + + if (!quiet) { + void showExtensionsDetails(); + } + + if (data.isUpToDate) { + if (!quiet) { + toastr.success('Extension is already up to date'); + } + } else { + toastr.success(t`Extension ${extensionName} updated to ${data.shortCommitHash}`, t`Reload the page to apply updates`); + } + } catch (error) { + console.error('Error:', error); + } +} + +/** + * Handles the click event for the delete button of an extension. + * This function makes a POST request to '/api/extensions/delete' with the extension's name. + * If the extension is deleted, it displays a success message. + * Creates a popup for the user to confirm before delete. + */ +async function onDeleteClick() { + const extensionName = $(this).data('name'); + const isCurrentUserAdmin = isAdmin(); + const isGlobal = getExtensionType(extensionName) === 'global'; + if (isGlobal && !isCurrentUserAdmin) { + toastr.error(t`You don't have permission to delete global extensions.`); + return; + } + + // use callPopup to create a popup for the user to confirm before delete + const confirmation = await callGenericPopup(t`Are you sure you want to delete ${extensionName}?`, POPUP_TYPE.CONFIRM, '', {}); + if (confirmation === POPUP_RESULT.AFFIRMATIVE) { + await deleteExtension(extensionName); + } +} + +async function onMoveClick() { + const extensionName = $(this).data('name'); + const isCurrentUserAdmin = isAdmin(); + const isGlobal = getExtensionType(extensionName) === 'global'; + if (isGlobal && !isCurrentUserAdmin) { + toastr.error(t`You don't have permission to move extensions.`); + return; + } + + const source = getExtensionType(extensionName); + const destination = source === 'global' ? 'local' : 'global'; + + const confirmationHeader = t`Move extension`; + const confirmationText = source == 'global' + ? t`Are you sure you want to move ${extensionName} to your local extensions? This will make it available only for you.` + : t`Are you sure you want to move ${extensionName} to the global extensions? This will make it available for all users.`; + + const confirmation = await Popup.show.confirm(confirmationHeader, confirmationText); + + if (!confirmation) { + return; + } + + $(this).find('i').addClass('fa-spin'); + await moveExtension(extensionName, source, destination); +} + +/** + * Moves an extension via the API. + * @param {string} extensionName Extension name + * @param {string} source Source type + * @param {string} destination Destination type + * @returns {Promise} + */ +async function moveExtension(extensionName, source, destination) { + try { + const result = await fetch('/api/extensions/move', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + extensionName, + source, + destination, + }), + }); + + if (!result.ok) { + const text = await result.text(); + toastr.error(text || result.statusText, t`Extension move failed`, { timeOut: 5000 }); + console.error('Extension move failed', result.status, result.statusText, text); + return; + } + + toastr.success(t`Extension ${extensionName} moved.`); + await loadExtensionSettings({}, false, false); + void showExtensionsDetails(); + } catch (error) { + console.error('Error:', error); + } +} + +/** + * Deletes an extension via the API. + * @param {string} extensionName Extension name to delete + */ +export async function deleteExtension(extensionName) { + try { + await fetch('/api/extensions/delete', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + extensionName, + global: getExtensionType(extensionName) === 'global', + }), + }); + } catch (error) { + console.error('Error:', error); + } + + toastr.success(t`Extension ${extensionName} deleted`); + delay(1000).then(() => location.reload()); +} + +/** + * Fetches the version details of a specific extension. + * + * @param {string} extensionName - The name of the extension. + * @param {AbortSignal} [abortSignal] - The signal to abort the operation. + * @return {Promise} - An object containing the extension's version details. + * This object includes the currentBranchName, currentCommitHash, isUpToDate, and remoteUrl. + * @throws {error} - If there is an error during the fetch operation, it logs the error to the console. + */ +async function getExtensionVersion(extensionName, abortSignal) { + try { + const response = await fetch('/api/extensions/version', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + extensionName, + global: getExtensionType(extensionName) === 'global', + }), + signal: abortSignal, + }); + + const data = await response.json(); + return data; + } catch (error) { + console.error('Error:', error); + } +} + +/** + * Installs a third-party extension via the API. + * @param {string} url Extension repository URL + * @param {boolean} global Is the extension global? + * @returns {Promise} + */ +export async function installExtension(url, global) { + console.debug('Extension installation started', url); + + toastr.info(t`Please wait...`, t`Installing extension`); + + const request = await fetch('/api/extensions/install', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + url, + global, + }), + }); + + if (!request.ok) { + const text = await request.text(); + toastr.warning(text || request.statusText, t`Extension installation failed`, { timeOut: 5000 }); + console.error('Extension installation failed', request.status, request.statusText, text); + return; + } + + const response = await request.json(); + toastr.success(t`Extension '${response.display_name}' by ${response.author} (version ${response.version}) has been installed successfully!`, t`Extension installation successful`); + console.debug(`Extension "${response.display_name}" has been installed successfully at ${response.extensionPath}`); + await loadExtensionSettings({}, false, false); + await eventSource.emit(event_types.EXTENSION_SETTINGS_LOADED, response); +} + +/** + * Loads extension settings from the app settings. + * @param {object} settings App Settings + * @param {boolean} versionChanged Is this a version change? + * @param {boolean} enableAutoUpdate Enable auto-update + */ +export async function loadExtensionSettings(settings, versionChanged, enableAutoUpdate) { + if (settings.extension_settings) { + Object.assign(extension_settings, settings.extension_settings); + } + + $('#extensions_url').val(extension_settings.apiUrl); + $('#extensions_api_key').val(extension_settings.apiKey); + $('#extensions_autoconnect').prop('checked', extension_settings.autoConnect); + $('#extensions_notify_updates').prop('checked', extension_settings.notifyUpdates); + + // Activate offline extensions + await eventSource.emit(event_types.EXTENSIONS_FIRST_LOAD); + const extensions = await discoverExtensions(); + extensionNames = extensions.map(x => x.name); + extensionTypes = Object.fromEntries(extensions.map(x => [x.name, x.type])); + manifests = await getManifests(extensionNames); + + if (versionChanged && enableAutoUpdate) { + await autoUpdateExtensions(false); + } + + await activateExtensions(); + if (extension_settings.autoConnect && extension_settings.apiUrl) { + connectToApi(extension_settings.apiUrl); + } +} + +export function doDailyExtensionUpdatesCheck() { + setTimeout(() => { + if (extension_settings.notifyUpdates) { + checkForExtensionUpdates(false); + } + }, 1); +} + +const concurrencyLimit = 5; +let activeRequestsCount = 0; +const versionCheckQueue = []; + +function enqueueVersionCheck(fn) { + return new Promise((resolve, reject) => { + versionCheckQueue.push(() => fn().then(resolve).catch(reject)); + processVersionCheckQueue(); + }); +} + +function processVersionCheckQueue() { + if (activeRequestsCount >= concurrencyLimit || versionCheckQueue.length === 0) { + return; + } + activeRequestsCount++; + const fn = versionCheckQueue.shift(); + fn().finally(() => { + activeRequestsCount--; + processVersionCheckQueue(); + }); +} + +/** + * Performs a manual check for updates on all 3rd-party extensions. + * @param {function} sortFn Sort function + * @param {AbortSignal} abortSignal Signal to abort the operation + * @returns {Promise} + */ +async function checkForUpdatesManual(sortFn, abortSignal) { + const promises = []; + for (const id of Object.keys(manifests).filter(x => x.startsWith('third-party')).sort((a, b) => sortFn(manifests[a], manifests[b]))) { + const externalId = id.replace('third-party', ''); + const promise = enqueueVersionCheck(async () => { + try { + const data = await getExtensionVersion(externalId, abortSignal); + const extensionBlock = document.querySelector(`.extension_block[data-name="${externalId}"]`); + if (extensionBlock && data) { + if (data.isUpToDate === false) { + const buttonElement = extensionBlock.querySelector('.btn_update'); + if (buttonElement) { + buttonElement.classList.remove('displayNone'); + } + const nameElement = extensionBlock.querySelector('.extension_name'); + if (nameElement) { + nameElement.classList.add('update_available'); + } + } + let branch = data.currentBranchName; + let commitHash = data.currentCommitHash; + let origin = data.remoteUrl; + + const originLink = extensionBlock.querySelector('a'); + if (originLink) { + try { + const url = new URL(origin); + if (!['https:', 'http:'].includes(url.protocol)) { + throw new Error('Invalid protocol'); + } + originLink.href = url.href; + originLink.target = '_blank'; + originLink.rel = 'noopener noreferrer'; + } catch (error) { + console.log('Error setting origin link', originLink, error); + } + } + + const versionElement = extensionBlock.querySelector('.extension_version'); + if (versionElement) { + versionElement.textContent += ` (${branch}-${commitHash.substring(0, 7)})`; + } + } + } catch (error) { + console.error('Error checking for extension updates', error); + } + }); + promises.push(promise); + } + return Promise.allSettled(promises); +} + +/** + * Checks if there are updates available for 3rd-party extensions. + * @param {boolean} force Skip nag check + * @returns {Promise} + */ +async function checkForExtensionUpdates(force) { + if (!force) { + const STORAGE_NAG_KEY = 'extension_update_nag'; + const currentDate = new Date().toDateString(); + + // Don't nag more than once a day + if (accountStorage.getItem(STORAGE_NAG_KEY) === currentDate) { + return; + } + + accountStorage.setItem(STORAGE_NAG_KEY, currentDate); + } + + const isCurrentUserAdmin = isAdmin(); + const updatesAvailable = []; + const promises = []; + + for (const [id, manifest] of Object.entries(manifests)) { + const isGlobal = getExtensionType(id) === 'global'; + if (isGlobal && !isCurrentUserAdmin) { + console.debug(`Skipping global extension: ${manifest.display_name} (${id}) for non-admin user`); + continue; + } + + if (manifest.auto_update && id.startsWith('third-party')) { + const promise = enqueueVersionCheck(async () => { + try { + const data = await getExtensionVersion(id.replace('third-party', '')); + if (!data.isUpToDate) { + updatesAvailable.push(manifest.display_name); + } + } catch (error) { + console.error('Error checking for extension updates', error); + } + }); + promises.push(promise); + } + } + + await Promise.allSettled(promises); + + if (updatesAvailable.length > 0) { + toastr.info(`${updatesAvailable.map(x => `• ${x}`).join('\n')}`, t`Extension updates available`); + } +} + +/** + * Updates all 3rd-party extensions that have auto-update enabled. + * @param {boolean} forceAll Force update all even if not auto-updating + * @returns {Promise} + */ +async function autoUpdateExtensions(forceAll) { + if (!Object.values(manifests).some(x => x.auto_update)) { + return; + } + + const banner = toastr.info(t`Auto-updating extensions. This may take several minutes.`, t`Please wait...`, { timeOut: 10000, extendedTimeOut: 10000 }); + const isCurrentUserAdmin = isAdmin(); + const promises = []; + for (const [id, manifest] of Object.entries(manifests)) { + const isGlobal = getExtensionType(id) === 'global'; + if (isGlobal && !isCurrentUserAdmin) { + console.debug(`Skipping global extension: ${manifest.display_name} (${id}) for non-admin user`); + continue; + } + if ((forceAll || manifest.auto_update) && id.startsWith('third-party')) { + console.debug(`Auto-updating 3rd-party extension: ${manifest.display_name} (${id})`); + promises.push(updateExtension(id.replace('third-party', ''), true)); + } + } + await Promise.allSettled(promises); + toastr.clear(banner); +} + +/** + * Runs the generate interceptors for all extensions. + * @param {any[]} chat Chat array + * @param {number} contextSize Context size + * @param {string} type Generation type + * @returns {Promise} True if generation should be aborted + */ +export async function runGenerationInterceptors(chat, contextSize, type) { + let aborted = false; + let exitImmediately = false; + + const abort = (/** @type {boolean} */ immediately) => { + aborted = true; + exitImmediately = immediately; + }; + + for (const manifest of Object.values(manifests).filter(x => x.generate_interceptor).sort((a, b) => sortManifestsByOrder(a, b))) { + const interceptorKey = manifest.generate_interceptor; + if (typeof globalThis[interceptorKey] === 'function') { + try { + await globalThis[interceptorKey](chat, contextSize, abort, type); + } catch (e) { + console.error(`Failed running interceptor for ${manifest.display_name}`, e); + } + } + + if (exitImmediately) { + break; + } + } + + return aborted; +} + +/** + * Writes a field to the character's data extensions object. + * @param {number} characterId Index in the character array + * @param {string} key Field name + * @param {any} value Field value + * @returns {Promise} When the field is written + */ +export async function writeExtensionField(characterId, key, value) { + const context = getContext(); + const character = context.characters[characterId]; + if (!character) { + console.warn('Character not found', characterId); + return; + } + const path = `data.extensions.${key}`; + setValueByPath(character, path, value); + + // Process JSON data + if (character.json_data) { + const jsonData = JSON.parse(character.json_data); + setValueByPath(jsonData, path, value); + character.json_data = JSON.stringify(jsonData); + + // Make sure the data doesn't get lost when saving the current character + if (Number(characterId) === Number(context.characterId)) { + $('#character_json_data').val(character.json_data); + } + } + + // Save data to the server + const saveDataRequest = { + avatar: character.avatar, + data: { + extensions: { + [key]: value, + }, + }, + }; + const mergeResponse = await fetch('/api/characters/merge-attributes', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify(saveDataRequest), + }); + + if (!mergeResponse.ok) { + console.error('Failed to save extension field', mergeResponse.statusText); + } +} + +/** + * Prompts the user to enter the Git URL of the extension to import. + * After obtaining the Git URL, makes a POST request to '/api/extensions/install' to import the extension. + * If the extension is imported successfully, a success message is displayed. + * If the extension import fails, an error message is displayed and the error is logged to the console. + * After successfully importing the extension, the extension settings are reloaded and a 'EXTENSION_SETTINGS_LOADED' event is emitted. + * @param {string} [suggestUrl] Suggested URL to install + * @returns {Promise} + */ +export async function openThirdPartyExtensionMenu(suggestUrl = '') { + const isCurrentUserAdmin = isAdmin(); + const html = await renderTemplateAsync('installExtension', { isCurrentUserAdmin }); + const okButton = isCurrentUserAdmin ? t`Install just for me` : t`Install`; + + let global = false; + const installForAllButton = { + text: t`Install for all users`, + appendAtEnd: false, + action: async () => { + global = true; + await popup.complete(POPUP_RESULT.AFFIRMATIVE); + }, + }; + + const customButtons = isCurrentUserAdmin ? [installForAllButton] : []; + const popup = new Popup(html, POPUP_TYPE.INPUT, suggestUrl ?? '', { okButton, customButtons }); + const input = await popup.show(); + + if (!input) { + console.debug('Extension install cancelled'); + return; + } + + const url = String(input).trim(); + await installExtension(url, global); +} + +export async function initExtensions() { + await addExtensionsButtonAndMenu(); + $('#extensionsMenuButton').css('display', 'flex'); + + $('#extensions_connect').on('click', connectClickHandler); + $('#extensions_autoconnect').on('input', autoConnectInputHandler); + $('#extensions_details').on('click', showExtensionsDetails); + $('#extensions_notify_updates').on('input', notifyUpdatesInputHandler); + $(document).on('click', '.extensions_info .extension_block .toggle_disable', onDisableExtensionClick); + $(document).on('click', '.extensions_info .extension_block .toggle_enable', onEnableExtensionClick); + $(document).on('click', '.extensions_info .extension_block .btn_update', onUpdateClick); + $(document).on('click', '.extensions_info .extension_block .btn_delete', onDeleteClick); + $(document).on('click', '.extensions_info .extension_block .btn_move', onMoveClick); + + /** + * Handles the click event for the third-party extension import button. + * + * @listens #third_party_extension_button#click - The click event of the '#third_party_extension_button' element. + */ + $('#third_party_extension_button').on('click', () => openThirdPartyExtensionMenu()); +} diff --git a/jiuguan2025cc/public/scripts/extensions/assets/character.html b/jiuguan2025cc/public/scripts/extensions/assets/character.html new file mode 100644 index 0000000000000000000000000000000000000000..e59889161840d08706bfe92279a5678ab2bda3c2 --- /dev/null +++ b/jiuguan2025cc/public/scripts/extensions/assets/character.html @@ -0,0 +1,9 @@ +
      +
      {{name}}
      + {{name}} +
      {{description}}
      +
      +
      +
      +
      +
      diff --git a/jiuguan2025cc/public/scripts/extensions/assets/index.js b/jiuguan2025cc/public/scripts/extensions/assets/index.js new file mode 100644 index 0000000000000000000000000000000000000000..f50cca3148dee85029c4fce3ebbaa11fb120ca35 --- /dev/null +++ b/jiuguan2025cc/public/scripts/extensions/assets/index.js @@ -0,0 +1,472 @@ +/* +TODO: +*/ +//const DEBUG_TONY_SAMA_FORK_MODE = true + +import { DOMPurify } from '../../../lib.js'; +import { getRequestHeaders, processDroppedFiles, eventSource, event_types } from '../../../script.js'; +import { deleteExtension, extensionNames, getContext, installExtension, renderExtensionTemplateAsync } from '../../extensions.js'; +import { POPUP_TYPE, Popup, callGenericPopup } from '../../popup.js'; +import { executeSlashCommands } from '../../slash-commands.js'; +import { accountStorage } from '../../util/AccountStorage.js'; +import { flashHighlight, getStringHash, isValidUrl } from '../../utils.js'; +import { t } from '../../i18n.js'; +export { MODULE_NAME }; + +const MODULE_NAME = 'assets'; +const DEBUG_PREFIX = ' '; +let previewAudio = null; +let ASSETS_JSON_URL = 'https://raw.githubusercontent.com/SillyTavern/SillyTavern-Content/main/index.json'; + + +// DBG +//if (DEBUG_TONY_SAMA_FORK_MODE) +// ASSETS_JSON_URL = "https://raw.githubusercontent.com/Tony-sama/SillyTavern-Content/main/index.json" +let availableAssets = {}; +let currentAssets = {}; + +//#############################// +// Extension UI and Settings // +//#############################// + +function filterAssets() { + const searchValue = String($('#assets_search').val()).toLowerCase().trim(); + const typeValue = String($('#assets_type_select').val()); + + if (typeValue === '') { + $('#assets_menu .assets-list-div').show(); + $('#assets_menu .assets-list-div h3').show(); + } else { + $('#assets_menu .assets-list-div h3').hide(); + $('#assets_menu .assets-list-div').hide(); + $(`#assets_menu .assets-list-div[data-type="${typeValue}"]`).show(); + } + + if (searchValue === '') { + $('#assets_menu .asset-block').show(); + } else { + $('#assets_menu .asset-block').hide(); + $('#assets_menu .asset-block').filter(function () { + return $(this).text().toLowerCase().includes(searchValue); + }).show(); + } +} + +const KNOWN_TYPES = { + 'extension': 'Extensions', + 'character': 'Characters', + 'ambient': 'Ambient sounds', + 'bgm': 'Background music', + 'blip': 'Blip sounds', +}; + +async function downloadAssetsList(url) { + updateCurrentAssets().then(async function () { + fetch(url, { cache: 'no-cache' }) + .then(response => response.json()) + .then(async function(json) { + + availableAssets = {}; + $('#assets_menu').empty(); + + console.debug(DEBUG_PREFIX, 'Received assets dictionary', json); + + for (const i of json) { + //console.log(DEBUG_PREFIX,i) + if (availableAssets[i['type']] === undefined) + availableAssets[i['type']] = []; + + availableAssets[i['type']].push(i); + } + + console.debug(DEBUG_PREFIX, 'Updated available assets to', availableAssets); + // First extensions, then everything else + const assetTypes = Object.keys(availableAssets).sort((a, b) => (a === 'extension') ? -1 : (b === 'extension') ? 1 : 0); + + $('#assets_type_select').empty(); + $('#assets_search').val(''); + $('#assets_type_select').append($('