diff --git a/.devcontainer/postCreateCommand.sh b/.devcontainer/postCreateCommand.sh index dd613dbe..a59fbfbf 100755 --- a/.devcontainer/postCreateCommand.sh +++ b/.devcontainer/postCreateCommand.sh @@ -1,5 +1,16 @@ #!/bin/sh +export PATH="$PATH:$HOME/.composer/vendor/bin" +export PATH="$PATH:$PWD/vendor/bin" +echo 'export PATH="$PATH:$HOME/.composer/vendor/bin"' >> ~/.bashrc +echo 'export PATH="$PATH:$PWD/vendor/bin"' >> ~/.bashrc +ln -s ./conf.sample.php cfg/conf.php composer install --no-dev --optimize-autoloader + +# for PHP unit testing +# composer require google/cloud-storage +# composer install --optimize-autoloader + sudo chmod a+x "$(pwd)" && sudo rm -rf /var/www/html && sudo ln -s "$(pwd)" /var/www/html + npm install --global nyc diff --git a/.gitattributes b/.gitattributes index 28fc0f26..9073910f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -26,8 +26,6 @@ js/test/ export-ignore .vscode export-ignore codacy-analysis.yml export-ignore crowdin.yml export-ignore -composer.json export-ignore -composer.lock export-ignore BADGES.md export-ignore CODE_OF_CONDUCT.md export-ignore Makefile export-ignore diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index ac6143c7..25c8d787 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -33,7 +33,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7847c9c9..bb396de5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Fetch changelog from tag - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: sparse-checkout: CHANGELOG.md sparse-checkout-cone-mode: false @@ -43,7 +43,7 @@ jobs: actions: read id-token: write contents: write - uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.9.0 + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0 with: base64-subjects: "${{ needs.release.outputs.hashes }}" draft-release: true diff --git a/.github/workflows/snyk-scan.yml b/.github/workflows/snyk-scan.yml index 29bc2b45..851211f2 100644 --- a/.github/workflows/snyk-scan.yml +++ b/.github/workflows/snyk-scan.yml @@ -12,8 +12,14 @@ jobs: # https://github.com/snyk/actions/tree/master/php snyk-php: runs-on: ubuntu-latest + if: | + github.repository == 'PrivateBin/PrivateBin' && ( + github.event.pull_request.author_association == 'COLLABORATOR' || + github.event.pull_request.author_association == 'CONTRIBUTOR' || + github.event.pull_request.author_association == 'MEMBER' || + github.event.pull_request.author_association == 'OWNER' ) steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install Google Cloud Storage run: composer require --no-update google/cloud-storage && composer update --no-dev - name: Run Snyk to check for vulnerabilities diff --git a/.github/workflows/test-results.yml b/.github/workflows/test-results.yml new file mode 100644 index 00000000..2a315b7a --- /dev/null +++ b/.github/workflows/test-results.yml @@ -0,0 +1,38 @@ +name: Test Results + +on: + workflow_run: + workflows: ["Tests"] + types: + - completed +permissions: {} + +jobs: + test-results: + name: Test Results + runs-on: ubuntu-latest + if: github.event.workflow_run.conclusion != 'skipped' + + permissions: + checks: write + + # needed unless run with comment_mode: off + pull-requests: write + + # required by download step to access artifacts API + actions: read + + steps: + - name: Download and Extract Artifacts + uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 + with: + run_id: ${{ github.event.workflow_run.id }} + path: artifacts + + - name: Publish Test Results + uses: EnricoMi/publish-unit-test-result-action@v2 + with: + commit: ${{ github.event.workflow_run.head_sha }} + event_file: artifacts/Event File/event.json + event_name: ${{ github.event.workflow_run.event }} + files: "artifacts/**/*.xml" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 730de26e..a33660b2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,6 +1,8 @@ name: Tests on: push: + pull_request: + branches: [ master ] workflow_dispatch: jobs: @@ -9,18 +11,25 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Validate composer.json and composer.lock run: composer validate - name: Install dependencies run: composer install --prefer-dist --no-dev PHPunit: + name: PHP ${{ matrix.php-versions }} unit tests runs-on: ubuntu-latest + # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#handling-failures + continue-on-error: "${{ matrix.experimental }}" strategy: matrix: - php-versions: ['7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] - name: PHP ${{ matrix.php-versions }} unit tests on ${{ matrix.operating-system }} + php-versions: ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] + experimental: [false] +# uncomment this to start testing on development release +# include: +# - php-versions: '8.5' # development release, things can break +# experimental: true env: extensions: gd, sqlite3 extensions-cache-key-name: phpextensions @@ -29,7 +38,7 @@ jobs: # let's get started! - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 # cache PHP extensions - name: Setup cache environment @@ -68,6 +77,7 @@ jobs: - name: Get composer cache directory id: composer-cache run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + # http://man7.org/linux/man-pages/man1/date.1.html # https://github.com/actions/cache#creating-a-cache-key - name: Get Date @@ -78,11 +88,14 @@ jobs: - name: Cache dependencies uses: actions/cache@v4 with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ steps.get-date.outputs.date }}-${{ hashFiles('**/composer.json') }} - restore-keys: ${{ runner.os }}-composer-${{ steps.get-date.outputs.date }}- + path: "${{ steps.composer-cache.outputs.dir }}" + key: "${{ runner.os }}-composer-${{ steps.get-date.outputs.date }}-${{ hashFiles('**/composer.json') }}" + restore-keys: "${{ runner.os }}-composer-${{ steps.get-date.outputs.date }}-" # composer installation + - name: Unset platform requirement + run: composer config --unset platform + - name: Setup PHPunit run: composer install -n @@ -91,20 +104,118 @@ jobs: # testing - name: Run unit tests - run: ../vendor/bin/phpunit --no-coverage + run: ../vendor/bin/phpunit --no-coverage --log-junit results.xml working-directory: tst + - name: Upload Test Results + if: always() + uses: actions/upload-artifact@v4 + with: + name: Test Results (PHP ${{ matrix.php-versions }}) + path: tst/results.xml + + PHPunitConfigCombinations: + name: PHP configuration combination unit tests + runs-on: ubuntu-latest + env: + php-version: '8.4' + extensions: gd, sqlite3 + extensions-cache-key-name: phpextensions + + steps: + + # let's get started! + - name: Checkout + uses: actions/checkout@v5 + + # cache PHP extensions + - name: Setup cache environment + id: extcache + uses: shivammathur/cache-extensions@v1 + with: + php-version: ${{ env.php-version }} + extensions: ${{ env.extensions }} + key: ${{ runner.os }}-${{ env.extensions-cache-key }} + + - name: Cache extensions + uses: actions/cache@v4 + with: + path: ${{ steps.extcache.outputs.dir }} + key: ${{ steps.extcache.outputs.key }} + restore-keys: ${{ runner.os }}-${{ env.extensions-cache-key }} + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ env.php-version }} + extensions: ${{ env.extensions }} + + # Setup GitHub CI PHP problem matchers + # https://github.com/shivammathur/setup-php#problem-matchers + - name: Setup problem matchers for PHP + run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" + + - name: Setup problem matchers for PHPUnit + run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + + # composer cache + - name: Remove composer lock + run: rm composer.lock + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + # http://man7.org/linux/man-pages/man1/date.1.html + # https://github.com/actions/cache#creating-a-cache-key + - name: Get Date + id: get-date + run: echo "date=$(/bin/date -u "+%Y%m%d")" >> $GITHUB_OUTPUT + shell: bash + + - name: Cache dependencies + uses: actions/cache@v4 + with: + path: "${{ steps.composer-cache.outputs.dir }}" + key: "${{ runner.os }}-composer-${{ steps.get-date.outputs.date }}-${{ hashFiles('**/composer.json') }}" + restore-keys: "${{ runner.os }}-composer-${{ steps.get-date.outputs.date }}-" + + # composer installation + - name: Unset platform requirement + run: composer config --unset platform + + - name: Setup PHPunit + run: composer install -n + + - name: Install Google Cloud Storage + run: composer require google/cloud-storage + + # testing + - name: Generate configuration combination unit tests + run: bin/configuration-test-generator + + - name: Run unit tests + run: ../vendor/bin/phpunit --no-coverage --log-junit results.xml ConfigurationCombinationsTest.php + working-directory: tst + + - name: Upload Test Results + if: always() + uses: actions/upload-artifact@v4 + with: + name: Test Results + path: tst/results.xml + Mocha: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Node - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: - node-version: '20' + node-version: '18' cache: 'npm' cache-dependency-path: 'js/package-lock.json' @@ -116,5 +227,22 @@ jobs: working-directory: js - name: Run unit tests - run: npm test + run: npm run ci-test working-directory: js + + - name: Upload Test Results + if: always() + uses: actions/upload-artifact@v4 + with: + name: Test Results (Mocha) + path: js/mocha-results.xml + + event_file: + name: "Event File" + runs-on: ubuntu-latest + steps: + - name: Upload + uses: actions/upload-artifact@v4 + with: + name: Event File + path: "${{ github.event_path }}" diff --git a/.gitignore b/.gitignore index ee344551..09ca72e8 100644 --- a/.gitignore +++ b/.gitignore @@ -25,9 +25,11 @@ vendor/**/tst vendor/**/tests vendor/**/build_phar.php !vendor/**/*.php +vendor/bin/** # Ignore local node modules, unit testing logs, api docs and IDE project files js/node_modules/ +js/mocha-results.xml js/test.log tst/log/ tst/ConfigurationCombinationsTest.php diff --git a/.htaccess.disabled b/.htaccess.disabled index 5a3abe46..b635612b 100644 --- a/.htaccess.disabled +++ b/.htaccess.disabled @@ -2,6 +2,7 @@ RewriteEngine on RewriteCond !%{HTTP_USER_AGENT} "Let's Encrypt validation server" [NC] RewriteCond %{HTTP_USER_AGENT} ^.*(bot|spider|crawl|https?://|WhatsApp|SkypeUriPreview|facebookexternalhit) [NC] RewriteRule .* - [R=403,L] +AddType application/wasm .wasm php_value max_execution_time 30 diff --git a/.scrutinizer.yml b/.scrutinizer.yml index bd393ccc..d27e1bc6 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -15,14 +15,12 @@ coding_style: additive: false concatenation: true build: - image: default-bionic environment: php: - version: 7.4 + version: 8.2 tests: override: - - - command: 'composer require google/cloud-storage && cd tst && ../vendor/bin/phpunit' + - command: 'composer require google/cloud-storage && cd tst && XDEBUG_MODE=coverage ../vendor/bin/phpunit' coverage: file: 'tst/log/coverage-clover.xml' format: 'clover' diff --git a/CHANGELOG.md b/CHANGELOG.md index 055339a3..88e2d05d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,94 @@ # PrivateBin version history +## 2.0.1 (not yet released) +* CHANGED: CSP recommendation around bootstrap5 template resolved in Firefox 131 (#1613) +* FIXED: Allow pasting a password for decrypting a paste (#1620) +* FIXED: Allow copying the shortened link after using a URL shortener (#1624) +* ADDED: Auto shorten URLs with config option `shortenbydefault` (#1627) +* ADDED: Added `shortenviashlink` endpoint with an `shlink` configuration section +* FIXED: Check for quotes and conical braces when extracting short url (#1644) + +## 2.0.0 (2025-07-28) +* ADDED: Error logging in database and filesystem backend (#1554) +* ADDED: Statistics on v1 pastes in administration script and option to delete them +* CHANGED: Removed page template (#265) +* CHANGED: Removed support for ZeroBin & v1 pastes - since release 1.3 the v2 format is used (#551) +* CHANGED: Removed use of base64 & rawinflate libraries (#551) +* CHANGED: Removed support for `privatebin_data`, `privatebin_db` & `zerobin_db` model class configurations, must be replaced with `Filesystem` or `Database` in `cfg/conf.php`, if still present +* CHANGED: Removed unused columns in database schema of tables `paste` & `comment` +* CHANGED: Jdenticons are now used as the default icons +* CHANGED: Upgrading libraries to: base-x 5.0.1, bootstrap 5.3.7, jdenticon 2.0.0 & kjua 0.10.0 +* CHANGED: Minimum required PHP version is 7.4, due to a change in the jdenticon library +* CHANGED: Set bootstrap5 template as default for PrivateBin (#1572) +* CHANGED: Switched from binary bytes to SI-units (#1565) +* CHANGED: Replaced the term "paste" with the more generic "document" (#397) +* FIXED: Name mismatches in attached files (#1584) +* FIXED: Unable to paste attachments from clipboard (#1589) +* FIXED: Configuration combinations test errors + +## 1.7.8 (2025-06-30) +* FIXED: Duplicate attachment for every comment (#1577) +* FIXED: Attachments with empty file names (#1577) +* FIXED: Page template scripts loading order (#1579) + +## 1.7.7 (2025-06-28) +* ADDED: Switching templates using the web ui (#1501) +* ADDED: Show file name and size on download page (#603) +* CHANGED: Passing large data structures by reference to reduce memory consumption (#858) +* CHANGED: Removed use of ctype functions and polyfill library for ctype +* CHANGED: Upgrading libraries to: DOMpurify 3.2.6, ip-lib 1.20.0 +* CHANGED: Support for multiple file uploads (#1060) +* CHANGED: Documented CSP change necessary to allow PDF attachment preview (#1552) +* FIXED: Hide Reply button in the discussions once clicked to avoid losing the text input (#1508) +* FIXED: Bump zlib library suffix, ensuring cache refresh for WASM streaming change +* FIXED: Handle undefined globals in file based persisted values (#1544) + +## 1.7.6 (2025-02-01) +* ADDED: Ability to copy the paste by clicking the copy icon button or using the keyboard shortcut ctrl+c/cmd+c (#1390 & #12) +* CHANGED: Allow toggling tab-key-support using `[Ctrl]+[m]` or `[Esc]` in textarea for keyboard navigation (#1386) +* CHANGED: Switched to WASM streaming and replace unsafe-eval with wasm-unsafe-eval CSP declaration (#1464), requires webserver to have `application/wasm` MIME type configured. +* CHANGED: Replaced usage of strpos with str_starts_with & str_contains (#1373) +* CHANGED: Added polyfill libraries for ctype, str_starts_with & str_contains functions (#1476) +* CHANGED: Turned paste delete link into a button (#266) +* CHANGED: Upgrading libraries to: DOMpurify 3.2.4, cloud-storage 1.45.0, aws-sdk-php 3.336.2 +* CHANGED: `bootstrap5` template UI improvements +* FIXED: Redirect to the home page after changing the language (#92) + +## 1.7.5 (2024-11-16) +* ADDED: Allow non persistent SQL connections, if configured (#1394) +* ADDED: Show a button (that redirects to the `basepath` URL) inside the alert after a paste is deleted +* CHANGED: Tweaked page footer of the `bootstrap5` template (#1392) +* CHANGED: Simpler PostgreSQL table lookup query (#1361) +* CHANGED: SRI hashes are now configurable, no longer hardcoded in templates (#1365) +* CHANGED: Upgrading libraries to: DOMpurify 3.1.7, ip-lib 1.18.1, cloud-storage 1.43.0, aws-sdk-php 3.325.0 +* FIXED: Numeric array keys being cast to integer causing failures under strict type checking (#1435) + +## 1.7.4 (2024-07-09) +* CHANGED: Saving markdown pastes uses `.md` extension instead of `.txt` (#1293) +* CHANGED: Enable strict type checking in PHP (#1350) +* CHANGED: Various tweaks of the `bootstrap5` template, suggested by the community +* FIXED: Reset password input field on creation of new paste (#1194) +* FIXED: Allow database schema upgrade to skip versions (#1343) +* FIXED: `bootstrap5` dark mode toggle unset on dark browser preference (#1340) +* FIXED: Prevent bypassing YOURLS proxy URL filter, allowing to shorten non-self URLs + +## 1.7.3 (2024-05-13) +* CHANGED: Various tweaks of the `bootstrap5` template, suggested by the community +* CHANGED: Upgrading libraries to: DOMpurify 3.1.3 +* FIXED: Selected expiration not being applied, when using bootstrap template (#1309) + +## 1.7.2 (2024-05-05) +* ADDED: Allow use of `shortenviayourls` in query parameters (#1267) +* ADDED: Input sanitation to some not yet filtered query and server parameters +* ADDED: Optional Bootstrap CSS 5.3.3 based template, use configuration `template = "bootstrap5"` to switch to it (#728) +* CHANGED: "Send" button now labeled "Create" (#946) +* CHANGED: Drop some PHP < 5.6 fallbacks, minimum version is PHP 7.3 as of release 1.6.0 +* CHANGED: Set `lang` cookie with lax `SameSite` property +* CHANGED: Upgrading libraries to: DOMpurify 3.1.2 (#1299) & jQuery 3.7.1 +* CHANGED: `create` attribute is no longer returned in API for pastes & can be disabled for comments using `discussiondatedisplay` as well (#1290) +* FIXED: Add cache control headers also to API calls (#1263) +* FIXED: Shortened paste URL does not appear in email (#606) + ## 1.7.1 (2024-02-11) * FIXED: zlib 1.3.1 wasm file reference @@ -24,7 +113,7 @@ ## 1.6.0 (2023-09-11) * ADDED: Translations for Japanese & Arabic -* ADDED: Configuration option to disable Email button (#1164) +* ADDED: Configuration option to disable email button (#1164) * CHANGED: Minimum required PHP version is 7.3, due to upgrading PHPunit (#707) * CHANGED: Removed PHP 5 polyfill for random_bytes() diff --git a/CREDITS.md b/CREDITS.md index e77348d4..aabc732e 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -5,6 +5,8 @@ * Simon Rupf - current developer and maintainer * rugk - security review, doc improvment, JS refactoring & various other stuff * R4SAS - python client, compression, blob URI to support larger attachments +* Mikhail Romanov - UI improvements, theme switching, clipboard support, multi-file upload, bugfixes, code refactoring +* karthikkasturi - shlink proxy and url shortening bugfixes ## Past contributions @@ -32,6 +34,7 @@ * Felix J. Ogris - S3 Storage backend, script for data backend migrations, dropped singleton behaviour of data backends * Mounir Idrassi & J. Mozdzen - secure YOURLS integration * Felipe Nakandakari - enabled AWS SDK to use default credential provider chain in the S3 Storage backend +* Aaron Sherber - cache control headers for API calls & use of `shortenviayourls` in query parameters ## Translations * Hexalyse - French diff --git a/LICENSE.md b/LICENSE.md index 8b88a6d4..d1098f09 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,7 +1,7 @@ # License PrivateBin consists of PHP and JS code which was originally written by Sébastien -Sauvage in 2012 and falls unter the Zlib/libpng license. Also included are +Sauvage in 2012 and falls under the Zlib/libpng license. Also included are libraries that fall under the GPLv2 (rawinflate), BSD 3-clause (Showdown), MIT (base64.js version 1.7, Bootstrap, Identicon, random_compat, composer, kjua, base-x), Apache (prettify.js) and CC-BY (favicon, icon, logo) licenses. All of @@ -351,6 +351,7 @@ Copyright © 2016 Nils Adermann, Jordi Boggiano Copyright © 2016 Lars Jung (https://larsjung.de) Copyright © 2018 base-x contributors Copyright © 2014-2018 The Bitcoin Core developers +Copyright © 2019-2024 The Bootstrap Authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index 68628441..ff0f25ed 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ .PHONY: all coverage coverage-js coverage-php doc doc-js doc-php increment sign test test-js test-php help -CURRENT_VERSION = 1.7.1 -VERSION ?= 1.7.2 -VERSION_FILES = index.php bin/ cfg/ *.md doc/Installation.md css/ i18n/ img/ js/package.json js/privatebin.js lib/ Makefile tpl/ tst/ +CURRENT_VERSION = 2.0.0 +VERSION ?= 2.0.1 +VERSION_FILES = README.md SECURITY.md doc/Installation.md js/package*.json lib/Controller.php Makefile REGEX_CURRENT_VERSION := $(shell echo $(CURRENT_VERSION) | sed "s/\./\\\./g") REGEX_VERSION := $(shell echo $(VERSION) | sed "s/\./\\\./g") @@ -29,12 +29,11 @@ doc-php: ## Generate JS code documentation. phpdoc --visibility=public,protected,private --target=doc/phpdoc --directory=lib/ increment: ## Increment and commit new version number, set target version using `make increment VERSION=1.2.3`. - for F in `grep -l -R $(REGEX_CURRENT_VERSION) $(VERSION_FILES) | grep -v -e tst/log/ -e ":0" -e CHANGELOG.md`; \ + for F in `grep -l -R $(REGEX_CURRENT_VERSION) $(VERSION_FILES)`; \ do \ sed -i "s/$(REGEX_CURRENT_VERSION)/$(REGEX_VERSION)/g" $$F; \ done - cd tst && phpunit --no-coverage && cd .. - git add $(VERSION_FILES) tpl/ + git add $(VERSION_FILES) CHANGELOG.md git commit -m "incrementing version" sign: ## Sign a release. diff --git a/README.md b/README.md index 40c25112..e599c930 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # [![PrivateBin](https://cdn.rawgit.com/PrivateBin/assets/master/images/preview/logoSmall.png)](https://privatebin.info/) -*Current version: 1.7.1* +*Current version: 2.0.0* **PrivateBin** is a minimalist, open source online [pastebin](https://en.wikipedia.org/wiki/Pastebin) -where the server has zero knowledge of pasted data. +where the server has zero knowledge of stored data. Data is encrypted and decrypted in the browser using 256bit AES in [Galois Counter mode](https://en.wikipedia.org/wiki/Galois/Counter_Mode). @@ -12,9 +12,7 @@ Data is encrypted and decrypted in the browser using 256bit AES in This is a fork of ZeroBin, originally developed by [Sébastien Sauvage](https://github.com/sebsauvage/ZeroBin). PrivateBin was refactored to allow easier and cleaner extensions and has many additional -features. It is, however, still fully compatible to the original ZeroBin 0.19 -data storage scheme. Therefore, such installations can be upgraded to PrivateBin -without losing any data. +features. ## What PrivateBin provides @@ -81,7 +79,7 @@ file](https://github.com/PrivateBin/PrivateBin/wiki/Configuration): * File upload support, image, media and PDF preview (disabled by default, size limit adjustable) -* Templates: By default there are bootstrap CSS, darkstrap and "classic ZeroBin" +* Templates: By default there are bootstrap5, bootstrap CSS and darkstrap to choose from and it is easy to adapt these to your own websites layout or create your own. diff --git a/SECURITY.md b/SECURITY.md index d832facf..4cc9a465 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,8 +4,8 @@ | Version | Supported | | ------- | ------------------ | -| 1.7.1 | :heavy_check_mark: | -| < 1.7.1 | :x: | +| 2.0.0 | :heavy_check_mark: | +| < 2.0.0 | :x: | ## Reporting a Vulnerability @@ -14,5 +14,8 @@ a response within a week (usually during the next weekend). The respondee will reply from their personal address and can offer you their GPG public key to support end-to-end encrypted communication on sensitive topics or attachments. +You can also [use the corresponding GitHub form](https://github.com/PrivateBin/PrivateBin/security/advisories/new) +to report a new vulnerability directly on GitHub. + You can also contact us via the regular issue tracker if the risk of early publication is low or you would request input from other PrivateBin users. diff --git a/bin/administration b/bin/administration index f814be7e..9ddb6887 100755 --- a/bin/administration +++ b/bin/administration @@ -1,6 +1,5 @@ #!/usr/bin/env php -_store->exists($pasteId)) { self::_error('given ID does not exist, has expired or was already deleted', 6); } $this->_store->delete($pasteId); if ($this->_store->exists($pasteId)) { - self::_error('paste ID exists after deletion, permission problem?', 7); + self::_error('document ID exists after deletion, permission problem?', 7); } - exit("paste $pasteId successfully deleted" . PHP_EOL); + exit("document $pasteId successfully deleted" . PHP_EOL); + } + + /** + * deletes all stored documents (regardless of expiration) + * + * @access private + */ + private function _delete_all() + { + $ids = $this->_store->getAllPastes(); + foreach ($ids as $pasteid) { + echo "Deleting document ID: $pasteid" . PHP_EOL; + $this->_store->delete($pasteid); + } + exit("All documents successfully deleted" . PHP_EOL); + } + + /** + * deletes all unsupported v1 documents (regardless of expiration) + * + * @access private + */ + private function _delete_v1() + { + $ids = $this->_store->getAllPastes(); + foreach ($ids as $pasteid) { + try { + $paste = $this->_store->read($pasteid); + } catch (Exception $e) { + echo "Error reading document {$pasteid}: ", $e->getMessage(), PHP_EOL; + } + if (array_key_exists('adata', $paste)) { + continue; + } + echo "Deleting v1 document ID: $pasteid" . PHP_EOL; + $this->_store->delete($pasteid); + } + exit("All unsupported legacy v1 documents successfully deleted" . PHP_EOL); } /** @@ -126,19 +162,37 @@ class Administration { echo <<<'EOT' Usage: - administration [--delete | --empty-dirs | --help | --purge | --statistics] + administration [--delete | --delete-all | --delete-v1 | + --empty-dirs | --help | --list-ids | --purge | --statistics] Options: - -d, --delete deletes the requested paste ID + -d, --delete deletes the requested document ID + --delete-all deletes all documents + --delete-v1 deletes all unsupported v1 documents -e, --empty-dirs removes empty directories (only if Filesystem storage is configured) -h, --help displays this help message - -p, --purge purge all expired pastes - -s, --statistics reads all stored pastes and comments and reports statistics + -l, --list-ids lists all document IDs + -p, --purge purge all expired documents + -s, --statistics reads all stored documents and reports statistics EOT, PHP_EOL; exit($code); } + /** + * lists all stored document IDs + * + * @access private + */ + private function _list_ids() + { + $ids = $this->_store->getAllPastes(); + foreach ($ids as $pasteid) { + echo $pasteid, PHP_EOL; + } + exit; + } + /** * return option for given short or long keyname, if it got set * @@ -179,7 +233,8 @@ EOT, PHP_EOL; self::_help(2); } - $this->_opts = getopt('hd:eps', array('help', 'delete:', 'empty-dirs', 'purge', 'statistics')); + $this->_opts = getopt('hd:elps', array('help', 'delete:', 'delete-all', 'delete-v1', 'empty-dirs', 'list-ids', 'purge', 'statistics')); + if (!$this->_opts) { self::_error_echo('unsupported arguments given'); echo PHP_EOL; @@ -188,7 +243,7 @@ EOT, PHP_EOL; } /** - * reads all stored pastes and comments and reports statistics + * reads all stored documents and reports statistics * * @access public */ @@ -199,6 +254,7 @@ EOT, PHP_EOL; 'damaged' => 0, 'discussion' => 0, 'expired' => 0, + 'legacy' => 0, 'md' => 0, 'percent' => 1, 'plain' => 0, @@ -222,12 +278,13 @@ EOT, PHP_EOL; try { $paste = $this->_store->read($pasteid); } catch (Exception $e) { - echo "Error reading paste {$pasteid}: ", $e->getMessage(), PHP_EOL; + echo "Error reading document {$pasteid}: ", $e->getMessage(), PHP_EOL; ++$counters['damaged']; } ++$counters['progress']; if ( + array_key_exists('meta', $paste) && array_key_exists('expire_date', $paste['meta']) && $paste['meta']['expire_date'] < $time ) { @@ -235,28 +292,27 @@ EOT, PHP_EOL; } if (array_key_exists('adata', $paste)) { - $format = $paste['adata'][1]; - $discussion = $paste['adata'][2]; - $burn = $paste['adata'][3]; + switch ($paste['adata'][Paste::ADATA_FORMATTER]) { + case 'plaintext': + ++$counters['plain']; + break; + case 'syntaxhighlighting': + ++$counters['syntax']; + break; + case 'markdown': + ++$counters['md']; + break; + default: + ++$counters['unknown']; + break; + } + $counters['discussion'] += (int) $paste['adata'][Paste::ADATA_OPEN_DISCUSSION]; + $counters['burn'] += (int) $paste['adata'][Paste::ADATA_BURN_AFTER_READING]; } else { - $format = array_key_exists('formatter', $paste['meta']) ? $paste['meta']['formatter'] : 'plaintext'; - $discussion = array_key_exists('opendiscussion', $paste['meta']) ? $paste['meta']['opendiscussion'] : false; - $burn = array_key_exists('burnafterreading', $paste['meta']) ? $paste['meta']['burnafterreading'] : false; + echo "Unsupported v1 paste ", $pasteid, PHP_EOL; + ++$counters['legacy']; } - if ($format === 'plaintext') { - ++$counters['plain']; - } elseif ($format === 'syntaxhighlighting') { - ++$counters['syntax']; - } elseif ($format === 'markdown') { - ++$counters['md']; - } else { - ++$counters['unknown']; - } - - $counters['discussion'] += (int) $discussion; - $counters['burn'] += (int) $burn; - // display progress if ($counters['progress'] % $dots === 0) { echo '.'; @@ -278,6 +334,9 @@ Plain Text:\t\t{$counters['plain']} Source Code:\t\t{$counters['syntax']} Markdown:\t\t{$counters['md']} EOT, PHP_EOL; + if ($counters['legacy'] > 0) { + echo "Legacy v1:\t\t{$counters['legacy']}", PHP_EOL; + } if ($counters['damaged'] > 0) { echo "Damaged:\t\t{$counters['damaged']}", PHP_EOL; } @@ -314,14 +373,26 @@ EOT, PHP_EOL; $this->_delete($pasteId); } + if ($this->_option(null, 'delete-all') !== null) { + $this->_delete_all(); + } + + if ($this->_option(null, 'delete-v1') !== null) { + $this->_delete_v1(); + } + + if ($this->_option('l', 'list-ids') !== null) { + $this->_list_ids(); + } + if ($this->_option('p', 'purge') !== null) { try { $this->_store->purge(PHP_INT_MAX); } catch (Exception $e) { - echo 'Error purging pastes: ', $e->getMessage(), PHP_EOL, - 'Run the statistics to find damaged paste IDs and either delete them or restore them from backup.', PHP_EOL; + echo 'Error purging documents: ', $e->getMessage(), PHP_EOL, + 'Run the statistics to find damaged document IDs and either delete them or restore them from backup.', PHP_EOL; } - exit('purging of expired pastes concluded' . PHP_EOL); + exit('purging of expired documents concluded' . PHP_EOL); } if ($this->_option('s', 'statistics') !== null) { diff --git a/bin/configuration-test-generator b/bin/configuration-test-generator index 7cde2ab3..6abe0d55 100755 --- a/bin/configuration-test-generator +++ b/bin/configuration-test-generator @@ -1,6 +1,14 @@ #!/usr/bin/env php - array( array( - 'setting' => 'page', + 'setting' => 'bootstrap5', 'tests' => array( array( 'type' => 'MatchesRegularExpression', 'args' => array( - '#]+type="text/css"[^>]+rel="stylesheet"[^>]+href="css/privatebin\.css\\?\d[\d\.]+\d+"[^>]*/>#', + '#]+type="text/css"[^>]+rel="stylesheet"[^>]+href="css/bootstrap5/privatebin\.css\\?\d[\d\.]+\d+"[^>]*/>#', '$content', - 'outputs "page" stylesheet correctly', + 'outputs "bootstrap5" stylesheet correctly', ), ), array( 'type' => 'DoesNotMatchRegularExpression', @@ -181,9 +189,9 @@ new ConfigurationTestGenerator(array( array( 'type' => 'DoesNotMatchRegularExpression', 'args' => array( - '#]+type="text/css"[^>]+rel="stylesheet"[^>]+href="css/privatebin\.css\\?\d[\d\.]+\d+"[^>]*/>#', + '#]+type="text/css"[^>]+rel="stylesheet"[^>]+href="css/bootstrap5/privatebin\.css\\?\d[\d\.]+\d+"[^>]*/>#', '$content', - 'removes "page" stylesheet correctly', + 'removes "bootstrap5" stylesheet correctly', ), ), array( 'type' => 'MatchesRegularExpression', @@ -405,7 +413,7 @@ class ConfigurationTestGenerator private function _getHeader() { return <<<'EOT' -_model->create(Helper::getPasteId(), Helper::getPaste()); + $paste = Helper::getPaste(); + $this->_model->create(Helper::getPasteId(), $paste); $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data'); $_GET['pasteid'] = Helper::getPasteId(); $_GET['deletetoken'] = hash_hmac('sha256', Helper::getPasteId(), $this->_model->read(Helper::getPasteId())['meta']['salt']); @@ -566,7 +575,7 @@ EOT; $code .= <<<'EOT' $this->assertMatchesRegularExpression( - '#]*id="status"[^>]*>.*Paste was properly deleted[^<]*#s', + '#]*id="status"[^>]*>.*Document was properly deleted[^<]*()#s', $content, 'outputs deleted status correctly' ); diff --git a/bin/icon-test b/bin/icon-test index 57145e13..abf9f789 100755 --- a/bin/icon-test +++ b/bin/icon-test @@ -1,9 +1,17 @@ #!/usr/bin/env php - new Identicon(new GdGenerator()), diff --git a/bin/migrate b/bin/migrate index 76539ab6..9dfde61c 100755 --- a/bin/migrate +++ b/bin/migrate @@ -1,7 +1,16 @@ #!/usr/bin/env php -getStore(); $ids = $srcstore->getAllPastes(); foreach ($ids as $id) { - debug("Reading paste id " . $id); + debug("Reading document ID " . $id); $paste = $srcstore->read($id); $comments = $srcstore->readComments($id); @@ -82,10 +91,10 @@ debug("Done."); function deletePaste($dryrun, $pasteid, $srcstore) { if (!$dryrun) { - debug("Deleting paste id " . $pasteid); + debug("Deleting document ID " . $pasteid); $srcstore->delete($pasteid); } else { - debug("Would delete paste id " . $pasteid); + debug("Would delete document ID " . $pasteid); } } @@ -96,28 +105,28 @@ function saveComment ($force_overwrite, $dryrun, $pasteid, $comment, $dststore) if (!$dststore->existsComment($pasteid, $parentid, $commentid)) { if (!$dryrun) { - debug("Saving paste id " . $pasteid . ", parent id " . + debug("Saving document ID " . $pasteid . ", parent id " . $parentid . ", comment id " . $commentid); $dststore->createComment($pasteid, $parentid, $commentid, $comment); } else { - debug("Would save paste id " . $pasteid . ", parent id " . + debug("Would save document ID " . $pasteid . ", parent id " . $parentid . ", comment id " . $commentid); } } else if ($force_overwrite) { if (!$dryrun) { - debug("Overwriting paste id " . $pasteid . ", parent id " . + debug("Overwriting document ID " . $pasteid . ", parent id " . $parentid . ", comment id " . $commentid); $dststore->createComment($pasteid, $parentid, $commentid, $comment); } else { - debug("Would overwrite paste id " . $pasteid . ", parent id " . + debug("Would overwrite document ID " . $pasteid . ", parent id " . $parentid . ", comment id " . $commentid); } } else { if (!$dryrun) { - dieerr("Not overwriting paste id " . $pasteid . ", parent id " . + dieerr("Not overwriting document ID " . $pasteid . ", parent id " . $parentid . ", comment id " . $commentid); } else { - dieerr("Would not overwrite paste id " . $pasteid . ", parent id " . + dieerr("Would not overwrite document ID " . $pasteid . ", parent id " . $parentid . ", comment id " . $commentid); } } @@ -127,23 +136,23 @@ function savePaste ($force_overwrite, $dryrun, $pasteid, $paste, $dststore) { if (!$dststore->exists($pasteid)) { if (!$dryrun) { - debug("Saving paste id " . $pasteid); + debug("Saving document ID " . $pasteid); $dststore->create($pasteid, $paste); } else { - debug("Would save paste id " . $pasteid); + debug("Would save document ID " . $pasteid); } } else if ($force_overwrite) { if (!$dryrun) { - debug("Overwriting paste id " . $pasteid); + debug("Overwriting document ID " . $pasteid); $dststore->create($pasteid, $paste); } else { - debug("Would overwrite paste id " . $pasteid); + debug("Would overwrite document ID " . $pasteid); } } else { if (!$dryrun) { - dieerr("Not overwriting paste id " . $pasteid); + dieerr("Not overwriting document ID " . $pasteid); } else { - dieerr("Would not overwrite paste id " . $pasteid); + dieerr("Would not overwrite document ID " . $pasteid); } } } @@ -182,18 +191,18 @@ Usage: migrate [-h|--help] Options: - --delete-after delete data from source after all pastes and comments have + --delete-after delete data from source after all documents have successfully + been copied to the destination + --delete-during delete data from source after the current document have successfully been copied to the destination - --delete-during delete data from source after the current paste and its - comments have successfully been copied to the destination -f forcefully overwrite data which already exists at the destination -h, --help displays this help message -n dry run, do not copy data -v be verbose - use storage backend configration from conf.php found in + use storage backend configuration from conf.php found in this directory as source - optionally, use storage backend configration from conf.php + optionally, use storage backend configuration from conf.php found in this directory as destination; defaults to: " . PATH . "cfg" . DIRECTORY_SEPARATOR . "conf.php "); diff --git a/cfg/conf.sample.php b/cfg/conf.sample.php index 8c8eeb6a..8fb5288b 100644 --- a/cfg/conf.sample.php +++ b/cfg/conf.sample.php @@ -18,6 +18,11 @@ discussion = true ; preselect the discussion feature, defaults to false opendiscussion = false +; enable or disable the display of dates & times in the comments, defaults to true +; Note that internally the creation time will still get tracked in order to sort +; the comments by creation time, but you can choose not to display them. +; discussiondatedisplay = false + ; enable or disable the password feature, defaults to true password = true @@ -34,11 +39,29 @@ defaultformatter = "plaintext" ; (optional) set a syntax highlighting theme, as found in css/prettify/ ; syntaxhighlightingtheme = "sons-of-obsidian" -; size limit per paste or comment in bytes, defaults to 10 Mebibytes -sizelimit = 10485760 +; size limit per document or comment in bytes, defaults to 10 Megabytes +sizelimit = 10000000 -; template to include, default is "bootstrap" (tpl/bootstrap.php) -template = "bootstrap" +; by default PrivateBin use "bootstrap5" template (tpl/bootstrap5.php). +; Optionally you can enable the template selection menu, which uses +; a session cookie to store the choice until the browser is closed. +templateselection = false + +; List of available for selection templates when "templateselection" option is enabled +availabletemplates[] = "bootstrap5" +availabletemplates[] = "bootstrap" +availabletemplates[] = "bootstrap-page" +availabletemplates[] = "bootstrap-dark" +availabletemplates[] = "bootstrap-dark-page" +availabletemplates[] = "bootstrap-compact" +availabletemplates[] = "bootstrap-compact-page" + +; set the template your installs defaults to, defaults to "bootstrap5" (tpl/bootstrap5.php), also +; bootstrap template (tpl/bootstrap.php) and it's variants: "bootstrap-dark", "bootstrap-compact", "bootstrap-page", +; which can be combined with "-dark" and "-compact" for "bootstrap-dark-page", +; "bootstrap-compact-page" - previews at: +; https://privatebin.info/screenshots.html +; template = "bootstrap5" ; (optional) info text to display ; use single, instead of double quotes for HTML attributes @@ -56,17 +79,22 @@ languageselection = false ; if this is set and language selection is disabled, this will be the only language ; languagedefault = "en" -; (optional) URL shortener address to offer after a new paste is created. +; (optional) URL shortener address to offer after a new document is created. ; It is suggested to only use this with self-hosted shorteners as this will leak -; the pastes encryption key. +; the documents encryption key. ; urlshortener = "https://shortener.example.com/api?link=" -; (optional) Let users create a QR code for sharing the paste URL with one click. -; It works both when a new paste is created and when you view a paste. +; (optional) Whether to shorten the URL by default when a new document is created. +; If set to true, the "Shorten URL" functionality will be automatically called. +; This only works if the "urlshortener" option is set. +; shortenbydefault = false + +; (optional) Let users create a QR code for sharing the document URL with one click. +; It works both when a new document is created and when you view a document. ; qrcode = true -; (optional) Let users send an email sharing the paste URL with one click. -; It works both when a new paste is created and when you view a paste. +; (optional) Let users send an email sharing the document URL with one click. +; It works both when a new document is created and when you view a document. ; email = true ; (optional) IP based icons are a weak mechanism to detect if a comment was from @@ -74,7 +102,7 @@ languageselection = false ; used to get the IP of a comment poster if the server salt is leaked and a ; SHA512 HMAC rainbow table is generated for all (relevant) IPs. ; Can be set to one these values: -; "none" / "identicon" (default) / "jdenticon" / "vizhash". +; "none" / "identicon" / "jdenticon" (default) / "vizhash". ; icon = "none" ; Content Security Policy headers allow a website to restrict what sources are @@ -83,22 +111,21 @@ languageselection = false ; scripts or run your site behind certain DDoS-protection services. ; Check the documentation at https://content-security-policy.com/ ; Notes: -; - If you use a bootstrap theme, you can remove the allow-popups from the -; sandbox restrictions. ; - By default this disallows to load images from third-party servers, e.g. when -; they are embedded in pastes. If you wish to allow that, you can adjust the +; they are embedded in documents. If you wish to allow that, you can adjust the ; policy here. See https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-it-load-embedded-images ; for details. -; - The 'unsafe-eval' is used in two cases; to check if the browser supports -; async functions and display an error if not and for Chrome to enable -; webassembly support (used for zlib compression). You can remove it if Chrome -; doesn't need to be supported and old browsers don't need to be warned. -; cspheader = "default-src 'none'; base-uri 'self'; form-action 'none'; manifest-src 'self'; connect-src * blob:; script-src 'self' 'unsafe-eval'; style-src 'self'; font-src 'self'; frame-ancestors 'none'; img-src 'self' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-downloads" - -; stay compatible with PrivateBin Alpha 0.19, less secure -; if enabled will use base64.js version 1.7 instead of 2.1.9 and sha1 instead of -; sha256 in HMAC for the deletion token -; zerobincompatibility = false +; - The 'wasm-unsafe-eval' is used to enable webassembly support (used for zlib +; compression). You can remove it if compression doesn't need to be supported. +; - The 'unsafe-inline' style-src is used by Chrome when displaying PDF previews +; and can be omitted if attachment upload is disabled (which is the default). +; See https://issues.chromium.org/issues/343754409 +; - To allow displaying PDF previews in Firefox or Chrome, sandboxing must also +; get turned off. The following CSP allows PDF previews: +; cspheader = "default-src 'none'; base-uri 'self'; form-action 'none'; manifest-src 'self'; connect-src * blob:; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; font-src 'self'; frame-ancestors 'none'; frame-src blob:; img-src 'self' data: blob:; media-src blob:; object-src blob:" +; +; The recommended and default used CSP is: +; cspheader = "default-src 'none'; base-uri 'self'; form-action 'none'; manifest-src 'self'; connect-src * blob:; script-src 'self' 'wasm-unsafe-eval'; style-src 'self'; font-src 'self'; frame-ancestors 'none'; frame-src blob:; img-src 'self' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-modals allow-downloads" ; Enable or disable the warning message when the site is served over an insecure ; connection (insecure HTTP instead of HTTPS), defaults to true. @@ -107,7 +134,7 @@ languageselection = false ; See https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-it-show-me-an-error-about-an-insecure-connection for more information. ; httpwarning = true -; Pick compression algorithm or disable it. Only applies to pastes/comments +; Pick compression algorithm or disable it. Only applies to documents & comments ; created after changing the setting. ; Can be set to one these values: "none" / "zlib" (default). ; compression = "zlib" @@ -148,9 +175,9 @@ limit = 10 ; exempted = "1.2.3.4,10.10.10/24" ; (optional) If you want only some source IP addresses (v4 or v6) or subnets -; (CIDR) to be allowed to create pastes, set these here. Invalid IPs will be +; (CIDR) to be allowed to create documents, set these here. Invalid IPs will be ; ignored. If multiple values are to be exempted, the list needs to be comma -; separated. Leave unset to allow anyone to create pastes. +; separated. Leave unset to allow anyone to create documents. ; creators = "1.2.3.4,10.10.10/24" ; (optional) if your website runs behind a reverse proxy or load balancer, @@ -158,12 +185,12 @@ limit = 10 ; header = "X_FORWARDED_FOR" [purge] -; minimum time limit between two purgings of expired pastes, it is only -; triggered when pastes are created -; Set this to 0 to run a purge every time a paste is created. +; minimum time limit between two purgings of expired documents, it is only +; checked when documents get created +; Set this to 0 to run a purge every time a document is created. limit = 300 -; maximum amount of expired pastes to delete in one purge +; maximum amount of expired documents to delete in one purge ; Set this to 0 to disable purging. Set it higher, if you are running a large ; site batchsize = 10 @@ -240,26 +267,43 @@ dir = PATH "data" ; - AWS_ACCESS_KEY_ID ; - AWS_SECRET_ACCESS_KEY ; - AWS_SESSION_TOKEN (if needed) -; for more details, see https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/guide_credentials.html#default-credential-chain +; for more details, see https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/guide_credentials.html#default-credential-chain ;class = S3Storage ;[model_options] ;region = "eu-central-1" ;version = "latest" ;bucket = "my-bucket" -[yourls] +;[shlink] +; - Shlink requires you to make a post call with a generated API key. +; use this section to setup the API key and URL. In order to use this section, +; "urlshortener" needs to point to the base URL of your PrivateBin +; instance with "?shortenviashlink&link=" appended. For example: +; urlshortener = "${basepath}?shortenviashlink&link=" +; This URL will in turn call YOURLS on the server side, using the URL from +; "apiurl" and the API Key from the "apikey" parameters below. +; apiurl = "https://shlink.example.com/rest/v3/short-urls" +; apikey = "your_api_key" + +;[yourls] ; When using YOURLS as a "urlshortener" config item: ; - By default, "urlshortener" will point to the YOURLS API URL, with or without ; credentials, and will be visible in public on the PrivateBin web page. ; Only use this if you allow short URL creation without credentials. ; - Alternatively, using the parameters in this section ("signature" and ; "apiurl"), "urlshortener" needs to point to the base URL of your PrivateBin -; instance with "shortenviayourls?link=" appended. For example: -; urlshortener = "${basepath}shortenviayourls?link=" +; instance with "?shortenviayourls&link=" appended. For example: +; urlshortener = "${basepath}?shortenviayourls&link=" ; This URL will in turn call YOURLS on the server side, using the URL from ; "apiurl" and the "access signature" from the "signature" parameters below. ; (optional) the "signature" (access key) issued by YOURLS for the using account ; signature = "" ; (optional) the URL of the YOURLS API, called to shorten a PrivateBin URL -; apiurl = "https://yourls.example.com/yourls-api.php" \ No newline at end of file +; apiurl = "https://yourls.example.com/yourls-api.php" + +;[sri] +; Subresource integrity (SRI) hashes used in template files. Uncomment and set +; these for all js files used. See: +; https://github.com/PrivateBin/PrivateBin/wiki/FAQ#user-content-how-to-make-privatebin-work-when-i-have-changed-some-javascript-files +;js/privatebin.js = "sha512-[…]" diff --git a/codacy-analysis.yml b/codacy-analysis.yml index 9850708b..31d065cd 100644 --- a/codacy-analysis.yml +++ b/codacy-analysis.yml @@ -24,7 +24,7 @@ jobs: steps: # Checkout the repository to the GitHub Actions runner - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis - name: Run Codacy Analysis CLI diff --git a/composer.json b/composer.json index bbd720ae..3338e1ab 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name" : "privatebin/privatebin", - "description" : "PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted in the browser using 256 bit AES in Galois Counter mode (GCM).", + "description" : "PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted in the browser using 256 bit AES in Galois Counter mode (GCM).", "type" : "project", "keywords" : [ "private", @@ -24,14 +24,15 @@ "docs" : "https://privatebin.info/codedoc/" }, "require" : { - "php": "^7.3 || ^8.0", - "jdenticon/jdenticon": "1.0.2", - "mlocati/ip-lib": "1.18.0", + "php": "^7.4 || ^8.0", + "jdenticon/jdenticon": "2.0.0", + "mlocati/ip-lib": "1.20.0", + "symfony/polyfill-php80": "1.31.0", "yzalis/identicon": "2.0.0" }, "suggest" : { - "google/cloud-storage" : "1.32.0", - "aws/aws-sdk-php" : "3.275.1" + "google/cloud-storage" : "1.45.0", + "aws/aws-sdk-php" : "3.336.2" }, "require-dev" : { "phpunit/phpunit" : "^9" @@ -47,7 +48,7 @@ "preferred-install": "dist", "sort-packages": true, "platform": { - "php": "7.3" + "php": "7.4" } } } diff --git a/composer.lock b/composer.lock index 5f8d2963..b032e9c4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,27 +4,27 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "96f9b3968855bf9f45813d12568f1cac", + "content-hash": "cc778a671eac2ba1ec70bf9398b2e1bf", "packages": [ { "name": "jdenticon/jdenticon", - "version": "1.0.2", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/dmester/jdenticon-php.git", - "reference": "cabb7a44c413c318392a341c5d3ca30fcdd57a6f" + "reference": "fb39a98a0a54982a130b7e7b06305d4fd8c9717e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dmester/jdenticon-php/zipball/cabb7a44c413c318392a341c5d3ca30fcdd57a6f", - "reference": "cabb7a44c413c318392a341c5d3ca30fcdd57a6f", + "url": "https://api.github.com/repos/dmester/jdenticon-php/zipball/fb39a98a0a54982a130b7e7b06305d4fd8c9717e", + "reference": "fb39a98a0a54982a130b7e7b06305d4fd8c9717e", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=7.4.0" }, "require-dev": { - "phpunit/phpunit": "^5.7" + "phpunit/phpunit": "^9" }, "type": "library", "autoload": { @@ -53,20 +53,20 @@ "issues": "https://github.com/dmester/jdenticon-php/issues", "source": "https://github.com/dmester/jdenticon-php" }, - "time": "2022-10-30T17:15:02+00:00" + "time": "2025-07-14T18:30:29+00:00" }, { "name": "mlocati/ip-lib", - "version": "1.18.0", + "version": "1.20.0", "source": { "type": "git", "url": "https://github.com/mlocati/ip-lib.git", - "reference": "c77bd0b1f3e3956c7e9661e75cb1f54ed67d95d2" + "reference": "fd45fc3bf08ed6c7e665e2e70562082ac954afd4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mlocati/ip-lib/zipball/c77bd0b1f3e3956c7e9661e75cb1f54ed67d95d2", - "reference": "c77bd0b1f3e3956c7e9661e75cb1f54ed67d95d2", + "url": "https://api.github.com/repos/mlocati/ip-lib/zipball/fd45fc3bf08ed6c7e665e2e70562082ac954afd4", + "reference": "fd45fc3bf08ed6c7e665e2e70562082ac954afd4", "shasum": "" }, "require": { @@ -112,7 +112,7 @@ ], "support": { "issues": "https://github.com/mlocati/ip-lib/issues", - "source": "https://github.com/mlocati/ip-lib/tree/1.18.0" + "source": "https://github.com/mlocati/ip-lib/tree/1.20.0" }, "funding": [ { @@ -124,7 +124,87 @@ "type": "other" } ], - "time": "2022-01-13T18:05:33+00:00" + "time": "2025-02-04T17:30:58+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" }, { "name": "yzalis/identicon", @@ -257,16 +337,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.11.1", + "version": "1.13.3", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" + "reference": "faed855a7b5f4d4637717c2b3863e277116beb36" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/faed855a7b5f4d4637717c2b3863e277116beb36", + "reference": "faed855a7b5f4d4637717c2b3863e277116beb36", "shasum": "" }, "require": { @@ -274,11 +354,12 @@ }, "conflict": { "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3,<3.2.2" + "doctrine/common": "<2.13.3 || >=3 <3.2.2" }, "require-dev": { "doctrine/collections": "^1.6.8", "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", @@ -304,7 +385,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.3" }, "funding": [ { @@ -312,29 +393,31 @@ "type": "tidelift" } ], - "time": "2023-03-08T13:26:56+00:00" + "time": "2025-07-05T12:25:42+00:00" }, { "name": "nikic/php-parser", - "version": "v4.18.0", + "version": "v5.5.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9", + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9", "shasum": "" }, "require": { + "ext-ctype": "*", + "ext-json": "*", "ext-tokenizer": "*", - "php": ">=7.0" + "php": ">=7.4" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^9.0" }, "bin": [ "bin/php-parse" @@ -342,7 +425,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.9-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -366,26 +449,27 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0" }, - "time": "2023-12-10T21:03:43+00:00" + "time": "2025-05-31T08:24:38+00:00" }, { "name": "phar-io/manifest", - "version": "2.0.3", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + "reference": "54750ef60c58e43759730615a392c31c80e23176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", "shasum": "" }, "require": { "ext-dom": "*", + "ext-libxml": "*", "ext-phar": "*", "ext-xmlwriter": "*", "phar-io/version": "^3.0.1", @@ -426,9 +510,15 @@ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.3" + "source": "https://github.com/phar-io/manifest/tree/2.0.4" }, - "time": "2021-07-20T11:28:43+00:00" + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" }, { "name": "phar-io/version", @@ -483,35 +573,35 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.30", + "version": "9.2.32", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089" + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089", - "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5", + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.18 || ^5.0", + "nikic/php-parser": "^4.19.1 || ^5.1.0", "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-text-template": "^2.0.4", + "sebastian/code-unit-reverse-lookup": "^2.0.3", + "sebastian/complexity": "^2.0.3", + "sebastian/environment": "^5.1.5", + "sebastian/lines-of-code": "^1.0.4", + "sebastian/version": "^3.0.2", + "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.6" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -520,7 +610,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.2-dev" + "dev-main": "9.2.x-dev" } }, "autoload": { @@ -549,7 +639,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.30" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32" }, "funding": [ { @@ -557,7 +647,7 @@ "type": "github" } ], - "time": "2023-12-22T06:47:57+00:00" + "time": "2024-08-22T04:23:01+00:00" }, { "name": "phpunit/php-file-iterator", @@ -802,45 +892,45 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.16", + "version": "9.6.23", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "3767b2c56ce02d01e3491046f33466a1ae60a37f" + "reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3767b2c56ce02d01e3491046f33466a1ae60a37f", - "reference": "3767b2c56ce02d01e3491046f33466a1ae60a37f", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/43d2cb18d0675c38bd44982a5d1d88f6d53d8d95", + "reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.3.1 || ^2", + "doctrine/instantiator": "^1.5.0 || ^2", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.3", - "phar-io/version": "^3.0.2", + "myclabs/deep-copy": "^1.13.1", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.28", - "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-code-coverage": "^9.2.32", + "phpunit/php-file-iterator": "^3.0.6", "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.3", - "phpunit/php-timer": "^5.0.2", - "sebastian/cli-parser": "^1.0.1", - "sebastian/code-unit": "^1.0.6", + "phpunit/php-text-template": "^2.0.4", + "phpunit/php-timer": "^5.0.3", + "sebastian/cli-parser": "^1.0.2", + "sebastian/code-unit": "^1.0.8", "sebastian/comparator": "^4.0.8", - "sebastian/diff": "^4.0.3", - "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.5", - "sebastian/global-state": "^5.0.1", - "sebastian/object-enumerator": "^4.0.3", - "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^3.2", + "sebastian/diff": "^4.0.6", + "sebastian/environment": "^5.1.5", + "sebastian/exporter": "^4.0.6", + "sebastian/global-state": "^5.0.7", + "sebastian/object-enumerator": "^4.0.4", + "sebastian/resource-operations": "^3.0.4", + "sebastian/type": "^3.2.1", "sebastian/version": "^3.0.2" }, "suggest": { @@ -885,7 +975,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.16" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.23" }, "funding": [ { @@ -896,25 +986,33 @@ "url": "https://github.com/sebastianbergmann", "type": "github" }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, { "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", "type": "tidelift" } ], - "time": "2024-01-19T07:03:14+00:00" + "time": "2025-05-02T06:40:34+00:00" }, { "name": "sebastian/cli-parser", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", "shasum": "" }, "require": { @@ -949,7 +1047,7 @@ "homepage": "https://github.com/sebastianbergmann/cli-parser", "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" }, "funding": [ { @@ -957,7 +1055,7 @@ "type": "github" } ], - "time": "2020-09-28T06:08:49+00:00" + "time": "2024-03-02T06:27:43+00:00" }, { "name": "sebastian/code-unit", @@ -1203,16 +1301,16 @@ }, { "name": "sebastian/diff", - "version": "4.0.5", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", "shasum": "" }, "require": { @@ -1257,7 +1355,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" }, "funding": [ { @@ -1265,7 +1363,7 @@ "type": "github" } ], - "time": "2023-05-07T05:35:17+00:00" + "time": "2024-03-02T06:30:58+00:00" }, { "name": "sebastian/environment", @@ -1332,16 +1430,16 @@ }, { "name": "sebastian/exporter", - "version": "4.0.5", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", "shasum": "" }, "require": { @@ -1397,7 +1495,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" }, "funding": [ { @@ -1405,20 +1503,20 @@ "type": "github" } ], - "time": "2022-09-14T06:03:37+00:00" + "time": "2024-03-02T06:33:00+00:00" }, { "name": "sebastian/global-state", - "version": "5.0.6", + "version": "5.0.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bde739e7565280bda77be70044ac1047bc007e34" + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", - "reference": "bde739e7565280bda77be70044ac1047bc007e34", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", "shasum": "" }, "require": { @@ -1461,7 +1559,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7" }, "funding": [ { @@ -1469,7 +1567,7 @@ "type": "github" } ], - "time": "2023-08-02T09:26:13+00:00" + "time": "2024-03-02T06:35:11+00:00" }, { "name": "sebastian/lines-of-code", @@ -1705,16 +1803,16 @@ }, { "name": "sebastian/resource-operations", - "version": "3.0.3", + "version": "3.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", "shasum": "" }, "require": { @@ -1726,7 +1824,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -1747,8 +1845,7 @@ "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" }, "funding": [ { @@ -1756,7 +1853,7 @@ "type": "github" } ], - "time": "2020-09-28T06:45:17+00:00" + "time": "2024-03-14T16:00:52+00:00" }, { "name": "sebastian/type", @@ -1869,16 +1966,16 @@ }, { "name": "theseer/tokenizer", - "version": "1.2.2", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96" + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96", - "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", "shasum": "" }, "require": { @@ -1907,7 +2004,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.2" + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" }, "funding": [ { @@ -1915,7 +2012,7 @@ "type": "github" } ], - "time": "2023-11-20T00:12:19+00:00" + "time": "2024-03-03T12:36:25+00:00" } ], "aliases": [], @@ -1924,11 +2021,11 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.3 || ^8.0" + "php": "^7.4 || ^8.0" }, "platform-dev": [], "platform-overrides": { - "php": "7.3" + "php": "7.4" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" } diff --git a/css/bootstrap/privatebin.css b/css/bootstrap/privatebin.css index 20a7e4e4..ab2fdebc 100644 --- a/css/bootstrap/privatebin.css +++ b/css/bootstrap/privatebin.css @@ -1,14 +1,15 @@ /** * PrivateBin * - * a zero-knowledge paste bin + * Cascading style sheets for bootstrap template. * * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.7.1 */ +@import url("../common.css"); + body { padding: 0 0 30px; } @@ -68,97 +69,8 @@ body.loading { margin-right: 8px; } -#attachmentPreview img { - max-width: 100%; - height: auto; - margin-bottom: 20px; -} - -#attachmentPreview .pdfPreview { - width: 100%; - height: 100vh; - margin-bottom: 20px; -} - -#dropzone { - text-align: center; - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 1000; - opacity: 0.6; - background-color: #99ccff; - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM14 13v4h-4v-4H7l5-5 5 5h-3z'/%3E%3C/svg%3E"); - background-repeat: no-repeat; - background-position: center; - background-size: 25vh; - outline: 2px dashed #228bff; - outline-offset: -50px; -} - -.dragAndDropFile{ - color: #777; - font-size: 1em; - display: inline; - white-space: normal; -} - -#deletelink { - float: right; - margin-left: 5px; -} - -#qrcodemodalClose { - float: right; -} - -#qrcode-display { - width: 200px; - height: 200px; - margin: auto; -} - -#pastelink { - display: inline; -} - -#pastelink > a { - word-wrap: break-word; -} - -#preview { - margin-bottom: 10px; -} - -#message, .replymessage { - font-family: monospace; - resize: vertical; -} - -#nickname { - margin: 5px 0; -} - -#comments, #comments button { - margin-bottom: 10px; -} - -#filewrap { - transition: background-color 0.75s ease-out; -} - .comment { - border-left: 1px solid #ccc; padding: 5px 0 5px 10px; - white-space: pre-wrap; - transition: background-color 0.75s ease-out; -} - -.highlight { - background-color: #ffdd86; - transition: background-color 0.2s ease-in; } footer h4 { @@ -226,3 +138,31 @@ html[dir="rtl"] #language { html[dir="rtl"] #deletelink, html[dir="rtl"] #qrcodemodalClose { float: left; } + +#prettyprint { + padding-right: 30px; +} + +#prettyMessageCopyBtn { + position: absolute; + top: 8px; + right: 25px; + left: auto; + padding: 0; + background: none; + border: none; + z-index: 1; +} + +html[dir="rtl"] #prettyMessageCopyBtn { + left: 25px; + right: auto; +} + +#copySuccessIcon { + display: none; +} + +#copyShortcutHint { + margin-bottom: 5px; +} \ No newline at end of file diff --git a/css/bootstrap5/bootstrap-5.3.7.css b/css/bootstrap5/bootstrap-5.3.7.css new file mode 100644 index 00000000..01c7e4aa --- /dev/null +++ b/css/bootstrap5/bootstrap-5.3.7.css @@ -0,0 +1,5 @@ +@charset "UTF-8";/*! + * Bootstrap v5.3.7 (https://getbootstrap.com/) + * Copyright 2011-2025 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */:root,[data-bs-theme=light]{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-black:#000;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-primary-text-emphasis:#052c65;--bs-secondary-text-emphasis:#2b2f32;--bs-success-text-emphasis:#0a3622;--bs-info-text-emphasis:#055160;--bs-warning-text-emphasis:#664d03;--bs-danger-text-emphasis:#58151c;--bs-light-text-emphasis:#495057;--bs-dark-text-emphasis:#495057;--bs-primary-bg-subtle:#cfe2ff;--bs-secondary-bg-subtle:#e2e3e5;--bs-success-bg-subtle:#d1e7dd;--bs-info-bg-subtle:#cff4fc;--bs-warning-bg-subtle:#fff3cd;--bs-danger-bg-subtle:#f8d7da;--bs-light-bg-subtle:#fcfcfd;--bs-dark-bg-subtle:#ced4da;--bs-primary-border-subtle:#9ec5fe;--bs-secondary-border-subtle:#c4c8cb;--bs-success-border-subtle:#a3cfbb;--bs-info-border-subtle:#9eeaf9;--bs-warning-border-subtle:#ffe69c;--bs-danger-border-subtle:#f1aeb5;--bs-light-border-subtle:#e9ecef;--bs-dark-border-subtle:#adb5bd;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-font-sans-serif: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";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#212529;--bs-body-color-rgb:33,37,41;--bs-body-bg:#fff;--bs-body-bg-rgb:255,255,255;--bs-emphasis-color:#000;--bs-emphasis-color-rgb:0,0,0;--bs-secondary-color:rgba(33, 37, 41, 0.75);--bs-secondary-color-rgb:33,37,41;--bs-secondary-bg:#e9ecef;--bs-secondary-bg-rgb:233,236,239;--bs-tertiary-color:rgba(33, 37, 41, 0.5);--bs-tertiary-color-rgb:33,37,41;--bs-tertiary-bg:#f8f9fa;--bs-tertiary-bg-rgb:248,249,250;--bs-heading-color:inherit;--bs-link-color:#0d6efd;--bs-link-color-rgb:13,110,253;--bs-link-decoration:underline;--bs-link-hover-color:#0a58ca;--bs-link-hover-color-rgb:10,88,202;--bs-code-color:#d63384;--bs-highlight-color:#212529;--bs-highlight-bg:#fff3cd;--bs-border-width:1px;--bs-border-style:solid;--bs-border-color:#dee2e6;--bs-border-color-translucent:rgba(0, 0, 0, 0.175);--bs-border-radius:0.375rem;--bs-border-radius-sm:0.25rem;--bs-border-radius-lg:0.5rem;--bs-border-radius-xl:1rem;--bs-border-radius-xxl:2rem;--bs-border-radius-2xl:var(--bs-border-radius-xxl);--bs-border-radius-pill:50rem;--bs-box-shadow:0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm:0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg:0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset:inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width:0.25rem;--bs-focus-ring-opacity:0.25;--bs-focus-ring-color:rgba(13, 110, 253, 0.25);--bs-form-valid-color:#198754;--bs-form-valid-border-color:#198754;--bs-form-invalid-color:#dc3545;--bs-form-invalid-border-color:#dc3545}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color:#dee2e6;--bs-body-color-rgb:222,226,230;--bs-body-bg:#212529;--bs-body-bg-rgb:33,37,41;--bs-emphasis-color:#fff;--bs-emphasis-color-rgb:255,255,255;--bs-secondary-color:rgba(222, 226, 230, 0.75);--bs-secondary-color-rgb:222,226,230;--bs-secondary-bg:#343a40;--bs-secondary-bg-rgb:52,58,64;--bs-tertiary-color:rgba(222, 226, 230, 0.5);--bs-tertiary-color-rgb:222,226,230;--bs-tertiary-bg:#2b3035;--bs-tertiary-bg-rgb:43,48,53;--bs-primary-text-emphasis:#6ea8fe;--bs-secondary-text-emphasis:#a7acb1;--bs-success-text-emphasis:#75b798;--bs-info-text-emphasis:#6edff6;--bs-warning-text-emphasis:#ffda6a;--bs-danger-text-emphasis:#ea868f;--bs-light-text-emphasis:#f8f9fa;--bs-dark-text-emphasis:#dee2e6;--bs-primary-bg-subtle:#031633;--bs-secondary-bg-subtle:#161719;--bs-success-bg-subtle:#051b11;--bs-info-bg-subtle:#032830;--bs-warning-bg-subtle:#332701;--bs-danger-bg-subtle:#2c0b0e;--bs-light-bg-subtle:#343a40;--bs-dark-bg-subtle:#1a1d20;--bs-primary-border-subtle:#084298;--bs-secondary-border-subtle:#41464b;--bs-success-border-subtle:#0f5132;--bs-info-border-subtle:#087990;--bs-warning-border-subtle:#997404;--bs-danger-border-subtle:#842029;--bs-light-border-subtle:#495057;--bs-dark-border-subtle:#343a40;--bs-heading-color:inherit;--bs-link-color:#6ea8fe;--bs-link-hover-color:#8bb9fe;--bs-link-color-rgb:110,168,254;--bs-link-hover-color-rgb:139,185,254;--bs-code-color:#e685b5;--bs-highlight-color:#dee2e6;--bs-highlight-bg:#664d03;--bs-border-color:#495057;--bs-border-color-translucent:rgba(255, 255, 255, 0.15);--bs-form-valid-color:#75b798;--bs-form-valid-border-color:#75b798;--bs-form-invalid-color:#ea868f;--bs-form-invalid-border-color:#ea868f}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;border:0;border-top:var(--bs-border-width) solid;opacity:.25}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color)}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.1875em;color:var(--bs-highlight-color);background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,1));text-decoration:underline}a:hover{--bs-link-color-rgb:var(--bs-link-hover-color-rgb)}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:var(--bs-code-color);word-wrap:break-word}a>code{color:inherit}kbd{padding:.1875rem .375rem;font-size:.875em;color:var(--bs-body-bg);background-color:var(--bs-body-color);border-radius:.25rem}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-secondary-color);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none!important}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;line-height:inherit;font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-weight:300;line-height:1.2;font-size:calc(1.625rem + 4.5vw)}@media (min-width:1200px){.display-1{font-size:5rem}}.display-2{font-weight:300;line-height:1.2;font-size:calc(1.575rem + 3.9vw)}@media (min-width:1200px){.display-2{font-size:4.5rem}}.display-3{font-weight:300;line-height:1.2;font-size:calc(1.525rem + 3.3vw)}@media (min-width:1200px){.display-3{font-size:4rem}}.display-4{font-weight:300;line-height:1.2;font-size:calc(1.475rem + 2.7vw)}@media (min-width:1200px){.display-4{font-size:3.5rem}}.display-5{font-weight:300;line-height:1.2;font-size:calc(1.425rem + 2.1vw)}@media (min-width:1200px){.display-5{font-size:3rem}}.display-6{font-weight:300;line-height:1.2;font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:var(--bs-body-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:var(--bs-secondary-color)}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{--bs-gutter-x:1.5rem;--bs-gutter-y:0;width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}:root{--bs-breakpoint-xs:0;--bs-breakpoint-sm:576px;--bs-breakpoint-md:768px;--bs-breakpoint-lg:992px;--bs-breakpoint-xl:1200px;--bs-breakpoint-xxl:1400px}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--bs-gutter-y));margin-right:calc(-.5 * var(--bs-gutter-x));margin-left:calc(-.5 * var(--bs-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.66666667%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm{flex:1 0 0}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.66666667%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md{flex:1 0 0}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.66666667%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg{flex:1 0 0}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.66666667%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl{flex:1 0 0}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.66666667%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl{flex:1 0 0}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.66666667%}.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.table{--bs-table-color-type:initial;--bs-table-bg-type:initial;--bs-table-color-state:initial;--bs-table-bg-state:initial;--bs-table-color:var(--bs-emphasis-color);--bs-table-bg:var(--bs-body-bg);--bs-table-border-color:var(--bs-border-color);--bs-table-accent-bg:transparent;--bs-table-striped-color:var(--bs-emphasis-color);--bs-table-striped-bg:rgba(var(--bs-emphasis-color-rgb), 0.05);--bs-table-active-color:var(--bs-emphasis-color);--bs-table-active-bg:rgba(var(--bs-emphasis-color-rgb), 0.1);--bs-table-hover-color:var(--bs-emphasis-color);--bs-table-hover-bg:rgba(var(--bs-emphasis-color-rgb), 0.075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;color:var(--bs-table-color-state,var(--bs-table-color-type,var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:var(--bs-border-width);box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state,var(--bs-table-bg-type,var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(var(--bs-border-width) * 2) solid currentcolor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:var(--bs-border-width) 0}.table-bordered>:not(caption)>*>*{border-width:0 var(--bs-border-width)}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(2n){--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-active{--bs-table-color-state:var(--bs-table-active-color);--bs-table-bg-state:var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state:var(--bs-table-hover-color);--bs-table-bg-state:var(--bs-table-hover-bg)}.table-primary{--bs-table-color:#000;--bs-table-bg:#cfe2ff;--bs-table-border-color:#a6b5cc;--bs-table-striped-bg:#c5d7f2;--bs-table-striped-color:#000;--bs-table-active-bg:#bacbe6;--bs-table-active-color:#000;--bs-table-hover-bg:#bfd1ec;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color:#000;--bs-table-bg:#e2e3e5;--bs-table-border-color:#b5b6b7;--bs-table-striped-bg:#d7d8da;--bs-table-striped-color:#000;--bs-table-active-bg:#cbccce;--bs-table-active-color:#000;--bs-table-hover-bg:#d1d2d4;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color:#000;--bs-table-bg:#d1e7dd;--bs-table-border-color:#a7b9b1;--bs-table-striped-bg:#c7dbd2;--bs-table-striped-color:#000;--bs-table-active-bg:#bcd0c7;--bs-table-active-color:#000;--bs-table-hover-bg:#c1d6cc;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color:#000;--bs-table-bg:#cff4fc;--bs-table-border-color:#a6c3ca;--bs-table-striped-bg:#c5e8ef;--bs-table-striped-color:#000;--bs-table-active-bg:#badce3;--bs-table-active-color:#000;--bs-table-hover-bg:#bfe2e9;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color:#000;--bs-table-bg:#fff3cd;--bs-table-border-color:#ccc2a4;--bs-table-striped-bg:#f2e7c3;--bs-table-striped-color:#000;--bs-table-active-bg:#e6dbb9;--bs-table-active-color:#000;--bs-table-hover-bg:#ece1be;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color:#000;--bs-table-bg:#f8d7da;--bs-table-border-color:#c6acae;--bs-table-striped-bg:#eccccf;--bs-table-striped-color:#000;--bs-table-active-bg:#dfc2c4;--bs-table-active-color:#000;--bs-table-hover-bg:#e5c7ca;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color:#000;--bs-table-bg:#f8f9fa;--bs-table-border-color:#c6c7c8;--bs-table-striped-bg:#ecedee;--bs-table-striped-color:#000;--bs-table-active-bg:#dfe0e1;--bs-table-active-color:#000;--bs-table-hover-bg:#e5e6e7;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color:#fff;--bs-table-bg:#212529;--bs-table-border-color:#4d5154;--bs-table-striped-bg:#2c3034;--bs-table-striped-color:#fff;--bs-table-active-bg:#373b3e;--bs-table-active-color:#fff;--bs-table-hover-bg:#323539;--bs-table-hover-color:#fff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width:575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + var(--bs-border-width));padding-bottom:calc(.375rem + var(--bs-border-width));margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + var(--bs-border-width));padding-bottom:calc(.5rem + var(--bs-border-width));font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + var(--bs-border-width));padding-bottom:calc(.25rem + var(--bs-border-width));font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:var(--bs-secondary-color)}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-clip:padding-box;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::placeholder{color:var(--bs-secondary-color);opacity:1}.form-control:disabled{background-color:var(--bs-secondary-bg);opacity:1}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:var(--bs-secondary-bg)}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:var(--bs-secondary-bg)}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:var(--bs-body-color);background-color:transparent;border:solid transparent;border-width:var(--bs-border-width) 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2));padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2))}textarea.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}textarea.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-control-color{width:3rem;height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2));padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color::-webkit-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color.form-control-sm{height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon,none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:var(--bs-secondary-bg)}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 var(--bs-body-color)}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-reverse{padding-right:1.5em;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:-1.5em;margin-left:0}.form-check-input{--bs-form-check-bg:var(--bs-body-bg);flex-shrink:0;width:1em;height:1em;margin-top:.25em;vertical-align:top;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:var(--bs-border-width) solid var(--bs-border-color);-webkit-print-color-adjust:exact;color-adjust:exact;print-color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{cursor:default;opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check:disabled+.btn,.btn-check[disabled]+.btn{pointer-events:none;filter:none;opacity:.65}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;-webkit-appearance:none;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;-moz-appearance:none;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:var(--bs-secondary-color)}.form-range:disabled::-moz-range-thumb{background-color:var(--bs-secondary-color)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(var(--bs-border-width) * 2));min-height:calc(3.5rem + calc(var(--bs-border-width) * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;max-width:100%;height:100%;padding:1rem .75rem;overflow:hidden;color:rgba(var(--bs-body-color-rgb),.65);text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:var(--bs-border-width) solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control-plaintext::placeholder,.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown),.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control-plaintext:-webkit-autofill,.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem;padding-left:.75rem}.form-floating>.form-control-plaintext~label,.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:-webkit-autofill~label{transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>textarea:focus~label::after,.form-floating>textarea:not(:placeholder-shown)~label::after{position:absolute;inset:1rem 0.375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>textarea:disabled~label::after{background-color:var(--bs-secondary-bg)}.form-floating>.form-control-plaintext~label{border-width:var(--bs-border-width) 0}.form-floating>.form-control:disabled~label,.form-floating>:disabled~label{color:#6c757d}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-floating,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-floating:focus-within,.input-group>.form-select:focus{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);text-align:center;white-space:nowrap;background-color:var(--bs-tertiary-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius)}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-control,.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-select,.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-control,.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-select,.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(-1 * var(--bs-border-width));border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-valid-color)}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-success);border-radius:var(--bs-border-radius)}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:var(--bs-form-valid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:var(--bs-form-valid-border-color)}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-control-color.is-valid,.was-validated .form-control-color:valid{width:calc(3rem + calc(1.5em + .75rem))}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:var(--bs-form-valid-border-color)}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:var(--bs-form-valid-color)}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:var(--bs-form-valid-color)}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-valid,.input-group>.form-floating:not(:focus-within).is-valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-control:not(:focus):valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.was-validated .input-group>.form-select:not(:focus):valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-invalid-color)}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-danger);border-radius:var(--bs-border-radius)}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:var(--bs-form-invalid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:var(--bs-form-invalid-border-color)}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-control-color.is-invalid,.was-validated .form-control-color:invalid{width:calc(3rem + calc(1.5em + .75rem))}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:var(--bs-form-invalid-border-color)}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:var(--bs-form-invalid-color)}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:var(--bs-form-invalid-color)}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-invalid,.input-group>.form-floating:not(:focus-within).is-invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-control:not(:focus):invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.was-validated .input-group>.form-select:not(:focus):invalid{z-index:4}.btn{--bs-btn-padding-x:0.75rem;--bs-btn-padding-y:0.375rem;--bs-btn-font-family: ;--bs-btn-font-size:1rem;--bs-btn-font-weight:400;--bs-btn-line-height:1.5;--bs-btn-color:var(--bs-body-color);--bs-btn-bg:transparent;--bs-btn-border-width:var(--bs-border-width);--bs-btn-border-color:transparent;--bs-btn-border-radius:var(--bs-border-radius);--bs-btn-hover-border-color:transparent;--bs-btn-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.15),0 1px 1px rgba(0, 0, 0, 0.075);--bs-btn-disabled-opacity:0.65;--bs-btn-focus-box-shadow:0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);border-radius:var(--bs-btn-border-radius);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,.btn.active,.btn.show,.btn:first-child:active,:not(.btn-check)+.btn:active{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible,.btn:first-child:active:focus-visible,:not(.btn-check)+.btn:active:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked:focus-visible+.btn{box-shadow:var(--bs-btn-focus-box-shadow)}.btn.disabled,.btn:disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-primary{--bs-btn-color:#fff;--bs-btn-bg:#0d6efd;--bs-btn-border-color:#0d6efd;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#0b5ed7;--bs-btn-hover-border-color:#0a58ca;--bs-btn-focus-shadow-rgb:49,132,253;--bs-btn-active-color:#fff;--bs-btn-active-bg:#0a58ca;--bs-btn-active-border-color:#0a53be;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#0d6efd;--bs-btn-disabled-border-color:#0d6efd}.btn-secondary{--bs-btn-color:#fff;--bs-btn-bg:#6c757d;--bs-btn-border-color:#6c757d;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#5c636a;--bs-btn-hover-border-color:#565e64;--bs-btn-focus-shadow-rgb:130,138,145;--bs-btn-active-color:#fff;--bs-btn-active-bg:#565e64;--bs-btn-active-border-color:#51585e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#6c757d;--bs-btn-disabled-border-color:#6c757d}.btn-success{--bs-btn-color:#fff;--bs-btn-bg:#198754;--bs-btn-border-color:#198754;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#157347;--bs-btn-hover-border-color:#146c43;--bs-btn-focus-shadow-rgb:60,153,110;--bs-btn-active-color:#fff;--bs-btn-active-bg:#146c43;--bs-btn-active-border-color:#13653f;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#198754;--bs-btn-disabled-border-color:#198754}.btn-info{--bs-btn-color:#000;--bs-btn-bg:#0dcaf0;--bs-btn-border-color:#0dcaf0;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#31d2f2;--bs-btn-hover-border-color:#25cff2;--bs-btn-focus-shadow-rgb:11,172,204;--bs-btn-active-color:#000;--bs-btn-active-bg:#3dd5f3;--bs-btn-active-border-color:#25cff2;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#0dcaf0;--bs-btn-disabled-border-color:#0dcaf0}.btn-warning{--bs-btn-color:#000;--bs-btn-bg:#ffc107;--bs-btn-border-color:#ffc107;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#ffca2c;--bs-btn-hover-border-color:#ffc720;--bs-btn-focus-shadow-rgb:217,164,6;--bs-btn-active-color:#000;--bs-btn-active-bg:#ffcd39;--bs-btn-active-border-color:#ffc720;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#ffc107;--bs-btn-disabled-border-color:#ffc107}.btn-danger{--bs-btn-color:#fff;--bs-btn-bg:#dc3545;--bs-btn-border-color:#dc3545;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#bb2d3b;--bs-btn-hover-border-color:#b02a37;--bs-btn-focus-shadow-rgb:225,83,97;--bs-btn-active-color:#fff;--bs-btn-active-bg:#b02a37;--bs-btn-active-border-color:#a52834;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#dc3545;--bs-btn-disabled-border-color:#dc3545}.btn-light{--bs-btn-color:#000;--bs-btn-bg:#f8f9fa;--bs-btn-border-color:#f8f9fa;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#d3d4d5;--bs-btn-hover-border-color:#c6c7c8;--bs-btn-focus-shadow-rgb:211,212,213;--bs-btn-active-color:#000;--bs-btn-active-bg:#c6c7c8;--bs-btn-active-border-color:#babbbc;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#f8f9fa;--bs-btn-disabled-border-color:#f8f9fa}.btn-dark{--bs-btn-color:#fff;--bs-btn-bg:#212529;--bs-btn-border-color:#212529;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#424649;--bs-btn-hover-border-color:#373b3e;--bs-btn-focus-shadow-rgb:66,70,73;--bs-btn-active-color:#fff;--bs-btn-active-bg:#4d5154;--bs-btn-active-border-color:#373b3e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#212529;--bs-btn-disabled-border-color:#212529}.btn-outline-primary{--bs-btn-color:#0d6efd;--bs-btn-border-color:#0d6efd;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#0d6efd;--bs-btn-hover-border-color:#0d6efd;--bs-btn-focus-shadow-rgb:13,110,253;--bs-btn-active-color:#fff;--bs-btn-active-bg:#0d6efd;--bs-btn-active-border-color:#0d6efd;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#0d6efd;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#0d6efd;--bs-gradient:none}.btn-outline-secondary{--bs-btn-color:#6c757d;--bs-btn-border-color:#6c757d;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#6c757d;--bs-btn-hover-border-color:#6c757d;--bs-btn-focus-shadow-rgb:108,117,125;--bs-btn-active-color:#fff;--bs-btn-active-bg:#6c757d;--bs-btn-active-border-color:#6c757d;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#6c757d;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#6c757d;--bs-gradient:none}.btn-outline-success{--bs-btn-color:#198754;--bs-btn-border-color:#198754;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#198754;--bs-btn-hover-border-color:#198754;--bs-btn-focus-shadow-rgb:25,135,84;--bs-btn-active-color:#fff;--bs-btn-active-bg:#198754;--bs-btn-active-border-color:#198754;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#198754;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#198754;--bs-gradient:none}.btn-outline-info{--bs-btn-color:#0dcaf0;--bs-btn-border-color:#0dcaf0;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#0dcaf0;--bs-btn-hover-border-color:#0dcaf0;--bs-btn-focus-shadow-rgb:13,202,240;--bs-btn-active-color:#000;--bs-btn-active-bg:#0dcaf0;--bs-btn-active-border-color:#0dcaf0;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#0dcaf0;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#0dcaf0;--bs-gradient:none}.btn-outline-warning{--bs-btn-color:#ffc107;--bs-btn-border-color:#ffc107;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#ffc107;--bs-btn-hover-border-color:#ffc107;--bs-btn-focus-shadow-rgb:255,193,7;--bs-btn-active-color:#000;--bs-btn-active-bg:#ffc107;--bs-btn-active-border-color:#ffc107;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#ffc107;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#ffc107;--bs-gradient:none}.btn-outline-danger{--bs-btn-color:#dc3545;--bs-btn-border-color:#dc3545;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#dc3545;--bs-btn-hover-border-color:#dc3545;--bs-btn-focus-shadow-rgb:220,53,69;--bs-btn-active-color:#fff;--bs-btn-active-bg:#dc3545;--bs-btn-active-border-color:#dc3545;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#dc3545;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#dc3545;--bs-gradient:none}.btn-outline-light{--bs-btn-color:#f8f9fa;--bs-btn-border-color:#f8f9fa;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#f8f9fa;--bs-btn-hover-border-color:#f8f9fa;--bs-btn-focus-shadow-rgb:248,249,250;--bs-btn-active-color:#000;--bs-btn-active-bg:#f8f9fa;--bs-btn-active-border-color:#f8f9fa;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#f8f9fa;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#f8f9fa;--bs-gradient:none}.btn-outline-dark{--bs-btn-color:#212529;--bs-btn-border-color:#212529;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#212529;--bs-btn-hover-border-color:#212529;--bs-btn-focus-shadow-rgb:33,37,41;--bs-btn-active-color:#fff;--bs-btn-active-bg:#212529;--bs-btn-active-border-color:#212529;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#212529;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#212529;--bs-gradient:none}.btn-link{--bs-btn-font-weight:400;--bs-btn-color:var(--bs-link-color);--bs-btn-bg:transparent;--bs-btn-border-color:transparent;--bs-btn-hover-color:var(--bs-link-hover-color);--bs-btn-hover-border-color:transparent;--bs-btn-active-color:var(--bs-link-hover-color);--bs-btn-active-border-color:transparent;--bs-btn-disabled-color:#6c757d;--bs-btn-disabled-border-color:transparent;--bs-btn-box-shadow:0 0 0 #000;--bs-btn-focus-shadow-rgb:49,132,253;text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-group-lg>.btn,.btn-lg{--bs-btn-padding-y:0.5rem;--bs-btn-padding-x:1rem;--bs-btn-font-size:1.25rem;--bs-btn-border-radius:var(--bs-border-radius-lg)}.btn-group-sm>.btn,.btn-sm{--bs-btn-padding-y:0.25rem;--bs-btn-padding-x:0.5rem;--bs-btn-font-size:0.875rem;--bs-btn-border-radius:var(--bs-border-radius-sm)}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion:reduce){.collapsing.collapse-horizontal{transition:none}}.dropdown,.dropdown-center,.dropend,.dropstart,.dropup,.dropup-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex:1000;--bs-dropdown-min-width:10rem;--bs-dropdown-padding-x:0;--bs-dropdown-padding-y:0.5rem;--bs-dropdown-spacer:0.125rem;--bs-dropdown-font-size:1rem;--bs-dropdown-color:var(--bs-body-color);--bs-dropdown-bg:var(--bs-body-bg);--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-border-radius:var(--bs-border-radius);--bs-dropdown-border-width:var(--bs-border-width);--bs-dropdown-inner-border-radius:calc(var(--bs-border-radius) - var(--bs-border-width));--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-divider-margin-y:0.5rem;--bs-dropdown-box-shadow:var(--bs-box-shadow);--bs-dropdown-link-color:var(--bs-body-color);--bs-dropdown-link-hover-color:var(--bs-body-color);--bs-dropdown-link-hover-bg:var(--bs-tertiary-bg);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#0d6efd;--bs-dropdown-link-disabled-color:var(--bs-tertiary-color);--bs-dropdown-item-padding-x:1rem;--bs-dropdown-item-padding-y:0.25rem;--bs-dropdown-header-color:#6c757d;--bs-dropdown-header-padding-x:1rem;--bs-dropdown-header-padding-y:0.5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);border-radius:var(--bs-dropdown-border-radius)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position:start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position:end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-start{--bs-position:start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position:end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-start{--bs-position:start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position:end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-start{--bs-position:start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position:end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-start{--bs-position:start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position:end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1400px){.dropdown-menu-xxl-start{--bs-position:start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position:end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0;border-radius:var(--bs-dropdown-item-border-radius,0)}.dropdown-item:focus,.dropdown-item:hover{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color:#dee2e6;--bs-dropdown-bg:#343a40;--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color:#dee2e6;--bs-dropdown-link-hover-color:#fff;--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-link-hover-bg:rgba(255, 255, 255, 0.15);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#0d6efd;--bs-dropdown-link-disabled-color:#adb5bd;--bs-dropdown-header-color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group{border-radius:var(--bs-border-radius)}.btn-group>.btn-group:not(:first-child),.btn-group>:not(.btn-check:first-child)+.btn{margin-left:calc(-1 * var(--bs-border-width))}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn.dropdown-toggle-split:first-child,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:calc(-1 * var(--bs-border-width))}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:nth-child(n+3),.btn-group-vertical>:not(.btn-check)+.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{--bs-nav-link-padding-x:1rem;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-link-color);--bs-nav-link-hover-color:var(--bs-link-hover-color);--bs-nav-link-disabled-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;background:0 0;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width:var(--bs-border-width);--bs-nav-tabs-border-color:var(--bs-border-color);--bs-nav-tabs-border-radius:var(--bs-border-radius);--bs-nav-tabs-link-hover-border-color:var(--bs-secondary-bg) var(--bs-secondary-bg) var(--bs-border-color);--bs-nav-tabs-link-active-color:var(--bs-emphasis-color);--bs-nav-tabs-link-active-bg:var(--bs-body-bg);--bs-nav-tabs-link-active-border-color:var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg);border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1 * var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid transparent;border-top-left-radius:var(--bs-nav-tabs-border-radius);border-top-right-radius:var(--bs-nav-tabs-border-radius)}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1 * var(--bs-nav-tabs-border-width));border-top-left-radius:0;border-top-right-radius:0}.nav-pills{--bs-nav-pills-border-radius:var(--bs-border-radius);--bs-nav-pills-link-active-color:#fff;--bs-nav-pills-link-active-bg:#0d6efd}.nav-pills .nav-link{border-radius:var(--bs-nav-pills-border-radius)}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap:1rem;--bs-nav-underline-border-width:0.125rem;--bs-nav-underline-link-active-color:var(--bs-emphasis-color);gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid transparent}.nav-underline .nav-link:focus,.nav-underline .nav-link:hover{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:700;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-grow:1;flex-basis:0;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x:0;--bs-navbar-padding-y:0.5rem;--bs-navbar-color:rgba(var(--bs-emphasis-color-rgb), 0.65);--bs-navbar-hover-color:rgba(var(--bs-emphasis-color-rgb), 0.8);--bs-navbar-disabled-color:rgba(var(--bs-emphasis-color-rgb), 0.3);--bs-navbar-active-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-padding-y:0.3125rem;--bs-navbar-brand-margin-end:1rem;--bs-navbar-brand-font-size:1.25rem;--bs-navbar-brand-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-hover-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-nav-link-padding-x:0.5rem;--bs-navbar-toggler-padding-y:0.25rem;--bs-navbar-toggler-padding-x:0.75rem;--bs-navbar-toggler-font-size:1.25rem;--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color:rgba(var(--bs-emphasis-color-rgb), 0.15);--bs-navbar-toggler-border-radius:var(--bs-border-radius);--bs-navbar-toggler-focus-width:0.25rem;--bs-navbar-toggler-transition:box-shadow 0.15s ease-in-out;position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x:0;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-navbar-color);--bs-nav-link-hover-color:var(--bs-navbar-hover-color);--bs-nav-link-disabled-color:var(--bs-navbar-disabled-color);display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:focus,.navbar-text a:hover{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-grow:1;flex-basis:100%;align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:transparent;border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);border-radius:var(--bs-navbar-toggler-border-radius);transition:var(--bs-navbar-toggler-transition)}@media (prefers-reduced-motion:reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height,75vh);overflow-y:auto}@media (min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color:rgba(255, 255, 255, 0.55);--bs-navbar-hover-color:rgba(255, 255, 255, 0.75);--bs-navbar-disabled-color:rgba(255, 255, 255, 0.25);--bs-navbar-active-color:#fff;--bs-navbar-brand-color:#fff;--bs-navbar-brand-hover-color:#fff;--bs-navbar-toggler-border-color:rgba(255, 255, 255, 0.1);--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y:1rem;--bs-card-spacer-x:1rem;--bs-card-title-spacer-y:0.5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width:var(--bs-border-width);--bs-card-border-color:var(--bs-border-color-translucent);--bs-card-border-radius:var(--bs-border-radius);--bs-card-box-shadow: ;--bs-card-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-card-cap-padding-y:0.5rem;--bs-card-cap-padding-x:1rem;--bs-card-cap-bg:rgba(var(--bs-body-color-rgb), 0.03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg:var(--bs-body-bg);--bs-card-img-overlay-padding:1rem;--bs-card-group-margin:0.75rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color);border-radius:var(--bs-card-border-radius)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-.5 * var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header:first-child{border-radius:var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer:last-child{border-radius:0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius)}.card-header-tabs{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-bottom:calc(-1 * var(--bs-card-cap-padding-y));margin-left:calc(-.5 * var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-left:calc(-.5 * var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:var(--bs-card-img-overlay-padding);border-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-img,.card-img-top{border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child)>.card-header,.card-group>.card:not(:last-child)>.card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child)>.card-footer,.card-group>.card:not(:last-child)>.card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child)>.card-header,.card-group>.card:not(:first-child)>.card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child)>.card-footer,.card-group>.card:not(:first-child)>.card-img-bottom{border-bottom-left-radius:0}}.accordion{--bs-accordion-color:var(--bs-body-color);--bs-accordion-bg:var(--bs-body-bg);--bs-accordion-transition:color 0.15s ease-in-out,background-color 0.15s ease-in-out,border-color 0.15s ease-in-out,box-shadow 0.15s ease-in-out,border-radius 0.15s ease;--bs-accordion-border-color:var(--bs-border-color);--bs-accordion-border-width:var(--bs-border-width);--bs-accordion-border-radius:var(--bs-border-radius);--bs-accordion-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-accordion-btn-padding-x:1.25rem;--bs-accordion-btn-padding-y:1rem;--bs-accordion-btn-color:var(--bs-body-color);--bs-accordion-btn-bg:var(--bs-accordion-bg);--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23212529' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='m2 5 6 6 6-6'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width:1.25rem;--bs-accordion-btn-icon-transform:rotate(-180deg);--bs-accordion-btn-icon-transition:transform 0.2s ease-in-out;--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23052c65' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='m2 5 6 6 6-6'/%3e%3c/svg%3e");--bs-accordion-btn-focus-box-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-accordion-body-padding-x:1.25rem;--bs-accordion-body-padding-y:1rem;--bs-accordion-active-color:var(--bs-primary-text-emphasis);--bs-accordion-active-bg:var(--bs-primary-bg-subtle)}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media (prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed)::after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button::after{flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media (prefers-reduced-motion:reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:first-of-type{border-top-left-radius:var(--bs-accordion-border-radius);border-top-right-radius:var(--bs-accordion-border-radius)}.accordion-item:first-of-type>.accordion-header .accordion-button{border-top-left-radius:var(--bs-accordion-inner-border-radius);border-top-right-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-item:last-of-type>.accordion-header .accordion-button.collapsed{border-bottom-right-radius:var(--bs-accordion-inner-border-radius);border-bottom-left-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:last-of-type>.accordion-collapse{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush>.accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush>.accordion-item:first-child{border-top:0}.accordion-flush>.accordion-item:last-child{border-bottom:0}.accordion-flush>.accordion-item>.accordion-collapse,.accordion-flush>.accordion-item>.accordion-header .accordion-button,.accordion-flush>.accordion-item>.accordion-header .accordion-button.collapsed{border-radius:0}[data-bs-theme=dark] .accordion-button::after{--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708'/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x:0;--bs-breadcrumb-padding-y:0;--bs-breadcrumb-margin-bottom:1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color:var(--bs-secondary-color);--bs-breadcrumb-item-padding-x:0.5rem;--bs-breadcrumb-item-active-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg);border-radius:var(--bs-breadcrumb-border-radius)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x:0.75rem;--bs-pagination-padding-y:0.375rem;--bs-pagination-font-size:1rem;--bs-pagination-color:var(--bs-link-color);--bs-pagination-bg:var(--bs-body-bg);--bs-pagination-border-width:var(--bs-border-width);--bs-pagination-border-color:var(--bs-border-color);--bs-pagination-border-radius:var(--bs-border-radius);--bs-pagination-hover-color:var(--bs-link-hover-color);--bs-pagination-hover-bg:var(--bs-tertiary-bg);--bs-pagination-hover-border-color:var(--bs-border-color);--bs-pagination-focus-color:var(--bs-link-hover-color);--bs-pagination-focus-bg:var(--bs-secondary-bg);--bs-pagination-focus-box-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-pagination-active-color:#fff;--bs-pagination-active-bg:#0d6efd;--bs-pagination-active-border-color:#0d6efd;--bs-pagination-disabled-color:var(--bs-secondary-color);--bs-pagination-disabled-bg:var(--bs-secondary-bg);--bs-pagination-disabled-border-color:var(--bs-border-color);display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.active>.page-link,.page-link.active{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.disabled>.page-link,.page-link.disabled{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(-1 * var(--bs-border-width))}.page-item:first-child .page-link{border-top-left-radius:var(--bs-pagination-border-radius);border-bottom-left-radius:var(--bs-pagination-border-radius)}.page-item:last-child .page-link{border-top-right-radius:var(--bs-pagination-border-radius);border-bottom-right-radius:var(--bs-pagination-border-radius)}.pagination-lg{--bs-pagination-padding-x:1.5rem;--bs-pagination-padding-y:0.75rem;--bs-pagination-font-size:1.25rem;--bs-pagination-border-radius:var(--bs-border-radius-lg)}.pagination-sm{--bs-pagination-padding-x:0.5rem;--bs-pagination-padding-y:0.25rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius:var(--bs-border-radius-sm)}.badge{--bs-badge-padding-x:0.65em;--bs-badge-padding-y:0.35em;--bs-badge-font-size:0.75em;--bs-badge-font-weight:700;--bs-badge-color:#fff;--bs-badge-border-radius:var(--bs-border-radius);display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:var(--bs-badge-border-radius)}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg:transparent;--bs-alert-padding-x:1rem;--bs-alert-padding-y:1rem;--bs-alert-margin-bottom:1rem;--bs-alert-color:inherit;--bs-alert-border-color:transparent;--bs-alert-border:var(--bs-border-width) solid var(--bs-alert-border-color);--bs-alert-border-radius:var(--bs-border-radius);--bs-alert-link-color:inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border);border-radius:var(--bs-alert-border-radius)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{--bs-alert-color:var(--bs-primary-text-emphasis);--bs-alert-bg:var(--bs-primary-bg-subtle);--bs-alert-border-color:var(--bs-primary-border-subtle);--bs-alert-link-color:var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color:var(--bs-secondary-text-emphasis);--bs-alert-bg:var(--bs-secondary-bg-subtle);--bs-alert-border-color:var(--bs-secondary-border-subtle);--bs-alert-link-color:var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color:var(--bs-success-text-emphasis);--bs-alert-bg:var(--bs-success-bg-subtle);--bs-alert-border-color:var(--bs-success-border-subtle);--bs-alert-link-color:var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color:var(--bs-info-text-emphasis);--bs-alert-bg:var(--bs-info-bg-subtle);--bs-alert-border-color:var(--bs-info-border-subtle);--bs-alert-link-color:var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color:var(--bs-warning-text-emphasis);--bs-alert-bg:var(--bs-warning-bg-subtle);--bs-alert-border-color:var(--bs-warning-border-subtle);--bs-alert-link-color:var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color:var(--bs-danger-text-emphasis);--bs-alert-bg:var(--bs-danger-bg-subtle);--bs-alert-border-color:var(--bs-danger-border-subtle);--bs-alert-link-color:var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color:var(--bs-light-text-emphasis);--bs-alert-bg:var(--bs-light-bg-subtle);--bs-alert-border-color:var(--bs-light-border-subtle);--bs-alert-link-color:var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color:var(--bs-dark-text-emphasis);--bs-alert-bg:var(--bs-dark-bg-subtle);--bs-alert-border-color:var(--bs-dark-border-subtle);--bs-alert-link-color:var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:var(--bs-progress-height)}}.progress,.progress-stacked{--bs-progress-height:1rem;--bs-progress-font-size:0.75rem;--bs-progress-bg:var(--bs-secondary-bg);--bs-progress-border-radius:var(--bs-border-radius);--bs-progress-box-shadow:var(--bs-box-shadow-inset);--bs-progress-bar-color:#fff;--bs-progress-bar-bg:#0d6efd;--bs-progress-bar-transition:width 0.6s ease;display:flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg);border-radius:var(--bs-progress-border-radius)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion:reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color:var(--bs-body-color);--bs-list-group-bg:var(--bs-body-bg);--bs-list-group-border-color:var(--bs-border-color);--bs-list-group-border-width:var(--bs-border-width);--bs-list-group-border-radius:var(--bs-border-radius);--bs-list-group-item-padding-x:1rem;--bs-list-group-item-padding-y:0.5rem;--bs-list-group-action-color:var(--bs-secondary-color);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-tertiary-bg);--bs-list-group-action-active-color:var(--bs-body-color);--bs-list-group-action-active-bg:var(--bs-secondary-bg);--bs-list-group-disabled-color:var(--bs-secondary-color);--bs-list-group-disabled-bg:var(--bs-body-bg);--bs-list-group-active-color:#fff;--bs-list-group-active-bg:#0d6efd;--bs-list-group-active-border-color:#0d6efd;display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:var(--bs-list-group-border-radius)}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1 * var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:not(.active):focus,.list-group-item-action:not(.active):hover{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:not(.active):active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{--bs-list-group-color:var(--bs-primary-text-emphasis);--bs-list-group-bg:var(--bs-primary-bg-subtle);--bs-list-group-border-color:var(--bs-primary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-primary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-primary-border-subtle);--bs-list-group-active-color:var(--bs-primary-bg-subtle);--bs-list-group-active-bg:var(--bs-primary-text-emphasis);--bs-list-group-active-border-color:var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color:var(--bs-secondary-text-emphasis);--bs-list-group-bg:var(--bs-secondary-bg-subtle);--bs-list-group-border-color:var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-secondary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-secondary-border-subtle);--bs-list-group-active-color:var(--bs-secondary-bg-subtle);--bs-list-group-active-bg:var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color:var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color:var(--bs-success-text-emphasis);--bs-list-group-bg:var(--bs-success-bg-subtle);--bs-list-group-border-color:var(--bs-success-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-success-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-success-border-subtle);--bs-list-group-active-color:var(--bs-success-bg-subtle);--bs-list-group-active-bg:var(--bs-success-text-emphasis);--bs-list-group-active-border-color:var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color:var(--bs-info-text-emphasis);--bs-list-group-bg:var(--bs-info-bg-subtle);--bs-list-group-border-color:var(--bs-info-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-info-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-info-border-subtle);--bs-list-group-active-color:var(--bs-info-bg-subtle);--bs-list-group-active-bg:var(--bs-info-text-emphasis);--bs-list-group-active-border-color:var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color:var(--bs-warning-text-emphasis);--bs-list-group-bg:var(--bs-warning-bg-subtle);--bs-list-group-border-color:var(--bs-warning-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-warning-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-warning-border-subtle);--bs-list-group-active-color:var(--bs-warning-bg-subtle);--bs-list-group-active-bg:var(--bs-warning-text-emphasis);--bs-list-group-active-border-color:var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color:var(--bs-danger-text-emphasis);--bs-list-group-bg:var(--bs-danger-bg-subtle);--bs-list-group-border-color:var(--bs-danger-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-danger-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-danger-border-subtle);--bs-list-group-active-color:var(--bs-danger-bg-subtle);--bs-list-group-active-bg:var(--bs-danger-text-emphasis);--bs-list-group-active-border-color:var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color:var(--bs-light-text-emphasis);--bs-list-group-bg:var(--bs-light-bg-subtle);--bs-list-group-border-color:var(--bs-light-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-light-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-light-border-subtle);--bs-list-group-active-color:var(--bs-light-bg-subtle);--bs-list-group-active-bg:var(--bs-light-text-emphasis);--bs-list-group-active-border-color:var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color:var(--bs-dark-text-emphasis);--bs-list-group-bg:var(--bs-dark-bg-subtle);--bs-list-group-border-color:var(--bs-dark-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-dark-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-dark-border-subtle);--bs-list-group-active-color:var(--bs-dark-bg-subtle);--bs-list-group-active-bg:var(--bs-dark-text-emphasis);--bs-list-group-active-border-color:var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color:#000;--bs-btn-close-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414'/%3e%3c/svg%3e");--bs-btn-close-opacity:0.5;--bs-btn-close-hover-opacity:0.75;--bs-btn-close-focus-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-btn-close-focus-opacity:1;--bs-btn-close-disabled-opacity:0.25;box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:var(--bs-btn-close-color);background:transparent var(--bs-btn-close-bg) center/1em auto no-repeat;filter:var(--bs-btn-close-filter);border:0;border-radius:.375rem;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close.disabled,.btn-close:disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{--bs-btn-close-filter:invert(1) grayscale(100%) brightness(200%)}:root,[data-bs-theme=light]{--bs-btn-close-filter: }[data-bs-theme=dark]{--bs-btn-close-filter:invert(1) grayscale(100%) brightness(200%)}.toast{--bs-toast-zindex:1090;--bs-toast-padding-x:0.75rem;--bs-toast-padding-y:0.5rem;--bs-toast-spacing:1.5rem;--bs-toast-max-width:350px;--bs-toast-font-size:0.875rem;--bs-toast-color: ;--bs-toast-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-border-width:var(--bs-border-width);--bs-toast-border-color:var(--bs-border-color-translucent);--bs-toast-border-radius:var(--bs-border-radius);--bs-toast-box-shadow:var(--bs-box-shadow);--bs-toast-header-color:var(--bs-secondary-color);--bs-toast-header-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-header-border-color:var(--bs-border-color-translucent);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow);border-radius:var(--bs-toast-border-radius)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex:1090;position:absolute;z-index:var(--bs-toast-zindex);width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);border-top-left-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));border-top-right-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width))}.toast-header .btn-close{margin-right:calc(-.5 * var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex:1055;--bs-modal-width:500px;--bs-modal-padding:1rem;--bs-modal-margin:0.5rem;--bs-modal-color:var(--bs-body-color);--bs-modal-bg:var(--bs-body-bg);--bs-modal-border-color:var(--bs-border-color-translucent);--bs-modal-border-width:var(--bs-border-width);--bs-modal-border-radius:var(--bs-border-radius-lg);--bs-modal-box-shadow:var(--bs-box-shadow-sm);--bs-modal-inner-border-radius:calc(var(--bs-border-radius-lg) - (var(--bs-border-width)));--bs-modal-header-padding-x:1rem;--bs-modal-header-padding-y:1rem;--bs-modal-header-padding:1rem 1rem;--bs-modal-header-border-color:var(--bs-border-color);--bs-modal-header-border-width:var(--bs-border-width);--bs-modal-title-line-height:1.5;--bs-modal-footer-gap:0.5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color:var(--bs-border-color);--bs-modal-footer-border-width:var(--bs-border-width);position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transform:translate(0,-50px);transition:transform .3s ease-out}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin) * 2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - var(--bs-modal-margin) * 2)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);border-radius:var(--bs-modal-border-radius);outline:0}.modal-backdrop{--bs-backdrop-zindex:1050;--bs-backdrop-bg:#000;--bs-backdrop-opacity:0.5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;flex-shrink:0;align-items:center;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);border-top-left-radius:var(--bs-modal-inner-border-radius);border-top-right-radius:var(--bs-modal-inner-border-radius)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y) * .5) calc(var(--bs-modal-header-padding-x) * .5);margin-top:calc(-.5 * var(--bs-modal-header-padding-y));margin-right:calc(-.5 * var(--bs-modal-header-padding-x));margin-bottom:calc(-.5 * var(--bs-modal-header-padding-y));margin-left:auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * .5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);border-bottom-right-radius:var(--bs-modal-inner-border-radius);border-bottom-left-radius:var(--bs-modal-inner-border-radius)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap) * .5)}@media (min-width:576px){.modal{--bs-modal-margin:1.75rem;--bs-modal-box-shadow:var(--bs-box-shadow)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{--bs-modal-width:800px}}@media (min-width:1200px){.modal-xl{--bs-modal-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-footer,.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}@media (max-width:575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-footer,.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media (max-width:767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-footer,.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media (max-width:991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-footer,.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media (max-width:1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-footer,.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media (max-width:1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-footer,.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex:1080;--bs-tooltip-max-width:200px;--bs-tooltip-padding-x:0.5rem;--bs-tooltip-padding-y:0.25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size:0.875rem;--bs-tooltip-color:var(--bs-body-bg);--bs-tooltip-bg:var(--bs-emphasis-color);--bs-tooltip-border-radius:var(--bs-border-radius);--bs-tooltip-opacity:0.9;--bs-tooltip-arrow-width:0.8rem;--bs-tooltip-arrow-height:0.4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before,.bs-tooltip-top .tooltip-arrow::before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{left:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before,.bs-tooltip-end .tooltip-arrow::before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before,.bs-tooltip-bottom .tooltip-arrow::before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{right:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before,.bs-tooltip-start .tooltip-arrow::before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) 0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg);border-radius:var(--bs-tooltip-border-radius)}.popover{--bs-popover-zindex:1070;--bs-popover-max-width:276px;--bs-popover-font-size:0.875rem;--bs-popover-bg:var(--bs-body-bg);--bs-popover-border-width:var(--bs-border-width);--bs-popover-border-color:var(--bs-border-color-translucent);--bs-popover-border-radius:var(--bs-border-radius-lg);--bs-popover-inner-border-radius:calc(var(--bs-border-radius-lg) - var(--bs-border-width));--bs-popover-box-shadow:var(--bs-box-shadow);--bs-popover-header-padding-x:1rem;--bs-popover-header-padding-y:0.5rem;--bs-popover-header-font-size:1rem;--bs-popover-header-color:inherit;--bs-popover-header-bg:var(--bs-secondary-bg);--bs-popover-body-padding-x:1rem;--bs-popover-body-padding-y:1rem;--bs-popover-body-color:var(--bs-body-color);--bs-popover-arrow-width:1rem;--bs-popover-arrow-height:0.5rem;--bs-popover-arrow-border:var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-radius:var(--bs-popover-border-radius)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow::after,.popover .popover-arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid;border-width:0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::after,.bs-popover-top>.popover-arrow::before{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-top>.popover-arrow::after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{left:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::after,.bs-popover-end>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-end>.popover-arrow::after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::before{border-width:0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-.5 * var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{right:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::after,.bs-popover-start>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) 0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-start>.popover-arrow::after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-top-left-radius:var(--bs-popover-inner-border-radius);border-top-right-radius:var(--bs-popover-inner-border-radius)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translateX(100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;filter:var(--bs-carousel-control-icon-filter);border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:var(--bs-carousel-indicator-active-bg);background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:var(--bs-carousel-caption-color);text-align:center}.carousel-dark{--bs-carousel-indicator-active-bg:#000;--bs-carousel-caption-color:#000;--bs-carousel-control-icon-filter:invert(1) grayscale(100)}:root,[data-bs-theme=light]{--bs-carousel-indicator-active-bg:#fff;--bs-carousel-caption-color:#fff;--bs-carousel-control-icon-filter: }[data-bs-theme=dark]{--bs-carousel-indicator-active-bg:#000;--bs-carousel-caption-color:#000;--bs-carousel-control-icon-filter:invert(1) grayscale(100)}.spinner-border,.spinner-grow{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-border-width:0.25em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:transparent}.spinner-border-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem;--bs-spinner-border-width:0.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed:1.5s}}.offcanvas,.offcanvas-lg,.offcanvas-md,.offcanvas-sm,.offcanvas-xl,.offcanvas-xxl{--bs-offcanvas-zindex:1045;--bs-offcanvas-width:400px;--bs-offcanvas-height:30vh;--bs-offcanvas-padding-x:1rem;--bs-offcanvas-padding-y:1rem;--bs-offcanvas-color:var(--bs-body-color);--bs-offcanvas-bg:var(--bs-body-bg);--bs-offcanvas-border-width:var(--bs-border-width);--bs-offcanvas-border-color:var(--bs-border-color-translucent);--bs-offcanvas-box-shadow:var(--bs-box-shadow-sm);--bs-offcanvas-transition:transform 0.3s ease-in-out;--bs-offcanvas-title-line-height:1.5}@media (max-width:575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:575.98px) and (prefers-reduced-motion:reduce){.offcanvas-sm{transition:none}}@media (max-width:575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.show:not(.hiding),.offcanvas-sm.showing{transform:none}.offcanvas-sm.hiding,.offcanvas-sm.show,.offcanvas-sm.showing{visibility:visible}}@media (min-width:576px){.offcanvas-sm{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:767.98px) and (prefers-reduced-motion:reduce){.offcanvas-md{transition:none}}@media (max-width:767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.show:not(.hiding),.offcanvas-md.showing{transform:none}.offcanvas-md.hiding,.offcanvas-md.show,.offcanvas-md.showing{visibility:visible}}@media (min-width:768px){.offcanvas-md{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:991.98px) and (prefers-reduced-motion:reduce){.offcanvas-lg{transition:none}}@media (max-width:991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.show:not(.hiding),.offcanvas-lg.showing{transform:none}.offcanvas-lg.hiding,.offcanvas-lg.show,.offcanvas-lg.showing{visibility:visible}}@media (min-width:992px){.offcanvas-lg{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1199.98px) and (prefers-reduced-motion:reduce){.offcanvas-xl{transition:none}}@media (max-width:1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.show:not(.hiding),.offcanvas-xl.showing{transform:none}.offcanvas-xl.hiding,.offcanvas-xl.show,.offcanvas-xl.showing{visibility:visible}}@media (min-width:1200px){.offcanvas-xl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1399.98px) and (prefers-reduced-motion:reduce){.offcanvas-xxl{transition:none}}@media (max-width:1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.show:not(.hiding),.offcanvas-xxl.showing{transform:none}.offcanvas-xxl.hiding,.offcanvas-xxl.show,.offcanvas-xxl.showing{visibility:visible}}@media (min-width:1400px){.offcanvas-xxl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media (prefers-reduced-motion:reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.show:not(.hiding),.offcanvas.showing{transform:none}.offcanvas.hiding,.offcanvas.show,.offcanvas.showing{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y) * .5) calc(var(--bs-offcanvas-padding-x) * .5);margin-top:calc(-.5 * var(--bs-offcanvas-padding-y));margin-right:calc(-.5 * var(--bs-offcanvas-padding-x));margin-bottom:calc(-.5 * var(--bs-offcanvas-padding-y));margin-left:auto}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{-webkit-mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);-webkit-mask-size:200% 100%;mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.text-bg-primary{color:#fff!important;background-color:RGBA(var(--bs-primary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-secondary{color:#fff!important;background-color:RGBA(var(--bs-secondary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-success{color:#fff!important;background-color:RGBA(var(--bs-success-rgb),var(--bs-bg-opacity,1))!important}.text-bg-info{color:#000!important;background-color:RGBA(var(--bs-info-rgb),var(--bs-bg-opacity,1))!important}.text-bg-warning{color:#000!important;background-color:RGBA(var(--bs-warning-rgb),var(--bs-bg-opacity,1))!important}.text-bg-danger{color:#fff!important;background-color:RGBA(var(--bs-danger-rgb),var(--bs-bg-opacity,1))!important}.text-bg-light{color:#000!important;background-color:RGBA(var(--bs-light-rgb),var(--bs-bg-opacity,1))!important}.text-bg-dark{color:#fff!important;background-color:RGBA(var(--bs-dark-rgb),var(--bs-bg-opacity,1))!important}.link-primary{color:RGBA(var(--bs-primary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important}.link-primary:focus,.link-primary:hover{color:RGBA(10,88,202,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity,1))!important}.link-secondary{color:RGBA(var(--bs-secondary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important}.link-secondary:focus,.link-secondary:hover{color:RGBA(86,94,100,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity,1))!important}.link-success{color:RGBA(var(--bs-success-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important}.link-success:focus,.link-success:hover{color:RGBA(20,108,67,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity,1))!important}.link-info{color:RGBA(var(--bs-info-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important}.link-info:focus,.link-info:hover{color:RGBA(61,213,243,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity,1))!important}.link-warning{color:RGBA(var(--bs-warning-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important}.link-warning:focus,.link-warning:hover{color:RGBA(255,205,57,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity,1))!important}.link-danger{color:RGBA(var(--bs-danger-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important}.link-danger:focus,.link-danger:hover{color:RGBA(176,42,55,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity,1))!important}.link-light{color:RGBA(var(--bs-light-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important}.link-light:focus,.link-light:hover{color:RGBA(249,250,251,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity,1))!important}.link-dark{color:RGBA(var(--bs-dark-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important}.link-dark:focus,.link-dark:hover{color:RGBA(26,30,33,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity,1))!important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-body-emphasis:focus,.link-body-emphasis:hover{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,.75))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x,0) var(--bs-focus-ring-y,0) var(--bs-focus-ring-blur,0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-underline-offset:0.25em;-webkit-backface-visibility:hidden;backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media (prefers-reduced-motion:reduce){.icon-link>.bi{transition:none}}.icon-link-hover:focus-visible>.bi,.icon-link-hover:hover>.bi{transform:var(--bs-icon-link-transform,translate3d(.25em,0,0))}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio:100%}.ratio-4x3{--bs-aspect-ratio:75%}.ratio-16x9{--bs-aspect-ratio:56.25%}.ratio-21x9{--bs-aspect-ratio:42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}@media (min-width:576px){.sticky-sm-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:768px){.sticky-md-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:992px){.sticky-lg-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1200px){.sticky-xl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1400px){.sticky-xxl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption),.visually-hidden:not(caption){position:absolute!important}.visually-hidden *,.visually-hidden-focusable:not(:focus):not(:focus-within) *{overflow:hidden!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:var(--bs-border-width);min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.object-fit-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-none{-o-object-fit:none!important;object-fit:none!important}.opacity-0{opacity:0!important}.opacity-25{opacity:.25!important}.opacity-50{opacity:.5!important}.opacity-75{opacity:.75!important}.opacity-100{opacity:1!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.overflow-x-auto{overflow-x:auto!important}.overflow-x-hidden{overflow-x:hidden!important}.overflow-x-visible{overflow-x:visible!important}.overflow-x-scroll{overflow-x:scroll!important}.overflow-y-auto{overflow-y:auto!important}.overflow-y-hidden{overflow-y:hidden!important}.overflow-y-visible{overflow-y:visible!important}.overflow-y-scroll{overflow-y:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-inline-grid{display:inline-grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:var(--bs-box-shadow)!important}.shadow-sm{box-shadow:var(--bs-box-shadow-sm)!important}.shadow-lg{box-shadow:var(--bs-box-shadow-lg)!important}.shadow-none{box-shadow:none!important}.focus-ring-primary{--bs-focus-ring-color:rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color:rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color:rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color:rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color:rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color:rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color:rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color:rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translateX(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-0{border:0!important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-top-0{border-top:0!important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-start-0{border-left:0!important}.border-primary{--bs-border-opacity:1;border-color:rgba(var(--bs-primary-rgb),var(--bs-border-opacity))!important}.border-secondary{--bs-border-opacity:1;border-color:rgba(var(--bs-secondary-rgb),var(--bs-border-opacity))!important}.border-success{--bs-border-opacity:1;border-color:rgba(var(--bs-success-rgb),var(--bs-border-opacity))!important}.border-info{--bs-border-opacity:1;border-color:rgba(var(--bs-info-rgb),var(--bs-border-opacity))!important}.border-warning{--bs-border-opacity:1;border-color:rgba(var(--bs-warning-rgb),var(--bs-border-opacity))!important}.border-danger{--bs-border-opacity:1;border-color:rgba(var(--bs-danger-rgb),var(--bs-border-opacity))!important}.border-light{--bs-border-opacity:1;border-color:rgba(var(--bs-light-rgb),var(--bs-border-opacity))!important}.border-dark{--bs-border-opacity:1;border-color:rgba(var(--bs-dark-rgb),var(--bs-border-opacity))!important}.border-black{--bs-border-opacity:1;border-color:rgba(var(--bs-black-rgb),var(--bs-border-opacity))!important}.border-white{--bs-border-opacity:1;border-color:rgba(var(--bs-white-rgb),var(--bs-border-opacity))!important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle)!important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle)!important}.border-success-subtle{border-color:var(--bs-success-border-subtle)!important}.border-info-subtle{border-color:var(--bs-info-border-subtle)!important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle)!important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle)!important}.border-light-subtle{border-color:var(--bs-light-border-subtle)!important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle)!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.border-opacity-10{--bs-border-opacity:0.1}.border-opacity-25{--bs-border-opacity:0.25}.border-opacity-50{--bs-border-opacity:0.5}.border-opacity-75{--bs-border-opacity:0.75}.border-opacity-100{--bs-border-opacity:1}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.row-gap-0{row-gap:0!important}.row-gap-1{row-gap:.25rem!important}.row-gap-2{row-gap:.5rem!important}.row-gap-3{row-gap:1rem!important}.row-gap-4{row-gap:1.5rem!important}.row-gap-5{row-gap:3rem!important}.column-gap-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-lighter{font-weight:lighter!important}.fw-light{font-weight:300!important}.fw-normal{font-weight:400!important}.fw-medium{font-weight:500!important}.fw-semibold{font-weight:600!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{--bs-text-opacity:1;color:rgba(var(--bs-primary-rgb),var(--bs-text-opacity))!important}.text-secondary{--bs-text-opacity:1;color:rgba(var(--bs-secondary-rgb),var(--bs-text-opacity))!important}.text-success{--bs-text-opacity:1;color:rgba(var(--bs-success-rgb),var(--bs-text-opacity))!important}.text-info{--bs-text-opacity:1;color:rgba(var(--bs-info-rgb),var(--bs-text-opacity))!important}.text-warning{--bs-text-opacity:1;color:rgba(var(--bs-warning-rgb),var(--bs-text-opacity))!important}.text-danger{--bs-text-opacity:1;color:rgba(var(--bs-danger-rgb),var(--bs-text-opacity))!important}.text-light{--bs-text-opacity:1;color:rgba(var(--bs-light-rgb),var(--bs-text-opacity))!important}.text-dark{--bs-text-opacity:1;color:rgba(var(--bs-dark-rgb),var(--bs-text-opacity))!important}.text-black{--bs-text-opacity:1;color:rgba(var(--bs-black-rgb),var(--bs-text-opacity))!important}.text-white{--bs-text-opacity:1;color:rgba(var(--bs-white-rgb),var(--bs-text-opacity))!important}.text-body{--bs-text-opacity:1;color:rgba(var(--bs-body-color-rgb),var(--bs-text-opacity))!important}.text-muted{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-black-50{--bs-text-opacity:1;color:rgba(0,0,0,.5)!important}.text-white-50{--bs-text-opacity:1;color:rgba(255,255,255,.5)!important}.text-body-secondary{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-body-tertiary{--bs-text-opacity:1;color:var(--bs-tertiary-color)!important}.text-body-emphasis{--bs-text-opacity:1;color:var(--bs-emphasis-color)!important}.text-reset{--bs-text-opacity:1;color:inherit!important}.text-opacity-25{--bs-text-opacity:0.25}.text-opacity-50{--bs-text-opacity:0.5}.text-opacity-75{--bs-text-opacity:0.75}.text-opacity-100{--bs-text-opacity:1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis)!important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis)!important}.text-success-emphasis{color:var(--bs-success-text-emphasis)!important}.text-info-emphasis{color:var(--bs-info-text-emphasis)!important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis)!important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis)!important}.text-light-emphasis{color:var(--bs-light-text-emphasis)!important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis)!important}.link-opacity-10{--bs-link-opacity:0.1}.link-opacity-10-hover:hover{--bs-link-opacity:0.1}.link-opacity-25{--bs-link-opacity:0.25}.link-opacity-25-hover:hover{--bs-link-opacity:0.25}.link-opacity-50{--bs-link-opacity:0.5}.link-opacity-50-hover:hover{--bs-link-opacity:0.5}.link-opacity-75{--bs-link-opacity:0.75}.link-opacity-75-hover:hover{--bs-link-opacity:0.75}.link-opacity-100{--bs-link-opacity:1}.link-opacity-100-hover:hover{--bs-link-opacity:1}.link-offset-1{text-underline-offset:0.125em!important}.link-offset-1-hover:hover{text-underline-offset:0.125em!important}.link-offset-2{text-underline-offset:0.25em!important}.link-offset-2-hover:hover{text-underline-offset:0.25em!important}.link-offset-3{text-underline-offset:0.375em!important}.link-offset-3-hover:hover{text-underline-offset:0.375em!important}.link-underline-primary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-secondary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-success{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important}.link-underline-info{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important}.link-underline-warning{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important}.link-underline-danger{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important}.link-underline-light{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important}.link-underline-dark{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important}.link-underline{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-underline-opacity-0{--bs-link-underline-opacity:0}.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity:0}.link-underline-opacity-10{--bs-link-underline-opacity:0.1}.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity:0.1}.link-underline-opacity-25{--bs-link-underline-opacity:0.25}.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity:0.25}.link-underline-opacity-50{--bs-link-underline-opacity:0.5}.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity:0.5}.link-underline-opacity-75{--bs-link-underline-opacity:0.75}.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity:0.75}.link-underline-opacity-100{--bs-link-underline-opacity:1}.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity:1}.bg-primary{--bs-bg-opacity:1;background-color:rgba(var(--bs-primary-rgb),var(--bs-bg-opacity))!important}.bg-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-rgb),var(--bs-bg-opacity))!important}.bg-success{--bs-bg-opacity:1;background-color:rgba(var(--bs-success-rgb),var(--bs-bg-opacity))!important}.bg-info{--bs-bg-opacity:1;background-color:rgba(var(--bs-info-rgb),var(--bs-bg-opacity))!important}.bg-warning{--bs-bg-opacity:1;background-color:rgba(var(--bs-warning-rgb),var(--bs-bg-opacity))!important}.bg-danger{--bs-bg-opacity:1;background-color:rgba(var(--bs-danger-rgb),var(--bs-bg-opacity))!important}.bg-light{--bs-bg-opacity:1;background-color:rgba(var(--bs-light-rgb),var(--bs-bg-opacity))!important}.bg-dark{--bs-bg-opacity:1;background-color:rgba(var(--bs-dark-rgb),var(--bs-bg-opacity))!important}.bg-black{--bs-bg-opacity:1;background-color:rgba(var(--bs-black-rgb),var(--bs-bg-opacity))!important}.bg-white{--bs-bg-opacity:1;background-color:rgba(var(--bs-white-rgb),var(--bs-bg-opacity))!important}.bg-body{--bs-bg-opacity:1;background-color:rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity))!important}.bg-transparent{--bs-bg-opacity:1;background-color:transparent!important}.bg-body-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-bg-rgb),var(--bs-bg-opacity))!important}.bg-body-tertiary{--bs-bg-opacity:1;background-color:rgba(var(--bs-tertiary-bg-rgb),var(--bs-bg-opacity))!important}.bg-opacity-10{--bs-bg-opacity:0.1}.bg-opacity-25{--bs-bg-opacity:0.25}.bg-opacity-50{--bs-bg-opacity:0.5}.bg-opacity-75{--bs-bg-opacity:0.75}.bg-opacity-100{--bs-bg-opacity:1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle)!important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle)!important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle)!important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle)!important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle)!important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle)!important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle)!important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle)!important}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:var(--bs-border-radius)!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:var(--bs-border-radius-sm)!important}.rounded-2{border-radius:var(--bs-border-radius)!important}.rounded-3{border-radius:var(--bs-border-radius-lg)!important}.rounded-4{border-radius:var(--bs-border-radius-xl)!important}.rounded-5{border-radius:var(--bs-border-radius-xxl)!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:var(--bs-border-radius-pill)!important}.rounded-top{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-0{border-top-left-radius:0!important;border-top-right-radius:0!important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm)!important;border-top-right-radius:var(--bs-border-radius-sm)!important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg)!important;border-top-right-radius:var(--bs-border-radius-lg)!important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl)!important;border-top-right-radius:var(--bs-border-radius-xl)!important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl)!important;border-top-right-radius:var(--bs-border-radius-xxl)!important}.rounded-top-circle{border-top-left-radius:50%!important;border-top-right-radius:50%!important}.rounded-top-pill{border-top-left-radius:var(--bs-border-radius-pill)!important;border-top-right-radius:var(--bs-border-radius-pill)!important}.rounded-end{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-0{border-top-right-radius:0!important;border-bottom-right-radius:0!important}.rounded-end-1{border-top-right-radius:var(--bs-border-radius-sm)!important;border-bottom-right-radius:var(--bs-border-radius-sm)!important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg)!important;border-bottom-right-radius:var(--bs-border-radius-lg)!important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl)!important;border-bottom-right-radius:var(--bs-border-radius-xl)!important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-right-radius:var(--bs-border-radius-xxl)!important}.rounded-end-circle{border-top-right-radius:50%!important;border-bottom-right-radius:50%!important}.rounded-end-pill{border-top-right-radius:var(--bs-border-radius-pill)!important;border-bottom-right-radius:var(--bs-border-radius-pill)!important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-0{border-bottom-right-radius:0!important;border-bottom-left-radius:0!important}.rounded-bottom-1{border-bottom-right-radius:var(--bs-border-radius-sm)!important;border-bottom-left-radius:var(--bs-border-radius-sm)!important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg)!important;border-bottom-left-radius:var(--bs-border-radius-lg)!important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl)!important;border-bottom-left-radius:var(--bs-border-radius-xl)!important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-left-radius:var(--bs-border-radius-xxl)!important}.rounded-bottom-circle{border-bottom-right-radius:50%!important;border-bottom-left-radius:50%!important}.rounded-bottom-pill{border-bottom-right-radius:var(--bs-border-radius-pill)!important;border-bottom-left-radius:var(--bs-border-radius-pill)!important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-0{border-bottom-left-radius:0!important;border-top-left-radius:0!important}.rounded-start-1{border-bottom-left-radius:var(--bs-border-radius-sm)!important;border-top-left-radius:var(--bs-border-radius-sm)!important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg)!important;border-top-left-radius:var(--bs-border-radius-lg)!important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl)!important;border-top-left-radius:var(--bs-border-radius-xl)!important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl)!important;border-top-left-radius:var(--bs-border-radius-xxl)!important}.rounded-start-circle{border-bottom-left-radius:50%!important;border-top-left-radius:50%!important}.rounded-start-pill{border-bottom-left-radius:var(--bs-border-radius-pill)!important;border-top-left-radius:var(--bs-border-radius-pill)!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}.z-n1{z-index:-1!important}.z-0{z-index:0!important}.z-1{z-index:1!important}.z-2{z-index:2!important}.z-3{z-index:3!important}@media (min-width:576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.object-fit-sm-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-sm-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-sm-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-sm-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-sm-none{-o-object-fit:none!important;object-fit:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-inline-grid{display:inline-grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.row-gap-sm-0{row-gap:0!important}.row-gap-sm-1{row-gap:.25rem!important}.row-gap-sm-2{row-gap:.5rem!important}.row-gap-sm-3{row-gap:1rem!important}.row-gap-sm-4{row-gap:1.5rem!important}.row-gap-sm-5{row-gap:3rem!important}.column-gap-sm-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-sm-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-sm-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-sm-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-sm-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-sm-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.object-fit-md-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-md-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-md-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-md-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-md-none{-o-object-fit:none!important;object-fit:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-inline-grid{display:inline-grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.row-gap-md-0{row-gap:0!important}.row-gap-md-1{row-gap:.25rem!important}.row-gap-md-2{row-gap:.5rem!important}.row-gap-md-3{row-gap:1rem!important}.row-gap-md-4{row-gap:1.5rem!important}.row-gap-md-5{row-gap:3rem!important}.column-gap-md-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-md-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-md-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-md-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-md-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-md-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.object-fit-lg-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-lg-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-lg-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-lg-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-lg-none{-o-object-fit:none!important;object-fit:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-inline-grid{display:inline-grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.row-gap-lg-0{row-gap:0!important}.row-gap-lg-1{row-gap:.25rem!important}.row-gap-lg-2{row-gap:.5rem!important}.row-gap-lg-3{row-gap:1rem!important}.row-gap-lg-4{row-gap:1.5rem!important}.row-gap-lg-5{row-gap:3rem!important}.column-gap-lg-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-lg-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-lg-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-lg-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-lg-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-lg-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.object-fit-xl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xl-none{-o-object-fit:none!important;object-fit:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-inline-grid{display:inline-grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.row-gap-xl-0{row-gap:0!important}.row-gap-xl-1{row-gap:.25rem!important}.row-gap-xl-2{row-gap:.5rem!important}.row-gap-xl-3{row-gap:1rem!important}.row-gap-xl-4{row-gap:1.5rem!important}.row-gap-xl-5{row-gap:3rem!important}.column-gap-xl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width:1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.object-fit-xxl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xxl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xxl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xxl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xxl-none{-o-object-fit:none!important;object-fit:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-inline-grid{display:inline-grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.row-gap-xxl-0{row-gap:0!important}.row-gap-xxl-1{row-gap:.25rem!important}.row-gap-xxl-2{row-gap:.5rem!important}.row-gap-xxl-3{row-gap:1rem!important}.row-gap-xxl-4{row-gap:1.5rem!important}.row-gap-xxl-5{row-gap:3rem!important}.column-gap-xxl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xxl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xxl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xxl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xxl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xxl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media (min-width:1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-inline-grid{display:inline-grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}} diff --git a/css/bootstrap5/bootstrap.rtl-5.3.7.css b/css/bootstrap5/bootstrap.rtl-5.3.7.css new file mode 100644 index 00000000..052566f1 --- /dev/null +++ b/css/bootstrap5/bootstrap.rtl-5.3.7.css @@ -0,0 +1,5 @@ +@charset "UTF-8";/*! + * Bootstrap v5.3.7 (https://getbootstrap.com/) + * Copyright 2011-2025 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */:root,[data-bs-theme=light]{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-black:#000;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-primary-text-emphasis:#052c65;--bs-secondary-text-emphasis:#2b2f32;--bs-success-text-emphasis:#0a3622;--bs-info-text-emphasis:#055160;--bs-warning-text-emphasis:#664d03;--bs-danger-text-emphasis:#58151c;--bs-light-text-emphasis:#495057;--bs-dark-text-emphasis:#495057;--bs-primary-bg-subtle:#cfe2ff;--bs-secondary-bg-subtle:#e2e3e5;--bs-success-bg-subtle:#d1e7dd;--bs-info-bg-subtle:#cff4fc;--bs-warning-bg-subtle:#fff3cd;--bs-danger-bg-subtle:#f8d7da;--bs-light-bg-subtle:#fcfcfd;--bs-dark-bg-subtle:#ced4da;--bs-primary-border-subtle:#9ec5fe;--bs-secondary-border-subtle:#c4c8cb;--bs-success-border-subtle:#a3cfbb;--bs-info-border-subtle:#9eeaf9;--bs-warning-border-subtle:#ffe69c;--bs-danger-border-subtle:#f1aeb5;--bs-light-border-subtle:#e9ecef;--bs-dark-border-subtle:#adb5bd;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-font-sans-serif: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";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#212529;--bs-body-color-rgb:33,37,41;--bs-body-bg:#fff;--bs-body-bg-rgb:255,255,255;--bs-emphasis-color:#000;--bs-emphasis-color-rgb:0,0,0;--bs-secondary-color:rgba(33, 37, 41, 0.75);--bs-secondary-color-rgb:33,37,41;--bs-secondary-bg:#e9ecef;--bs-secondary-bg-rgb:233,236,239;--bs-tertiary-color:rgba(33, 37, 41, 0.5);--bs-tertiary-color-rgb:33,37,41;--bs-tertiary-bg:#f8f9fa;--bs-tertiary-bg-rgb:248,249,250;--bs-heading-color:inherit;--bs-link-color:#0d6efd;--bs-link-color-rgb:13,110,253;--bs-link-decoration:underline;--bs-link-hover-color:#0a58ca;--bs-link-hover-color-rgb:10,88,202;--bs-code-color:#d63384;--bs-highlight-color:#212529;--bs-highlight-bg:#fff3cd;--bs-border-width:1px;--bs-border-style:solid;--bs-border-color:#dee2e6;--bs-border-color-translucent:rgba(0, 0, 0, 0.175);--bs-border-radius:0.375rem;--bs-border-radius-sm:0.25rem;--bs-border-radius-lg:0.5rem;--bs-border-radius-xl:1rem;--bs-border-radius-xxl:2rem;--bs-border-radius-2xl:var(--bs-border-radius-xxl);--bs-border-radius-pill:50rem;--bs-box-shadow:0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm:0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg:0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset:inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width:0.25rem;--bs-focus-ring-opacity:0.25;--bs-focus-ring-color:rgba(13, 110, 253, 0.25);--bs-form-valid-color:#198754;--bs-form-valid-border-color:#198754;--bs-form-invalid-color:#dc3545;--bs-form-invalid-border-color:#dc3545}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color:#dee2e6;--bs-body-color-rgb:222,226,230;--bs-body-bg:#212529;--bs-body-bg-rgb:33,37,41;--bs-emphasis-color:#fff;--bs-emphasis-color-rgb:255,255,255;--bs-secondary-color:rgba(222, 226, 230, 0.75);--bs-secondary-color-rgb:222,226,230;--bs-secondary-bg:#343a40;--bs-secondary-bg-rgb:52,58,64;--bs-tertiary-color:rgba(222, 226, 230, 0.5);--bs-tertiary-color-rgb:222,226,230;--bs-tertiary-bg:#2b3035;--bs-tertiary-bg-rgb:43,48,53;--bs-primary-text-emphasis:#6ea8fe;--bs-secondary-text-emphasis:#a7acb1;--bs-success-text-emphasis:#75b798;--bs-info-text-emphasis:#6edff6;--bs-warning-text-emphasis:#ffda6a;--bs-danger-text-emphasis:#ea868f;--bs-light-text-emphasis:#f8f9fa;--bs-dark-text-emphasis:#dee2e6;--bs-primary-bg-subtle:#031633;--bs-secondary-bg-subtle:#161719;--bs-success-bg-subtle:#051b11;--bs-info-bg-subtle:#032830;--bs-warning-bg-subtle:#332701;--bs-danger-bg-subtle:#2c0b0e;--bs-light-bg-subtle:#343a40;--bs-dark-bg-subtle:#1a1d20;--bs-primary-border-subtle:#084298;--bs-secondary-border-subtle:#41464b;--bs-success-border-subtle:#0f5132;--bs-info-border-subtle:#087990;--bs-warning-border-subtle:#997404;--bs-danger-border-subtle:#842029;--bs-light-border-subtle:#495057;--bs-dark-border-subtle:#343a40;--bs-heading-color:inherit;--bs-link-color:#6ea8fe;--bs-link-hover-color:#8bb9fe;--bs-link-color-rgb:110,168,254;--bs-link-hover-color-rgb:139,185,254;--bs-code-color:#e685b5;--bs-highlight-color:#dee2e6;--bs-highlight-bg:#664d03;--bs-border-color:#495057;--bs-border-color-translucent:rgba(255, 255, 255, 0.15);--bs-form-valid-color:#75b798;--bs-form-valid-border-color:#75b798;--bs-form-invalid-color:#ea868f;--bs-form-invalid-border-color:#ea868f}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;border:0;border-top:var(--bs-border-width) solid;opacity:.25}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color)}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-right:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-right:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.1875em;color:var(--bs-highlight-color);background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,1));text-decoration:underline}a:hover{--bs-link-color-rgb:var(--bs-link-hover-color-rgb)}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:var(--bs-code-color);word-wrap:break-word}a>code{color:inherit}kbd{padding:.1875rem .375rem;font-size:.875em;color:var(--bs-body-bg);background-color:var(--bs-body-color);border-radius:.25rem}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-secondary-color);text-align:right}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none!important}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:right;width:100%;padding:0;margin-bottom:.5rem;line-height:inherit;font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:right}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=email],[type=number],[type=tel],[type=url]{direction:ltr}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-weight:300;line-height:1.2;font-size:calc(1.625rem + 4.5vw)}@media (min-width:1200px){.display-1{font-size:5rem}}.display-2{font-weight:300;line-height:1.2;font-size:calc(1.575rem + 3.9vw)}@media (min-width:1200px){.display-2{font-size:4.5rem}}.display-3{font-weight:300;line-height:1.2;font-size:calc(1.525rem + 3.3vw)}@media (min-width:1200px){.display-3{font-size:4rem}}.display-4{font-weight:300;line-height:1.2;font-size:calc(1.475rem + 2.7vw)}@media (min-width:1200px){.display-4{font-size:3.5rem}}.display-5{font-weight:300;line-height:1.2;font-size:calc(1.425rem + 2.1vw)}@media (min-width:1200px){.display-5{font-size:3rem}}.display-6{font-weight:300;line-height:1.2;font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-right:0;list-style:none}.list-inline{padding-right:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-left:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:var(--bs-body-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:var(--bs-secondary-color)}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{--bs-gutter-x:1.5rem;--bs-gutter-y:0;width:100%;padding-left:calc(var(--bs-gutter-x) * .5);padding-right:calc(var(--bs-gutter-x) * .5);margin-left:auto;margin-right:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}:root{--bs-breakpoint-xs:0;--bs-breakpoint-sm:576px;--bs-breakpoint-md:768px;--bs-breakpoint-lg:992px;--bs-breakpoint-xl:1200px;--bs-breakpoint-xxl:1400px}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--bs-gutter-y));margin-left:calc(-.5 * var(--bs-gutter-x));margin-right:calc(-.5 * var(--bs-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-left:calc(var(--bs-gutter-x) * .5);padding-right:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.66666667%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-right:8.33333333%}.offset-2{margin-right:16.66666667%}.offset-3{margin-right:25%}.offset-4{margin-right:33.33333333%}.offset-5{margin-right:41.66666667%}.offset-6{margin-right:50%}.offset-7{margin-right:58.33333333%}.offset-8{margin-right:66.66666667%}.offset-9{margin-right:75%}.offset-10{margin-right:83.33333333%}.offset-11{margin-right:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm{flex:1 0 0}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.66666667%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-right:0}.offset-sm-1{margin-right:8.33333333%}.offset-sm-2{margin-right:16.66666667%}.offset-sm-3{margin-right:25%}.offset-sm-4{margin-right:33.33333333%}.offset-sm-5{margin-right:41.66666667%}.offset-sm-6{margin-right:50%}.offset-sm-7{margin-right:58.33333333%}.offset-sm-8{margin-right:66.66666667%}.offset-sm-9{margin-right:75%}.offset-sm-10{margin-right:83.33333333%}.offset-sm-11{margin-right:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md{flex:1 0 0}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.66666667%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-right:0}.offset-md-1{margin-right:8.33333333%}.offset-md-2{margin-right:16.66666667%}.offset-md-3{margin-right:25%}.offset-md-4{margin-right:33.33333333%}.offset-md-5{margin-right:41.66666667%}.offset-md-6{margin-right:50%}.offset-md-7{margin-right:58.33333333%}.offset-md-8{margin-right:66.66666667%}.offset-md-9{margin-right:75%}.offset-md-10{margin-right:83.33333333%}.offset-md-11{margin-right:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg{flex:1 0 0}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.66666667%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-right:0}.offset-lg-1{margin-right:8.33333333%}.offset-lg-2{margin-right:16.66666667%}.offset-lg-3{margin-right:25%}.offset-lg-4{margin-right:33.33333333%}.offset-lg-5{margin-right:41.66666667%}.offset-lg-6{margin-right:50%}.offset-lg-7{margin-right:58.33333333%}.offset-lg-8{margin-right:66.66666667%}.offset-lg-9{margin-right:75%}.offset-lg-10{margin-right:83.33333333%}.offset-lg-11{margin-right:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl{flex:1 0 0}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.66666667%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-right:0}.offset-xl-1{margin-right:8.33333333%}.offset-xl-2{margin-right:16.66666667%}.offset-xl-3{margin-right:25%}.offset-xl-4{margin-right:33.33333333%}.offset-xl-5{margin-right:41.66666667%}.offset-xl-6{margin-right:50%}.offset-xl-7{margin-right:58.33333333%}.offset-xl-8{margin-right:66.66666667%}.offset-xl-9{margin-right:75%}.offset-xl-10{margin-right:83.33333333%}.offset-xl-11{margin-right:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl{flex:1 0 0}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.66666667%}.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-right:0}.offset-xxl-1{margin-right:8.33333333%}.offset-xxl-2{margin-right:16.66666667%}.offset-xxl-3{margin-right:25%}.offset-xxl-4{margin-right:33.33333333%}.offset-xxl-5{margin-right:41.66666667%}.offset-xxl-6{margin-right:50%}.offset-xxl-7{margin-right:58.33333333%}.offset-xxl-8{margin-right:66.66666667%}.offset-xxl-9{margin-right:75%}.offset-xxl-10{margin-right:83.33333333%}.offset-xxl-11{margin-right:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.table{--bs-table-color-type:initial;--bs-table-bg-type:initial;--bs-table-color-state:initial;--bs-table-bg-state:initial;--bs-table-color:var(--bs-emphasis-color);--bs-table-bg:var(--bs-body-bg);--bs-table-border-color:var(--bs-border-color);--bs-table-accent-bg:transparent;--bs-table-striped-color:var(--bs-emphasis-color);--bs-table-striped-bg:rgba(var(--bs-emphasis-color-rgb), 0.05);--bs-table-active-color:var(--bs-emphasis-color);--bs-table-active-bg:rgba(var(--bs-emphasis-color-rgb), 0.1);--bs-table-hover-color:var(--bs-emphasis-color);--bs-table-hover-bg:rgba(var(--bs-emphasis-color-rgb), 0.075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;color:var(--bs-table-color-state,var(--bs-table-color-type,var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:var(--bs-border-width);box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state,var(--bs-table-bg-type,var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(var(--bs-border-width) * 2) solid currentcolor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:var(--bs-border-width) 0}.table-bordered>:not(caption)>*>*{border-width:0 var(--bs-border-width)}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(2n){--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-active{--bs-table-color-state:var(--bs-table-active-color);--bs-table-bg-state:var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state:var(--bs-table-hover-color);--bs-table-bg-state:var(--bs-table-hover-bg)}.table-primary{--bs-table-color:#000;--bs-table-bg:#cfe2ff;--bs-table-border-color:#a6b5cc;--bs-table-striped-bg:#c5d7f2;--bs-table-striped-color:#000;--bs-table-active-bg:#bacbe6;--bs-table-active-color:#000;--bs-table-hover-bg:#bfd1ec;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color:#000;--bs-table-bg:#e2e3e5;--bs-table-border-color:#b5b6b7;--bs-table-striped-bg:#d7d8da;--bs-table-striped-color:#000;--bs-table-active-bg:#cbccce;--bs-table-active-color:#000;--bs-table-hover-bg:#d1d2d4;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color:#000;--bs-table-bg:#d1e7dd;--bs-table-border-color:#a7b9b1;--bs-table-striped-bg:#c7dbd2;--bs-table-striped-color:#000;--bs-table-active-bg:#bcd0c7;--bs-table-active-color:#000;--bs-table-hover-bg:#c1d6cc;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color:#000;--bs-table-bg:#cff4fc;--bs-table-border-color:#a6c3ca;--bs-table-striped-bg:#c5e8ef;--bs-table-striped-color:#000;--bs-table-active-bg:#badce3;--bs-table-active-color:#000;--bs-table-hover-bg:#bfe2e9;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color:#000;--bs-table-bg:#fff3cd;--bs-table-border-color:#ccc2a4;--bs-table-striped-bg:#f2e7c3;--bs-table-striped-color:#000;--bs-table-active-bg:#e6dbb9;--bs-table-active-color:#000;--bs-table-hover-bg:#ece1be;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color:#000;--bs-table-bg:#f8d7da;--bs-table-border-color:#c6acae;--bs-table-striped-bg:#eccccf;--bs-table-striped-color:#000;--bs-table-active-bg:#dfc2c4;--bs-table-active-color:#000;--bs-table-hover-bg:#e5c7ca;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color:#000;--bs-table-bg:#f8f9fa;--bs-table-border-color:#c6c7c8;--bs-table-striped-bg:#ecedee;--bs-table-striped-color:#000;--bs-table-active-bg:#dfe0e1;--bs-table-active-color:#000;--bs-table-hover-bg:#e5e6e7;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color:#fff;--bs-table-bg:#212529;--bs-table-border-color:#4d5154;--bs-table-striped-bg:#2c3034;--bs-table-striped-color:#fff;--bs-table-active-bg:#373b3e;--bs-table-active-color:#fff;--bs-table-hover-bg:#323539;--bs-table-hover-color:#fff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width:575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + var(--bs-border-width));padding-bottom:calc(.375rem + var(--bs-border-width));margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + var(--bs-border-width));padding-bottom:calc(.5rem + var(--bs-border-width));font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + var(--bs-border-width));padding-bottom:calc(.25rem + var(--bs-border-width));font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:var(--bs-secondary-color)}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-clip:padding-box;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::placeholder{color:var(--bs-secondary-color);opacity:1}.form-control:disabled{background-color:var(--bs-secondary-bg);opacity:1}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:var(--bs-secondary-bg)}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:var(--bs-secondary-bg)}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:var(--bs-body-color);background-color:transparent;border:solid transparent;border-width:var(--bs-border-width) 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-left:0;padding-right:0}.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2));padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2))}textarea.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}textarea.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-control-color{width:3rem;height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2));padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color::-webkit-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color.form-control-sm{height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem .75rem .375rem 2.25rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon,none);background-repeat:no-repeat;background-position:left .75rem center;background-size:16px 12px;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-left:.75rem;background-image:none}.form-select:disabled{background-color:var(--bs-secondary-bg)}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 var(--bs-body-color)}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-right:.5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-right:1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check{display:block;min-height:1.5rem;padding-right:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:right;margin-right:-1.5em}.form-check-reverse{padding-left:1.5em;padding-right:0;text-align:left}.form-check-reverse .form-check-input{float:left;margin-left:-1.5em;margin-right:0}.form-check-input{--bs-form-check-bg:var(--bs-body-bg);flex-shrink:0;width:1em;height:1em;margin-top:.25em;vertical-align:top;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:var(--bs-border-width) solid var(--bs-border-color);-webkit-print-color-adjust:exact;color-adjust:exact;print-color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{cursor:default;opacity:.5}.form-switch{padding-right:2.5em}.form-switch .form-check-input{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-right:-2.5em;background-image:var(--bs-form-switch-bg);background-position:right center;border-radius:2em;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:left center;--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-left:2.5em;padding-right:0}.form-switch.form-check-reverse .form-check-input{margin-left:-2.5em;margin-right:0}.form-check-inline{display:inline-block;margin-left:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check:disabled+.btn,.btn-check[disabled]+.btn{pointer-events:none;filter:none;opacity:.65}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;-webkit-appearance:none;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;-moz-appearance:none;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:var(--bs-secondary-color)}.form-range:disabled::-moz-range-thumb{background-color:var(--bs-secondary-color)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(var(--bs-border-width) * 2));min-height:calc(3.5rem + calc(var(--bs-border-width) * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;right:0;z-index:2;max-width:100%;height:100%;padding:1rem .75rem;overflow:hidden;color:rgba(var(--bs-body-color-rgb),.65);text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:var(--bs-border-width) solid transparent;transform-origin:100% 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control-plaintext::placeholder,.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown),.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control-plaintext:-webkit-autofill,.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem;padding-right:.75rem}.form-floating>.form-control-plaintext~label,.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{transform:scale(.85) translateY(-.5rem) translateX(-.15rem)}.form-floating>.form-control:-webkit-autofill~label{transform:scale(.85) translateY(-.5rem) translateX(-.15rem)}.form-floating>textarea:focus~label::after,.form-floating>textarea:not(:placeholder-shown)~label::after{position:absolute;inset:1rem 0.375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>textarea:disabled~label::after{background-color:var(--bs-secondary-bg)}.form-floating>.form-control-plaintext~label{border-width:var(--bs-border-width) 0}.form-floating>.form-control:disabled~label,.form-floating>:disabled~label{color:#6c757d}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-floating,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-floating:focus-within,.input-group>.form-select:focus{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);text-align:center;white-space:nowrap;background-color:var(--bs-tertiary-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius)}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-left:3rem}.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-control,.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-select,.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-left-radius:0;border-bottom-left-radius:0}.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-control,.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-select,.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-right:calc(-1 * var(--bs-border-width));border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-right-radius:0;border-bottom-right-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-valid-color)}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-success);border-radius:var(--bs-border-radius)}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:var(--bs-form-valid-border-color);padding-left:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:left calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-left:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) left calc(.375em + .1875rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:var(--bs-form-valid-border-color)}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1'/%3e%3c/svg%3e");padding-left:4.125rem;background-position:left .75rem center,center left 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-control-color.is-valid,.was-validated .form-control-color:valid{width:calc(3rem + calc(1.5em + .75rem))}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:var(--bs-form-valid-border-color)}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:var(--bs-form-valid-color)}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:var(--bs-form-valid-color)}.form-check-inline .form-check-input~.valid-feedback{margin-right:.5em}.input-group>.form-control:not(:focus).is-valid,.input-group>.form-floating:not(:focus-within).is-valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-control:not(:focus):valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.was-validated .input-group>.form-select:not(:focus):valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-invalid-color)}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-danger);border-radius:var(--bs-border-radius)}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:var(--bs-form-invalid-border-color);padding-left:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:left calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-left:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) left calc(.375em + .1875rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:var(--bs-form-invalid-border-color)}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");padding-left:4.125rem;background-position:left .75rem center,center left 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-control-color.is-invalid,.was-validated .form-control-color:invalid{width:calc(3rem + calc(1.5em + .75rem))}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:var(--bs-form-invalid-border-color)}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:var(--bs-form-invalid-color)}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:var(--bs-form-invalid-color)}.form-check-inline .form-check-input~.invalid-feedback{margin-right:.5em}.input-group>.form-control:not(:focus).is-invalid,.input-group>.form-floating:not(:focus-within).is-invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-control:not(:focus):invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.was-validated .input-group>.form-select:not(:focus):invalid{z-index:4}.btn{--bs-btn-padding-x:0.75rem;--bs-btn-padding-y:0.375rem;--bs-btn-font-family: ;--bs-btn-font-size:1rem;--bs-btn-font-weight:400;--bs-btn-line-height:1.5;--bs-btn-color:var(--bs-body-color);--bs-btn-bg:transparent;--bs-btn-border-width:var(--bs-border-width);--bs-btn-border-color:transparent;--bs-btn-border-radius:var(--bs-border-radius);--bs-btn-hover-border-color:transparent;--bs-btn-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.15),0 1px 1px rgba(0, 0, 0, 0.075);--bs-btn-disabled-opacity:0.65;--bs-btn-focus-box-shadow:0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);border-radius:var(--bs-btn-border-radius);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,.btn.active,.btn.show,.btn:first-child:active,:not(.btn-check)+.btn:active{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible,.btn:first-child:active:focus-visible,:not(.btn-check)+.btn:active:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked:focus-visible+.btn{box-shadow:var(--bs-btn-focus-box-shadow)}.btn.disabled,.btn:disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-primary{--bs-btn-color:#fff;--bs-btn-bg:#0d6efd;--bs-btn-border-color:#0d6efd;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#0b5ed7;--bs-btn-hover-border-color:#0a58ca;--bs-btn-focus-shadow-rgb:49,132,253;--bs-btn-active-color:#fff;--bs-btn-active-bg:#0a58ca;--bs-btn-active-border-color:#0a53be;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#0d6efd;--bs-btn-disabled-border-color:#0d6efd}.btn-secondary{--bs-btn-color:#fff;--bs-btn-bg:#6c757d;--bs-btn-border-color:#6c757d;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#5c636a;--bs-btn-hover-border-color:#565e64;--bs-btn-focus-shadow-rgb:130,138,145;--bs-btn-active-color:#fff;--bs-btn-active-bg:#565e64;--bs-btn-active-border-color:#51585e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#6c757d;--bs-btn-disabled-border-color:#6c757d}.btn-success{--bs-btn-color:#fff;--bs-btn-bg:#198754;--bs-btn-border-color:#198754;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#157347;--bs-btn-hover-border-color:#146c43;--bs-btn-focus-shadow-rgb:60,153,110;--bs-btn-active-color:#fff;--bs-btn-active-bg:#146c43;--bs-btn-active-border-color:#13653f;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#198754;--bs-btn-disabled-border-color:#198754}.btn-info{--bs-btn-color:#000;--bs-btn-bg:#0dcaf0;--bs-btn-border-color:#0dcaf0;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#31d2f2;--bs-btn-hover-border-color:#25cff2;--bs-btn-focus-shadow-rgb:11,172,204;--bs-btn-active-color:#000;--bs-btn-active-bg:#3dd5f3;--bs-btn-active-border-color:#25cff2;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#0dcaf0;--bs-btn-disabled-border-color:#0dcaf0}.btn-warning{--bs-btn-color:#000;--bs-btn-bg:#ffc107;--bs-btn-border-color:#ffc107;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#ffca2c;--bs-btn-hover-border-color:#ffc720;--bs-btn-focus-shadow-rgb:217,164,6;--bs-btn-active-color:#000;--bs-btn-active-bg:#ffcd39;--bs-btn-active-border-color:#ffc720;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#ffc107;--bs-btn-disabled-border-color:#ffc107}.btn-danger{--bs-btn-color:#fff;--bs-btn-bg:#dc3545;--bs-btn-border-color:#dc3545;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#bb2d3b;--bs-btn-hover-border-color:#b02a37;--bs-btn-focus-shadow-rgb:225,83,97;--bs-btn-active-color:#fff;--bs-btn-active-bg:#b02a37;--bs-btn-active-border-color:#a52834;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#dc3545;--bs-btn-disabled-border-color:#dc3545}.btn-light{--bs-btn-color:#000;--bs-btn-bg:#f8f9fa;--bs-btn-border-color:#f8f9fa;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#d3d4d5;--bs-btn-hover-border-color:#c6c7c8;--bs-btn-focus-shadow-rgb:211,212,213;--bs-btn-active-color:#000;--bs-btn-active-bg:#c6c7c8;--bs-btn-active-border-color:#babbbc;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#f8f9fa;--bs-btn-disabled-border-color:#f8f9fa}.btn-dark{--bs-btn-color:#fff;--bs-btn-bg:#212529;--bs-btn-border-color:#212529;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#424649;--bs-btn-hover-border-color:#373b3e;--bs-btn-focus-shadow-rgb:66,70,73;--bs-btn-active-color:#fff;--bs-btn-active-bg:#4d5154;--bs-btn-active-border-color:#373b3e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#212529;--bs-btn-disabled-border-color:#212529}.btn-outline-primary{--bs-btn-color:#0d6efd;--bs-btn-border-color:#0d6efd;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#0d6efd;--bs-btn-hover-border-color:#0d6efd;--bs-btn-focus-shadow-rgb:13,110,253;--bs-btn-active-color:#fff;--bs-btn-active-bg:#0d6efd;--bs-btn-active-border-color:#0d6efd;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#0d6efd;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#0d6efd;--bs-gradient:none}.btn-outline-secondary{--bs-btn-color:#6c757d;--bs-btn-border-color:#6c757d;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#6c757d;--bs-btn-hover-border-color:#6c757d;--bs-btn-focus-shadow-rgb:108,117,125;--bs-btn-active-color:#fff;--bs-btn-active-bg:#6c757d;--bs-btn-active-border-color:#6c757d;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#6c757d;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#6c757d;--bs-gradient:none}.btn-outline-success{--bs-btn-color:#198754;--bs-btn-border-color:#198754;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#198754;--bs-btn-hover-border-color:#198754;--bs-btn-focus-shadow-rgb:25,135,84;--bs-btn-active-color:#fff;--bs-btn-active-bg:#198754;--bs-btn-active-border-color:#198754;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#198754;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#198754;--bs-gradient:none}.btn-outline-info{--bs-btn-color:#0dcaf0;--bs-btn-border-color:#0dcaf0;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#0dcaf0;--bs-btn-hover-border-color:#0dcaf0;--bs-btn-focus-shadow-rgb:13,202,240;--bs-btn-active-color:#000;--bs-btn-active-bg:#0dcaf0;--bs-btn-active-border-color:#0dcaf0;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#0dcaf0;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#0dcaf0;--bs-gradient:none}.btn-outline-warning{--bs-btn-color:#ffc107;--bs-btn-border-color:#ffc107;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#ffc107;--bs-btn-hover-border-color:#ffc107;--bs-btn-focus-shadow-rgb:255,193,7;--bs-btn-active-color:#000;--bs-btn-active-bg:#ffc107;--bs-btn-active-border-color:#ffc107;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#ffc107;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#ffc107;--bs-gradient:none}.btn-outline-danger{--bs-btn-color:#dc3545;--bs-btn-border-color:#dc3545;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#dc3545;--bs-btn-hover-border-color:#dc3545;--bs-btn-focus-shadow-rgb:220,53,69;--bs-btn-active-color:#fff;--bs-btn-active-bg:#dc3545;--bs-btn-active-border-color:#dc3545;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#dc3545;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#dc3545;--bs-gradient:none}.btn-outline-light{--bs-btn-color:#f8f9fa;--bs-btn-border-color:#f8f9fa;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#f8f9fa;--bs-btn-hover-border-color:#f8f9fa;--bs-btn-focus-shadow-rgb:248,249,250;--bs-btn-active-color:#000;--bs-btn-active-bg:#f8f9fa;--bs-btn-active-border-color:#f8f9fa;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#f8f9fa;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#f8f9fa;--bs-gradient:none}.btn-outline-dark{--bs-btn-color:#212529;--bs-btn-border-color:#212529;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#212529;--bs-btn-hover-border-color:#212529;--bs-btn-focus-shadow-rgb:33,37,41;--bs-btn-active-color:#fff;--bs-btn-active-bg:#212529;--bs-btn-active-border-color:#212529;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#212529;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#212529;--bs-gradient:none}.btn-link{--bs-btn-font-weight:400;--bs-btn-color:var(--bs-link-color);--bs-btn-bg:transparent;--bs-btn-border-color:transparent;--bs-btn-hover-color:var(--bs-link-hover-color);--bs-btn-hover-border-color:transparent;--bs-btn-active-color:var(--bs-link-hover-color);--bs-btn-active-border-color:transparent;--bs-btn-disabled-color:#6c757d;--bs-btn-disabled-border-color:transparent;--bs-btn-box-shadow:0 0 0 #000;--bs-btn-focus-shadow-rgb:49,132,253;text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-group-lg>.btn,.btn-lg{--bs-btn-padding-y:0.5rem;--bs-btn-padding-x:1rem;--bs-btn-font-size:1.25rem;--bs-btn-border-radius:var(--bs-border-radius-lg)}.btn-group-sm>.btn,.btn-sm{--bs-btn-padding-y:0.25rem;--bs-btn-padding-x:0.5rem;--bs-btn-font-size:0.875rem;--bs-btn-border-radius:var(--bs-border-radius-sm)}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion:reduce){.collapsing.collapse-horizontal{transition:none}}.dropdown,.dropdown-center,.dropend,.dropstart,.dropup,.dropup-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-left:.3em solid transparent;border-bottom:0;border-right:.3em solid transparent}.dropdown-toggle:empty::after{margin-right:0}.dropdown-menu{--bs-dropdown-zindex:1000;--bs-dropdown-min-width:10rem;--bs-dropdown-padding-x:0;--bs-dropdown-padding-y:0.5rem;--bs-dropdown-spacer:0.125rem;--bs-dropdown-font-size:1rem;--bs-dropdown-color:var(--bs-body-color);--bs-dropdown-bg:var(--bs-body-bg);--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-border-radius:var(--bs-border-radius);--bs-dropdown-border-width:var(--bs-border-width);--bs-dropdown-inner-border-radius:calc(var(--bs-border-radius) - var(--bs-border-width));--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-divider-margin-y:0.5rem;--bs-dropdown-box-shadow:var(--bs-box-shadow);--bs-dropdown-link-color:var(--bs-body-color);--bs-dropdown-link-hover-color:var(--bs-body-color);--bs-dropdown-link-hover-bg:var(--bs-tertiary-bg);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#0d6efd;--bs-dropdown-link-disabled-color:var(--bs-tertiary-color);--bs-dropdown-item-padding-x:1rem;--bs-dropdown-item-padding-y:0.25rem;--bs-dropdown-header-color:#6c757d;--bs-dropdown-header-padding-x:1rem;--bs-dropdown-header-padding-y:0.5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:right;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);border-radius:var(--bs-dropdown-border-radius)}.dropdown-menu[data-bs-popper]{top:100%;right:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position:start}.dropdown-menu-start[data-bs-popper]{left:auto;right:0}.dropdown-menu-end{--bs-position:end}.dropdown-menu-end[data-bs-popper]{left:0;right:auto}@media (min-width:576px){.dropdown-menu-sm-start{--bs-position:start}.dropdown-menu-sm-start[data-bs-popper]{left:auto;right:0}.dropdown-menu-sm-end{--bs-position:end}.dropdown-menu-sm-end[data-bs-popper]{left:0;right:auto}}@media (min-width:768px){.dropdown-menu-md-start{--bs-position:start}.dropdown-menu-md-start[data-bs-popper]{left:auto;right:0}.dropdown-menu-md-end{--bs-position:end}.dropdown-menu-md-end[data-bs-popper]{left:0;right:auto}}@media (min-width:992px){.dropdown-menu-lg-start{--bs-position:start}.dropdown-menu-lg-start[data-bs-popper]{left:auto;right:0}.dropdown-menu-lg-end{--bs-position:end}.dropdown-menu-lg-end[data-bs-popper]{left:0;right:auto}}@media (min-width:1200px){.dropdown-menu-xl-start{--bs-position:start}.dropdown-menu-xl-start[data-bs-popper]{left:auto;right:0}.dropdown-menu-xl-end{--bs-position:end}.dropdown-menu-xl-end[data-bs-popper]{left:0;right:auto}}@media (min-width:1400px){.dropdown-menu-xxl-start{--bs-position:start}.dropdown-menu-xxl-start[data-bs-popper]{left:auto;right:0}.dropdown-menu-xxl-end{--bs-position:end}.dropdown-menu-xxl-end[data-bs-popper]{left:0;right:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle::after{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:0;border-left:.3em solid transparent;border-bottom:.3em solid;border-right:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-right:0}.dropend .dropdown-menu[data-bs-popper]{top:0;left:auto;right:100%;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-left:0;border-bottom:.3em solid transparent;border-right:.3em solid}.dropend .dropdown-toggle:empty::after{margin-right:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;left:100%;right:auto;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle::after{display:inline-block;margin-right:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-left:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-right:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0;border-radius:var(--bs-dropdown-item-border-radius,0)}.dropdown-item:focus,.dropdown-item:hover{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color:#dee2e6;--bs-dropdown-bg:#343a40;--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color:#dee2e6;--bs-dropdown-link-hover-color:#fff;--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-link-hover-bg:rgba(255, 255, 255, 0.15);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#0d6efd;--bs-dropdown-link-disabled-color:#adb5bd;--bs-dropdown-header-color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group{border-radius:var(--bs-border-radius)}.btn-group>.btn-group:not(:first-child),.btn-group>:not(.btn-check:first-child)+.btn{margin-right:calc(-1 * var(--bs-border-width))}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn.dropdown-toggle-split:first-child,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn{border-top-right-radius:0;border-bottom-right-radius:0}.dropdown-toggle-split{padding-left:.5625rem;padding-right:.5625rem}.dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-right:0}.dropstart .dropdown-toggle-split::before{margin-left:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-left:.375rem;padding-right:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-left:.75rem;padding-right:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:calc(-1 * var(--bs-border-width))}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-left-radius:0;border-bottom-right-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:nth-child(n+3),.btn-group-vertical>:not(.btn-check)+.btn{border-top-right-radius:0;border-top-left-radius:0}.nav{--bs-nav-link-padding-x:1rem;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-link-color);--bs-nav-link-hover-color:var(--bs-link-hover-color);--bs-nav-link-disabled-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding-right:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;background:0 0;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width:var(--bs-border-width);--bs-nav-tabs-border-color:var(--bs-border-color);--bs-nav-tabs-border-radius:var(--bs-border-radius);--bs-nav-tabs-link-hover-border-color:var(--bs-secondary-bg) var(--bs-secondary-bg) var(--bs-border-color);--bs-nav-tabs-link-active-color:var(--bs-emphasis-color);--bs-nav-tabs-link-active-bg:var(--bs-body-bg);--bs-nav-tabs-link-active-border-color:var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg);border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1 * var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid transparent;border-top-right-radius:var(--bs-nav-tabs-border-radius);border-top-left-radius:var(--bs-nav-tabs-border-radius)}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1 * var(--bs-nav-tabs-border-width));border-top-right-radius:0;border-top-left-radius:0}.nav-pills{--bs-nav-pills-border-radius:var(--bs-border-radius);--bs-nav-pills-link-active-color:#fff;--bs-nav-pills-link-active-bg:#0d6efd}.nav-pills .nav-link{border-radius:var(--bs-nav-pills-border-radius)}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap:1rem;--bs-nav-underline-border-width:0.125rem;--bs-nav-underline-link-active-color:var(--bs-emphasis-color);gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-left:0;padding-right:0;border-bottom:var(--bs-nav-underline-border-width) solid transparent}.nav-underline .nav-link:focus,.nav-underline .nav-link:hover{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:700;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-grow:1;flex-basis:0;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x:0;--bs-navbar-padding-y:0.5rem;--bs-navbar-color:rgba(var(--bs-emphasis-color-rgb), 0.65);--bs-navbar-hover-color:rgba(var(--bs-emphasis-color-rgb), 0.8);--bs-navbar-disabled-color:rgba(var(--bs-emphasis-color-rgb), 0.3);--bs-navbar-active-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-padding-y:0.3125rem;--bs-navbar-brand-margin-end:1rem;--bs-navbar-brand-font-size:1.25rem;--bs-navbar-brand-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-hover-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-nav-link-padding-x:0.5rem;--bs-navbar-toggler-padding-y:0.25rem;--bs-navbar-toggler-padding-x:0.75rem;--bs-navbar-toggler-font-size:1.25rem;--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color:rgba(var(--bs-emphasis-color-rgb), 0.15);--bs-navbar-toggler-border-radius:var(--bs-border-radius);--bs-navbar-toggler-focus-width:0.25rem;--bs-navbar-toggler-transition:box-shadow 0.15s ease-in-out;position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-left:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x:0;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-navbar-color);--bs-nav-link-hover-color:var(--bs-navbar-hover-color);--bs-nav-link-disabled-color:var(--bs-navbar-disabled-color);display:flex;flex-direction:column;padding-right:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:focus,.navbar-text a:hover{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-grow:1;flex-basis:100%;align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:transparent;border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);border-radius:var(--bs-navbar-toggler-border-radius);transition:var(--bs-navbar-toggler-transition)}@media (prefers-reduced-motion:reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height,75vh);overflow-y:auto}@media (min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-left:var(--bs-navbar-nav-link-padding-x);padding-right:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-left:var(--bs-navbar-nav-link-padding-x);padding-right:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-left:var(--bs-navbar-nav-link-padding-x);padding-right:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-left:var(--bs-navbar-nav-link-padding-x);padding-right:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-left:var(--bs-navbar-nav-link-padding-x);padding-right:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-left:var(--bs-navbar-nav-link-padding-x);padding-right:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color:rgba(255, 255, 255, 0.55);--bs-navbar-hover-color:rgba(255, 255, 255, 0.75);--bs-navbar-disabled-color:rgba(255, 255, 255, 0.25);--bs-navbar-active-color:#fff;--bs-navbar-brand-color:#fff;--bs-navbar-brand-hover-color:#fff;--bs-navbar-toggler-border-color:rgba(255, 255, 255, 0.1);--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y:1rem;--bs-card-spacer-x:1rem;--bs-card-title-spacer-y:0.5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width:var(--bs-border-width);--bs-card-border-color:var(--bs-border-color-translucent);--bs-card-border-radius:var(--bs-border-radius);--bs-card-box-shadow: ;--bs-card-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-card-cap-padding-y:0.5rem;--bs-card-cap-padding-x:1rem;--bs-card-cap-bg:rgba(var(--bs-body-color-rgb), 0.03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg:var(--bs-body-bg);--bs-card-img-overlay-padding:1rem;--bs-card-group-margin:0.75rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color);border-radius:var(--bs-card-border-radius)}.card>hr{margin-left:0;margin-right:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-right-radius:var(--bs-card-inner-border-radius);border-top-left-radius:var(--bs-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-left-radius:var(--bs-card-inner-border-radius);border-bottom-right-radius:var(--bs-card-inner-border-radius)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-.5 * var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-right:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header:first-child{border-radius:var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer:last-child{border-radius:0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius)}.card-header-tabs{margin-left:calc(-.5 * var(--bs-card-cap-padding-x));margin-bottom:calc(-1 * var(--bs-card-cap-padding-y));margin-right:calc(-.5 * var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-left:calc(-.5 * var(--bs-card-cap-padding-x));margin-right:calc(-.5 * var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;left:0;bottom:0;right:0;padding:var(--bs-card-img-overlay-padding);border-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-img,.card-img-top{border-top-right-radius:var(--bs-card-inner-border-radius);border-top-left-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-left-radius:var(--bs-card-inner-border-radius);border-bottom-right-radius:var(--bs-card-inner-border-radius)}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0;margin-bottom:0}.card-group>.card+.card{margin-right:0;border-right:0}.card-group>.card:not(:last-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:last-child)>.card-header,.card-group>.card:not(:last-child)>.card-img-top{border-top-left-radius:0}.card-group>.card:not(:last-child)>.card-footer,.card-group>.card:not(:last-child)>.card-img-bottom{border-bottom-left-radius:0}.card-group>.card:not(:first-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:first-child)>.card-header,.card-group>.card:not(:first-child)>.card-img-top{border-top-right-radius:0}.card-group>.card:not(:first-child)>.card-footer,.card-group>.card:not(:first-child)>.card-img-bottom{border-bottom-right-radius:0}}.accordion{--bs-accordion-color:var(--bs-body-color);--bs-accordion-bg:var(--bs-body-bg);--bs-accordion-transition:color 0.15s ease-in-out,background-color 0.15s ease-in-out,border-color 0.15s ease-in-out,box-shadow 0.15s ease-in-out,border-radius 0.15s ease;--bs-accordion-border-color:var(--bs-border-color);--bs-accordion-border-width:var(--bs-border-width);--bs-accordion-border-radius:var(--bs-border-radius);--bs-accordion-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-accordion-btn-padding-x:1.25rem;--bs-accordion-btn-padding-y:1rem;--bs-accordion-btn-color:var(--bs-body-color);--bs-accordion-btn-bg:var(--bs-accordion-bg);--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23212529' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='m2 5 6 6 6-6'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width:1.25rem;--bs-accordion-btn-icon-transform:rotate(-180deg);--bs-accordion-btn-icon-transition:transform 0.2s ease-in-out;--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23052c65' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='m2 5 6 6 6-6'/%3e%3c/svg%3e");--bs-accordion-btn-focus-box-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-accordion-body-padding-x:1.25rem;--bs-accordion-body-padding-y:1rem;--bs-accordion-active-color:var(--bs-primary-text-emphasis);--bs-accordion-active-bg:var(--bs-primary-bg-subtle)}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:right;background-color:var(--bs-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media (prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed)::after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button::after{flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-right:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media (prefers-reduced-motion:reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:first-of-type{border-top-right-radius:var(--bs-accordion-border-radius);border-top-left-radius:var(--bs-accordion-border-radius)}.accordion-item:first-of-type>.accordion-header .accordion-button{border-top-right-radius:var(--bs-accordion-inner-border-radius);border-top-left-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-left-radius:var(--bs-accordion-border-radius);border-bottom-right-radius:var(--bs-accordion-border-radius)}.accordion-item:last-of-type>.accordion-header .accordion-button.collapsed{border-bottom-left-radius:var(--bs-accordion-inner-border-radius);border-bottom-right-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:last-of-type>.accordion-collapse{border-bottom-left-radius:var(--bs-accordion-border-radius);border-bottom-right-radius:var(--bs-accordion-border-radius)}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush>.accordion-item{border-left:0;border-right:0;border-radius:0}.accordion-flush>.accordion-item:first-child{border-top:0}.accordion-flush>.accordion-item:last-child{border-bottom:0}.accordion-flush>.accordion-item>.accordion-collapse,.accordion-flush>.accordion-item>.accordion-header .accordion-button,.accordion-flush>.accordion-item>.accordion-header .accordion-button.collapsed{border-radius:0}[data-bs-theme=dark] .accordion-button::after{--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708'/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x:0;--bs-breadcrumb-padding-y:0;--bs-breadcrumb-margin-bottom:1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color:var(--bs-secondary-color);--bs-breadcrumb-item-padding-x:0.5rem;--bs-breadcrumb-item-active-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg);border-radius:var(--bs-breadcrumb-border-radius)}.breadcrumb-item+.breadcrumb-item{padding-right:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:right;padding-left:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x:0.75rem;--bs-pagination-padding-y:0.375rem;--bs-pagination-font-size:1rem;--bs-pagination-color:var(--bs-link-color);--bs-pagination-bg:var(--bs-body-bg);--bs-pagination-border-width:var(--bs-border-width);--bs-pagination-border-color:var(--bs-border-color);--bs-pagination-border-radius:var(--bs-border-radius);--bs-pagination-hover-color:var(--bs-link-hover-color);--bs-pagination-hover-bg:var(--bs-tertiary-bg);--bs-pagination-hover-border-color:var(--bs-border-color);--bs-pagination-focus-color:var(--bs-link-hover-color);--bs-pagination-focus-bg:var(--bs-secondary-bg);--bs-pagination-focus-box-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-pagination-active-color:#fff;--bs-pagination-active-bg:#0d6efd;--bs-pagination-active-border-color:#0d6efd;--bs-pagination-disabled-color:var(--bs-secondary-color);--bs-pagination-disabled-bg:var(--bs-secondary-bg);--bs-pagination-disabled-border-color:var(--bs-border-color);display:flex;padding-right:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.active>.page-link,.page-link.active{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.disabled>.page-link,.page-link.disabled{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-right:calc(-1 * var(--bs-border-width))}.page-item:first-child .page-link{border-top-right-radius:var(--bs-pagination-border-radius);border-bottom-right-radius:var(--bs-pagination-border-radius)}.page-item:last-child .page-link{border-top-left-radius:var(--bs-pagination-border-radius);border-bottom-left-radius:var(--bs-pagination-border-radius)}.pagination-lg{--bs-pagination-padding-x:1.5rem;--bs-pagination-padding-y:0.75rem;--bs-pagination-font-size:1.25rem;--bs-pagination-border-radius:var(--bs-border-radius-lg)}.pagination-sm{--bs-pagination-padding-x:0.5rem;--bs-pagination-padding-y:0.25rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius:var(--bs-border-radius-sm)}.badge{--bs-badge-padding-x:0.65em;--bs-badge-padding-y:0.35em;--bs-badge-font-size:0.75em;--bs-badge-font-weight:700;--bs-badge-color:#fff;--bs-badge-border-radius:var(--bs-border-radius);display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:var(--bs-badge-border-radius)}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg:transparent;--bs-alert-padding-x:1rem;--bs-alert-padding-y:1rem;--bs-alert-margin-bottom:1rem;--bs-alert-color:inherit;--bs-alert-border-color:transparent;--bs-alert-border:var(--bs-border-width) solid var(--bs-alert-border-color);--bs-alert-border-radius:var(--bs-border-radius);--bs-alert-link-color:inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border);border-radius:var(--bs-alert-border-radius)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-left:3rem}.alert-dismissible .btn-close{position:absolute;top:0;left:0;z-index:2;padding:1.25rem 1rem}.alert-primary{--bs-alert-color:var(--bs-primary-text-emphasis);--bs-alert-bg:var(--bs-primary-bg-subtle);--bs-alert-border-color:var(--bs-primary-border-subtle);--bs-alert-link-color:var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color:var(--bs-secondary-text-emphasis);--bs-alert-bg:var(--bs-secondary-bg-subtle);--bs-alert-border-color:var(--bs-secondary-border-subtle);--bs-alert-link-color:var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color:var(--bs-success-text-emphasis);--bs-alert-bg:var(--bs-success-bg-subtle);--bs-alert-border-color:var(--bs-success-border-subtle);--bs-alert-link-color:var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color:var(--bs-info-text-emphasis);--bs-alert-bg:var(--bs-info-bg-subtle);--bs-alert-border-color:var(--bs-info-border-subtle);--bs-alert-link-color:var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color:var(--bs-warning-text-emphasis);--bs-alert-bg:var(--bs-warning-bg-subtle);--bs-alert-border-color:var(--bs-warning-border-subtle);--bs-alert-link-color:var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color:var(--bs-danger-text-emphasis);--bs-alert-bg:var(--bs-danger-bg-subtle);--bs-alert-border-color:var(--bs-danger-border-subtle);--bs-alert-link-color:var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color:var(--bs-light-text-emphasis);--bs-alert-bg:var(--bs-light-bg-subtle);--bs-alert-border-color:var(--bs-light-border-subtle);--bs-alert-link-color:var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color:var(--bs-dark-text-emphasis);--bs-alert-bg:var(--bs-dark-bg-subtle);--bs-alert-border-color:var(--bs-dark-border-subtle);--bs-alert-link-color:var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:var(--bs-progress-height)}}.progress,.progress-stacked{--bs-progress-height:1rem;--bs-progress-font-size:0.75rem;--bs-progress-bg:var(--bs-secondary-bg);--bs-progress-border-radius:var(--bs-border-radius);--bs-progress-box-shadow:var(--bs-box-shadow-inset);--bs-progress-bar-color:#fff;--bs-progress-bar-bg:#0d6efd;--bs-progress-bar-transition:width 0.6s ease;display:flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg);border-radius:var(--bs-progress-border-radius)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(-45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion:reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color:var(--bs-body-color);--bs-list-group-bg:var(--bs-body-bg);--bs-list-group-border-color:var(--bs-border-color);--bs-list-group-border-width:var(--bs-border-width);--bs-list-group-border-radius:var(--bs-border-radius);--bs-list-group-item-padding-x:1rem;--bs-list-group-item-padding-y:0.5rem;--bs-list-group-action-color:var(--bs-secondary-color);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-tertiary-bg);--bs-list-group-action-active-color:var(--bs-body-color);--bs-list-group-action-active-bg:var(--bs-secondary-bg);--bs-list-group-disabled-color:var(--bs-secondary-color);--bs-list-group-disabled-bg:var(--bs-body-bg);--bs-list-group-active-color:#fff;--bs-list-group-active-bg:#0d6efd;--bs-list-group-active-border-color:#0d6efd;display:flex;flex-direction:column;padding-right:0;margin-bottom:0;border-radius:var(--bs-list-group-border-radius)}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item:first-child{border-top-right-radius:inherit;border-top-left-radius:inherit}.list-group-item:last-child{border-bottom-left-radius:inherit;border-bottom-right-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1 * var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:not(.active):focus,.list-group-item-action:not(.active):hover{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:not(.active):active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child:not(:last-child){border-bottom-right-radius:var(--bs-list-group-border-radius);border-top-left-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-left-radius:var(--bs-list-group-border-radius);border-bottom-right-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-right-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-right:calc(-1 * var(--bs-list-group-border-width));border-right-width:var(--bs-list-group-border-width)}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child:not(:last-child){border-bottom-right-radius:var(--bs-list-group-border-radius);border-top-left-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-left-radius:var(--bs-list-group-border-radius);border-bottom-right-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-right-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-right:calc(-1 * var(--bs-list-group-border-width));border-right-width:var(--bs-list-group-border-width)}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child:not(:last-child){border-bottom-right-radius:var(--bs-list-group-border-radius);border-top-left-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-left-radius:var(--bs-list-group-border-radius);border-bottom-right-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-right-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-right:calc(-1 * var(--bs-list-group-border-width));border-right-width:var(--bs-list-group-border-width)}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child:not(:last-child){border-bottom-right-radius:var(--bs-list-group-border-radius);border-top-left-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-left-radius:var(--bs-list-group-border-radius);border-bottom-right-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-right-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-right:calc(-1 * var(--bs-list-group-border-width));border-right-width:var(--bs-list-group-border-width)}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child:not(:last-child){border-bottom-right-radius:var(--bs-list-group-border-radius);border-top-left-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-left-radius:var(--bs-list-group-border-radius);border-bottom-right-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-right-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-right:calc(-1 * var(--bs-list-group-border-width));border-right-width:var(--bs-list-group-border-width)}}@media (min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child:not(:last-child){border-bottom-right-radius:var(--bs-list-group-border-radius);border-top-left-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-left-radius:var(--bs-list-group-border-radius);border-bottom-right-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-right-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-right:calc(-1 * var(--bs-list-group-border-width));border-right-width:var(--bs-list-group-border-width)}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{--bs-list-group-color:var(--bs-primary-text-emphasis);--bs-list-group-bg:var(--bs-primary-bg-subtle);--bs-list-group-border-color:var(--bs-primary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-primary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-primary-border-subtle);--bs-list-group-active-color:var(--bs-primary-bg-subtle);--bs-list-group-active-bg:var(--bs-primary-text-emphasis);--bs-list-group-active-border-color:var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color:var(--bs-secondary-text-emphasis);--bs-list-group-bg:var(--bs-secondary-bg-subtle);--bs-list-group-border-color:var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-secondary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-secondary-border-subtle);--bs-list-group-active-color:var(--bs-secondary-bg-subtle);--bs-list-group-active-bg:var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color:var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color:var(--bs-success-text-emphasis);--bs-list-group-bg:var(--bs-success-bg-subtle);--bs-list-group-border-color:var(--bs-success-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-success-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-success-border-subtle);--bs-list-group-active-color:var(--bs-success-bg-subtle);--bs-list-group-active-bg:var(--bs-success-text-emphasis);--bs-list-group-active-border-color:var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color:var(--bs-info-text-emphasis);--bs-list-group-bg:var(--bs-info-bg-subtle);--bs-list-group-border-color:var(--bs-info-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-info-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-info-border-subtle);--bs-list-group-active-color:var(--bs-info-bg-subtle);--bs-list-group-active-bg:var(--bs-info-text-emphasis);--bs-list-group-active-border-color:var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color:var(--bs-warning-text-emphasis);--bs-list-group-bg:var(--bs-warning-bg-subtle);--bs-list-group-border-color:var(--bs-warning-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-warning-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-warning-border-subtle);--bs-list-group-active-color:var(--bs-warning-bg-subtle);--bs-list-group-active-bg:var(--bs-warning-text-emphasis);--bs-list-group-active-border-color:var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color:var(--bs-danger-text-emphasis);--bs-list-group-bg:var(--bs-danger-bg-subtle);--bs-list-group-border-color:var(--bs-danger-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-danger-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-danger-border-subtle);--bs-list-group-active-color:var(--bs-danger-bg-subtle);--bs-list-group-active-bg:var(--bs-danger-text-emphasis);--bs-list-group-active-border-color:var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color:var(--bs-light-text-emphasis);--bs-list-group-bg:var(--bs-light-bg-subtle);--bs-list-group-border-color:var(--bs-light-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-light-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-light-border-subtle);--bs-list-group-active-color:var(--bs-light-bg-subtle);--bs-list-group-active-bg:var(--bs-light-text-emphasis);--bs-list-group-active-border-color:var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color:var(--bs-dark-text-emphasis);--bs-list-group-bg:var(--bs-dark-bg-subtle);--bs-list-group-border-color:var(--bs-dark-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-dark-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-dark-border-subtle);--bs-list-group-active-color:var(--bs-dark-bg-subtle);--bs-list-group-active-bg:var(--bs-dark-text-emphasis);--bs-list-group-active-border-color:var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color:#000;--bs-btn-close-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414'/%3e%3c/svg%3e");--bs-btn-close-opacity:0.5;--bs-btn-close-hover-opacity:0.75;--bs-btn-close-focus-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-btn-close-focus-opacity:1;--bs-btn-close-disabled-opacity:0.25;box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:var(--bs-btn-close-color);background:transparent var(--bs-btn-close-bg) center/1em auto no-repeat;filter:var(--bs-btn-close-filter);border:0;border-radius:.375rem;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close.disabled,.btn-close:disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{--bs-btn-close-filter:invert(1) grayscale(100%) brightness(200%)}:root,[data-bs-theme=light]{--bs-btn-close-filter: }[data-bs-theme=dark]{--bs-btn-close-filter:invert(1) grayscale(100%) brightness(200%)}.toast{--bs-toast-zindex:1090;--bs-toast-padding-x:0.75rem;--bs-toast-padding-y:0.5rem;--bs-toast-spacing:1.5rem;--bs-toast-max-width:350px;--bs-toast-font-size:0.875rem;--bs-toast-color: ;--bs-toast-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-border-width:var(--bs-border-width);--bs-toast-border-color:var(--bs-border-color-translucent);--bs-toast-border-radius:var(--bs-border-radius);--bs-toast-box-shadow:var(--bs-box-shadow);--bs-toast-header-color:var(--bs-secondary-color);--bs-toast-header-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-header-border-color:var(--bs-border-color-translucent);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow);border-radius:var(--bs-toast-border-radius)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex:1090;position:absolute;z-index:var(--bs-toast-zindex);width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);border-top-right-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));border-top-left-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width))}.toast-header .btn-close{margin-left:calc(-.5 * var(--bs-toast-padding-x));margin-right:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex:1055;--bs-modal-width:500px;--bs-modal-padding:1rem;--bs-modal-margin:0.5rem;--bs-modal-color:var(--bs-body-color);--bs-modal-bg:var(--bs-body-bg);--bs-modal-border-color:var(--bs-border-color-translucent);--bs-modal-border-width:var(--bs-border-width);--bs-modal-border-radius:var(--bs-border-radius-lg);--bs-modal-box-shadow:var(--bs-box-shadow-sm);--bs-modal-inner-border-radius:calc(var(--bs-border-radius-lg) - (var(--bs-border-width)));--bs-modal-header-padding-x:1rem;--bs-modal-header-padding-y:1rem;--bs-modal-header-padding:1rem 1rem;--bs-modal-header-border-color:var(--bs-border-color);--bs-modal-header-border-width:var(--bs-border-width);--bs-modal-title-line-height:1.5;--bs-modal-footer-gap:0.5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color:var(--bs-border-color);--bs-modal-footer-border-width:var(--bs-border-width);position:fixed;top:0;right:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transform:translate(0,-50px);transition:transform .3s ease-out}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin) * 2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - var(--bs-modal-margin) * 2)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);border-radius:var(--bs-modal-border-radius);outline:0}.modal-backdrop{--bs-backdrop-zindex:1050;--bs-backdrop-bg:#000;--bs-backdrop-opacity:0.5;position:fixed;top:0;right:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;flex-shrink:0;align-items:center;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);border-top-right-radius:var(--bs-modal-inner-border-radius);border-top-left-radius:var(--bs-modal-inner-border-radius)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y) * .5) calc(var(--bs-modal-header-padding-x) * .5);margin-top:calc(-.5 * var(--bs-modal-header-padding-y));margin-left:calc(-.5 * var(--bs-modal-header-padding-x));margin-bottom:calc(-.5 * var(--bs-modal-header-padding-y));margin-right:auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * .5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);border-bottom-left-radius:var(--bs-modal-inner-border-radius);border-bottom-right-radius:var(--bs-modal-inner-border-radius)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap) * .5)}@media (min-width:576px){.modal{--bs-modal-margin:1.75rem;--bs-modal-box-shadow:var(--bs-box-shadow)}.modal-dialog{max-width:var(--bs-modal-width);margin-left:auto;margin-right:auto}.modal-sm{--bs-modal-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{--bs-modal-width:800px}}@media (min-width:1200px){.modal-xl{--bs-modal-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-footer,.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}@media (max-width:575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-footer,.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media (max-width:767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-footer,.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media (max-width:991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-footer,.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media (max-width:1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-footer,.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media (max-width:1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-footer,.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex:1080;--bs-tooltip-max-width:200px;--bs-tooltip-padding-x:0.5rem;--bs-tooltip-padding-y:0.25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size:0.875rem;--bs-tooltip-color:var(--bs-body-bg);--bs-tooltip-bg:var(--bs-emphasis-color);--bs-tooltip-border-radius:var(--bs-border-radius);--bs-tooltip-opacity:0.9;--bs-tooltip-arrow-width:0.8rem;--bs-tooltip-arrow-height:0.4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:right;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before,.bs-tooltip-top .tooltip-arrow::before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{left:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before,.bs-tooltip-end .tooltip-arrow::before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before,.bs-tooltip-bottom .tooltip-arrow::before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{right:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before,.bs-tooltip-start .tooltip-arrow::before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) 0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg);border-radius:var(--bs-tooltip-border-radius)}.popover{--bs-popover-zindex:1070;--bs-popover-max-width:276px;--bs-popover-font-size:0.875rem;--bs-popover-bg:var(--bs-body-bg);--bs-popover-border-width:var(--bs-border-width);--bs-popover-border-color:var(--bs-border-color-translucent);--bs-popover-border-radius:var(--bs-border-radius-lg);--bs-popover-inner-border-radius:calc(var(--bs-border-radius-lg) - var(--bs-border-width));--bs-popover-box-shadow:var(--bs-box-shadow);--bs-popover-header-padding-x:1rem;--bs-popover-header-padding-y:0.5rem;--bs-popover-header-font-size:1rem;--bs-popover-header-color:inherit;--bs-popover-header-bg:var(--bs-secondary-bg);--bs-popover-body-padding-x:1rem;--bs-popover-body-padding-y:1rem;--bs-popover-body-color:var(--bs-body-color);--bs-popover-arrow-width:1rem;--bs-popover-arrow-height:0.5rem;--bs-popover-arrow-border:var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:right;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-radius:var(--bs-popover-border-radius)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow::after,.popover .popover-arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid;border-width:0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::after,.bs-popover-top>.popover-arrow::before{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-top>.popover-arrow::after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{left:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::after,.bs-popover-end>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-end>.popover-arrow::after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::before{border-width:0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;right:50%;display:block;width:var(--bs-popover-arrow-width);margin-right:calc(-.5 * var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{right:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::after,.bs-popover-start>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) 0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-start>.popover-arrow::after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-top-right-radius:var(--bs-popover-inner-border-radius);border-top-left-radius:var(--bs-popover-inner-border-radius)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:right;width:100%;margin-left:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translateX(-100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translateX(100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;filter:var(--bs-carousel-control-icon-filter);border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{right:0}.carousel-control-next{left:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;left:0;bottom:0;right:0;z-index:2;display:flex;justify-content:center;padding:0;margin-left:15%;margin-bottom:1rem;margin-right:15%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-left:3px;margin-right:3px;text-indent:-999px;cursor:pointer;background-color:var(--bs-carousel-indicator-active-bg);background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;left:15%;bottom:1.25rem;right:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:var(--bs-carousel-caption-color);text-align:center}.carousel-dark{--bs-carousel-indicator-active-bg:#000;--bs-carousel-caption-color:#000;--bs-carousel-control-icon-filter:invert(1) grayscale(100)}:root,[data-bs-theme=light]{--bs-carousel-indicator-active-bg:#fff;--bs-carousel-caption-color:#fff;--bs-carousel-control-icon-filter: }[data-bs-theme=dark]{--bs-carousel-indicator-active-bg:#000;--bs-carousel-caption-color:#000;--bs-carousel-control-icon-filter:invert(1) grayscale(100)}.spinner-border,.spinner-grow{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-border-width:0.25em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-left-color:transparent}.spinner-border-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem;--bs-spinner-border-width:0.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed:1.5s}}.offcanvas,.offcanvas-lg,.offcanvas-md,.offcanvas-sm,.offcanvas-xl,.offcanvas-xxl{--bs-offcanvas-zindex:1045;--bs-offcanvas-width:400px;--bs-offcanvas-height:30vh;--bs-offcanvas-padding-x:1rem;--bs-offcanvas-padding-y:1rem;--bs-offcanvas-color:var(--bs-body-color);--bs-offcanvas-bg:var(--bs-body-bg);--bs-offcanvas-border-width:var(--bs-border-width);--bs-offcanvas-border-color:var(--bs-border-color-translucent);--bs-offcanvas-box-shadow:var(--bs-box-shadow-sm);--bs-offcanvas-transition:transform 0.3s ease-in-out;--bs-offcanvas-title-line-height:1.5}@media (max-width:575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:575.98px) and (prefers-reduced-motion:reduce){.offcanvas-sm{transition:none}}@media (max-width:575.98px){.offcanvas-sm.offcanvas-start{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-sm.offcanvas-end{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-sm.offcanvas-top{top:0;left:0;right:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{left:0;right:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.show:not(.hiding),.offcanvas-sm.showing{transform:none}.offcanvas-sm.hiding,.offcanvas-sm.show,.offcanvas-sm.showing{visibility:visible}}@media (min-width:576px){.offcanvas-sm{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:767.98px) and (prefers-reduced-motion:reduce){.offcanvas-md{transition:none}}@media (max-width:767.98px){.offcanvas-md.offcanvas-start{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-md.offcanvas-end{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-md.offcanvas-top{top:0;left:0;right:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{left:0;right:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.show:not(.hiding),.offcanvas-md.showing{transform:none}.offcanvas-md.hiding,.offcanvas-md.show,.offcanvas-md.showing{visibility:visible}}@media (min-width:768px){.offcanvas-md{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:991.98px) and (prefers-reduced-motion:reduce){.offcanvas-lg{transition:none}}@media (max-width:991.98px){.offcanvas-lg.offcanvas-start{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-lg.offcanvas-end{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-lg.offcanvas-top{top:0;left:0;right:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{left:0;right:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.show:not(.hiding),.offcanvas-lg.showing{transform:none}.offcanvas-lg.hiding,.offcanvas-lg.show,.offcanvas-lg.showing{visibility:visible}}@media (min-width:992px){.offcanvas-lg{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1199.98px) and (prefers-reduced-motion:reduce){.offcanvas-xl{transition:none}}@media (max-width:1199.98px){.offcanvas-xl.offcanvas-start{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xl.offcanvas-end{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xl.offcanvas-top{top:0;left:0;right:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{left:0;right:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.show:not(.hiding),.offcanvas-xl.showing{transform:none}.offcanvas-xl.hiding,.offcanvas-xl.show,.offcanvas-xl.showing{visibility:visible}}@media (min-width:1200px){.offcanvas-xl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1399.98px) and (prefers-reduced-motion:reduce){.offcanvas-xxl{transition:none}}@media (max-width:1399.98px){.offcanvas-xxl.offcanvas-start{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xxl.offcanvas-end{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xxl.offcanvas-top{top:0;left:0;right:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{left:0;right:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.show:not(.hiding),.offcanvas-xxl.showing{transform:none}.offcanvas-xxl.hiding,.offcanvas-xxl.show,.offcanvas-xxl.showing{visibility:visible}}@media (min-width:1400px){.offcanvas-xxl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media (prefers-reduced-motion:reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas.offcanvas-end{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas.offcanvas-top{top:0;left:0;right:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{left:0;right:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.show:not(.hiding),.offcanvas.showing{transform:none}.offcanvas.hiding,.offcanvas.show,.offcanvas.showing{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;right:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y) * .5) calc(var(--bs-offcanvas-padding-x) * .5);margin-top:calc(-.5 * var(--bs-offcanvas-padding-y));margin-left:calc(-.5 * var(--bs-offcanvas-padding-x));margin-bottom:calc(-.5 * var(--bs-offcanvas-padding-y));margin-right:auto}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{-webkit-mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);-webkit-mask-size:200% 100%;mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.text-bg-primary{color:#fff!important;background-color:RGBA(var(--bs-primary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-secondary{color:#fff!important;background-color:RGBA(var(--bs-secondary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-success{color:#fff!important;background-color:RGBA(var(--bs-success-rgb),var(--bs-bg-opacity,1))!important}.text-bg-info{color:#000!important;background-color:RGBA(var(--bs-info-rgb),var(--bs-bg-opacity,1))!important}.text-bg-warning{color:#000!important;background-color:RGBA(var(--bs-warning-rgb),var(--bs-bg-opacity,1))!important}.text-bg-danger{color:#fff!important;background-color:RGBA(var(--bs-danger-rgb),var(--bs-bg-opacity,1))!important}.text-bg-light{color:#000!important;background-color:RGBA(var(--bs-light-rgb),var(--bs-bg-opacity,1))!important}.text-bg-dark{color:#fff!important;background-color:RGBA(var(--bs-dark-rgb),var(--bs-bg-opacity,1))!important}.link-primary{color:RGBA(var(--bs-primary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important}.link-primary:focus,.link-primary:hover{color:RGBA(10,88,202,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity,1))!important}.link-secondary{color:RGBA(var(--bs-secondary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important}.link-secondary:focus,.link-secondary:hover{color:RGBA(86,94,100,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity,1))!important}.link-success{color:RGBA(var(--bs-success-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important}.link-success:focus,.link-success:hover{color:RGBA(20,108,67,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity,1))!important}.link-info{color:RGBA(var(--bs-info-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important}.link-info:focus,.link-info:hover{color:RGBA(61,213,243,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity,1))!important}.link-warning{color:RGBA(var(--bs-warning-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important}.link-warning:focus,.link-warning:hover{color:RGBA(255,205,57,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity,1))!important}.link-danger{color:RGBA(var(--bs-danger-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important}.link-danger:focus,.link-danger:hover{color:RGBA(176,42,55,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity,1))!important}.link-light{color:RGBA(var(--bs-light-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important}.link-light:focus,.link-light:hover{color:RGBA(249,250,251,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity,1))!important}.link-dark{color:RGBA(var(--bs-dark-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important}.link-dark:focus,.link-dark:hover{color:RGBA(26,30,33,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity,1))!important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-body-emphasis:focus,.link-body-emphasis:hover{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,.75))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x,0) var(--bs-focus-ring-y,0) var(--bs-focus-ring-blur,0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-underline-offset:0.25em;-webkit-backface-visibility:hidden;backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media (prefers-reduced-motion:reduce){.icon-link>.bi{transition:none}}.icon-link-hover:focus-visible>.bi,.icon-link-hover:hover>.bi{transform:var(--bs-icon-link-transform,translate3d(-.25em,0,0))}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;right:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio:100%}.ratio-4x3{--bs-aspect-ratio:75%}.ratio-16x9{--bs-aspect-ratio:56.25%}.ratio-21x9{--bs-aspect-ratio:42.8571428571%}.fixed-top{position:fixed;top:0;left:0;right:0;z-index:1030}.fixed-bottom{position:fixed;left:0;bottom:0;right:0;z-index:1030}.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}@media (min-width:576px){.sticky-sm-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:768px){.sticky-md-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:992px){.sticky-lg-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1200px){.sticky-xl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1400px){.sticky-xxl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption),.visually-hidden:not(caption){position:absolute!important}.visually-hidden *,.visually-hidden-focusable:not(:focus):not(:focus-within) *{overflow:hidden!important}.stretched-link::after{position:absolute;top:0;left:0;bottom:0;right:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:var(--bs-border-width);min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:right!important}.float-end{float:left!important}.float-none{float:none!important}.object-fit-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-none{-o-object-fit:none!important;object-fit:none!important}.opacity-0{opacity:0!important}.opacity-25{opacity:.25!important}.opacity-50{opacity:.5!important}.opacity-75{opacity:.75!important}.opacity-100{opacity:1!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.overflow-x-auto{overflow-x:auto!important}.overflow-x-hidden{overflow-x:hidden!important}.overflow-x-visible{overflow-x:visible!important}.overflow-x-scroll{overflow-x:scroll!important}.overflow-y-auto{overflow-y:auto!important}.overflow-y-hidden{overflow-y:hidden!important}.overflow-y-visible{overflow-y:visible!important}.overflow-y-scroll{overflow-y:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-inline-grid{display:inline-grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:var(--bs-box-shadow)!important}.shadow-sm{box-shadow:var(--bs-box-shadow-sm)!important}.shadow-lg{box-shadow:var(--bs-box-shadow-lg)!important}.shadow-none{box-shadow:none!important}.focus-ring-primary{--bs-focus-ring-color:rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color:rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color:rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color:rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color:rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color:rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color:rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color:rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{right:0!important}.start-50{right:50%!important}.start-100{right:100%!important}.end-0{left:0!important}.end-50{left:50%!important}.end-100{left:100%!important}.translate-middle{transform:translate(50%,-50%)!important}.translate-middle-x{transform:translateX(50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-0{border:0!important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-top-0{border-top:0!important}.border-end{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-end-0{border-left:0!important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-bottom-0{border-bottom:0!important}.border-start{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-start-0{border-right:0!important}.border-primary{--bs-border-opacity:1;border-color:rgba(var(--bs-primary-rgb),var(--bs-border-opacity))!important}.border-secondary{--bs-border-opacity:1;border-color:rgba(var(--bs-secondary-rgb),var(--bs-border-opacity))!important}.border-success{--bs-border-opacity:1;border-color:rgba(var(--bs-success-rgb),var(--bs-border-opacity))!important}.border-info{--bs-border-opacity:1;border-color:rgba(var(--bs-info-rgb),var(--bs-border-opacity))!important}.border-warning{--bs-border-opacity:1;border-color:rgba(var(--bs-warning-rgb),var(--bs-border-opacity))!important}.border-danger{--bs-border-opacity:1;border-color:rgba(var(--bs-danger-rgb),var(--bs-border-opacity))!important}.border-light{--bs-border-opacity:1;border-color:rgba(var(--bs-light-rgb),var(--bs-border-opacity))!important}.border-dark{--bs-border-opacity:1;border-color:rgba(var(--bs-dark-rgb),var(--bs-border-opacity))!important}.border-black{--bs-border-opacity:1;border-color:rgba(var(--bs-black-rgb),var(--bs-border-opacity))!important}.border-white{--bs-border-opacity:1;border-color:rgba(var(--bs-white-rgb),var(--bs-border-opacity))!important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle)!important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle)!important}.border-success-subtle{border-color:var(--bs-success-border-subtle)!important}.border-info-subtle{border-color:var(--bs-info-border-subtle)!important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle)!important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle)!important}.border-light-subtle{border-color:var(--bs-light-border-subtle)!important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle)!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.border-opacity-10{--bs-border-opacity:0.1}.border-opacity-25{--bs-border-opacity:0.25}.border-opacity-50{--bs-border-opacity:0.5}.border-opacity-75{--bs-border-opacity:0.75}.border-opacity-100{--bs-border-opacity:1}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-left:0!important;margin-right:0!important}.mx-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-3{margin-left:1rem!important;margin-right:1rem!important}.mx-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-5{margin-left:3rem!important;margin-right:3rem!important}.mx-auto{margin-left:auto!important;margin-right:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-left:0!important}.me-1{margin-left:.25rem!important}.me-2{margin-left:.5rem!important}.me-3{margin-left:1rem!important}.me-4{margin-left:1.5rem!important}.me-5{margin-left:3rem!important}.me-auto{margin-left:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-right:0!important}.ms-1{margin-right:.25rem!important}.ms-2{margin-right:.5rem!important}.ms-3{margin-right:1rem!important}.ms-4{margin-right:1.5rem!important}.ms-5{margin-right:3rem!important}.ms-auto{margin-right:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-left:0!important;padding-right:0!important}.px-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-3{padding-left:1rem!important;padding-right:1rem!important}.px-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-5{padding-left:3rem!important;padding-right:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-left:0!important}.pe-1{padding-left:.25rem!important}.pe-2{padding-left:.5rem!important}.pe-3{padding-left:1rem!important}.pe-4{padding-left:1.5rem!important}.pe-5{padding-left:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-right:0!important}.ps-1{padding-right:.25rem!important}.ps-2{padding-right:.5rem!important}.ps-3{padding-right:1rem!important}.ps-4{padding-right:1.5rem!important}.ps-5{padding-right:3rem!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.row-gap-0{row-gap:0!important}.row-gap-1{row-gap:.25rem!important}.row-gap-2{row-gap:.5rem!important}.row-gap-3{row-gap:1rem!important}.row-gap-4{row-gap:1.5rem!important}.row-gap-5{row-gap:3rem!important}.column-gap-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-lighter{font-weight:lighter!important}.fw-light{font-weight:300!important}.fw-normal{font-weight:400!important}.fw-medium{font-weight:500!important}.fw-semibold{font-weight:600!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:right!important}.text-end{text-align:left!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-primary{--bs-text-opacity:1;color:rgba(var(--bs-primary-rgb),var(--bs-text-opacity))!important}.text-secondary{--bs-text-opacity:1;color:rgba(var(--bs-secondary-rgb),var(--bs-text-opacity))!important}.text-success{--bs-text-opacity:1;color:rgba(var(--bs-success-rgb),var(--bs-text-opacity))!important}.text-info{--bs-text-opacity:1;color:rgba(var(--bs-info-rgb),var(--bs-text-opacity))!important}.text-warning{--bs-text-opacity:1;color:rgba(var(--bs-warning-rgb),var(--bs-text-opacity))!important}.text-danger{--bs-text-opacity:1;color:rgba(var(--bs-danger-rgb),var(--bs-text-opacity))!important}.text-light{--bs-text-opacity:1;color:rgba(var(--bs-light-rgb),var(--bs-text-opacity))!important}.text-dark{--bs-text-opacity:1;color:rgba(var(--bs-dark-rgb),var(--bs-text-opacity))!important}.text-black{--bs-text-opacity:1;color:rgba(var(--bs-black-rgb),var(--bs-text-opacity))!important}.text-white{--bs-text-opacity:1;color:rgba(var(--bs-white-rgb),var(--bs-text-opacity))!important}.text-body{--bs-text-opacity:1;color:rgba(var(--bs-body-color-rgb),var(--bs-text-opacity))!important}.text-muted{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-black-50{--bs-text-opacity:1;color:rgba(0,0,0,.5)!important}.text-white-50{--bs-text-opacity:1;color:rgba(255,255,255,.5)!important}.text-body-secondary{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-body-tertiary{--bs-text-opacity:1;color:var(--bs-tertiary-color)!important}.text-body-emphasis{--bs-text-opacity:1;color:var(--bs-emphasis-color)!important}.text-reset{--bs-text-opacity:1;color:inherit!important}.text-opacity-25{--bs-text-opacity:0.25}.text-opacity-50{--bs-text-opacity:0.5}.text-opacity-75{--bs-text-opacity:0.75}.text-opacity-100{--bs-text-opacity:1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis)!important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis)!important}.text-success-emphasis{color:var(--bs-success-text-emphasis)!important}.text-info-emphasis{color:var(--bs-info-text-emphasis)!important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis)!important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis)!important}.text-light-emphasis{color:var(--bs-light-text-emphasis)!important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis)!important}.link-opacity-10{--bs-link-opacity:0.1}.link-opacity-10-hover:hover{--bs-link-opacity:0.1}.link-opacity-25{--bs-link-opacity:0.25}.link-opacity-25-hover:hover{--bs-link-opacity:0.25}.link-opacity-50{--bs-link-opacity:0.5}.link-opacity-50-hover:hover{--bs-link-opacity:0.5}.link-opacity-75{--bs-link-opacity:0.75}.link-opacity-75-hover:hover{--bs-link-opacity:0.75}.link-opacity-100{--bs-link-opacity:1}.link-opacity-100-hover:hover{--bs-link-opacity:1}.link-offset-1{text-underline-offset:0.125em!important}.link-offset-1-hover:hover{text-underline-offset:0.125em!important}.link-offset-2{text-underline-offset:0.25em!important}.link-offset-2-hover:hover{text-underline-offset:0.25em!important}.link-offset-3{text-underline-offset:0.375em!important}.link-offset-3-hover:hover{text-underline-offset:0.375em!important}.link-underline-primary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-secondary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-success{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important}.link-underline-info{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important}.link-underline-warning{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important}.link-underline-danger{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important}.link-underline-light{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important}.link-underline-dark{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important}.link-underline{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-underline-opacity-0{--bs-link-underline-opacity:0}.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity:0}.link-underline-opacity-10{--bs-link-underline-opacity:0.1}.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity:0.1}.link-underline-opacity-25{--bs-link-underline-opacity:0.25}.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity:0.25}.link-underline-opacity-50{--bs-link-underline-opacity:0.5}.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity:0.5}.link-underline-opacity-75{--bs-link-underline-opacity:0.75}.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity:0.75}.link-underline-opacity-100{--bs-link-underline-opacity:1}.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity:1}.bg-primary{--bs-bg-opacity:1;background-color:rgba(var(--bs-primary-rgb),var(--bs-bg-opacity))!important}.bg-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-rgb),var(--bs-bg-opacity))!important}.bg-success{--bs-bg-opacity:1;background-color:rgba(var(--bs-success-rgb),var(--bs-bg-opacity))!important}.bg-info{--bs-bg-opacity:1;background-color:rgba(var(--bs-info-rgb),var(--bs-bg-opacity))!important}.bg-warning{--bs-bg-opacity:1;background-color:rgba(var(--bs-warning-rgb),var(--bs-bg-opacity))!important}.bg-danger{--bs-bg-opacity:1;background-color:rgba(var(--bs-danger-rgb),var(--bs-bg-opacity))!important}.bg-light{--bs-bg-opacity:1;background-color:rgba(var(--bs-light-rgb),var(--bs-bg-opacity))!important}.bg-dark{--bs-bg-opacity:1;background-color:rgba(var(--bs-dark-rgb),var(--bs-bg-opacity))!important}.bg-black{--bs-bg-opacity:1;background-color:rgba(var(--bs-black-rgb),var(--bs-bg-opacity))!important}.bg-white{--bs-bg-opacity:1;background-color:rgba(var(--bs-white-rgb),var(--bs-bg-opacity))!important}.bg-body{--bs-bg-opacity:1;background-color:rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity))!important}.bg-transparent{--bs-bg-opacity:1;background-color:transparent!important}.bg-body-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-bg-rgb),var(--bs-bg-opacity))!important}.bg-body-tertiary{--bs-bg-opacity:1;background-color:rgba(var(--bs-tertiary-bg-rgb),var(--bs-bg-opacity))!important}.bg-opacity-10{--bs-bg-opacity:0.1}.bg-opacity-25{--bs-bg-opacity:0.25}.bg-opacity-50{--bs-bg-opacity:0.5}.bg-opacity-75{--bs-bg-opacity:0.75}.bg-opacity-100{--bs-bg-opacity:1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle)!important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle)!important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle)!important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle)!important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle)!important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle)!important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle)!important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle)!important}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:var(--bs-border-radius)!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:var(--bs-border-radius-sm)!important}.rounded-2{border-radius:var(--bs-border-radius)!important}.rounded-3{border-radius:var(--bs-border-radius-lg)!important}.rounded-4{border-radius:var(--bs-border-radius-xl)!important}.rounded-5{border-radius:var(--bs-border-radius-xxl)!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:var(--bs-border-radius-pill)!important}.rounded-top{border-top-right-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-top-0{border-top-right-radius:0!important;border-top-left-radius:0!important}.rounded-top-1{border-top-right-radius:var(--bs-border-radius-sm)!important;border-top-left-radius:var(--bs-border-radius-sm)!important}.rounded-top-2{border-top-right-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-top-3{border-top-right-radius:var(--bs-border-radius-lg)!important;border-top-left-radius:var(--bs-border-radius-lg)!important}.rounded-top-4{border-top-right-radius:var(--bs-border-radius-xl)!important;border-top-left-radius:var(--bs-border-radius-xl)!important}.rounded-top-5{border-top-right-radius:var(--bs-border-radius-xxl)!important;border-top-left-radius:var(--bs-border-radius-xxl)!important}.rounded-top-circle{border-top-right-radius:50%!important;border-top-left-radius:50%!important}.rounded-top-pill{border-top-right-radius:var(--bs-border-radius-pill)!important;border-top-left-radius:var(--bs-border-radius-pill)!important}.rounded-end{border-top-left-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-end-0{border-top-left-radius:0!important;border-bottom-left-radius:0!important}.rounded-end-1{border-top-left-radius:var(--bs-border-radius-sm)!important;border-bottom-left-radius:var(--bs-border-radius-sm)!important}.rounded-end-2{border-top-left-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-end-3{border-top-left-radius:var(--bs-border-radius-lg)!important;border-bottom-left-radius:var(--bs-border-radius-lg)!important}.rounded-end-4{border-top-left-radius:var(--bs-border-radius-xl)!important;border-bottom-left-radius:var(--bs-border-radius-xl)!important}.rounded-end-5{border-top-left-radius:var(--bs-border-radius-xxl)!important;border-bottom-left-radius:var(--bs-border-radius-xxl)!important}.rounded-end-circle{border-top-left-radius:50%!important;border-bottom-left-radius:50%!important}.rounded-end-pill{border-top-left-radius:var(--bs-border-radius-pill)!important;border-bottom-left-radius:var(--bs-border-radius-pill)!important}.rounded-bottom{border-bottom-left-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-bottom-0{border-bottom-left-radius:0!important;border-bottom-right-radius:0!important}.rounded-bottom-1{border-bottom-left-radius:var(--bs-border-radius-sm)!important;border-bottom-right-radius:var(--bs-border-radius-sm)!important}.rounded-bottom-2{border-bottom-left-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-bottom-3{border-bottom-left-radius:var(--bs-border-radius-lg)!important;border-bottom-right-radius:var(--bs-border-radius-lg)!important}.rounded-bottom-4{border-bottom-left-radius:var(--bs-border-radius-xl)!important;border-bottom-right-radius:var(--bs-border-radius-xl)!important}.rounded-bottom-5{border-bottom-left-radius:var(--bs-border-radius-xxl)!important;border-bottom-right-radius:var(--bs-border-radius-xxl)!important}.rounded-bottom-circle{border-bottom-left-radius:50%!important;border-bottom-right-radius:50%!important}.rounded-bottom-pill{border-bottom-left-radius:var(--bs-border-radius-pill)!important;border-bottom-right-radius:var(--bs-border-radius-pill)!important}.rounded-start{border-bottom-right-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-start-0{border-bottom-right-radius:0!important;border-top-right-radius:0!important}.rounded-start-1{border-bottom-right-radius:var(--bs-border-radius-sm)!important;border-top-right-radius:var(--bs-border-radius-sm)!important}.rounded-start-2{border-bottom-right-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-start-3{border-bottom-right-radius:var(--bs-border-radius-lg)!important;border-top-right-radius:var(--bs-border-radius-lg)!important}.rounded-start-4{border-bottom-right-radius:var(--bs-border-radius-xl)!important;border-top-right-radius:var(--bs-border-radius-xl)!important}.rounded-start-5{border-bottom-right-radius:var(--bs-border-radius-xxl)!important;border-top-right-radius:var(--bs-border-radius-xxl)!important}.rounded-start-circle{border-bottom-right-radius:50%!important;border-top-right-radius:50%!important}.rounded-start-pill{border-bottom-right-radius:var(--bs-border-radius-pill)!important;border-top-right-radius:var(--bs-border-radius-pill)!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}.z-n1{z-index:-1!important}.z-0{z-index:0!important}.z-1{z-index:1!important}.z-2{z-index:2!important}.z-3{z-index:3!important}@media (min-width:576px){.float-sm-start{float:right!important}.float-sm-end{float:left!important}.float-sm-none{float:none!important}.object-fit-sm-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-sm-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-sm-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-sm-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-sm-none{-o-object-fit:none!important;object-fit:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-inline-grid{display:inline-grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-left:0!important;margin-right:0!important}.mx-sm-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-sm-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-sm-3{margin-left:1rem!important;margin-right:1rem!important}.mx-sm-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-sm-5{margin-left:3rem!important;margin-right:3rem!important}.mx-sm-auto{margin-left:auto!important;margin-right:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-left:0!important}.me-sm-1{margin-left:.25rem!important}.me-sm-2{margin-left:.5rem!important}.me-sm-3{margin-left:1rem!important}.me-sm-4{margin-left:1.5rem!important}.me-sm-5{margin-left:3rem!important}.me-sm-auto{margin-left:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-right:0!important}.ms-sm-1{margin-right:.25rem!important}.ms-sm-2{margin-right:.5rem!important}.ms-sm-3{margin-right:1rem!important}.ms-sm-4{margin-right:1.5rem!important}.ms-sm-5{margin-right:3rem!important}.ms-sm-auto{margin-right:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-left:0!important;padding-right:0!important}.px-sm-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-sm-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-sm-3{padding-left:1rem!important;padding-right:1rem!important}.px-sm-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-sm-5{padding-left:3rem!important;padding-right:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-left:0!important}.pe-sm-1{padding-left:.25rem!important}.pe-sm-2{padding-left:.5rem!important}.pe-sm-3{padding-left:1rem!important}.pe-sm-4{padding-left:1.5rem!important}.pe-sm-5{padding-left:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-right:0!important}.ps-sm-1{padding-right:.25rem!important}.ps-sm-2{padding-right:.5rem!important}.ps-sm-3{padding-right:1rem!important}.ps-sm-4{padding-right:1.5rem!important}.ps-sm-5{padding-right:3rem!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.row-gap-sm-0{row-gap:0!important}.row-gap-sm-1{row-gap:.25rem!important}.row-gap-sm-2{row-gap:.5rem!important}.row-gap-sm-3{row-gap:1rem!important}.row-gap-sm-4{row-gap:1.5rem!important}.row-gap-sm-5{row-gap:3rem!important}.column-gap-sm-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-sm-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-sm-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-sm-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-sm-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-sm-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-sm-start{text-align:right!important}.text-sm-end{text-align:left!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.float-md-start{float:right!important}.float-md-end{float:left!important}.float-md-none{float:none!important}.object-fit-md-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-md-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-md-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-md-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-md-none{-o-object-fit:none!important;object-fit:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-inline-grid{display:inline-grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-left:0!important;margin-right:0!important}.mx-md-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-md-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-md-3{margin-left:1rem!important;margin-right:1rem!important}.mx-md-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-md-5{margin-left:3rem!important;margin-right:3rem!important}.mx-md-auto{margin-left:auto!important;margin-right:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-left:0!important}.me-md-1{margin-left:.25rem!important}.me-md-2{margin-left:.5rem!important}.me-md-3{margin-left:1rem!important}.me-md-4{margin-left:1.5rem!important}.me-md-5{margin-left:3rem!important}.me-md-auto{margin-left:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-right:0!important}.ms-md-1{margin-right:.25rem!important}.ms-md-2{margin-right:.5rem!important}.ms-md-3{margin-right:1rem!important}.ms-md-4{margin-right:1.5rem!important}.ms-md-5{margin-right:3rem!important}.ms-md-auto{margin-right:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-left:0!important;padding-right:0!important}.px-md-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-md-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-md-3{padding-left:1rem!important;padding-right:1rem!important}.px-md-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-md-5{padding-left:3rem!important;padding-right:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-left:0!important}.pe-md-1{padding-left:.25rem!important}.pe-md-2{padding-left:.5rem!important}.pe-md-3{padding-left:1rem!important}.pe-md-4{padding-left:1.5rem!important}.pe-md-5{padding-left:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-right:0!important}.ps-md-1{padding-right:.25rem!important}.ps-md-2{padding-right:.5rem!important}.ps-md-3{padding-right:1rem!important}.ps-md-4{padding-right:1.5rem!important}.ps-md-5{padding-right:3rem!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.row-gap-md-0{row-gap:0!important}.row-gap-md-1{row-gap:.25rem!important}.row-gap-md-2{row-gap:.5rem!important}.row-gap-md-3{row-gap:1rem!important}.row-gap-md-4{row-gap:1.5rem!important}.row-gap-md-5{row-gap:3rem!important}.column-gap-md-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-md-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-md-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-md-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-md-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-md-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-md-start{text-align:right!important}.text-md-end{text-align:left!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.float-lg-start{float:right!important}.float-lg-end{float:left!important}.float-lg-none{float:none!important}.object-fit-lg-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-lg-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-lg-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-lg-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-lg-none{-o-object-fit:none!important;object-fit:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-inline-grid{display:inline-grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-left:0!important;margin-right:0!important}.mx-lg-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-lg-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-lg-3{margin-left:1rem!important;margin-right:1rem!important}.mx-lg-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-lg-5{margin-left:3rem!important;margin-right:3rem!important}.mx-lg-auto{margin-left:auto!important;margin-right:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-left:0!important}.me-lg-1{margin-left:.25rem!important}.me-lg-2{margin-left:.5rem!important}.me-lg-3{margin-left:1rem!important}.me-lg-4{margin-left:1.5rem!important}.me-lg-5{margin-left:3rem!important}.me-lg-auto{margin-left:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-right:0!important}.ms-lg-1{margin-right:.25rem!important}.ms-lg-2{margin-right:.5rem!important}.ms-lg-3{margin-right:1rem!important}.ms-lg-4{margin-right:1.5rem!important}.ms-lg-5{margin-right:3rem!important}.ms-lg-auto{margin-right:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-left:0!important;padding-right:0!important}.px-lg-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-lg-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-lg-3{padding-left:1rem!important;padding-right:1rem!important}.px-lg-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-lg-5{padding-left:3rem!important;padding-right:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-left:0!important}.pe-lg-1{padding-left:.25rem!important}.pe-lg-2{padding-left:.5rem!important}.pe-lg-3{padding-left:1rem!important}.pe-lg-4{padding-left:1.5rem!important}.pe-lg-5{padding-left:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-right:0!important}.ps-lg-1{padding-right:.25rem!important}.ps-lg-2{padding-right:.5rem!important}.ps-lg-3{padding-right:1rem!important}.ps-lg-4{padding-right:1.5rem!important}.ps-lg-5{padding-right:3rem!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.row-gap-lg-0{row-gap:0!important}.row-gap-lg-1{row-gap:.25rem!important}.row-gap-lg-2{row-gap:.5rem!important}.row-gap-lg-3{row-gap:1rem!important}.row-gap-lg-4{row-gap:1.5rem!important}.row-gap-lg-5{row-gap:3rem!important}.column-gap-lg-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-lg-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-lg-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-lg-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-lg-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-lg-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-lg-start{text-align:right!important}.text-lg-end{text-align:left!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.float-xl-start{float:right!important}.float-xl-end{float:left!important}.float-xl-none{float:none!important}.object-fit-xl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xl-none{-o-object-fit:none!important;object-fit:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-inline-grid{display:inline-grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-left:0!important;margin-right:0!important}.mx-xl-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-xl-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-xl-3{margin-left:1rem!important;margin-right:1rem!important}.mx-xl-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-xl-5{margin-left:3rem!important;margin-right:3rem!important}.mx-xl-auto{margin-left:auto!important;margin-right:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-left:0!important}.me-xl-1{margin-left:.25rem!important}.me-xl-2{margin-left:.5rem!important}.me-xl-3{margin-left:1rem!important}.me-xl-4{margin-left:1.5rem!important}.me-xl-5{margin-left:3rem!important}.me-xl-auto{margin-left:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-right:0!important}.ms-xl-1{margin-right:.25rem!important}.ms-xl-2{margin-right:.5rem!important}.ms-xl-3{margin-right:1rem!important}.ms-xl-4{margin-right:1.5rem!important}.ms-xl-5{margin-right:3rem!important}.ms-xl-auto{margin-right:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-left:0!important;padding-right:0!important}.px-xl-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-xl-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-xl-3{padding-left:1rem!important;padding-right:1rem!important}.px-xl-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-xl-5{padding-left:3rem!important;padding-right:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-left:0!important}.pe-xl-1{padding-left:.25rem!important}.pe-xl-2{padding-left:.5rem!important}.pe-xl-3{padding-left:1rem!important}.pe-xl-4{padding-left:1.5rem!important}.pe-xl-5{padding-left:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-right:0!important}.ps-xl-1{padding-right:.25rem!important}.ps-xl-2{padding-right:.5rem!important}.ps-xl-3{padding-right:1rem!important}.ps-xl-4{padding-right:1.5rem!important}.ps-xl-5{padding-right:3rem!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.row-gap-xl-0{row-gap:0!important}.row-gap-xl-1{row-gap:.25rem!important}.row-gap-xl-2{row-gap:.5rem!important}.row-gap-xl-3{row-gap:1rem!important}.row-gap-xl-4{row-gap:1.5rem!important}.row-gap-xl-5{row-gap:3rem!important}.column-gap-xl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xl-start{text-align:right!important}.text-xl-end{text-align:left!important}.text-xl-center{text-align:center!important}}@media (min-width:1400px){.float-xxl-start{float:right!important}.float-xxl-end{float:left!important}.float-xxl-none{float:none!important}.object-fit-xxl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xxl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xxl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xxl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xxl-none{-o-object-fit:none!important;object-fit:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-inline-grid{display:inline-grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-left:0!important;margin-right:0!important}.mx-xxl-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-xxl-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-xxl-3{margin-left:1rem!important;margin-right:1rem!important}.mx-xxl-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-xxl-5{margin-left:3rem!important;margin-right:3rem!important}.mx-xxl-auto{margin-left:auto!important;margin-right:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-left:0!important}.me-xxl-1{margin-left:.25rem!important}.me-xxl-2{margin-left:.5rem!important}.me-xxl-3{margin-left:1rem!important}.me-xxl-4{margin-left:1.5rem!important}.me-xxl-5{margin-left:3rem!important}.me-xxl-auto{margin-left:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-right:0!important}.ms-xxl-1{margin-right:.25rem!important}.ms-xxl-2{margin-right:.5rem!important}.ms-xxl-3{margin-right:1rem!important}.ms-xxl-4{margin-right:1.5rem!important}.ms-xxl-5{margin-right:3rem!important}.ms-xxl-auto{margin-right:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-left:0!important;padding-right:0!important}.px-xxl-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-xxl-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-xxl-3{padding-left:1rem!important;padding-right:1rem!important}.px-xxl-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-xxl-5{padding-left:3rem!important;padding-right:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-left:0!important}.pe-xxl-1{padding-left:.25rem!important}.pe-xxl-2{padding-left:.5rem!important}.pe-xxl-3{padding-left:1rem!important}.pe-xxl-4{padding-left:1.5rem!important}.pe-xxl-5{padding-left:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-right:0!important}.ps-xxl-1{padding-right:.25rem!important}.ps-xxl-2{padding-right:.5rem!important}.ps-xxl-3{padding-right:1rem!important}.ps-xxl-4{padding-right:1.5rem!important}.ps-xxl-5{padding-right:3rem!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.row-gap-xxl-0{row-gap:0!important}.row-gap-xxl-1{row-gap:.25rem!important}.row-gap-xxl-2{row-gap:.5rem!important}.row-gap-xxl-3{row-gap:1rem!important}.row-gap-xxl-4{row-gap:1.5rem!important}.row-gap-xxl-5{row-gap:3rem!important}.column-gap-xxl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xxl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xxl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xxl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xxl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xxl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xxl-start{text-align:right!important}.text-xxl-end{text-align:left!important}.text-xxl-center{text-align:center!important}}@media (min-width:1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-inline-grid{display:inline-grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}} diff --git a/css/bootstrap5/privatebin.css b/css/bootstrap5/privatebin.css new file mode 100644 index 00000000..29481963 --- /dev/null +++ b/css/bootstrap5/privatebin.css @@ -0,0 +1,90 @@ +/** + * PrivateBin + * + * Cascading style sheets for bootstrap 5 template. + * + * @link https://github.com/PrivateBin/PrivateBin + * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) + * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License + */ + +@import url("../common.css"); + +.hidden { + display: none !important; +} + +.opacity-05-1-hover { + opacity: 0.5; + transition: all 0.15s ease; +} + +.opacity-05-1-hover:hover { + opacity: 1; +} + +.dropdown-menu { + --bs-dropdown-min-width: 23rem; +} + +pre { + margin-bottom: 0; +} + +[data-bs-theme=light] pre, [data-bs-theme=light] .card { + background-color: RGBA(var(--bs-light-rgb), var(--bs-bg-opacity, 1)); +} + +li.L0, li.L1, li.L2, li.L3, li.L4, li.L5, li.L6, li.L7, li.L8, li.L9 { + color: revert !important; + list-style-type: decimal !important; +} + +[data-bs-theme=dark] li.L1, [data-bs-theme=dark] li.L3, [data-bs-theme=dark] li.L5, +[data-bs-theme=dark] li.L7, [data-bs-theme=dark] li.L9 { + background-color: var(--bs-gray-dark) !important; +} + +.text-right button { + float: right; +} + +html[dir="rtl"] #deletelink, html[dir="rtl"] #qrcodemodalClose { + float: left; +} + +#prettyprint { + padding-right: 30px; +} + +#prettyMessageCopyBtn { + position: absolute; + top: 8px; + right: 8px; + left: auto; + width: 20px; + height: 20px; + padding: 0; + background: none; + border: none; + z-index: 1; +} + +html[dir="rtl"] #prettyMessageCopyBtn { + left: 8px; + right: auto; +} + +#prettyMessageCopyBtn svg { + width: 100%; + height: 100%; + vertical-align: baseline; +} + +#copySuccessIcon { + display: none; +} + +#sendbutton svg { + transform: translateY(1.5px); +} diff --git a/css/common.css b/css/common.css new file mode 100644 index 00000000..b5019c47 --- /dev/null +++ b/css/common.css @@ -0,0 +1,107 @@ +/** + * PrivateBin + * + * Common cascading style sheets for all templates. + * + * @link https://github.com/PrivateBin/PrivateBin + * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) + * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License + */ + +#attachmentPreview { + display: flex; + flex-direction: column; + align-items: center; +} + +#attachmentPreview img { + max-width: 100%; + height: auto; + margin-bottom: 20px; +} + +#attachmentPreview .pdfPreview { + width: 100%; + height: 100vh; + margin-bottom: 20px; +} + +#dropzone { + text-align: center; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1000; + opacity: 0.6; + background-color: #9cf; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM14 13v4h-4v-4H7l5-5 5 5h-3z'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: center; + background-size: 25vh; + outline: 2px dashed #28f; + outline-offset: -50px; +} + +#filewrap { + transition: background-color 0.75s ease-out; +} + +#deletelink { + float: right; + margin-left: 5px; +} + +#qrcodemodalClose { + float: right; +} + +#qrcode-display { + width: 200px; + margin: auto; +} + +#pastelink { + display: inline; +} + +#pastelink > a, #plaintext > a { + word-wrap: break-word; +} + +#message { + height: 70dvh; +} + +@media ((max-width: 450px) and (max-height: 950px)) { + #message { + height: 55dvh; + } +} + +#message, .replymessage { + font-family: monospace; + resize: vertical; +} + +.comment { + border-left: 1px solid #ccc; + transition: background-color 0.75s ease-out; +} + +.commentdata { + white-space: pre-wrap; +} + +.dragAndDropFile { + color: #777; + font-size: 1em; + display: inline; + white-space: normal; +} + +.highlight { + background-color: #fd8; + transition: background-color 0.2s ease-in; +} diff --git a/css/noscript.css b/css/noscript.css index 29f7a707..60d288ab 100644 --- a/css/noscript.css +++ b/css/noscript.css @@ -1,15 +1,13 @@ /** * PrivateBin * - * CSS file only loaded when no JavaScript available. + * Cascading style sheet only loaded when JavaScript is not available. * * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.7.1 */ -/* When there is no script at all other */ .noscript-hide { display: none; } diff --git a/css/privatebin.css b/css/privatebin.css deleted file mode 100644 index 6ee043e5..00000000 --- a/css/privatebin.css +++ /dev/null @@ -1,505 +0,0 @@ -/** - * PrivateBin - * - * Main CSS file. - * - * @link https://github.com/PrivateBin/PrivateBin - * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) - * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.7.1 - */ - -/* CSS Reset from YUI 3.4.1 (build 4118) - Copyright 2011 Yahoo! Inc. All rights reserved. -Licensed under the BSD License. - http://yuilibrary.com/license/ */ -html{color:#000;background:#fff}body,div,dl,dt,dd,ul,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0}table{border-collapse:collapse;border-spacing:0}fieldset,img{border:0}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal}ol,ul{list-style:none}caption,th{text-align:left}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}q:before,q:after{content:''}abbr,acronym{border:0;font-variant:normal}sup{vertical-align:text-top}sub{vertical-align:text-bottom}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit}input,textarea,select{font-size:100%;}legend{color:#000} - -html { - background-color: #455463; - color: #fff; - min-height: 100%; - background-image: linear-gradient(bottom, #0f1823 0, #455463 100%); - background-image: -o-linear-gradient(bottom, #0f1823 0, #455463 100%); - background-image: -moz-linear-gradient(bottom, #0f1823 0, #455463 100%); - background-image: -webkit-linear-gradient(bottom, #0f1823 0, #455463 100%); - background-image: -ms-linear-gradient(bottom, #0f1823 0, #455463 100%); - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #0f1823), color-stop(1, #455463)); -} - -body { - font-family: Helvetica, Arial, sans-serif; - font-size: 0.9em; - margin-bottom: 15px; - padding-left: 60px; - padding-right: 60px; -} - -a { color: #0f388f; cursor:pointer; } - -h1.title { - font-size: 3.5em; - font-weight: bold; - color: #000; - position: relative; - display: inline; - cursor: pointer; -} - -h1.title:before { - content: attr(title); - position: absolute; - color: rgba(255,255,255,0.15); - top: 1px; - left: 1px; - cursor: pointer; -} - -h2.title { - color: #000; - font-size: 1em; - display: inline; - font-style: italic; - font-weight: bold; - position: relative; - bottom: 8px; -} - -h3.title { - color: #94a3b4; - font-size: 0.7em; - display: inline; - margin-top: 10px; - position: relative; - bottom: 8px; -} - -#aboutbox { - color: #94a3b4; - padding: 4px 8px 4px 16px; - position: relative; - top: 10px; - border-left: 2px solid #94a3b4; - float: right; - width: 60%; -} - -#aboutbox a { color: #94a3b4; } - -#message, #cleartext, #prettymessage, #attachment, .replymessage { - clear: both; - color: #000; - background-color: #fff; - font-size: 9pt; - border: 1px solid #28343F; - box-sizing: border-box; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - -o-box-sizing: border-box; - width: 100%; -} - -#message, .replymessage { - padding: 5px; - white-space: pre-wrap; - font-family: Consolas, "Lucida Console", "DejaVu Sans Mono", Monaco, monospace; - resize: vertical; -} - -#attachmentPreview img { - max-width: 100%; - height: auto; -} - -#attachmentPreview .pdfPreview { - width: 100%; - height: 100vh; - margin-bottom: 20px; -} - -#dropzone { - text-align: center; - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 1000; - opacity: 0.6; - background-color: #99ccff; - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM14 13v4h-4v-4H7l5-5 5 5h-3z'/%3E%3C/svg%3E"); - background-repeat: no-repeat; - background-position: center; - background-size: 25vh; - outline: 2px dashed #228bff; - outline-offset: -50px; -} - -.dragAndDropFile{ - color: #777; - font-size: 1em; - display: inline; - white-space: normal; -} - -#status { - clear: both; - padding: 5px 10px; -} - -#pasteresult { - background-color: #1F2833; - color: #fff; - padding: 4px 12px; - clear: both; - -moz-box-shadow: inset 0 2px 2px #000; - -webkit-box-shadow: inset 0 2px 2px #000; - box-shadow: inset 0 2px 2px #000; -} - -#pasteresult a { color: #fff; } - -#pasteresult button { margin-left: 11px; } - -#deletelink { float: right; } - -#toolbar, #status { margin-bottom: 5px; } - -#copyhint { color: #666; font-size: 0.85em } - -button, .button { - color: #fff; - background-color: #323b47; - background-repeat: no-repeat; - background-position: center left; - padding: 4px 8px; - font-size: 1em; - margin-right: 5px; - display: inline-block; - background-image: linear-gradient(bottom, #323b47 0, #51606e 100%); - background-image: -o-linear-gradient(bottom, #323b47 0, #51606e 100%); - background-image: -moz-linear-gradient(bottom, #323b47 0, #51606e 100%); - background-image: -webkit-linear-gradient(bottom, #323b47 0, #51606e 100%); - background-image: -ms-linear-gradient(bottom, #323b47 0, #51606e 100%); - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #323b47), color-stop(1, #51606e)); - border: 1px solid #28343F; - -moz-box-shadow: inset 0 1px 2px #647384; - -webkit-box-shadow: inset 0 1px 2px #647384; - box-shadow: inset 0 1px 2px #647384; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - -moz-background-clip: padding; - -webkit-background-clip: padding-box; - background-clip: padding-box; -} - -button:hover { - background-image: linear-gradient(bottom, #424b57 0%, #61707e 100%); - background-image: -o-linear-gradient(bottom, #424b57 0%, #61707e 100%); - background-image: -moz-linear-gradient(bottom, #424b57 0%, #61707e 100%); - background-image: -webkit-linear-gradient(bottom, #424b57 0%, #61707e 100%); - background-image: -ms-linear-gradient(bottom, #424b57 0%, #61707e 100%); - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #424b57), color-stop(1, #61707e)); -} - -button:active { - background-image: linear-gradient(bottom, #51606e 0, #323b47 100%); - background-image: -o-linear-gradient(bottom, #51606e 0, #323b47 100%); - background-image: -moz-linear-gradient(bottom, #51606e 0, #323b47 100%); - background-image: -webkit-linear-gradient(bottom, #51606e 0, #323b47 100%); - background-image: -ms-linear-gradient(bottom, #51606e 0, #323b47 100%); - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #51606e), color-stop(1, #323b47)); - position:relative; - top:1px; -} - -button:disabled, .buttondisabled { - background: #ccc; - color: #888; - top: 0; -} - -button img { - margin-right: 8px; - position: relative; - top: 2px; -} - -.button { - background-color: #414d5a; - padding: 6px 8px; - margin: 0 5px 0 0; - position: relative; - bottom: 1px; /* WTF ? Why is this shifted by 1 pixel ? */ -} - -.button select { - color: #eee; - background: transparent; - border: none; -} - - -.button select option { - color:#eee; - background: #414d5a; -} - -#rawtextbutton img { - padding: 1px 0 1px 0; -} - -#downloadtextbutton img { - padding: 1px 0 1px 0; -} - -#remainingtime, #password { - color: #94a3b4; - display: inline; - font-size: 0.85em; -} - -#newbutton { - float: right; - margin-left: 0; - margin-right: 0; - margin-bottom: 5px; - display: inline; -} - -input { - color: #777; - font-size: 1em; - padding: 6px; - border: 1px solid #28343f; -} - -.blink { - text-decoration: blink; - font-size: 0.8em; - color: #a4b3c4; -} - -.foryoureyesonly { - color: #ff0 !important; - font-size: 1em !important; - font-weight: bold !important; -} - -#attachmentPreview, .nonworking { - background-color: #fff; - color: #000; - width: 100%; - text-align: center; - font-weight: bold; - font-size: 10pt; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - padding: 5px 0; -} - -.hidden { display: none !important; } - -#ienotice { - background-color: #7e98af; - color: #000; - font-size: 0.85em; - padding: 3px 5px; - text-align: center; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - display: none; -} - -#ienotice a { color: #000; } - -#oldnotice, #httpnotice { display: none; } - -#errormessage, .errorMessage { - background-color: #f77 !important; - color:#ff0; -} - -.small { - font-size: 80%; -} - -/* --- discussion related CSS ------- */ - -#discussion { /* Discussion container */ - margin-top: 20px; - width: 100%; - margin-left: -30px; - min-width: 200px; -} - -h4.title { - font-size: 1.2em; - color: #94a3b4; - font-style: italic; - font-weight: bold; - position: relative; - margin-left: 30px; -} - -.comment /* One single reply */ -{ - background-color: #ceced6; - color: #000; - white-space: pre-wrap; - font-family: Consolas,"Lucida Console","DejaVu Sans Mono",Monaco,monospace; - font-size: 9pt; - border-left: 1px solid #859AAE; - border-top: 1px solid #859AAE; - padding: 5px 0px 5px 5px; - margin-left: 30px; - -moz-box-shadow: -3px -3px 5px rgba(0,0,0,0.15); - -webkit-box-shadow: -3px -3px 5px rgba(0,0,0,0.15); - box-shadow: -3px -3px 5px rgba(0,0,0,0.15); - min-width: 200px; - overflow: auto; -} - -.reply { margin: 5px 0 0 30px; } - -#replystatus { - display: inline; - padding: 1px 7px; - font-family: Arial, Helvetica, sans-serif; -} - -.comment button { - color: #446; - background-color: #aab; - background-repeat: no-repeat; - background-position: center left; - padding: 0 2px; - font-size: 0.73em; - margin: 3px 5px 3px 0; - display: inline; - background-image: linear-gradient(bottom, #aab 0, #ccc 100%); - background-image: -o-linear-gradient(bottom, #aab 0, #ccc 100%); - background-image: -moz-linear-gradient(bottom, #aab 0, #ccc 100%); - background-image: -webkit-linear-gradient(bottom, #aab 0, #ccc 100%); - background-image: -ms-linear-gradient(bottom, #aab 0, #ccc 100%); - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #aab), color-stop(1, #ccc)); - border: 1px solid #ccd; - -moz-box-shadow: inset 0 1px 2px #ddd; - -webkit-box-shadow: inset 0 1px 2px #fff; - box-shadow: inset 0 1px 2px #eee; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - -moz-background-clip: padding; - -webkit-background-clip: padding-box; - background-clip: padding-box; -} - -.comment button:hover { - background-image: linear-gradient(bottom, #ccd 0, #fff 100%); - background-image: -o-linear-gradient(bottom, #ccd 0, #fff 100%); - background-image: -moz-linear-gradient(bottom, #ccd 0, #fff 100%); - background-image: -webkit-linear-gradient(bottom, #ccd 0, #fff 100%); - background-image: -ms-linear-gradient(bottom, #ccd 0, #fff 100%); - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccd), color-stop(1, #fff)); -} - -.comment button:active { - background-image: linear-gradient(bottom, #fff 0, #889 100%); - background-image: -o-linear-gradient(bottom, #fff 0, #889 100%); - background-image: -moz-linear-gradient(bottom, #fff 0, #889 100%); - background-image: -webkit-linear-gradient(bottom, #fff 0, #889 100%); - background-image: -ms-linear-gradient(bottom, #fff 0, #889 100%); - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(1, #889)); - position:relative; - top:1px; -} - -.comment input { padding: 2px; } - -#replymessage { margin-top: 5px; } - -.commentmeta { - color: #fff; - background-color: #8ea0b2; - margin-bottom: 3px; - padding: 0 0 0 3px; -} - -.commentdate { color: #bfcede; } - -#filewrap { - transition: background-color 0.75s ease-out; -} - -.highlight { - background-color: #ffdd86; - transition: background-color 0.2s ease-in; -} - -img.vizhash { - width: 16px; - height: 16px; - position: relative; - top: 2px; - left: -3px; -} - -#prettyprint { - color: #000000; - font-size: 1.2em; -} - -#prettyprint.prettyprinted { - overflow: auto; -} - -#cleartext { - padding: 10px; -} - -#cleartext * { - margin-bottom: 10px; -} - -#cleartext ol { - list-style: auto; - margin-left: 15px; -} - -#cleartext ul { - list-style: disc; - margin-left: 15px; -} - -#cleartext h1, #cleartext h2, #cleartext h3, #cleartext h4, #cleartext h5, #cleartext h6 { - font-weight: bold; -} - -#cleartext h1 { - font-size: 2em; -} - -#cleartext h2 { - font-size: 1.5em; -} - -#cleartext h3 { - font-size: 1.2em; -} - -/* right-to-left overrides */ -html[dir="rtl"] #aboutbox, html[dir="rtl"] #deletelink, html[dir="rtl"] #newbutton { - float: left; -} - -html[dir="rtl"] button, html[dir="rtl"] .button, html[dir="rtl"] button img { - margin-left: 5px; - margin-right: inherit; -} - -html[dir="rtl"] button img { - margin-left: 8px; -} diff --git a/doc/Installation.md b/doc/Installation.md index d24dcbe7..6b8e86cf 100644 --- a/doc/Installation.md +++ b/doc/Installation.md @@ -21,13 +21,21 @@ for more information. ### Minimal Requirements -- PHP version 7.3 or above -- GD extension (when using identicon or vizhash icons, jdenticon works without it) -- zlib extension -- some disk space or a database supported by [PDO](https://php.net/manual/book.pdo.php) -- ability to create files and folders in the installation directory and the PATH - defined in index.php -- A web browser with JavaScript and (optional) WebAssembly support +- PHP version 7.4 or above +- PHP with zlib extension +- some disk space and the capability to create files and folders in the + installation directory and the `PATH` defined in index.php +- A web browser with JavaScript support enabled + +### Optional Requirements + +- PHP with GD extension (when using identicon or vizhash icons, jdenticon works + without it) +- a database supported by [PHP PDO](https://php.net/manual/book.pdo.php) and the + PHP PDO extension (when using database storage) +- a Ceph cluster with Rados gateway or AWS S3 storage (when using S3 storage) +- Google Cloud Storage (when using GCP storage) +- A web browser with WebAssembly support ## Hardening and Security @@ -169,20 +177,15 @@ user these additional privileges: For reference or if you want to create the table schema for yourself to avoid having to give PrivateBin too many permissions (replace `prefix_` with your own -table prefix and create the table schema with your favourite MariaDB/MySQL +table prefix and create the table schema with your favorite MariaDB/MySQL client): ```sql CREATE TABLE prefix_paste ( dataid CHAR(16) NOT NULL, data MEDIUMBLOB, - postdate INT, expiredate INT, - opendiscussion INT, - burnafterreading INT, meta TEXT, - attachment MEDIUMBLOB, - attachmentname BLOB, PRIMARY KEY (dataid) ); @@ -191,7 +194,6 @@ CREATE TABLE prefix_comment ( pasteid CHAR(16), parentid CHAR(16), data BLOB, - nickname BLOB, vizhash BLOB, postdate INT, PRIMARY KEY (dataid) @@ -201,7 +203,7 @@ CREATE INDEX parent ON prefix_comment(pasteid); CREATE TABLE prefix_config ( id CHAR(16) NOT NULL, value TEXT, PRIMARY KEY (id) ); -INSERT INTO prefix_config VALUES('VERSION', '1.7.1'); +INSERT INTO prefix_config VALUES('VERSION', '2.0.0'); ``` In **PostgreSQL**, the `data`, `attachment`, `nickname` and `vizhash` columns @@ -228,7 +230,12 @@ If you want to deploy PrivateBin in a serverless manner in the Google Cloud, you can choose the `GoogleCloudStorage` as backend. To use this backend, you first have to install the SDK from the installation -directory of PrivateBin: `composer require google/cloud-storage` +directory of PrivateBin: + +```console +composer require --no-update google/cloud-storage +composer update --no-dev --optimize-autoloader +``` You have to create a GCS bucket and specify the name as the model option `bucket`. Alternatively, you can set the name through the environment variable `PRIVATEBIN_GCS_BUCKET`. @@ -246,7 +253,12 @@ the AWS SDK for PHP, but can also talk to a Rados gateway as part of a Ceph cluster. To use this backend, you first have to install the SDK from the installation -directory of PrivateBin: `composer require aws/aws-sdk-php` +directory of PrivateBin: + +```console +composer require --no-update aws/aws-sdk-php +composer update --no-dev --optimize-autoloader +``` You have to create an S3 bucket on the Ceph cluster before using the S3 backend. diff --git a/doc/Release.md b/doc/Release.md index 209c4471..b14f91ac 100644 --- a/doc/Release.md +++ b/doc/Release.md @@ -37,7 +37,7 @@ Primary key fingerprint: 28CA 7C96 4938 EA5C 1481 D42A E11B 7950 E9E1 83DB For a more step-by-step guide in detail [see this FAQ](https://github.com/PrivateBin/PrivateBin/wiki/FAQ#how-can-i-securely-clonedownload-your-project). -SLSA verification can be performed using the [SLSA verifier](https://github.com/slsa-framework/slsa-verifier#verification-of-slsa-provenance). +SLSA verification can be performed using the [SLSA verifier](https://github.com/slsa-framework/slsa-verifier?tab=readme-ov-file#verification-for-github-builders). ## Release process diff --git a/doc/Running Unit Tests.md b/doc/Running Unit Tests.md index 95078258..bf020789 100644 --- a/doc/Running Unit Tests.md +++ b/doc/Running Unit Tests.md @@ -18,7 +18,7 @@ The parameters in detail: an accidentally destructive test case in it. - `--read-only` - This image supports running in read-only mode. Only /tmp may be written into. -- `-rm` - Remove the container after the run. This saves you doing a cleanup +- `--rm` - Remove the container after the run. This saves you doing a cleanup on your docker environment, if you run the image frequently. You can also run just the php and javascript test suites instead of both: @@ -43,6 +43,14 @@ Example for Debian and Ubuntu: $ sudo apt install phpunit php-gd php-sqlite3 php-xdebug ``` +Because the unit tests depend on this, you also need to install the optional. Otherwise they won't run: +```console +composer require google/cloud-storage +``` + +If you do this and want to develop further, please go into `.gitignore` and adjust it to ignore the whole +vendor directory. Otherwise your `git status` will be filled with lot's of unrelated PHP files. + To run the tests, change into the `tst` directory and run phpunit: ```console diff --git a/i18n/ar.json b/i18n/ar.json index 3752a362..1ba7dc63 100644 --- a/i18n/ar.json +++ b/i18n/ar.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s عبارة عن أداة لصق على الإنترنت بسيطة ومفتوحة المصدر حيث لا يمتلك الخادم أي معرفة بالبيانات الملصقة. يتم تشفير / فك تشفير البيانات %sفي المتصفح%s باستخدام 256 بت AES.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s عبارة عن أداة لصق على الإنترنت بسيطة ومفتوحة المصدر حيث لا يمتلك الخادم أي معرفة بالبيانات الملصقة. يتم تشفير / فك تشفير البيانات %sفي المتصفح%s باستخدام 256 بت AES.", "More information on the project page.": "مزيد من المعلومات على صفحة المشروع.", "Because ignorance is bliss": "لأن الجهل نعمة", - "Paste does not exist, has expired or has been deleted.": "اللصق غير موجود أو انتهت صلاحيته أو تم حذفه.", + "Document does not exist, has expired or has been deleted.": "اللصق غير موجود أو انتهت صلاحيته أو تم حذفه.", "%s requires php %s or above to work. Sorry.": "%s يتطلب php %s أو أعلى للعمل. آسف.", "%s requires configuration section [%s] to be present in configuration file.": "%s يتطلب وجود قسم [%s] تضبيط في ملف تضبيط.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "الرجاء الانتظار %d ثواني بين كل مشاركة.", "الرجاء الانتظار %d ثواني بين كل مشاركة." ], - "Paste is limited to %s of encrypted data.": "يقتصر اللصق على %s البيانات المشفرة.", + "Document is limited to %s of encrypted data.": "يقتصر اللصق على %s البيانات المشفرة.", "Invalid data.": "بيانات غير صالحة.", "You are unlucky. Try again.": "أنت غير محظوظ. أعِد المحاولة.", "Error saving comment. Sorry.": "خطأ في حفظ التعليق. آسف.", - "Error saving paste. Sorry.": "خطأ في حفظ اللصق. آسف.", - "Invalid paste ID.": "معرف لصق غير صالح.", - "Paste is not of burn-after-reading type.": "اللصق ليس من النوع الذي يحرق بعد القراءة.", - "Wrong deletion token. Paste was not deleted.": "رمز حذف خاطئ. لم يتم يحُذف اللصق.", - "Paste was properly deleted.": "حُذفت اللصق بشكل صحيح.", + "Error saving document. Sorry.": "خطأ في حفظ اللصق. آسف.", + "Invalid document ID.": "معرف لصق غير صالح.", + "Document is not of burn-after-reading type.": "اللصق ليس من النوع الذي يحرق بعد القراءة.", + "Wrong deletion token. Document was not deleted.": "رمز حذف خاطئ. لم يتم يحُذف اللصق.", + "Document was properly deleted.": "حُذفت اللصق بشكل صحيح.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "جافاسكرِبت (JavaScript) مطلوب %s للعمل. نأسف للإزعاج.", "%s requires a modern browser to work.": "%s يتطلب متصفحًا حديثًا للعمل.", "New": "جديد", - "Send": "إرسال", + "Create": "أنشِئ", "Clone": "استنساخ", "Raw text": "نص خام", "Expires": "تنتهي", @@ -133,9 +133,9 @@ "ستنتهي صلاحية هذا المستند خلال %d شهور.", "ستنتهي صلاحية هذا المستند خلال %d شهور." ], - "Please enter the password for this paste:": "الرجاء إدخال كلمة المرور لهذا اللصق:", + "Please enter the password for this document:": "الرجاء إدخال كلمة المرور لهذا اللصق:", "Could not decrypt data (Wrong key?)": "تعذر فك تشفير البيانات (مفتاح غير صحيح؟)", - "Could not delete the paste, it was not stored in burn after reading mode.": "تعذر حذف اللصق، ولم يخزين في وضع النسخ بعد القراءة.", + "Could not delete the document, it was not stored in burn after reading mode.": "تعذر حذف اللصق، ولم يخزين في وضع النسخ بعد القراءة.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "فقط من أجل عينيك. لا تغلق هذه النافذة، لا يمكن عرض هذه الرسالة مرة أخرى.", "Could not decrypt comment; Wrong key?": "تعذر فك تشفير التعليق؛ المفتاح غير صحيح؟", "Reply": "رد", @@ -150,31 +150,31 @@ "unknown status": "حالة غير معروفة", "server error or not responding": "خطأ في الخادم أو لا يستجيب", "Could not post comment: %s": "لا يمكن نشر تعليق: %s", - "Sending paste…": "يُرسل لصق…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "لصقك هو %s (اضغط على [Ctrl] + [c] للنسخ)", + "Sending document…": "يُرسل لصق…", + "Your document is %s (Hit Ctrl+c to copy)": "لصقك هو %s (اضغط على Ctrl + c للنسخ)", "Delete data": "حذف البيانات", - "Could not create paste: %s": "تعذر إنشاء اللصق: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "لا يمكن فك تشفير اللصق: مفتاح فك التشفير مفقود في URL (هل استخدمت معيد توجيه أو أداة تقصير لعناوين URL تزيل جزءًا من عنوان URL؟)", + "Could not create document: %s": "تعذر إنشاء اللصق: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "لا يمكن فك تشفير اللصق: مفتاح فك التشفير مفقود في URL (هل استخدمت معيد توجيه أو أداة تقصير لعناوين URL تزيل جزءًا من عنوان URL؟)", "B": "بايت", - "KiB": "كيلوبايت", - "MiB": "ميجابايت", - "GiB": "جيجابايت", - "TiB": "تيرابايت", - "PiB": "بيتابايت", - "EiB": "إكسابايت", - "ZiB": "زيتابايت", - "YiB": "يوتابايت", + "kB": "كيلوبايت", + "MB": "ميجابايت", + "GB": "جيجابايت", + "TB": "تيرابايت", + "PB": "بيتابايت", + "EB": "إكسابايت", + "ZB": "زيتابايت", + "YB": "يوتابايت", "Format": "التنسيق", "Plain Text": "نص عادي", "Source Code": "كود مصدر", "Markdown": "ماركداون", - "Download attachment": "تنزيل المرفقات", + "Download attachment": "نزّل المرفق", "Cloned: '%s'": "مستنسخ: '%s'", - "The cloned file '%s' was attached to this paste.": "تم إرفاق المِلَفّ المستنسخ '%s' بهذا اللصق.", - "Attach a file": "إرفاق مِلَفّ", + "The cloned file '%s' was attached to this document.": "تم إرفاق الملف المستنسخ '%s' بهذا اللصق.", + "Attach a file": "أرفق ملف", "alternatively drag & drop a file or paste an image from the clipboard": "بدلاً من ذلك، اسحب ملفًا وأسقطه أو الصق صورة من الحافظة", - "File too large, to display a preview. Please download the attachment.": "المِلَفّ كبير جدًا، بحيث لا يمكن عرض معاينة. الرجاء تنزيل المرفق.", - "Remove attachment": "إزالة المرفق", + "File too large, to display a preview. Please download the attachment.": "الملف كبير جدًا، بحيث لا يمكن عرض معاينة. الرجاء تنزيل المرفق.", + "Remove attachment": "أزِل المرفق", "Your browser does not support uploading encrypted files. Please use a newer browser.": "متصفحك لا يدعم رفع الملفات المشفرة. الرجاء استخدام متصفح أحدث.", "Invalid attachment.": "مرفق غير صحيح.", "Options": "الخيارات", @@ -185,11 +185,11 @@ "Decrypt": "فك التشفير", "Enter password": "أدخل كلمة المرور", "Loading…": "تحميل…", - "Decrypting paste…": "يفك تشفير اللصق…", - "Preparing new paste…": "تحضير لصقة جديدة…", + "Decrypting document…": "يفك تشفير اللصق…", + "Preparing new document…": "تحضير لصقة جديدة…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "في حالة عدم اختفاء هذه الرسالة مطلقًا ، يرجى إلقاء نظرة على الأسئلة الشائعة هذه للحصول على معلومات لتحري الخلل وإصلاحه.", - "+++ no paste text +++": "+++ لا يوجد نص لصق +++", - "Could not get paste data: %s": "تعذر الحصول على لصق البيانات: %s", + "+++ no document text +++": "+++ لا يوجد نص لصق +++", + "Could not get document data: %s": "تعذر الحصول على لصق البيانات: %s", "QR code": "رمز QR", "This website is using an insecure HTTP connection! Please use it only for testing.": "هذا الموقع يستخدم اتصال HTTP غير آمن! الرجاء استخدامه للاختبار فقط.", "For more information see this FAQ entry.": "لمزيد من المعلومات راجع هذه الأسئلة الشائعة.", @@ -210,11 +210,24 @@ "Encrypted note on %s": "ملاحظة مشفرة على %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "زُر هذا الرابط لرؤية الملاحظة. يتيح إعطاء عنوان URL لأي شخص الوصول إلى الملاحظة أيضًا.", "URL shortener may expose your decrypt key in URL.": "قد يفضح أداة تقصير عناوين URL مفتاح فك التشفير الخاص بك في URL.", - "Save paste": "احفظ اللصق", - "Your IP is not authorized to create pastes.": "عنوان IP الخاص بك غير مصرح له بإنشاء لصُق.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "احفظ اللصق", + "Your IP is not authorized to create documents.": "عنوان IP الخاص بك غير مصرح له بإنشاء لصُق.", "Trying to shorten a URL that isn't pointing at our instance.": "محاولة تقصير عنوان URL لا يشير إلى خادمنا.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "خطأ في الاتصال بـ YOURLS. ربما تكون هناك مشكلة في التضبيط، مثل \"apiurl\" أو \"التوقيع\" الخاطئ أو المفقود.", - "Error parsing YOURLS response.": "خطأ في تحليل استجابة YOURLS.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "خطأ في الاتصال بـ YOURLS. ربما تكون هناك مشكلة في التضبيط، مثل \"apiurl\" أو \"التوقيع\" الخاطئ أو المفقود.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "خطأ في تحليل استجابة YOURLS.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "يمكن عرض هذه الرسالة السرية مرة واحدة فقط. هل ترغب في رؤيتها الآن؟", + "Yes, see it": "نعم، دعني اراها", + "Dark Mode": "الوضع الداكن", + "Error compressing document, due to missing WebAssembly support.": "خطأ في ضغط اللصق، بسبب فقدان دعم WebAssembly.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "خطأ في فك ضغط اللصق، متصفحك لا يدعم WebAssembly. الرجاء استخدام متصفح آخر لعرض هذه اللصقة.", + "Start over": "ابدأ من جديد", + "Document copied to clipboard": "نُسخ اللصق إلى الحافظة", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "لنسخ اللصق انقر على زر النسخ أو استخدم اختصار الحافظة Ctrl+c/Cmd+c", + "Copy link": "نسخ الرابط", + "Link copied to clipboard": "نُسخ الرابط إلى الحافظة", + "Document text": "لصق النص", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "مفتاح التبويب يعمل كشخصية (انقر Ctrl+m أو Esc للتبديل)", + "Theme": "السمة" } diff --git a/i18n/bg.json b/i18n/bg.json index e7cb35a3..5aa0b00d 100644 --- a/i18n/bg.json +++ b/i18n/bg.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s е изчистен и изцяло достъпен като отворен код, онлайн \"paste\" услуга, където сървъра не знае подадената информация. Тя се шифрова/дешифрова %sвъв браузъра%s използвайки 256 битов AES алгоритъм.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s е изчистен и изцяло достъпен като отворен код, онлайн \"document\" услуга, където сървъра не знае подадената информация. Тя се шифрова/дешифрова %sвъв браузъра%s използвайки 256 битов AES алгоритъм.", "More information on the project page.": "Повече информация може да намерите на страницата на проекта (Английски).", "Because ignorance is bliss": "Невежеството е блаженство", - "Paste does not exist, has expired or has been deleted.": "Информацията не съществува, срокът и е изтекъл или е била изтрита.", + "Document does not exist, has expired or has been deleted.": "Информацията не съществува, срокът и е изтекъл или е била изтрита.", "%s requires php %s or above to work. Sorry.": "%s има нужда от PHP %s или по-нова, за да работи. Съжалявам.", "%s requires configuration section [%s] to be present in configuration file.": "%s задължава отдела от настройките [%s] да съществува във файла със настройките.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Моля изчакайте %d секунди между всяка публикация.", "Моля изчакайте %d секунди между всяка публикация." ], - "Paste is limited to %s of encrypted data.": "Съдържанието е ограничено до %s криптирана информация.", + "Document is limited to %s of encrypted data.": "Съдържанието е ограничено до %s криптирана информация.", "Invalid data.": "Невалидна информация.", "You are unlucky. Try again.": "Нямаш късмет. Пробвай отново.", "Error saving comment. Sorry.": "Грешка в запазването на коментара. Съжалявам.", - "Error saving paste. Sorry.": "Грешка в записването на информацията. Съжалявам.", - "Invalid paste ID.": "Невалиден идентификационен код.", - "Paste is not of burn-after-reading type.": "Информацията не е от тип \"унищожаване след преглед\".", - "Wrong deletion token. Paste was not deleted.": "Невалиден код за изтриване. Информацията Ви не беше изтрита.", - "Paste was properly deleted.": "Информацията Ви е изтрита.", + "Error saving document. Sorry.": "Грешка в записването на информацията. Съжалявам.", + "Invalid document ID.": "Невалиден идентификационен код.", + "Document is not of burn-after-reading type.": "Информацията не е от тип \"унищожаване след преглед\".", + "Wrong deletion token. Document was not deleted.": "Невалиден код за изтриване. Информацията Ви не беше изтрита.", + "Document was properly deleted.": "Информацията Ви е изтрита.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "Услугата %s се нуждае от JavaScript, за да работи. Съжаляваме за неудобството.", "%s requires a modern browser to work.": "%s се нуждае от съвременен браузър за да работи.", "New": "Създаване", - "Send": "Изпрати", + "Create": "Създай", "Clone": "Дублирай", "Raw text": "Чист текст", "Expires": "Изтича", @@ -133,9 +133,9 @@ "Този документ изтича след %d години.", "Този документ изтича след %d години." ], - "Please enter the password for this paste:": "Моля въведете паролата за това съдържание:", + "Please enter the password for this document:": "Моля въведете паролата за това съдържание:", "Could not decrypt data (Wrong key?)": "Информацията не можеше да се дешифрова (Грешен ключ?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Изтриването на информацията беше неуспешно. Тя не е от тип \"унищожаване след преглед\".", + "Could not delete the document, it was not stored in burn after reading mode.": "Изтриването на информацията беше неуспешно. Тя не е от тип \"унищожаване след преглед\".", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "САМО ЗА ВАШИТЕ ОЧИ. Не затваряйте прозореца, понеже тази информация няма да може да бъде показана отново.", "Could not decrypt comment; Wrong key?": "Дешифроването на коментара беше неуспешно. Грешен ключ?", "Reply": "Отговор", @@ -150,27 +150,27 @@ "unknown status": "Неизвестно състояние", "server error or not responding": "Грешка в сървъра или не отговаря", "Could not post comment: %s": "Публикуването на коментара Ви беше неуспешно: %s", - "Sending paste…": "Изпращане на информацията Ви…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Вашата връзка е %s (Натиснете [Ctrl]+[c] за да копирате)", + "Sending document…": "Изпращане на информацията Ви…", + "Your document is %s (Hit Ctrl+c to copy)": "Вашата връзка е %s (Натиснете Ctrl+c за да копирате)", "Delete data": "Изтриване на информацията", - "Could not create paste: %s": "Създаването на връзката ви беше неуспешно: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Дешифроването на информацията беше неуспешно: Ключа за декриптиране липсва във връзката (Да не сте използвали услуга за пренасочване или скъсяване на връзката, което би изрязало части от нея?)", + "Could not create document: %s": "Създаването на връзката ви беше неуспешно: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Дешифроването на информацията беше неуспешно: Ключа за декриптиране липсва във връзката (Да не сте използвали услуга за пренасочване или скъсяване на връзката, което би изрязало части от нея?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Формат", "Plain Text": "Чист текст", "Source Code": "Изходен код", "Markdown": "Markdown", "Download attachment": "Свали прикачения файл", "Cloned: '%s'": "Дублирано: '%s'", - "The cloned file '%s' was attached to this paste.": "Дублирания файл '%s' беше прикачен.", + "The cloned file '%s' was attached to this document.": "Дублирания файл '%s' беше прикачен.", "Attach a file": "Прикачи файл", "alternatively drag & drop a file or paste an image from the clipboard": "Също можеш да пуснеш файла върху този прозорец или да поставиш изображение от клипборда", "File too large, to display a preview. Please download the attachment.": "Файла е твърде голям, за да се представи визуализация. Моля, свалете файла.", @@ -185,11 +185,11 @@ "Decrypt": "Дешифровай", "Enter password": "Въведи паролата", "Loading…": "Зареждане…", - "Decrypting paste…": "Дешифроване на информацията…", - "Preparing new paste…": "Приготвяне на връзката Ви…", + "Decrypting document…": "Дешифроване на информацията…", + "Preparing new document…": "Приготвяне на връзката Ви…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "Във случай, че това съобщение не изчезне след време, моля прегледайте този FAQ (Английски), за информация, която би ви помогнала.", - "+++ no paste text +++": "+++ няма текстово съдържание +++", - "Could not get paste data: %s": "Взимането на информацията беше неуспешно: %s", + "+++ no document text +++": "+++ няма текстово съдържание +++", + "Could not get document data: %s": "Взимането на информацията беше неуспешно: %s", "QR code": "QR код", "This website is using an insecure HTTP connection! Please use it only for testing.": "Този сайт използва несигурна HTTP връзка. Моля използвайте само за проби.", "For more information see this FAQ entry.": "Вижте тази страница за повече информация.", @@ -199,10 +199,10 @@ "Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.", "Retry": "Нов опит", "Showing raw text…": "Showing raw text…", - "Notice:": "Notice:", + "Notice:": "Известие:", "This link will expire after %s.": "This link will expire after %s.", "This link can only be accessed once, do not use back or refresh button in your browser.": "This link can only be accessed once, do not use back or refresh button in your browser.", - "Link:": "Link:", + "Link:": "Връзка:", "Recipient may become aware of your timezone, convert time to UTC?": "Recipient may become aware of your timezone, convert time to UTC?", "Use Current Timezone": "Use Current Timezone", "Convert To UTC": "Convert To UTC", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Encrypted note on %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.", "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.", - "Save paste": "Save paste", - "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Save document", + "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.", "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?", + "Yes, see it": "Yes, see it", + "Dark Mode": "Dark Mode", + "Error compressing document, due to missing WebAssembly support.": "Error compressing document, due to missing WebAssembly support.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.", + "Start over": "Start over", + "Document copied to clipboard": "Document copied to clipboard", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/ca.json b/i18n/ca.json index 7ed9846b..5c3c6073 100644 --- a/i18n/ca.json +++ b/i18n/ca.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s és un pastebin en línia de codi obert i minimalista on el servidor no té coneixement de les dades enganxades. Les dades estan encriptades/desxifrades %sen el navegador%s utilitzant AES de 256 bits.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s és un pastebin en línia de codi obert i minimalista on el servidor no té coneixement de les dades enganxades. Les dades estan encriptades/desxifrades %sen el navegador%s utilitzant AES de 256 bits.", "More information on the project page.": "Més informació a la pàgina del projecte.", "Because ignorance is bliss": "Perquè la ignorància és felicitat", - "Paste does not exist, has expired or has been deleted.": "El paste no existeix, ha caducat o s'ha eliminat.", + "Document does not exist, has expired or has been deleted.": "El document no existeix, ha caducat o s'ha eliminat.", "%s requires php %s or above to work. Sorry.": "%s requereix php %s o superior per funcionar. Ho sento.", "%s requires configuration section [%s] to be present in configuration file.": "%s requereix que la secció de configuració [%s] sigui present al fitxer de configuració.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Espereu %d segons entre cada entrada.", "Espereu %d segons entre cada entrada." ], - "Paste is limited to %s of encrypted data.": "L'enganxat està limitat a %s de dades encriptades.", + "Document is limited to %s of encrypted data.": "L'enganxat està limitat a %s de dades encriptades.", "Invalid data.": "Dades no vàlides.", "You are unlucky. Try again.": "Mala sort. Torna-ho a provar.", "Error saving comment. Sorry.": "S'ha produït un error en desar el comentari. Ho sento.", - "Error saving paste. Sorry.": "S'ha produït un error en desar l'enganxat. Ho sento.", - "Invalid paste ID.": "Identificador d'enganxament no vàlid.", - "Paste is not of burn-after-reading type.": "Paste is not of burn-after-reading type.", - "Wrong deletion token. Paste was not deleted.": "El token d'eliminació és incorrecte. El Paste no s'ha eliminat.", - "Paste was properly deleted.": "El Paste s'ha esborrat correctament.", + "Error saving document. Sorry.": "S'ha produït un error en desar l'enganxat. Ho sento.", + "Invalid document ID.": "Identificador d'enganxament no vàlid.", + "Document is not of burn-after-reading type.": "La nota no és del tipus eliminar després de llegir.", + "Wrong deletion token. Document was not deleted.": "El token d'eliminació és incorrecte. El Document no s'ha eliminat.", + "Document was properly deleted.": "El Document s'ha esborrat correctament.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "Cal JavaScript perquè %s funcioni. Em sap greu les molèsties.", "%s requires a modern browser to work.": "%s requereix un navegador modern per funcionar.", "New": "Nou", - "Send": "Enviar", + "Create": "Crear", "Clone": "Clona", "Raw text": "Text sense processar", "Expires": "Caducitat", @@ -92,7 +92,7 @@ "%d anys" ], "Never": "Mai", - "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.", + "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "Nota: Aquest és un servei de prova. Les dades s'eliminaran. Molts gatets moriran si abuses d'aquest servei.", "This document will expire in %d seconds.": [ "Aquest document caducarà d'aquí %d segon.", "Aquest document caducarà d'aquí %d segons.", @@ -133,9 +133,9 @@ "Aquest document caducarà d'aquí %d mesos.", "Aquest document caducarà d'aquí %d mesos." ], - "Please enter the password for this paste:": "Si us plau, introdueix la contrasenya per aquest paste:", + "Please enter the password for this document:": "Si us plau, introdueix la contrasenya per aquest document:", "Could not decrypt data (Wrong key?)": "No s'han pogut desxifrar les dades (Clau incorrecte?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Could not delete the paste, it was not stored in burn after reading mode.", + "Could not delete the document, it was not stored in burn after reading mode.": "Could not delete the document, it was not stored in burn after reading mode.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.", "Could not decrypt comment; Wrong key?": "Could not decrypt comment; Wrong key?", "Reply": "Respondre", @@ -150,30 +150,30 @@ "unknown status": "estat desconegut", "server error or not responding": "server error or not responding", "Could not post comment: %s": "No s'ha pogut publicar el comentari: %s", - "Sending paste…": "Enviant paste…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Your paste is %s (Hit [Ctrl]+[c] to copy)", + "Sending document…": "Enviant document…", + "Your document is %s (Hit Ctrl+c to copy)": "Your document is %s (Hit Ctrl+c to copy)", "Delete data": "Esborrar les dades", - "Could not create paste: %s": "Could not create paste: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)", + "Could not create document: %s": "Could not create document: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "No es pot desxifrar la nota: falta la clau de desxifrat a l'URL (vau utilitzar un adreçament o un escurçador d'URL que elimina part de l'URL?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Text sense format", "Source Code": "Codi font", "Markdown": "Markdown", "Download attachment": "Baixar els adjunts", "Cloned: '%s'": "Cloned: '%s'", - "The cloned file '%s' was attached to this paste.": "The cloned file '%s' was attached to this paste.", + "The cloned file '%s' was attached to this document.": "The cloned file '%s' was attached to this document.", "Attach a file": "Adjuntar un fitxer", - "alternatively drag & drop a file or paste an image from the clipboard": "alternatively drag & drop a file or paste an image from the clipboard", - "File too large, to display a preview. Please download the attachment.": "File too large, to display a preview. Please download the attachment.", + "alternatively drag & drop a file or paste an image from the clipboard": "alternativament, pots arrossegar i deixar anar un fitxer o enganxar una imatge des del porta-retalls", + "File too large, to display a preview. Please download the attachment.": "El fitxer és massa gran per fer una vista prèvia. Si us plau, descarrega l'adjunt.", "Remove attachment": "Remove attachment", "Your browser does not support uploading encrypted files. Please use a newer browser.": "Your browser does not support uploading encrypted files. Please use a newer browser.", "Invalid attachment.": "Invalid attachment.", @@ -185,11 +185,11 @@ "Decrypt": "Decrypt", "Enter password": "Enter password", "Loading…": "Loading…", - "Decrypting paste…": "Decrypting paste…", - "Preparing new paste…": "Preparing new paste…", + "Decrypting document…": "Decrypting document…", + "Preparing new document…": "Preparing new document…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "In case this message never disappears please have a look at this FAQ for information to troubleshoot.", - "+++ no paste text +++": "+++ no paste text +++", - "Could not get paste data: %s": "Could not get paste data: %s", + "+++ no document text +++": "+++ no document text +++", + "Could not get document data: %s": "Could not get document data: %s", "QR code": "QR code", "This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.", "For more information see this FAQ entry.": "For more information see this FAQ entry.", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Encrypted note on %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.", "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.", - "Save paste": "Save paste", - "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.", - "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Save document", + "Your IP is not authorized to create documents.": "La teva IP no està autoritzada a crear notes.", + "Trying to shorten a URL that isn't pointing at our instance.": "S'està intentant escurçar un URL que no apunta a la nostra instància.", + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Error en la crida a YOURLS. Probablement és un problema de configuració, com ara \"apiurl\" o \"signature\" incorrectes o que falten.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "Aquest missatge secret sols es pot veure una vegada. Vols obrir-ho ara?", + "Yes, see it": "Yes, see it", + "Dark Mode": "Dark Mode", + "Error compressing document, due to missing WebAssembly support.": "Error de compressió de la nota, no hi ha suport de WebAssembly.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.", + "Start over": "Start over", + "Document copied to clipboard": "Document copied to clipboard", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/co.json b/i18n/co.json index a50d2def..b029068e 100644 --- a/i18n/co.json +++ b/i18n/co.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s hè un serviziu in linea di tipu « pastebin » (ghjestiunariu d’appiccicu di pezzi di testu è di codice di fonte) minimalistu è à fonte aperta induve u servitore ùn hà micca cunnuscenza di i dati mandati. I dati sò cifrati è dicifrati %sin u navigatore%s cù una cifratura AES di 256 bit.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s hè un serviziu in linea, minimalistu è à fonte aperta, di tipu « pastebin », vole à dì chì face a ghjestione d’appiccicu di pezzi di testu è di codice di fonte, induve u servitore ùn hà manc’appena a cunnuscenza di i dati mandati. I dati sò cifrati è dicifrati %sin u navigatore%s cù una cifratura AES di 256 bit.", "More information on the project page.": "Più d’infurmazione annant’à a pagina di u prughjettu.", "Because ignorance is bliss": "Perchè l’ignurenza hè una campa", - "Paste does not exist, has expired or has been deleted.": "L’appiccicu ùn esiste micca, hè scadutu o hè statu squassatu.", + "Document does not exist, has expired or has been deleted.": "U ducumentu ùn esiste micca, hè scadutu o hè statu squassatu.", "%s requires php %s or above to work. Sorry.": "Per disgrazzia, %s richiede php %s o più recente per funziunà.", "%s requires configuration section [%s] to be present in configuration file.": "%s richiede a presenza di a sezzione di cunfigurazione [%s] in a schedariu di cunfigurazione.", "Please wait %d seconds between each post.": [ @@ -14,26 +14,26 @@ "Aspettate %d seconde trà dui publicazioni.", "Aspettate %d seconde trà dui publicazioni." ], - "Paste is limited to %s of encrypted data.": "L’appiccicu hè limitatu à %s di dati cifrati.", + "Document is limited to %s of encrypted data.": "U ducumentu hè limitatu à %s di dati cifrati.", "Invalid data.": "Dati inaccetevule.", "You are unlucky. Try again.": "Pruvate torna, Serete più furtunati.", "Error saving comment. Sorry.": "Per disgrazzia, ci hè un sbagliu à l’arregistramentu di u cummentu.", - "Error saving paste. Sorry.": "Per disgrazzia, ci hè un sbagliu à l’arregistramentu di l’appiccicu.", - "Invalid paste ID.": "N° di l’appiccicu inaccettevule.", - "Paste is not of burn-after-reading type.": "L’appiccicu ùn hè micca di tipu « Squassà dopu a lettura ».", - "Wrong deletion token. Paste was not deleted.": "Gettone di squassatura incurrettu. L’appiccicu ùn hè micca statu squassatu.", - "Paste was properly deleted.": "L’appiccicu hè statu squassatu currettamente.", + "Error saving document. Sorry.": "Per disgrazzia, ci hè un sbagliu à l’arregistramentu di u ducumentu.", + "Invalid document ID.": "N° di u ducumentu inaccettevule.", + "Document is not of burn-after-reading type.": "U ducumentu ùn hè micca di tipu « Squassà dopu a lettura ».", + "Wrong deletion token. Document was not deleted.": "Gettone di squassatura incurrettu. U ducumentu ùn hè micca statu squassatu.", + "Document was properly deleted.": "U ducumentu hè statu squassatu currettamente.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript hè richiestu per fà funziunà %s. Scusate per stu penseru.", "%s requires a modern browser to work.": "%s richiede un navigatore mudernu per funziunà.", "New": "Novu", - "Send": "Mandà", + "Create": "Creà", "Clone": "Duppione", "Raw text": "Testu grossu", "Expires": "Scadenza", "Burn after reading": "Squassà dopu a lettura", - "Open discussion": "Apre una chjachjarata", + "Open discussion": "Apre una chjachjerata", "Password (recommended)": "Parolla d’intesa (ricumandata)", - "Discussion": "Chjachjarata", + "Discussion": "Chjachjerata", "Toggle navigation": "Invertisce a navigazione", "%d seconds": [ "%d seconda", @@ -133,9 +133,9 @@ "Stu ducumentu serà scadutu in %d mesi.", "Stu ducumentu serà scadutu in %d mesi." ], - "Please enter the password for this paste:": "Stampittate a parolla d’intesa per st’appiccicu :", + "Please enter the password for this document:": "Stampittate a parolla d’intesa per stu ducumentu :", "Could not decrypt data (Wrong key?)": "Ùn si pò micca dicifrà i dati ; seria incurretta a chjave ?", - "Could not delete the paste, it was not stored in burn after reading mode.": "Ùn si pò micca squassà l’appiccicu, ùn hè micca statu in u modu « Squassà dopu a lettura ».", + "Could not delete the document, it was not stored in burn after reading mode.": "Ùn si pò micca squassà u ducumentu perchè ùn hè micca statu creatu in u modu « Squassà dopu a lettura ».", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "SOLU CÙ L’OCHJI. Ùn chjudite micca sta finestra, stu messaghju un puderà più esse affissatu torna.", "Could not decrypt comment; Wrong key?": "Ùn si pò micca dicifrà u cummentu. Seria incurretta a chjave ?", "Reply": "Risponde", @@ -150,33 +150,33 @@ "unknown status": "statu scunnisciutu", "server error or not responding": "sbagliu di u servitore o u servitore ùn risponde micca", "Could not post comment: %s": "Ùn si pò micca impustà u cummentu : %s", - "Sending paste…": "Inviu di l’appiccicu…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "U vostru appiccicu si trova à l’indirizzu%s (Appughjate [Ctrl]+[c] per cupià u liame)", + "Sending document…": "Inviu di u ducumentu…", + "Your document is %s (Hit Ctrl+c to copy)": "U vostru ducumentu si trova à l’indirizzu %s (Appughjate nant’à Ctrl+c per cupià u liame)", "Delete data": "Squassà i dati", - "Could not create paste: %s": "Ùn si pò micca creà l’appiccicu : %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Ùn si pò micca dicifrà l’appiccicu : A chjave di dicifratura hè assente in l’indirizzu. Averiate impiegatu un orientadore d’indirizzu o un riduttore chì ammuzzeghja una parte di l’indirizzu ?", + "Could not create document: %s": "Ùn si pò micca creà u ducumentu : %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Ùn si pò micca dicifrà u ducumentu : A chjave di dicifratura hè assente in l’indirizzu. Averiate impiegatu un orientadore d’indirizzu o un riduttore chì ammuzzeghja una parte di l’indirizzu ?", "B": "o", - "KiB": "Ko", - "MiB": "Mo", - "GiB": "Go", - "TiB": "To", - "PiB": "Po", - "EiB": "Eo", - "ZiB": "Zo", - "YiB": "Yo", + "kB": "Ko", + "MB": "Mo", + "GB": "Go", + "TB": "To", + "PB": "Po", + "EB": "Eo", + "ZB": "Zo", + "YB": "Yo", "Format": "Furmatu", "Plain Text": "Testu in chjaru", "Source Code": "Codice di fonte", "Markdown": "Markdown", - "Download attachment": "Scaricà a pezza aghjunta", + "Download attachment": "Scaricà a pezza ghjunta", "Cloned: '%s'": "Duppiatu : « %s »", - "The cloned file '%s' was attached to this paste.": "U schedariu duppiatu « %s » hè statu aghjuntu à st’appiccicu.", + "The cloned file '%s' was attached to this document.": "U schedariu duppiatu « %s » hè statu aghjuntu à stu ducumentu.", "Attach a file": "Aghjunghje un schedariu", "alternatively drag & drop a file or paste an image from the clipboard": "in alternanza, sguillà è depone un schedariu o incullà una fiura da u preme’papei", - "File too large, to display a preview. Please download the attachment.": "Schedariu troppu maiò per affissà una fighjulata. Scaricate a pezza aghjunta.", - "Remove attachment": "Caccià a pezza aghjunta", + "File too large, to display a preview. Please download the attachment.": "Schedariu troppu maiò per affissà una fighjulata. Scaricate a pezza ghjunta.", + "Remove attachment": "Caccià a pezza ghjunta", "Your browser does not support uploading encrypted files. Please use a newer browser.": "U vostru navigatore ùn accetta micca l’inviu di i schedarii cifrati. Impiegate un navigatore più recente.", - "Invalid attachment.": "A pezza aghjunta hè inaccettevule.", + "Invalid attachment.": "A pezza ghjunta hè inaccettevule.", "Options": "Ozzioni", "Shorten URL": "Ammuzzà l’indirizzu", "Editor": "Editore", @@ -185,11 +185,11 @@ "Decrypt": "Dicifrà", "Enter password": "Stampittate a parolla d’intesa", "Loading…": "Caricamentu…", - "Decrypting paste…": "Dicifratura di l’appiccicu…", - "Preparing new paste…": "Approntu di u novu appiccicu…", + "Decrypting document…": "Dicifratura di u ducumentu…", + "Preparing new document…": "Approntu di u ducumentu novu…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "S’è stu messaghju ùn smarisce micca, lighjite sta FAQ per ottene infurmazioni annant’à a risuluzione di i prublemi.", - "+++ no paste text +++": "+++ nisunu testu incullatu +++", - "Could not get paste data: %s": "Ùn si pò micca ottene i dati di l’appiccicu : %s", + "+++ no document text +++": "+++ nisunu testu di ducumentu +++", + "Could not get document data: %s": "Ùn si pò micca ottene i dati di u ducumentu : %s", "QR code": "Codice QR", "This website is using an insecure HTTP connection! Please use it only for testing.": "Stu situ web impiegheghja una cunnessione HTTP non sicura ! impiegatelu solu per una prova.", "For more information see this FAQ entry.": "Per sapene di più, lighjite sta rubrica di a FAQ.", @@ -209,12 +209,25 @@ "Close": "Chjode", "Encrypted note on %s": "Nota cifrata nant’à %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visitate stu liame per vede a nota. Date l’indirizzu à qualunque li permette d’accede à a nota dinù.", - "URL shortener may expose your decrypt key in URL.": "Un ammuzzatore d’indirizzu pò palisà a vostra chjave di dicifratura in l’indirizzu.", - "Save paste": "Arregistrà l’appiccicu", - "Your IP is not authorized to create pastes.": "U vostru indirizzu IP ùn hè micca auturizatu à creà l’appiccichi.", + "URL shortener may expose your decrypt key in URL.": "Un riduttore d’indirizzu pò palisà a vostra chjave di dicifratura in l’indirizzu.", + "URL shortener is enabled by default.": "U riduttore d’indirizzu hè predefinitu attivu.", + "Save document": "Arregistrà u ducumentu", + "Your IP is not authorized to create documents.": "U vostru indirizzu IP ùn hè micca auturizatu à creà ducumenti.", "Trying to shorten a URL that isn't pointing at our instance.": "Pruvate d’ammuzzà un indirizzu web chì ùn punta micca versu a vostra instanza.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Sbagliu à a chjama di YOURLS. Seria forse una cunfigurazione gattiva, tale una \"apiurl\" o \"signature\" falsa o assente.", - "Error parsing YOURLS response.": "Sbagliu durante l’analisa di a risposta di YOURLS.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Si pò affissà l’appiccichi « Squassà dopu a lettura » solu dopu u so caricamentu. Vulete aprelu subitu ?", - "Yes, load it": "Iè, caricatelu" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Sbagliu di u proxy : L’indirizzu web di u proxy hè viotu. Forse per via d’un prublema di chjavi di cunfigurazione false o assente.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Sbagliu di u proxy : Sbagliu durante l’analisa di u proxy. Forse per via d’un prublema di chjavi di cunfigurazione false o assente.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Sbagliu di u proxy : Risposta gattiva. Forse per via d’un prublema di chjavi di cunfigurazione false o assente, osinnò un’interruzzione timpuraria.", + "This secret message can only be displayed once. Would you like to see it now?": "Stu messaghju secretu pò esse affissatu solu una volta. Vulete fighjallu subitu ?", + "Yes, see it": "Iè, fighjallu", + "Dark Mode": "Modu scuru", + "Error compressing document, due to missing WebAssembly support.": "Sbagliu durante a cumpressione di u ducumentu, perchè WebAssembly ùn hè micca accettatu.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Sbagliu durante a scumpressione di u ducumentu, perchè u vostru navigatore ùn accetteghja micca WebAssembly. Ci vole à impiegà un altru navigatore per affissà stu ducumentu.", + "Start over": "Principià torna", + "Document copied to clipboard": "U ducumentu hè statu cupiatu in u preme’papei", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "Per cupià u ducumentu, appughjate nant’à u buttone di copia o impiegate l’accurtatoghju di tastera Ctrl+c/Cmd+c", + "Copy link": "Cupià u liame", + "Link copied to clipboard": "U liame hè statu cupiatu in u preme’papei", + "Document text": "Testu di u ducumentu", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "U tastu di tabulazione ghjova cum’è un caratteru (Appughjate nant’à Ctrl+m o Scapp per scambià)", + "Theme": "Tema" } diff --git a/i18n/cs.json b/i18n/cs.json index 49afae50..3dfa081c 100644 --- a/i18n/cs.json +++ b/i18n/cs.json @@ -1,34 +1,34 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s je minimalistický open source 'pastebin' server, který neanalyzuje vložená data. Data jsou šifrována %sv prohlížeči%s pomocí 256 bitů AES.", - "More information on the project page.": "Více informací na stránce projetu.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s je minimalistický open source 'pastebin' server, který nemá přístup ke vloženým datům. Data jsou šifrována %sv prohlížeči%s pomocí 256bitového AES.", + "More information on the project page.": "Více informací na stránce projektu.", "Because ignorance is bliss": "Protože nevědomost je sladká", - "Paste does not exist, has expired or has been deleted.": "Vložený text neexistuje, expiroval nebo byl odstraněn.", + "Document does not exist, has expired or has been deleted.": "Vložený text neexistuje, expiroval nebo byl odstraněn.", "%s requires php %s or above to work. Sorry.": "%s vyžaduje php %s nebo vyšší. Lituji.", - "%s requires configuration section [%s] to be present in configuration file.": "%s vyžaduje, aby byla v konfiguračním souboru přítomna sekce [%s].", + "%s requires configuration section [%s] to be present in configuration file.": "%s vyžaduje, aby byla v konfiguračním souboru přítomna sekce [%s].", "Please wait %d seconds between each post.": [ - "Počet sekund do dalšího příspěvku: %d.", - "Počet sekund do dalšího příspěvku: %d.", - "Počet sekund do dalšího příspěvku: %d.", - "Počet sekund do dalšího příspěvku: %d.", - "Počet sekund do dalšího příspěvku: %d.", - "Počet sekund do dalšího příspěvku: %d." + "Vyčkejte prosím %d sekundu mezi následujícími příspěvky.", + "Vyčkejte prosím %d sekundy mezi následujícími příspěvky.", + "Vyčkejte prosím %d sekund mezi následujícími příspěvky.", + "Vyčkejte prosím %d sekund mezi následujícími příspěvky.", + "Vyčkejte prosím %d sekund mezi následujícími příspěvky.", + "Vyčkejte prosím %d sekund mezi následujícími příspěvky." ], - "Paste is limited to %s of encrypted data.": "Příspěvek je limitován na %s šífrovaných dat", + "Document is limited to %s of encrypted data.": "Příspěvek je limitován na %s šífrovaných dat", "Invalid data.": "Chybná data.", "You are unlucky. Try again.": "Lituji, zkuste to znovu.", - "Error saving comment. Sorry.": "Chyba při ukládání komentáře.", - "Error saving paste. Sorry.": "Chyba při ukládání příspěvku.", - "Invalid paste ID.": "Chybně vložené ID.", - "Paste is not of burn-after-reading type.": "Příspěvek není nastaven na smazaní po přečtení.", - "Wrong deletion token. Paste was not deleted.": "Chybný token pro odstranění. Příspěvek nebyl smazán.", - "Paste was properly deleted.": "Příspěvek byl řádně smazán.", + "Error saving comment. Sorry.": "Chyba při ukládání komentáře. Promiňte.", + "Error saving document. Sorry.": "Chyba při ukládání příspěvku. Promiňte.", + "Invalid document ID.": "Chybné ID příspěvku.", + "Document is not of burn-after-reading type.": "Příspěvek není nastaven na smazání po přečtení.", + "Wrong deletion token. Document was not deleted.": "Chybný token pro odstranění. Příspěvek nebyl smazán.", + "Document was properly deleted.": "Příspěvek byl řádně smazán.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "Pro fungování %s je vyžadován JavaScript. Omlouváme se za nepříjemnosti.", - "%s requires a modern browser to work.": "%%s requires a modern browser to work.", + "%s requires a modern browser to work.": "Pro fungování %s je vyžadován moderní prohlížeč.", "New": "Nový", - "Send": "Odeslat", + "Create": "Vytvořit", "Clone": "Klonovat", - "Raw text": "Pouze Text", + "Raw text": "Čistý text", "Expires": "Expirace", "Burn after reading": "Po přečtení smazat", "Open discussion": "Povolit komentáře", @@ -36,113 +36,113 @@ "Discussion": "Komentáře", "Toggle navigation": "Přepnout navigaci", "%d seconds": [ - "%d sekuda", - "%d sekundy", - "%d sekund", - "%d sekund", - "%d sekund", - "%d sekund" + "%d sekunda", + "%d sekundy", + "%d sekund", + "%d sekund", + "%d sekund", + "%d sekund" ], "%d minutes": [ - "%d minuta", - "%d minuty", - "%d minut", - "%d minut", - "%d minut", - "%d minut" + "%d minuta", + "%d minuty", + "%d minut", + "%d minut", + "%d minut", + "%d minut" ], "%d hours": [ - "%d hodina", - "%d hodiny", - "%d hodin", - "%d hodin", - "%d hodin", - "%d hodin" + "%d hodina", + "%d hodiny", + "%d hodin", + "%d hodin", + "%d hodin", + "%d hodin" ], "%d days": [ - "%d den", - "%d dny", - "%d dní", - "%d dní", - "%d dní", - "%d dní" + "%d den", + "%d dny", + "%d dní", + "%d dní", + "%d dní", + "%d dní" ], "%d weeks": [ - "%d týden", - "%d týdeny", - "%d týdnů", - "%d týdnů", - "%d týdnů", - "%d týdnů" + "%d týden", + "%d týdny", + "%d týdnů", + "%d týdnů", + "%d týdnů", + "%d týdnů" ], "%d months": [ - "%d měsíc", - "%d měsíce", - "%d měsíců", - "%d měsíců", - "%d měsíců", - "%d měsíců" + "%d měsíc", + "%d měsíce", + "%d měsíců", + "%d měsíců", + "%d měsíců", + "%d měsíců" ], "%d years": [ - "%d rok", - "%d roky", - "%d roků", - "%d roků", - "%d roků", - "%d roků" + "%d rok", + "%d roky", + "%d let", + "%d let", + "%d let", + "%d let" ], "Never": "Nikdy", - "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "Poznámka: Tato služba slouží k vyzkoušení: Data mohou být kdykoliv smazána. Při zneužití této služby zemřou koťátka.", + "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "Poznámka: Toto je testovací služba: Data mohou být kdykoliv smazána. Při zneužití této služby zemřou koťátka.", "This document will expire in %d seconds.": [ - "Tento dokument expiruje za %d sekundu.", - "Tento dokument expiruje za %d sekundy.", - "Tento dokument expiruje za %d sekund.", - "Tento dokument expiruje za %d sekund.", - "Tento dokument expiruje za %d sekund.", - "Tento dokument expiruje za %d sekund." + "Tento dokument expiruje za %d sekundu.", + "Tento dokument expiruje za %d sekundy.", + "Tento dokument expiruje za %d sekund.", + "Tento dokument expiruje za %d sekund.", + "Tento dokument expiruje za %d sekund.", + "Tento dokument expiruje za %d sekund." ], "This document will expire in %d minutes.": [ - "Tento dokument expiruje za %d minutu.", - "Tento dokument expiruje za %d minuty.", - "Tento dokument expiruje za %d minut.", - "Tento dokument expiruje za %d minut.", - "Tento dokument expiruje za %d minut.", - "Tento dokument expiruje za %d minut." + "Tento dokument expiruje za %d minutu.", + "Tento dokument expiruje za %d minuty.", + "Tento dokument expiruje za %d minut.", + "Tento dokument expiruje za %d minut.", + "Tento dokument expiruje za %d minut.", + "Tento dokument expiruje za %d minut." ], "This document will expire in %d hours.": [ - "Tento dokument expiruje za %d hodinu.", - "Tento dokument expiruje za %d hodiny.", - "Tento dokument expiruje za %d hodin.", - "Tento dokument expiruje za %d hodin.", - "Tento dokument expiruje za %d hodin.", - "Tento dokument expiruje za %d hodin." + "Tento dokument expiruje za %d hodinu.", + "Tento dokument expiruje za %d hodiny.", + "Tento dokument expiruje za %d hodin.", + "Tento dokument expiruje za %d hodin.", + "Tento dokument expiruje za %d hodin.", + "Tento dokument expiruje za %d hodin." ], "This document will expire in %d days.": [ - "Tento dokument expiruje za %d den.", - "Tento dokument expiruje za %d dny.", - "Tento dokument expiruje za %d dny.", - "Tento dokument expiruje za %d dny.", - "Tento dokument expiruje za %d dny.", - "Tento dokument expiruje za %d dny." + "Tento dokument expiruje za %d den.", + "Tento dokument expiruje za %d dny.", + "Tento dokument expiruje za %d dní.", + "Tento dokument expiruje za %d dní.", + "Tento dokument expiruje za %d dní.", + "Tento dokument expiruje za %d dní." ], "This document will expire in %d months.": [ - "Tento dokument expiruje za %d měsíc.", - "Tento dokument expiruje za %d měsíce.", - "Tento dokument expiruje za %d měsíců.", - "Tento dokument expiruje za %d měsíců.", - "Tento dokument expiruje za %d měsíců.", - "Tento dokument expiruje za %d měsíců." + "Tento dokument expiruje za %d měsíc.", + "Tento dokument expiruje za %d měsíce.", + "Tento dokument expiruje za %d měsíců.", + "Tento dokument expiruje za %d měsíců.", + "Tento dokument expiruje za %d měsíců.", + "Tento dokument expiruje za %d měsíců." ], - "Please enter the password for this paste:": "Zadejte prosím heslo:", + "Please enter the password for this document:": "Zadejte prosím heslo k tomuto příspěvku:", "Could not decrypt data (Wrong key?)": "Nepodařilo se dešifrovat data (Špatný klíč?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Nepodařilo se odstranit příspěvek, nebyl uložen v režimu smazání po přečtení.", + "Could not delete the document, it was not stored in burn after reading mode.": "Nepodařilo se odstranit příspěvek, nebyl uložen v režimu smazání po přečtení.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "POUZE PRO VAŠE OČI. Nezavírejte toto okno, tuto zprávu nelze znovu zobrazit.", "Could not decrypt comment; Wrong key?": "Nepodařilo se dešifrovat komentář; Špatný klíč?", "Reply": "Odpovědět", "Anonymous": "Anonym", - "Avatar generated from IP address": "Avatar vygenerován z IP adresy", + "Avatar generated from IP address": "Avatar vygenerován podle IP adresy", "Add comment": "Přidat komentář", - "Optional nickname…": "Volitelný nickname…", + "Optional nickname…": "Nepovinná přezdívka…", "Post comment": "Odeslat komentář", "Sending comment…": "Odesílání komentáře…", "Comment posted.": "Komentář odeslán.", @@ -150,71 +150,84 @@ "unknown status": "neznámý stav", "server error or not responding": "Chyba na serveru nebo server neodpovídá", "Could not post comment: %s": "Nelze odeslat komentář: %s", - "Sending paste…": "Odesílání příspěvku…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Váš link je %s (Stiskněte [Ctrl]+[c] pro zkopírování)", + "Sending document…": "Odesílání příspěvku…", + "Your document is %s (Hit Ctrl+c to copy)": "Váš příspěvek je %s (Stiskněte Ctrl+c pro zkopírování)", "Delete data": "Odstranit data", - "Could not create paste: %s": "Nelze vytvořit příspěvek: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Nepodařilo se dešifrovat příspěvek: V adrese chybí dešifrovací klíč (Možnou příčinou může být URL shortener?)", + "Could not create document: %s": "Nepodařilo se vytvořit příspěvek: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Nepodařilo se dešifrovat příspěvek: V adrese chybí dešifrovací klíč (Nepoužili jste přesměrovač nebo zkracovač URL, který maže části URL?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Formát", - "Plain Text": "Prostý Text", + "Plain Text": "Prostý text", "Source Code": "Zdrojový kód", "Markdown": "Markdown", "Download attachment": "Stáhnout přílohu", - "Cloned: '%s'": "Klonováno: '%s'", - "The cloned file '%s' was attached to this paste.": "Naklonovaný soubor '%s' byl připojen k tomuto příspěvku.", + "Cloned: '%s'": "Naklonováno: '%s'", + "The cloned file '%s' was attached to this document.": "Naklonovaný soubor „%s“ byl připojen k tomuto příspěvku.", "Attach a file": "Připojit soubor", - "alternatively drag & drop a file or paste an image from the clipboard": "alternativně přetáhněte soubor nebo vložte obrázek ze schránky", + "alternatively drag & drop a file or paste an image from the clipboard": "případně přetáhněte soubor nebo vložte obrázek ze schránky", "File too large, to display a preview. Please download the attachment.": "Soubor je příliš velký pro zobrazení náhledu. Stáhněte si přílohu.", "Remove attachment": "Odstranit přílohu", "Your browser does not support uploading encrypted files. Please use a newer browser.": "Váš prohlížeč nepodporuje nahrávání šifrovaných souborů. Použijte modernější verzi prohlížeče.", "Invalid attachment.": "Chybná příloha.", - "Options": "Volby", + "Options": "Možnosti", "Shorten URL": "Zkrátit URL", "Editor": "Editor", "Preview": "Náhled", - "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s vyžaduje, aby PATH skončil s \"%s\". Aktualizujte PATH ve vašem souboru index.php.", + "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s vyžaduje, aby PATH končilo na „%s“. Aktualizujte PATH ve vašem souboru index.php.", "Decrypt": "Dešifrovat", "Enter password": "Zadejte heslo", "Loading…": "Načítání…", - "Decrypting paste…": "Dešifruji příspěvek…", - "Preparing new paste…": "Připravuji nový příspěvek…", - "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "V případě, že tato zpráva nezmizí, se podívejte na tyto často kladené otázky pro řešení.", - "+++ no paste text +++": "+++ žádný vložený text +++", - "Could not get paste data: %s": "Nepodařilo se získat data příspěvku: %s", + "Decrypting document…": "Dešifruji příspěvek…", + "Preparing new document…": "Připravuji nový příspěvek…", + "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "Pokud tato zpráva nezmizí, podívejte se na tyto často kladené otázky pro řešení problémů.", + "+++ no document text +++": "+++ žádný text příspěvku +++", + "Could not get document data: %s": "Nepodařilo se získat data příspěvku: %s", "QR code": "QR kód", - "This website is using an insecure HTTP connection! Please use it only for testing.": "Tato stránka používá nezabezpečený připojení HTTP! Použijte ji prosím jen pro testování.", - "For more information see this FAQ entry.": "Více informací naleznete v této položce FAQ.", + "This website is using an insecure HTTP connection! Please use it only for testing.": "Tato stránka používá nezabezpečené HTTP připojení! Použijte ji prosím jen pro testování.", + "For more information see this FAQ entry.": "Více informací naleznete v této položce FAQ.", "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": "Váš prohlížeč může vyžadovat připojení HTTPS pro podporu WebCrypto API. Zkuste přepnout na HTTPS.", - "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "Váš prohlížeč nepodporuje WebAssembly, který se používá pro zlib kompresi. Můžete vytvořit nekomprimované dokumenty, ale nebudete moct číst ty komprimované.", + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "Váš prohlížeč nepodporuje WebAssembly, které se používá pro zlib kompresi. Můžete vytvořit nekomprimované dokumenty, ale nebudete moct číst ty komprimované.", "waiting on user to provide a password": "čekám na zadání hesla", "Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Nepodařilo se dešifrovat data. Zadali jste špatné heslo? Zkuste to znovu pomocí tlačítka nahoře.", "Retry": "Opakovat", - "Showing raw text…": "Zobrazuji surový text…", + "Showing raw text…": "Zobrazuji čistý text…", "Notice:": "Upozornění:", "This link will expire after %s.": "Tento odkaz vyprší za %s.", - "This link can only be accessed once, do not use back or refresh button in your browser.": "Tento odkaz je přístupný pouze jednou, nepoužívejte tlačítko zpět ani neobnovujte tuto stránku ve vašem prohlížeči.", + "This link can only be accessed once, do not use back or refresh button in your browser.": "Tento odkaz je přístupný pouze jednou, nepoužívejte tlačítko zpět ani neobnovujte tuto stránku v prohlížeči.", "Link:": "Odkaz:", - "Recipient may become aware of your timezone, convert time to UTC?": "Příjemce se může dozvědět o vašem časovém pásmu, převést čas na UTC?", + "Recipient may become aware of your timezone, convert time to UTC?": "Příjemce může zjistit vaše časové pásmo, převést čas na UTC?", "Use Current Timezone": "Použít aktuální časové pásmo", "Convert To UTC": "Převést na UTC", "Close": "Zavřít", "Encrypted note on %s": "Šifrovaná poznámka ve službě %s", - "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Navštivte tento odkaz pro zobrazení poznámky. Přeposláním URL umožníte také jiným lidem přístup.", - "URL shortener may expose your decrypt key in URL.": "Zkracovač URL může odhalit váš dešifrovací klíč v URL.", - "Save paste": "Uložit příspěvek", - "Your IP is not authorized to create pastes.": "Vaše IP adresa nemá oprávnění k vytvoření vložení.", - "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Pro zobrazení poznámky navštivte tento odkaz. Přeposláním URL umožníte přístup také jiným lidem.", + "URL shortener may expose your decrypt key in URL.": "Zkracovač URL může prozradit váš dešifrovací klíč v URL.", + "URL shortener is enabled by default.": "Ve výchozím nastavení je zkracovač URL povolen.", + "Save document": "Uložit příspěvek", + "Your IP is not authorized to create documents.": "Vaše IP adresa nemá oprávnění k vytváření příspěvků.", + "Trying to shorten a URL that isn't pointing at our instance.": "Pokus o zkrácení URL, které neodkazuje na naši instanci.", + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Chyba volání YOURLS. Pravděpodobně chyba konfigurace, např. nesprávné či chybějící „apiurl“ nebo „signature“.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Chyba čtení odpovědi YOURLS.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "Tuto tajnou zprávu lze zobrazit pouze jednou. Chcete si ji prohlédnout teď?", + "Yes, see it": "Ano, zobrazit", + "Dark Mode": "Tmavý režim", + "Error compressing document, due to missing WebAssembly support.": "Chyba při komprimování příspěvku kvůli chybějící podpoře WebAssembly.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Chyba při dekomprimování příspěvku, váš prohlížeč nepodporuje WebAssembly. Pro zobrazení tohoto příspěvku prosím použijte jiný prohlížeč.", + "Start over": "Začít znovu", + "Document copied to clipboard": "Dokument zkopírován do schránky", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "Pro zkopírování dokumentu klikněte na tlačítko nebo použijte klávesovou zkratku schránky Ctrl+c/Cmd+c", + "Copy link": "Zkopírovat odkaz", + "Link copied to clipboard": "Odkaz zkopírován do schránky", + "Document text": "Text dokumentu", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulátor funguje jako znak (pro přepnutí stiskněte Ctrl+m nebo Esc)", + "Theme": "Vzhled" } diff --git a/i18n/de.json b/i18n/de.json index aab96561..c4ed5739 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s ist ein minimalistischer, quelloffener \"Pastebin\"-artiger Dienst, bei dem der Server keinerlei Kenntnis der Inhalte hat. Die Daten werden %sim Browser%s mit 256 Bit AES ver- und entschlüsselt.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s ist ein minimalistischer, quelloffener \"Pastebin\"-artiger Dienst, bei dem der Server keinerlei Kenntnis der Inhalte hat. Die Daten werden %sim Browser%s mit 256 Bit AES ver- und entschlüsselt.", "More information on the project page.": "Weitere Informationen sind auf der Projektseite zu finden.", - "Because ignorance is bliss": "Unwissenheit ist ein Segen", - "Paste does not exist, has expired or has been deleted.": "Diesen Text gibt es nicht, er ist abgelaufen oder wurde gelöscht.", + "Because ignorance is bliss": "Was ich nicht weiß, macht mich nicht heiß", + "Document does not exist, has expired or has been deleted.": "Dieses Dokument gibt es nicht, es ist abgelaufen oder wurde gelöscht.", "%s requires php %s or above to work. Sorry.": "%s benötigt PHP %s oder höher, um zu funktionieren. Sorry.", "%s requires configuration section [%s] to be present in configuration file.": "%s benötigt den Konfigurationsabschnitt [%s] in der Konfigurationsdatei um zu funktionieren.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Bitte warte %d Sekunden zwischen dem Absenden zweier Beiträge.", "Bitte warte %d Sekunden zwischen dem Absenden zweier Beiträge." ], - "Paste is limited to %s of encrypted data.": "Texte sind auf %s verschlüsselte Datenmenge beschränkt.", + "Document is limited to %s of encrypted data.": "Texte sind auf %s verschlüsselte Datenmenge beschränkt.", "Invalid data.": "Ungültige Daten.", "You are unlucky. Try again.": "Du hast Pech. Versuchs nochmal.", "Error saving comment. Sorry.": "Fehler beim Speichern des Kommentars. Sorry.", - "Error saving paste. Sorry.": "Fehler beim Speichern des Textes. Sorry.", - "Invalid paste ID.": "Ungültige Text-ID.", - "Paste is not of burn-after-reading type.": "Text ist kein \"Einmal\"-Typ.", - "Wrong deletion token. Paste was not deleted.": "Falscher Lösch-Code. Text wurde nicht gelöscht.", - "Paste was properly deleted.": "Text wurde erfolgreich gelöscht.", + "Error saving document. Sorry.": "Fehler beim Speichern des Textes. Sorry.", + "Invalid document ID.": "Ungültige Dokument-ID.", + "Document is not of burn-after-reading type.": "Dokument ist kein \"Einmal\"-Typ.", + "Wrong deletion token. Document was not deleted.": "Falscher Lösch-Code. Dokument wurde nicht gelöscht.", + "Document was properly deleted.": "Dokument wurde erfolgreich gelöscht.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript ist eine Voraussetzung, um %s zu nutzen. Bitte entschuldige die Unannehmlichkeiten.", "%s requires a modern browser to work.": "%s setzt einen modernen Browser voraus, um funktionieren zu können.", "New": "Neu", - "Send": "Senden", + "Create": "Erstellen", "Clone": "Klonen", "Raw text": "Reiner Text", "Expires": "Ablaufzeit", @@ -133,9 +133,9 @@ "Dieses Dokument läuft in %d Monaten ab.", "Dieses Dokument läuft in %d Monaten ab." ], - "Please enter the password for this paste:": "Bitte gib das Passwort für diesen Text ein:", + "Please enter the password for this document:": "Bitte gib das Passwort für dieses Dokument ein:", "Could not decrypt data (Wrong key?)": "Konnte Daten nicht entschlüsseln (Falscher Schlüssel?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Konnte das Paste nicht löschen, es wurde nicht im Einmal-Modus gespeichert.", + "Could not delete the document, it was not stored in burn after reading mode.": "Konnte das Document nicht löschen, es wurde nicht im Einmal-Modus gespeichert.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "DIESER TEXT IST NUR FÜR DICH GEDACHT. Schließe das Fenster nicht, diese Nachricht kann nur einmal geöffnet werden.", "Could not decrypt comment; Wrong key?": "Konnte Kommentar nicht entschlüsseln; Falscher Schlüssel?", "Reply": "Antworten", @@ -150,27 +150,27 @@ "unknown status": "Unbekannter Grund", "server error or not responding": "Fehler auf dem Server oder keine Antwort vom Server", "Could not post comment: %s": "Konnte Kommentar nicht senden: %s", - "Sending paste…": "Sende Paste…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Dein Text ist unter %s zu finden (Drücke [Strg]+[c] um den Link zu kopieren)", + "Sending document…": "Sende Document…", + "Your document is %s (Hit Ctrl+c to copy)": "Dein Dokument ist unter %s zu finden (Drücke Strg+c um den Link zu kopieren)", "Delete data": "Lösche Daten", - "Could not create paste: %s": "Text konnte nicht erstellt werden: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Konnte Paste nicht entschlüsseln: Der Schlüssel fehlt in der Adresse (Hast du eine Umleitung oder einen URL-Verkürzer benutzt, der Teile der Adresse entfernt?)", + "Could not create document: %s": "Dokument konnte nicht erstellt werden: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Konnte Document nicht entschlüsseln: Der Schlüssel fehlt in der Adresse (Hast du eine Umleitung oder einen URL-Verkürzer benutzt, der Teile der Adresse entfernt?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Nur Text", "Source Code": "Quellcode", "Markdown": "Markdown", "Download attachment": "Anhang herunterladen", "Cloned: '%s'": "Geklont: '%s'", - "The cloned file '%s' was attached to this paste.": "Die geklonte Datei '%s' wurde angehängt.", + "The cloned file '%s' was attached to this document.": "Die geklonte Datei '%s' wurde angehängt.", "Attach a file": "Datei anhängen", "alternatively drag & drop a file or paste an image from the clipboard": "Eine Datei kann auch durch ziehen und loslassen ausgewählt oder ein Bild aus der Zwischenablage einfügt werden.", "File too large, to display a preview. Please download the attachment.": "Datei zu groß, um als Vorschau angezeigt zu werden. Bitte Anhang herunterladen.", @@ -185,11 +185,11 @@ "Decrypt": "Entschlüsseln", "Enter password": "Passwort eingeben", "Loading…": "Lädt…", - "Decrypting paste…": "Entschlüssle Text…", - "Preparing new paste…": "Bereite neuen Text vor…", + "Decrypting document…": "Entschlüssle Text…", + "Preparing new document…": "Bereite neues Dokument vor…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "Wenn diese Nachricht nicht mehr verschwindet, schau bitte in die FAQ (Englisch), um zu sehen, wie der Fehler behoben werden kann.", - "+++ no paste text +++": "+++ kein Paste-Text +++", - "Could not get paste data: %s": "Text konnte nicht geladen werden: %s", + "+++ no document text +++": "+++ kein Text im Dokument +++", + "Could not get document data: %s": "Dokument konnte nicht geladen werden: %s", "QR code": "QR code", "This website is using an insecure HTTP connection! Please use it only for testing.": "Diese Webseite verwendet eine unsichere HTTP Verbindung! Bitte benutze sie nur zum Testen.", "For more information see this FAQ entry.": "Besuche diesen FAQ Eintrag für weitere Informationen dazu.", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Verschlüsselte Notiz auf %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Besuche diesen Link um das Dokument zu sehen. Wird die URL an eine andere Person gegeben, so kann diese Person ebenfalls auf dieses Dokument zugreifen.", "URL shortener may expose your decrypt key in URL.": "Der URL-Verkürzer kann den Schlüssel in der URL enthüllen.", - "Save paste": "Text speichern", - "Your IP is not authorized to create pastes.": "Deine IP ist nicht berechtigt, Texte zu erstellen.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Dokument speichern", + "Your IP is not authorized to create documents.": "Deine IP ist nicht berechtigt, Texte zu erstellen.", "Trying to shorten a URL that isn't pointing at our instance.": "Versuch eine URL zu verkürzen, die nicht auf unsere Instanz zeigt.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Fehler beim Aufruf von YOURLS. Wahrscheinlich ein Konfigurationsproblem, wie eine falsche oder fehlende \"apiurl\" oder \"signature\".", - "Error parsing YOURLS response.": "Fehler beim Verarbeiten der YOURLS-Antwort.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Texte des \"Einmal\"-Typs können nach dem Herunterladen nur einmal angezeigt werden. Möchtest Du ihn jetzt öffnen?", - "Yes, load it": "Ja, jetzt öffnen" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Fehler beim Aufruf von YOURLS. Wahrscheinlich ein Konfigurationsproblem, wie eine falsche oder fehlende \"apiurl\" oder \"signature\".", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Fehler beim Verarbeiten der YOURLS-Antwort.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "Texte des \"Einmal\"-Typs können nach dem Öffnen nur einmal angezeigt werden. Möchtest Du ihn jetzt einsehen?", + "Yes, see it": "Ja, jetzt einsehen", + "Dark Mode": "Nachtmodus", + "Error compressing document, due to missing WebAssembly support.": "Fehler beim Komprimieren des Textes, da WebAssembly-Unterstützung fehlt.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Fehler beim Dekomprimieren des Dokumentes. Dein Browser unterstützt WebAssembly nicht. Bitte verwende einen anderen Browser, um dieses Dokument anzuzeigen.", + "Start over": "Neues Dokument erstellen", + "Document copied to clipboard": "Dokument wurde in Zwischenablage kopiert.", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "Zum Kopieren des Textes drücken Sie die Kopieren-Schaltfläche oder verwenden Sie die Tastenkombination Strg+c/Cmd+c", + "Copy link": "Verknüpfung kopieren", + "Link copied to clipboard": "Verknüpfung wurde in die Zwischenablage kopiert.", + "Document text": "Text des Dokuments", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulatortaste als Zeichen interpretieren (Umschalten durch Strg+m oder Esc)", + "Theme": "Design" } diff --git a/i18n/el.json b/i18n/el.json index 94e13fb9..0be86a5c 100644 --- a/i18n/el.json +++ b/i18n/el.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s είναι ένα λιτό, ανοικτού λογισμικού διαδικτυακής υπηρεσίας επικόλλησης όπου ο διακομιστής έχει πλήρη άγνια του περιεχομένου που επικολλήθηκαν. Τα Δεδομένα κρυπτογραφούνται και αποκρυπτογραφούνται %sστον φιλομετρητή (browser)%s χρησιμοποιόντας 256 bits AES.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "Το %s αποτελεί ένα εργαλείο επικόλλησης δεδομένων στο διαδίκτυο, που βασίζεται σε λογισμικό ανοιχτού κώδικα. Ο διακομιστής έχει πλήρη άγνοια αυτών των δεδομένων, τα οποία από/κρυπτογραφούνται %sστο πρόγραμμα περιήγησης%s, χρησιμοποιώντας τη μέθοδο 256-bits AES.", "More information on the project page.": "Περισσότερες πληροφορίες στον ιστότοπο του εργαλείου.", "Because ignorance is bliss": "Επειδή η άγνοια είναι ευτυχία", - "Paste does not exist, has expired or has been deleted.": "Η επικόλληση δεν υπάρχει, έληξε ή διαγράφηκε", + "Document does not exist, has expired or has been deleted.": "Η επικόλληση δεν υπάρχει, έληξε ή διαγράφηκε", "%s requires php %s or above to work. Sorry.": "%s απαιτεί php %s ή νεότερη για να λειτουργήσει. Συγγνώμη.", "%s requires configuration section [%s] to be present in configuration file.": "%s απαιτεί οι ρυθμίσεις [%s] να υπάρχουν στο αρχείο ρυθμίσεων.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Παρακαλώ περιμένετε %d δευτερόλεπτα μεταξύ κάθε επικόλλησης.", "Παρακαλώ περιμένετε %d δευτερόλεπτα μεταξύ κάθε επικόλλησης." ], - "Paste is limited to %s of encrypted data.": "Η επικόλληση είναι περιορισμένη σε %s κρυπτογραφημένων δεδομένων.", + "Document is limited to %s of encrypted data.": "Η επικόλληση είναι περιορισμένη σε %s κρυπτογραφημένων δεδομένων.", "Invalid data.": "Λάθος δεδομένα.", "You are unlucky. Try again.": "Ατυχήσατε. Προσπαθήστε πάλι.", "Error saving comment. Sorry.": "Λάθος στην αποθήκευση του σχόλιου. Συγγνώμη.", - "Error saving paste. Sorry.": "Λάθος στην αποθήκευση της επικόλλησης. Συγγνώμη.", - "Invalid paste ID.": "Λάθος αναγνωριστικό επικόλλησης.", - "Paste is not of burn-after-reading type.": "Η επικόληση δεν είναι τύπου καταστροφή-μετά-το-διάβασμα.", - "Wrong deletion token. Paste was not deleted.": "Λάθος αναγνωριστικό διαγραφής. Η επικόλληση δεν διαγράφηκε.", - "Paste was properly deleted.": "Η επικόλληση διαγράφηκε επιτυχώς.", + "Error saving document. Sorry.": "Λάθος στην αποθήκευση της επικόλλησης. Συγγνώμη.", + "Invalid document ID.": "Λάθος αναγνωριστικό επικόλλησης.", + "Document is not of burn-after-reading type.": "Η επικόληση δεν είναι τύπου καταστροφή-μετά-το-διάβασμα.", + "Wrong deletion token. Document was not deleted.": "Λάθος αναγνωριστικό διαγραφής. Η επικόλληση δεν διαγράφηκε.", + "Document was properly deleted.": "Η επικόλληση διαγράφηκε επιτυχώς.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "Η JavaScript είναι απαραίτητη για να λειτουργήσει το %s. Συγγνώμη για την ταλαιπωρία.", "%s requires a modern browser to work.": "%s απαιτεί σύγχρονο φυλλομετρητή (browser) για να λειτουργήσει.", "New": "Νέο", - "Send": "Αποστολή", + "Create": "Δημιουργία", "Clone": "Κλωνοποίηση", "Raw text": "Κείμενο", "Expires": "Λήγει", @@ -133,9 +133,9 @@ "Αυτό το έγγραφο θα λήξει σε %d μήνες.", "Αυτό το έγγραφο θα λήξει σε %d μήνες." ], - "Please enter the password for this paste:": "Παρακαλώ εισάγετε τον κωδικό για αυτή την επικόληση:", + "Please enter the password for this document:": "Παρακαλώ εισάγετε τον κωδικό για αυτή την επικόληση:", "Could not decrypt data (Wrong key?)": "Δεν ήταν δυνατή η αποκρυπτογράφηση των δεδομένων (πιθανώς λανθασμένο κλειδί;)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Δεν ήταν δυνατή η διαγραφή της επικόλλησης, δεν ήταν αποθηκευμένη σε μορφή διαγραφής μετά την ανάγνωση.", + "Could not delete the document, it was not stored in burn after reading mode.": "Δεν ήταν δυνατή η διαγραφή της επικόλλησης, δεν ήταν αποθηκευμένη σε μορφή διαγραφής μετά την ανάγνωση.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "ΜΟΝΟ ΓΙΑ ΕΣΑΣ. Μην κλείσετε το αυτό το παράθυρο, αυτό το μήνυμα δεν μπορεί να εμφανιστεί ξανά.", "Could not decrypt comment; Wrong key?": "Δεν ήταν δυνατή η αποκρυπτογράφηση του σχολίου. Λάθος κλειδί;", "Reply": "Απάντηση", @@ -150,27 +150,27 @@ "unknown status": "άγνωστη κατάσταση", "server error or not responding": "Πρόβλημα του διακομιστή ή δεν υπάρχει απάντηση", "Could not post comment: %s": "Δεν ήταν δυνατή η δημοσίευση του σχολίου: %s", - "Sending paste…": "Η επικόλληση αποστέλλεται…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Η επικόλλησή σας είναι %s (Πληκτρολογήστε [Ctrl]+[c] για αντιγραφή)", + "Sending document…": "Η επικόλληση αποστέλλεται…", + "Your document is %s (Hit Ctrl+c to copy)": "Η επικόλλησή σας είναι %s (Πληκτρολογήστε Ctrl+c για αντιγραφή)", "Delete data": "Διαγραφή δεδομένων", - "Could not create paste: %s": "Δεν ήταν δυνατή η δημιουργία επικόλλησης: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Δεν ήταν δυνατή η αποκρυπτογράφηση της επικόλλησης: Το κλειδί αποκρυπτογράφησης λείπει από τον σύνδεσμο (Μήπως χρησιμοποιήσατε ανακατεύθυνση συνδέσμου ή υπηρεσία συντόμευσης συνδέσμου;)", + "Could not create document: %s": "Δεν ήταν δυνατή η δημιουργία επικόλλησης: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Δεν ήταν δυνατή η αποκρυπτογράφηση της επικόλλησης: Το κλειδί αποκρυπτογράφησης λείπει από τον σύνδεσμο (Μήπως χρησιμοποιήσατε ανακατεύθυνση συνδέσμου ή υπηρεσία συντόμευσης συνδέσμου;)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Μορφοποίηση", "Plain Text": "Απλό κείμενο", "Source Code": "Πηγαίος Κώδικας", "Markdown": "Markdown", "Download attachment": "Λήψη επισυναπτόμενου", "Cloned: '%s'": "Κλώνος: '%s'", - "The cloned file '%s' was attached to this paste.": "Το κλωνοποιημένο αρχείο '%s' επισυνάφθηκε στ αυτή την επικόλληση.", + "The cloned file '%s' was attached to this document.": "Το κλωνοποιημένο αρχείο '%s' επισυνάφθηκε στ αυτή την επικόλληση.", "Attach a file": "Επισύναψη αρχείου", "alternatively drag & drop a file or paste an image from the clipboard": "εναλλακτικά σύρετε το αρχείο ή επικολλήστε μία εικόνα από το clipboard", "File too large, to display a preview. Please download the attachment.": "Πολύ μεγάλο αρχείο για προεπισκόπηση. Παρακαλώ κατεβάστε το επισυναπτόμενο.", @@ -185,11 +185,11 @@ "Decrypt": "Αποκρυπτογράφηση", "Enter password": "Εισαγωγή κωδικού", "Loading…": "Φόρτωση…", - "Decrypting paste…": "Η επικόλληση αποκρυπτογραφείται…", - "Preparing new paste…": "Προετοιμασία νέας επικόλλησης…", + "Decrypting document…": "Η επικόλληση αποκρυπτογραφείται…", + "Preparing new document…": "Προετοιμασία νέας επικόλλησης…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "Σε περίπτωση που αυτό το μήνυμα δεν εξαφανίζεται παρακαλώ κοιτάξτε στις Ερωταποκρίσεις για πληροφορίες στην αντιμετώπιση προβλημάτων.", - "+++ no paste text +++": "+++ Δεν υπάρχει επικόλληση +++", - "Could not get paste data: %s": "Δεν ήταν δυνατή η λήψη της επικόλλησης: %s", + "+++ no document text +++": "+++ Δεν υπάρχει επικόλληση +++", + "Could not get document data: %s": "Δεν ήταν δυνατή η λήψη της επικόλλησης: %s", "QR code": "QR εικονοστοιχειοσειρά", "This website is using an insecure HTTP connection! Please use it only for testing.": "Αυτός ο ιστότοπος χρησιμοποιεί μη ασφαλή HTTP σύνδεση! Παρακαλώ χρησιμοποιήστε το μόνο δοκιμαστικά.", "For more information see this FAQ entry.": "Για περισσότερες πληροφορίες δείτε τις ερωταπαντήσεις.", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Κρυπτογραφημένο μήνυμα από το %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Επισκεφτείτε αυτόν τον σύνδεσμο για να δείτε το μήνυμα. Δίνοντας τον σύνδεσμο σε οποιονδήποτε, του επιτρέπετε να επισκεφτεί το μήνυμα επίσης.", "URL shortener may expose your decrypt key in URL.": "Συντομευτές συνδέσμων πιθανώς να δημοσιοποιήσουν το κλειδί αποκρυπτογράφισης στον σύνδεσμο.", - "Save paste": "Αποθήκευση επικόλλησης", - "Your IP is not authorized to create pastes.": "Η IP σας δεν επιτρέπεται να δημιουργεί επικολλήσεις.", - "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Αποθήκευση επικόλλησης", + "Your IP is not authorized to create documents.": "Η IP σας δεν επιτρέπεται να δημιουργεί επικολλήσεις.", + "Trying to shorten a URL that isn't pointing at our instance.": "Έγινε προσπάθεια συντόμευσης ενός URL που δε δείχνει προς τη δική μας υπηρεσία.", + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Σφάλμα κατά την κλήση YOURLS. Πιθανώς ένα ζήτημα διαμόρφωσης, όπως λάθος ή λείπει \"apiurl\" ή \"υπογραφή\".", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Σφάλμα ανάλυσης της απόκρισης YOURLS.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "Αυτό το μυστικό μήνυμα μπορεί να εμφανιστεί μόνο μία φορά. Θα θέλατε να το δείτε τώρα;", + "Yes, see it": "Ναι, δείτε το", + "Dark Mode": "Σκοτεινό Θέμα", + "Error compressing document, due to missing WebAssembly support.": "Σφάλμα συμπίεσης επικόλλησης, λόγω έλλειψης υποστήριξης WebAssembly.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Σφάλμα αποσυμπίεσης της επικόλλησης, ο περιηγητής σας δεν υποστηρίζει WebAssembly. Παρακαλούμε χρησιμοποιήστε έναν άλλο περιηγητή για να δείτε αυτή την επικόλληση.", + "Start over": "Start over", + "Document copied to clipboard": "Document copied to clipboard", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/en.json b/i18n/en.json index 6ef3280b..c0d21fca 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.", "More information on the project page.": "More information on the project page.", "Because ignorance is bliss": "Because ignorance is bliss", - "Paste does not exist, has expired or has been deleted.": "Paste does not exist, has expired or has been deleted.", + "Document does not exist, has expired or has been deleted.": "Document does not exist, has expired or has been deleted.", "%s requires php %s or above to work. Sorry.": "%s requires php %s or above to work. Sorry.", "%s requires configuration section [%s] to be present in configuration file.": "%s requires configuration section [%s] to be present in configuration file.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Please wait %d seconds between each post. (4th plural)", "Please wait %d seconds between each post. (5th plural)" ], - "Paste is limited to %s of encrypted data.": "Paste is limited to %s of encrypted data.", + "Document is limited to %s of encrypted data.": "Document is limited to %s of encrypted data.", "Invalid data.": "Invalid data.", "You are unlucky. Try again.": "You are unlucky. Try again.", "Error saving comment. Sorry.": "Error saving comment. Sorry.", - "Error saving paste. Sorry.": "Error saving paste. Sorry.", - "Invalid paste ID.": "Invalid paste ID.", - "Paste is not of burn-after-reading type.": "Paste is not of burn-after-reading type.", - "Wrong deletion token. Paste was not deleted.": "Wrong deletion token. Paste was not deleted.", - "Paste was properly deleted.": "Paste was properly deleted.", + "Error saving document. Sorry.": "Error saving document. Sorry.", + "Invalid document ID.": "Invalid document ID.", + "Document is not of burn-after-reading type.": "Document is not of burn-after-reading type.", + "Wrong deletion token. Document was not deleted.": "Wrong deletion token. Document was not deleted.", + "Document was properly deleted.": "Document was properly deleted.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript is required for %s to work. Sorry for the inconvenience.", "%s requires a modern browser to work.": "%s requires a modern browser to work.", "New": "New", - "Send": "Send", + "Create": "Create", "Clone": "Clone", "Raw text": "Raw text", "Expires": "Expires", @@ -133,9 +133,9 @@ "This document will expire in %d months. (4th plural)", "This document will expire in %d months. (5th plural)" ], - "Please enter the password for this paste:": "Please enter the password for this paste:", + "Please enter the password for this document:": "Please enter the password for this document:", "Could not decrypt data (Wrong key?)": "Could not decrypt data (Wrong key?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Could not delete the paste, it was not stored in burn after reading mode.", + "Could not delete the document, it was not stored in burn after reading mode.": "Could not delete the document, it was not stored in burn after reading mode.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.", "Could not decrypt comment; Wrong key?": "Could not decrypt comment; Wrong key?", "Reply": "Reply", @@ -150,27 +150,27 @@ "unknown status": "unknown status", "server error or not responding": "server error or not responding", "Could not post comment: %s": "Could not post comment: %s", - "Sending paste…": "Sending paste…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Your paste is %s (Hit [Ctrl]+[c] to copy)", + "Sending document…": "Sending document…", + "Your document is %s (Hit Ctrl+c to copy)": "Your document is %s (Hit Ctrl+c to copy)", "Delete data": "Delete data", - "Could not create paste: %s": "Could not create paste: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)", + "Could not create document: %s": "Could not create document: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Plain Text", "Source Code": "Source Code", "Markdown": "Markdown", "Download attachment": "Download attachment", "Cloned: '%s'": "Cloned: '%s'", - "The cloned file '%s' was attached to this paste.": "The cloned file '%s' was attached to this paste.", + "The cloned file '%s' was attached to this document.": "The cloned file '%s' was attached to this document.", "Attach a file": "Attach a file", "alternatively drag & drop a file or paste an image from the clipboard": "alternatively drag & drop a file or paste an image from the clipboard", "File too large, to display a preview. Please download the attachment.": "File too large, to display a preview. Please download the attachment.", @@ -185,11 +185,11 @@ "Decrypt": "Decrypt", "Enter password": "Enter password", "Loading…": "Loading…", - "Decrypting paste…": "Decrypting paste…", - "Preparing new paste…": "Preparing new paste…", + "Decrypting document…": "Decrypting document…", + "Preparing new document…": "Preparing new document…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "In case this message never disappears please have a look at this FAQ for information to troubleshoot.", - "+++ no paste text +++": "+++ no paste text +++", - "Could not get paste data: %s": "Could not get paste data: %s", + "+++ no document text +++": "+++ no document text +++", + "Could not get document data: %s": "Could not get document data: %s", "QR code": "QR code", "This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.", "For more information see this FAQ entry.": "For more information see this FAQ entry.", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Encrypted note on %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.", "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.", - "Save paste": "Save paste", - "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Save document", + "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.", "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?", + "Yes, see it": "Yes, see it", + "Dark Mode": "Dark Mode", + "Error compressing document, due to missing WebAssembly support.": "Error compressing document, due to missing WebAssembly support.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.", + "Start over": "Start over", + "Document copied to clipboard": "Document copied to clipboard", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/es.json b/i18n/es.json index e5e4c9b5..a792b5ab 100644 --- a/i18n/es.json +++ b/i18n/es.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s es un \"pastebin\" en línea minimalista de código abierto, donde el servidor no tiene ningún conocimiento de los datos guardados. Los datos son cifrados/descifrados %sen el navegador%s usando 256 bits AES.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s es un \"pastebin\" en línea minimalista de código abierto, donde el servidor no tiene ningún conocimiento de los datos guardados. Los datos son cifrados/descifrados %sen el navegador%s usando 256 bits AES.", "More information on the project page.": "Más información en la página del proyecto.", "Because ignorance is bliss": "Porque la ignorancia es felicidad", - "Paste does not exist, has expired or has been deleted.": "El \"paste\" no existe, ha caducado o ha sido eliminado.", + "Document does not exist, has expired or has been deleted.": "El documento no existe, ha caducado o ha sido eliminado.", "%s requires php %s or above to work. Sorry.": "%s requiere php %s o superior para funcionar. Lo siento.", "%s requires configuration section [%s] to be present in configuration file.": "%s requiere que la sección de configuración [%s] esté presente en el archivo de configuración.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Por favor espere %d segundos entre cada publicación.", "Por favor espere %d segundos entre cada publicación." ], - "Paste is limited to %s of encrypted data.": "El \"paste\" está limitado a %s de datos cifrados.", + "Document is limited to %s of encrypted data.": "El documento está limitado a %s de datos cifrados.", "Invalid data.": "Datos inválidos.", "You are unlucky. Try again.": "Tienes mala suerte. Inténtalo de nuevo", "Error saving comment. Sorry.": "Error al guardar el comentario. Lo siento.", - "Error saving paste. Sorry.": "Error al guardar el \"paste\". Lo siento", - "Invalid paste ID.": "ID del \"paste\" inválido.", - "Paste is not of burn-after-reading type.": "El \"paste\" no es del tipo \"destruir despues de leer\".", - "Wrong deletion token. Paste was not deleted.": "Token de eliminación erróneo. El \"paste\" no fue eliminado.", - "Paste was properly deleted.": "El \"paste\" se ha eliminado correctamente.", + "Error saving document. Sorry.": "Error al guardar el documento. Lo siento", + "Invalid document ID.": "ID del documento inválido.", + "Document is not of burn-after-reading type.": "El documento no es del tipo \"destruir despues de leer\".", + "Wrong deletion token. Document was not deleted.": "Token de eliminación erróneo. El documento no fue eliminado.", + "Document was properly deleted.": "El documento se ha eliminado correctamente.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript es necesario para que %s funcione. Sentimos los inconvenientes ocasionados.", "%s requires a modern browser to work.": "%s requiere un navegador moderno para funcionar.", "New": "Nuevo", - "Send": "Enviar", + "Create": "Crear", "Clone": "Clonar", "Raw text": "Texto sin formato", "Expires": "Caducar en", @@ -133,9 +133,9 @@ "Este documento caducará en %d meses", "Este documento caducará en %d meses" ], - "Please enter the password for this paste:": "Por favor ingrese la contraseña para este \"paste\":", + "Please enter the password for this document:": "Por favor ingrese la contraseña para este documento:", "Could not decrypt data (Wrong key?)": "No fue posible descifrar los datos (¿Clave errónea?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "No fue posible eliminar el documento, no fue guardado en modo \"destruir despues de leer\".", + "Could not delete the document, it was not stored in burn after reading mode.": "No fue posible eliminar el documento, no fue guardado en modo \"destruir despues de leer\".", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "SÓLO PARA TUS OJOS. No cierres esta ventana, este mensaje no se puede volver a mostrar.", "Could not decrypt comment; Wrong key?": "No se pudo descifrar el comentario; ¿Llave incorrecta?", "Reply": "Responder", @@ -150,27 +150,27 @@ "unknown status": "Estado desconocido", "server error or not responding": "Error del servidor o el servidor no responde", "Could not post comment: %s": "No fue posible publicar comentario: %s", - "Sending paste…": "Enviando \"paste\"…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Su texto está en %s (Presione [Ctrl]+[c] para copiar)", + "Sending document…": "Enviando documento…", + "Your document is %s (Hit Ctrl+c to copy)": "Su texto está en %s (Presione Ctrl+c para copiar)", "Delete data": "Eliminar datos", - "Could not create paste: %s": "No fue posible crear el archivo: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "No es posible descifrar el documento: Falta la clave de descifrado en la URL (¿Utilizó un redirector o un acortador de URL que quite parte de la URL?)", + "Could not create document: %s": "No fue posible crear el archivo: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "No es posible descifrar el documento: Falta la clave de descifrado en la URL (¿Utilizó un redirector o un acortador de URL que quite parte de la URL?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Formato", "Plain Text": "Texto sin formato", "Source Code": "Código fuente", "Markdown": "Markdown", "Download attachment": "Descargar adjunto", "Cloned: '%s'": "Clonado: '%s'.", - "The cloned file '%s' was attached to this paste.": "El archivo clonado '%s' ha sido adjuntado a este texto.", + "The cloned file '%s' was attached to this document.": "El archivo clonado '%s' ha sido adjuntado a este texto.", "Attach a file": "Adjuntar archivo", "alternatively drag & drop a file or paste an image from the clipboard": "alternativamente, arrastre y suelte un archivo o pegue una imagen desde el portapapeles", "File too large, to display a preview. Please download the attachment.": "Archivo demasiado grande para mostrar una vista previa. Por favor, descargue el archivo adjunto.", @@ -185,11 +185,11 @@ "Decrypt": "Descifrar", "Enter password": "Ingrese contraseña", "Loading…": "Cargando…", - "Decrypting paste…": "Descifrando \"paste\"…", - "Preparing new paste…": "Preparando \"paste\" nuevo…", + "Decrypting document…": "Descifrando documento…", + "Preparing new document…": "Preparando documento nuevo…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "En caso de que este mensaje nunca desaparezca por favor revise este FAQ para obtener información para solucionar problemas.", - "+++ no paste text +++": "+++ \"paste\" sin texto +++", - "Could not get paste data: %s": "No se pudieron obtener los datos: %s", + "+++ no document text +++": "+++ documento sin texto +++", + "Could not get document data: %s": "No se pudieron obtener los datos: %s", "QR code": "Código QR", "This website is using an insecure HTTP connection! Please use it only for testing.": "¡Este sitio está usando una conexión HTTP insegura! Por favor úselo solo para pruebas.", "For more information see this FAQ entry.": "Para más información consulte esta entrada de las preguntas frecuentes.", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Nota cifrada en %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visite este enlace para ver la nota. Dar la URL a cualquier persona también les permite acceder a la nota.", "URL shortener may expose your decrypt key in URL.": "El acortador de URL puede exponer su clave de descifrado en el URL.", - "Save paste": "Guardar \"paste\"", - "Your IP is not authorized to create pastes.": "Tu IP no está autorizada para crear contenido.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Guardar documento", + "Your IP is not authorized to create documents.": "Tu IP no está autorizada para crear contenido.", "Trying to shorten a URL that isn't pointing at our instance.": "Intentando acortar una URL que no apunta a nuestra instancia.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Error llamando a YOURLS. Probablemente un problema de configuración, como error o falta \"apiurl\" o \"signature\".", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Error al analizar la respuesta de YOURLS.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "Este mensaje secreto sólo se puede mostrar una vez. ¿Quieres verlo ahora?", + "Yes, see it": "Sí, verlo", + "Dark Mode": "Modo nocturno", + "Error compressing document, due to missing WebAssembly support.": "Error compressing document, due to missing WebAssembly support.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.", + "Start over": "Start over", + "Document copied to clipboard": "Document copied to clipboard", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/et.json b/i18n/et.json index e589197b..dfa643e3 100644 --- a/i18n/et.json +++ b/i18n/et.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s on minimalistlik, avatud lähtekoodiga online pastebin, kus serveril pole kleebitud andmete kohta teadmist. Andmed krüpteeritakse/dekrüpteeritakse %sbrauseris%s kasutades 256-bitist AES-i.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s on minimalistlik, avatud lähtekoodiga online pastebin, kus serveril pole kleebitud andmete kohta teadmist. Andmed krüpteeritakse/dekrüpteeritakse %sbrauseris%s kasutades 256-bitist AES-i.", "More information on the project page.": "Lisateave projekti lehel.", "Because ignorance is bliss": "Kuna teadmatus on õndsus", - "Paste does not exist, has expired or has been deleted.": "Kleebet ei eksisteeri, on aegunud või on kustutatud.", + "Document does not exist, has expired or has been deleted.": "Kleebet ei eksisteeri, on aegunud või on kustutatud.", "%s requires php %s or above to work. Sorry.": "%s vajab, et oleks php %s või kõrgem, et töötada. Vabandame.", "%s requires configuration section [%s] to be present in configuration file.": "%s vajab, et [%s] seadistamise jaotis oleks olemas konfiguratsioonifailis.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Palun oota %d sekundit iga postituse vahel.", "Palun oota %d sekundit iga postituse vahel." ], - "Paste is limited to %s of encrypted data.": "Kleepe limiit on %s krüpteeritud andmeid.", + "Document is limited to %s of encrypted data.": "Kleepe limiit on %s krüpteeritud andmeid.", "Invalid data.": "Valed andmed.", "You are unlucky. Try again.": "Sul ei vea. Proovi uuesti.", "Error saving comment. Sorry.": "Viga kommentaari salvestamisel. Vabandame.", - "Error saving paste. Sorry.": "Viga kleepe salvestamisel. Vabandame.", - "Invalid paste ID.": "Vale kleepe ID.", - "Paste is not of burn-after-reading type.": "Kleebe ei ole põleta-pärast-lugemist tüüpi.", - "Wrong deletion token. Paste was not deleted.": "Vale kustutamiskood. Kleebet ei kustutatud.", - "Paste was properly deleted.": "Kleebe kustutati korralikult.", + "Error saving document. Sorry.": "Viga kleepe salvestamisel. Vabandame.", + "Invalid document ID.": "Vale kleepe ID.", + "Document is not of burn-after-reading type.": "Kleebe ei ole põleta-pärast-lugemist tüüpi.", + "Wrong deletion token. Document was not deleted.": "Vale kustutamiskood. Kleebet ei kustutatud.", + "Document was properly deleted.": "Kleebe kustutati korralikult.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript on vajalik %s'i töötamiseks. Vabandame ebamugavuste pärast.", "%s requires a modern browser to work.": "%s vajab töötamiseks kaasaegset brauserit.", "New": "Uus", - "Send": "Saada", + "Create": "Loo", "Clone": "Klooni", "Raw text": "Lähtetekst", "Expires": "Aegub", @@ -133,9 +133,9 @@ "See dokument aegub %d kuu pärast.", "See dokument aegub %d kuu pärast." ], - "Please enter the password for this paste:": "Palun sisesta selle kleepe parool:", + "Please enter the password for this document:": "Palun sisesta selle kleepe parool:", "Could not decrypt data (Wrong key?)": "Ei suutnud andmeid dekrüpteerida (Vale võti?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Ei suutnud kleebet kustutada, seda ei salvestatud põleta pärast lugemist režiimis.", + "Could not delete the document, it was not stored in burn after reading mode.": "Ei suutnud kleebet kustutada, seda ei salvestatud põleta pärast lugemist režiimis.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "AINULT SINU SILMADELE. Ära sulge seda akent, seda sõnumit ei saa enam kuvada.", "Could not decrypt comment; Wrong key?": "Ei suutnud kommentaari dekrüpteerida; Vale võti?", "Reply": "Vasta", @@ -150,27 +150,27 @@ "unknown status": "tundmatu staatus", "server error or not responding": "serveri viga või ei vasta", "Could not post comment: %s": "Ei suutnud kommentaari postitada: %s", - "Sending paste…": "Kleepe saatmine…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Sinu kleebe on %s (Kopeerimiseks vajuta [Ctrl]+[c])", + "Sending document…": "Kleepe saatmine…", + "Your document is %s (Hit Ctrl+c to copy)": "Sinu kleebe on %s (Kopeerimiseks vajuta Ctrl+c)", "Delete data": "Kustuta andmed", - "Could not create paste: %s": "Ei suutnud kleebet luua: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Ei suutnud kleebet dekrüpteerida: Dekrüpteerimisvõti on URL-ist puudu (Kas kasutasid ümbersuunajat või URL-i lühendajat, mis eemaldab osa URL-ist?)", + "Could not create document: %s": "Ei suutnud kleebet luua: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Ei suutnud kleebet dekrüpteerida: Dekrüpteerimisvõti on URL-ist puudu (Kas kasutasid ümbersuunajat või URL-i lühendajat, mis eemaldab osa URL-ist?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Formaat", "Plain Text": "Lihttekst", "Source Code": "Lähtekood", "Markdown": "Markdown", "Download attachment": "Laadi manus alla", "Cloned: '%s'": "Kloonitud: '%s'", - "The cloned file '%s' was attached to this paste.": "Kloonitud fail '%s' manustati sellele kleepele.", + "The cloned file '%s' was attached to this document.": "Kloonitud fail '%s' manustati sellele kleepele.", "Attach a file": "Manusta fail", "alternatively drag & drop a file or paste an image from the clipboard": "teise võimalusena lohista fail või kleebi pilt lõikelaualt", "File too large, to display a preview. Please download the attachment.": "Fail on eelvaate kuvamiseks liiga suur. Palun laadi manus alla.", @@ -185,11 +185,11 @@ "Decrypt": "Dekrüpteeri", "Enter password": "Sisesta parool", "Loading…": "Laadimine…", - "Decrypting paste…": "Kleepe dekrüpteerimine…", - "Preparing new paste…": "Uue kleepe ettevalmistamine…", + "Decrypting document…": "Kleepe dekrüpteerimine…", + "Preparing new document…": "Uue kleepe ettevalmistamine…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "Kui see sõnum ei kao, palun vaata seda KKK-d, et saada tõrkeotsinguks teavet..", - "+++ no paste text +++": "+++ kleepe tekst puudub +++", - "Could not get paste data: %s": "Ei suutnud saada kleepe andmeid: %s", + "+++ no document text +++": "+++ kleepe tekst puudub +++", + "Could not get document data: %s": "Ei suutnud saada kleepe andmeid: %s", "QR code": "QR kood", "This website is using an insecure HTTP connection! Please use it only for testing.": "See veebisait kasutab ebaturvalist HTTP ühendust! Palun kasuta seda ainult katsetamiseks.", "For more information see this FAQ entry.": "Lisateabe saamiseks vaata seda KKK sissekannet.", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Krüpteeritud kiri %s-is", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Kirja nägemiseks külasta seda linki. Teistele URL-i andmine lubab ka neil ligi pääseda kirjale.", "URL shortener may expose your decrypt key in URL.": "URL-i lühendaja võib paljastada sinu dekrüpteerimisvõtme URL-is.", - "Save paste": "Salvesta kleebe", - "Your IP is not authorized to create pastes.": "Su IP-l ei ole lubatud kleepeid luua.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Salvesta kleebe", + "Your IP is not authorized to create documents.": "Su IP-l ei ole lubatud kleepeid luua.", "Trying to shorten a URL that isn't pointing at our instance.": "Püüame lühendada URL-i, mis ei viita meie instantsile.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Viga YOURLS-i kutsumisel. Tõenäoliselt konfiguratsiooniprobleem, näiteks vale või puuduv \"apiurl\" või \"signature\".", - "Error parsing YOURLS response.": "Viga YOURLS vastuse parsimisel.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Viga YOURLS-i kutsumisel. Tõenäoliselt konfiguratsiooniprobleem, näiteks vale või puuduv \"apiurl\" või \"signature\".", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Viga YOURLS vastuse parsimisel.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "Seda turvalist sõnumit saab kuvada vaid ühe korra. \nKas soovid seda näha nüüd?", + "Yes, see it": "Jah, vaata seda", + "Dark Mode": "Tume režiim", + "Error compressing document, due to missing WebAssembly support.": "Error compressing document, due to missing WebAssembly support.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.", + "Start over": "Alusta uuesti", + "Document copied to clipboard": "Kleebe kopeeriti lõikelauale", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Kopeeri link", + "Link copied to clipboard": "Link kopeeriti lõikelauale", + "Document text": "Kleebi tekst", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Teema" } diff --git a/i18n/fi.json b/i18n/fi.json index da935c52..185db758 100644 --- a/i18n/fi.json +++ b/i18n/fi.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s on minimalistinen, avoimen lähdekoodin online pastebin jossa palvelimella ei ole tietoa syötetystä datasta. Data salataan/puretaan %sselaimessa%s käyttäen 256-bittistä AES:ää.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s on minimalistinen, avoimen lähdekoodin online pastebin jossa palvelimella ei ole tietoa syötetystä datasta. Data salataan/puretaan %sselaimessa%s käyttäen 256-bittistä AES:ää.", "More information on the project page.": "Lisää tietoa projektisivulla.", "Because ignorance is bliss": "Koska tieto lisää tuskaa", - "Paste does not exist, has expired or has been deleted.": "Pastea ei ole olemassa, se on vanhentunut tai se on poistettu.", + "Document does not exist, has expired or has been deleted.": "Pastea ei ole olemassa, se on vanhentunut tai se on poistettu.", "%s requires php %s or above to work. Sorry.": "%s vaatii php:n %s-version tai uudemman toimiakseen. Anteeksi.", "%s requires configuration section [%s] to be present in configuration file.": "%s vaatii konfiguraatio-osion [%s] olevan läsnä konfiguraatiotiedostossa.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Odotathan %d sekuntia jokaisen lähetyksen välillä.", "Odotathan %d sekuntia jokaisen lähetyksen välillä." ], - "Paste is limited to %s of encrypted data.": "Paste on rajoitettu kokoon %s salattua dataa.", + "Document is limited to %s of encrypted data.": "Asiakirja on rajoitettu kokoon %s salattua dataa.", "Invalid data.": "Virheellinen data.", "You are unlucky. Try again.": "Olet epäonnekas. Yritä uudelleen.", "Error saving comment. Sorry.": "Virhe kommenttia tallentaessa. Anteeksi.", - "Error saving paste. Sorry.": "Virhe pastea tallentaessa. Anteeksi.", - "Invalid paste ID.": "Virheellinen paste ID.", - "Paste is not of burn-after-reading type.": "Paste ei ole polta-lukemisen-jälkeen-tyyppiä.", - "Wrong deletion token. Paste was not deleted.": "Virheellinen poistotunniste. Pastea ei poistettu.", - "Paste was properly deleted.": "Paste poistettiin kunnolla.", + "Error saving document. Sorry.": "Virhe pastea tallentaessa. Anteeksi.", + "Invalid document ID.": "Virheellinen asiakirja ID.", + "Document is not of burn-after-reading type.": "Asiakirja ei ole polta-lukemisen-jälkeen-tyyppiä.", + "Wrong deletion token. Document was not deleted.": "Virheellinen poistotunniste. Pastea ei poistettu.", + "Document was properly deleted.": "Asiakirja poistettiin kunnolla.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "%s vaatii JavaScriptiä toimiakseen. Anteeksi haitasta.", "%s requires a modern browser to work.": "%s vaatii modernin selaimen toimiakseen.", "New": "Uusi", - "Send": "Lähetä", + "Create": "Luo", "Clone": "Kloonaa", "Raw text": "Raaka teksti", "Expires": "Vanhenee", @@ -133,9 +133,9 @@ "Tämä dokumentti vanhenee %d kuukaudessa.", "Tämä dokumentti vanhenee %d kuukaudessa." ], - "Please enter the password for this paste:": "Syötä salasana tälle pastelle:", + "Please enter the password for this document:": "Syötä salasana tälle pastelle:", "Could not decrypt data (Wrong key?)": "Dataa ei voitu purkaa (Väärä avain?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Pastea ei voitu poistaa, sitä ei säilytetty \"Polta lukemisen jälkeen\" -tilassa.", + "Could not delete the document, it was not stored in burn after reading mode.": "Pastea ei voitu poistaa, sitä ei säilytetty \"Polta lukemisen jälkeen\" -tilassa.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "VAIN SINUN SILMILLESI. Älä sulje tätä ikkunaa, tätä viestiä ei voida näyttää uudelleen.", "Could not decrypt comment; Wrong key?": "Kommenttia ei voitu purkaa; väärä avain?", "Reply": "Vastaa", @@ -150,27 +150,27 @@ "unknown status": "tuntematon status", "server error or not responding": "palvelinvirhe tai palvelin ei vastaa", "Could not post comment: %s": "Kommenttia ei voitu lähettää: %s", - "Sending paste…": "Lähetetään pastea…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Pastesi on %s (Paina [Ctrl]+[c] kopioidaksesi)", + "Sending document…": "Lähetetään pastea…", + "Your document is %s (Hit Ctrl+c to copy)": "Pastesi on %s (Paina Ctrl+c kopioidaksesi)", "Delete data": "Poista data", - "Could not create paste: %s": "Pastea ei voitu luoda: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Pastea ei voitu purkaa: Purkausavain puuttuu URL:stä (Käytitkö uudelleenohjaajaa tai URL-lyhentäjää joka poistaa osan URL:stä?)", - "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "Could not create document: %s": "Pastea ei voitu luoda: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Pastea ei voitu purkaa: Purkausavain puuttuu URL:stä (Käytitkö uudelleenohjaajaa tai URL-lyhentäjää joka poistaa osan URL:stä?)", + "B": "t", + "kB": "kt", + "MB": "Mt", + "GB": "Gt", + "TB": "Tt", + "PB": "Pt", + "EB": "Et", + "ZB": "Zt", + "YB": "Yt", "Format": "Formaatti", "Plain Text": "Perusteksti", "Source Code": "Lähdekoodi", "Markdown": "Markdown", "Download attachment": "Lataa liite", "Cloned: '%s'": "Kloonattu: '%s'", - "The cloned file '%s' was attached to this paste.": "Kloonattu tiedosto '%s' liitettiin tähän pasteen", + "The cloned file '%s' was attached to this document.": "Kloonattu tiedosto '%s' liitettiin tähän pasteen", "Attach a file": "Liitä tiedosto", "alternatively drag & drop a file or paste an image from the clipboard": "vaihtoehtoisesti vedä & pudota tiedosto tai liitä kuva leikepöydältä", "File too large, to display a preview. Please download the attachment.": "Tiedosto on liian iso esikatselun näyttämiseksi. Lataathan liitteen.", @@ -185,11 +185,11 @@ "Decrypt": "Pura", "Enter password": "Syötä salasana", "Loading…": "Ladataan…", - "Decrypting paste…": "Puretaan pastea…", - "Preparing new paste…": "Valmistellaan uutta pastea", + "Decrypting document…": "Puretaan pastea…", + "Preparing new document…": "Valmistellaan uutta pastea", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "Jos tämä viesti ei katoa koskaan, katsothan tämän FAQ:n ongelmanratkaisutiedon löytämiseksi.", - "+++ no paste text +++": "+++ ei paste-tekstiä +++", - "Could not get paste data: %s": "Paste-tietoja ei löydetty: %s", + "+++ no document text +++": "+++ ei asiakirja-tekstiä +++", + "Could not get document data: %s": "Asiakirja-tietoja ei löydetty: %s", "QR code": "QR-koodi", "This website is using an insecure HTTP connection! Please use it only for testing.": "Tämä sivusto käyttää epäturvallista HTTP-yhteyttä! Käytäthän sitä vain testaukseen.", "For more information see this FAQ entry.": "Lisätietoja varten lue tämä FAQ-kohta.", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Salattu viesti %sissä", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Vieraile tässä linkissä nähdäksesi viestin. URL:n antaminen kenellekään antaa heidänkin päästä katsomaan viestiä.", "URL shortener may expose your decrypt key in URL.": "URL-lyhentäjä voi paljastaa purkuavaimesi URL:ssä.", - "Save paste": "Tallenna paste", - "Your IP is not authorized to create pastes.": "IP:llesi ei ole annettu oikeutta luoda pasteja.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Tallenna asiakirja", + "Your IP is not authorized to create documents.": "IP:llesi ei ole annettu oikeutta luoda pasteja.", "Trying to shorten a URL that isn't pointing at our instance.": "Yritetään lyhentää URL-osoite, joka ei osoita meidän instanssiiin.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Virhe kutsuttaessa YOURLS. Luultavasti asetusongelma kuten väärä tai puuttuuva \"apiurl\" tai \"signature\".", - "Error parsing YOURLS response.": "Virhe jäsennettäessä YOURLS-vastausta.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Virhe kutsuttaessa YOURLS. Luultavasti asetusongelma kuten väärä tai puuttuuva \"apiurl\" tai \"signature\".", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Virhe jäsennettäessä YOURLS-vastausta.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "Tämä salainen viesti voidaan näyttää vain kerran. Haluatko nähdä sen nyt?", + "Yes, see it": "Kyllä, näet sen", + "Dark Mode": "Tumma tila", + "Error compressing document, due to missing WebAssembly support.": "Virhe pakattaessa pastea, koska WebAssembly-tuki puuttuu.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Virhe pasten purkamisessa, selaimesi ei tue WebAssemblyä. Ole hyvä ja käytä toista selainta nähdäksesi tämä asiakirja.", + "Start over": "Aloita alusta", + "Document copied to clipboard": "Asiakirja kopioitu leikepöydälle", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "Voit kopioida pasten painamalla kopioi-painiketta tai käyttämällä leikepöydän oikotietä Ctrl+c/Cmd+c", + "Copy link": "Kopioi linkki", + "Link copied to clipboard": "Linkki kopioitu leikepöydälle", + "Document text": "Liitä teksti", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulaattori toimii merkkinä (Paina Ctrl+m tai Esc vaihtaaksesi)", + "Theme": "Teema" } diff --git a/i18n/fr.json b/i18n/fr.json index 0fc21aa0..ad71679e 100644 --- a/i18n/fr.json +++ b/i18n/fr.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s est un 'pastebin' (ou gestionnaire d'extraits de texte et de code source) minimaliste et open source, dans lequel le serveur n'a aucune connaissance des données envoyées. Les données sont chiffrées/déchiffrées %sdans le navigateur%s par un chiffrement AES 256 bits.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s est un 'pastebin' (ou gestionnaire d'extraits de texte et de code source) minimaliste et open source, dans lequel le serveur n'a aucune connaissance des données envoyées. Les données sont chiffrées/déchiffrées %sdans le navigateur%s par un chiffrement AES 256 bits.", "More information on the project page.": "Plus d'informations sur la page du projet.", "Because ignorance is bliss": "Vivons heureux, vivons cachés", - "Paste does not exist, has expired or has been deleted.": "Le paste n'existe pas, a expiré, ou a été supprimé.", + "Document does not exist, has expired or has been deleted.": "Le document n'existe pas, a expiré, ou a été supprimé.", "%s requires php %s or above to work. Sorry.": "Désolé, %s nécessite php %s ou supérieur pour fonctionner.", "%s requires configuration section [%s] to be present in configuration file.": "%s a besoin de la section de configuration [%s] dans le fichier de configuration pour fonctionner.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Merci d'attendre %d secondes entre chaque publication.", "Merci d'attendre %d secondes entre chaque publication." ], - "Paste is limited to %s of encrypted data.": "Le paste est limité à %s de données chiffrées.", + "Document is limited to %s of encrypted data.": "Le document est limité à %s de données chiffrées.", "Invalid data.": "Données invalides.", "You are unlucky. Try again.": "Pas de chance. Essayez encore.", "Error saving comment. Sorry.": "Erreur lors de la sauvegarde du commentaire.", - "Error saving paste. Sorry.": "Erreur lors de la sauvegarde du paste. Désolé.", - "Invalid paste ID.": "ID du paste invalide.", - "Paste is not of burn-after-reading type.": "Le paste n'est pas de type \"Effacer après lecture\".", - "Wrong deletion token. Paste was not deleted.": "Jeton de suppression incorrect. Le paste n'a pas été supprimé.", - "Paste was properly deleted.": "Le paste a été correctement supprimé.", + "Error saving document. Sorry.": "Erreur lors de la sauvegarde du document. Désolé.", + "Invalid document ID.": "ID du document invalide.", + "Document is not of burn-after-reading type.": "Le document n'est pas de type \"Effacer après lecture\".", + "Wrong deletion token. Document was not deleted.": "Jeton de suppression incorrect. Le document n'a pas été supprimé.", + "Document was properly deleted.": "Le document a été correctement supprimé.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript est requis pour faire fonctionner %s. Désolé pour cet inconvénient.", "%s requires a modern browser to work.": "%s nécessite un navigateur moderne pour fonctionner.", "New": "Nouveau", - "Send": "Envoyer", + "Create": "Créer", "Clone": "Cloner", "Raw text": "Texte brut", "Expires": "Expire", @@ -133,11 +133,11 @@ "Ce document expirera dans %d mois.", "Ce document expirera dans %d mois." ], - "Please enter the password for this paste:": "Entrez le mot de passe pour ce paste:", + "Please enter the password for this document:": "Entrez le mot de passe pour ce document:", "Could not decrypt data (Wrong key?)": "Impossible de déchiffrer les données (mauvaise clé ?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Impossible de supprimer le paste, car il n'a pas été stocké en mode \"Effacer après lecture\".", - "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "POUR VOS YEUX UNIQUEMENT. Ne fermez pas cette fenêtre, ce paste ne pourra plus être affiché.", - "Could not decrypt comment; Wrong key?": "Impossible de déchiffrer le commentaire; mauvaise clé ?", + "Could not delete the document, it was not stored in burn after reading mode.": "Impossible de supprimer le document, car il n'a pas été stocké en mode \"Effacer après lecture\".", + "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "POUR VOS YEUX UNIQUEMENT. Ne fermez pas cette fenêtre, ce document ne pourra plus être affiché.", + "Could not decrypt comment; Wrong key?": "Impossible de déchiffrer le commentaire ; mauvaise clé ?", "Reply": "Répondre", "Anonymous": "Anonyme", "Avatar generated from IP address": "Avatar généré à partir de l'adresse IP", @@ -150,27 +150,27 @@ "unknown status": "Statut inconnu", "server error or not responding": "Le serveur ne répond pas ou a rencontré une erreur", "Could not post comment: %s": "Impossible de poster le commentaire : %s", - "Sending paste…": "Envoi du paste…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Votre paste est disponible à l'adresse %s (Appuyez sur [Ctrl]+[c] pour copier)", - "Delete data": "Supprimer les données du paste", - "Could not create paste: %s": "Impossible de créer le paste : %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Impossible de déchiffrer le paste : Clé de déchiffrement manquante dans l'URL (Avez-vous utilisé un redirecteur ou un site de réduction d'URL qui supprime une partie de l'URL ?)", + "Sending document…": "Envoi du document…", + "Your document is %s (Hit Ctrl+c to copy)": "Votre document est disponible à l'adresse %s (Appuyez sur Ctrl+c/Cmd+c pour copier)", + "Delete data": "Supprimer les données du document", + "Could not create document: %s": "Impossible de créer le document : %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Impossible de déchiffrer le document : Clé de déchiffrement manquante dans l'URL (Avez-vous utilisé un redirecteur ou un site de réduction d'URL qui supprime une partie de l'URL ?)", "B": "o", - "KiB": "Kio", - "MiB": "Mio", - "GiB": "Gio", - "TiB": "Tio", - "PiB": "Pio", - "EiB": "Eio", - "ZiB": "Zio", - "YiB": "Yio", + "kB": "ko", + "MB": "Mo", + "GB": "Go", + "TB": "To", + "PB": "Po", + "EB": "Eo", + "ZB": "Zo", + "YB": "Yo", "Format": "Format", "Plain Text": "Texte brut", "Source Code": "Code source", "Markdown": "Markdown", "Download attachment": "Télécharger la pièce jointe", "Cloned: '%s'": "Cloner '%s'", - "The cloned file '%s' was attached to this paste.": "Le fichier cloné '%s' a été attaché à ce paste.", + "The cloned file '%s' was attached to this document.": "Le fichier cloné '%s' a été attaché à ce document.", "Attach a file": "Attacher un fichier", "alternatively drag & drop a file or paste an image from the clipboard": "au choix, glisser & déposer un fichier ou coller une image à partir du presse-papiers", "File too large, to display a preview. Please download the attachment.": "Fichier trop volumineux, pour afficher un aperçu. Veuillez télécharger la pièce jointe.", @@ -185,11 +185,11 @@ "Decrypt": "Déchiffrer", "Enter password": "Entrez le mot de passe", "Loading…": "Chargement…", - "Decrypting paste…": "Déchiffrement du paste…", - "Preparing new paste…": "Préparation du paste…", + "Decrypting document…": "Déchiffrement du document…", + "Preparing new document…": "Préparation du document…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "Si ce message ne disparaîssait pas, jetez un oeil à cette FAQ pour des idées de résolution (en Anglais).", - "+++ no paste text +++": "+++ pas de texte copié +++", - "Could not get paste data: %s": "Impossible d'obtenir les données du paste: %s", + "+++ no document text +++": "+++ pas de texte copié +++", + "Could not get document data: %s": "Impossible d'obtenir les données du document: %s", "QR code": "QR code", "This website is using an insecure HTTP connection! Please use it only for testing.": "Ce site web utilise une connexion HTTP non sécurisée ! Veuillez l’utiliser uniquement pour des tests.", "For more information see this FAQ entry.": "Pour plus d'informations consultez cette rubrique de la FAQ.", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Message chiffré sur %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visiter ce lien pour voir la note. Donner l'URL à une autre personne lui permet également d'accéder à la note.", "URL shortener may expose your decrypt key in URL.": "Raccourcir l'URL peut exposer votre clé de déchiffrement dans l'URL.", - "Save paste": "Sauver le paste", - "Your IP is not authorized to create pastes.": "Votre adresse IP n'est pas autorisée à créer des pastes.", - "Trying to shorten a URL that isn't pointing at our instance.": "Essayer de raccourcir une URL qui ne pointe pas vers notre instance.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Erreur lors de l'appel de YOURLS. Peut-être un problème de configuration, comme \"apiurl\" ou \"signature\" manquant.", - "Error parsing YOURLS response.": "Erreur d'analyse de la réponse YOURLS.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Effacer après la lecture des paste ne peut être affiché qu'une seule fois lors du chargement. Voulez-vous l'ouvrir maintenant ?", - "Yes, load it": "Oui, chargez-le" + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Sauver le document", + "Your IP is not authorized to create documents.": "Votre adresse IP n'est pas autorisée à créer des documents.", + "Trying to shorten a URL that isn't pointing at our instance.": "Tentative de raccourcir une URL qui ne pointe pas vers notre instance.", + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Erreur lors de l'appel de YOURLS. Peut-être un problème de configuration, comme \"apiurl\" ou \"signature\" manquant.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Erreur d'analyse de la réponse YOURLS.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "Les documents de type \"Effacer après la lecture\" ne peuvent être affichés qu'une seule fois. Voulez-vous le voir maintenant ?", + "Yes, see it": "Oui, le voir", + "Dark Mode": "Mode Sombre", + "Error compressing document, due to missing WebAssembly support.": "Erreur lors de la compression du document, en raison du support de WebAssembly manquant.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Erreur lors de la décompression du document, votre navigateur ne supporte pas WebAssembly. Veuillez utiliser un autre navigateur pour voir ce document.", + "Start over": "Recommencer", + "Document copied to clipboard": "Document copié dans le presse-papier", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "Pour copier appuyer sur le bouton Copier le lien ou utiliser le raccourci Ctrl+c/Cmd+c", + "Copy link": "Copier le lien", + "Link copied to clipboard": "Lien copié dans le presse-papier", + "Document text": "Texte du document", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "La touche de tabulation sert de caractère (Presser Ctrl+m ou Esc pour basculer)", + "Theme": "Thème" } diff --git a/i18n/he.json b/i18n/he.json index 658e586b..31d2afd9 100644 --- a/i18n/he.json +++ b/i18n/he.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.", - "More information on the project page.": "More information on the project page.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s הוא שירות pastebin מקוון, מינימליסטי וקוד פתוח, שבו לשרת אין כל ידע על המידע שהודבק. הנתונים מוצפנים ומפוענחים %sבדפדפן%s באמצעות הצפנת AES ב-256 סיביות.", + "More information on the project page.": "מידע נוסף בדף הפרויקט.", "Because ignorance is bliss": "כיוון שבורות היא ברכה", - "Paste does not exist, has expired or has been deleted.": "ההדבקה לא קיימת, פגה או נמחקה.", + "Document does not exist, has expired or has been deleted.": "ההדבקה לא קיימת, פגה או נמחקה.", "%s requires php %s or above to work. Sorry.": "%s דורש PHP %s כדי לפעול.", "%s requires configuration section [%s] to be present in configuration file.": "%s דורש שסעיף ההגדרות [%s] יהיה קיים בקובץ ההגדרות.", "Please wait %d seconds between each post.": [ @@ -14,22 +14,22 @@ "נא להמתין %d שניות בין פרסום לפרסום.", "נא להמתין %d שניות בין פרסום לפרסום." ], - "Paste is limited to %s of encrypted data.": "ההדבקה מוגבלת ל־%s של נתונים מוצפנים.", + "Document is limited to %s of encrypted data.": "ההדבקה מוגבלת ל־%s של נתונים מוצפנים.", "Invalid data.": "נתונים שגויים.", "You are unlucky. Try again.": "אין לך מזל. נא לנסות שוב.", "Error saving comment. Sorry.": "שגיאה בשמירת המסמך. סליחה.", - "Error saving paste. Sorry.": "שגיאה בשמירת ההדבקה. סליחה.", - "Invalid paste ID.": "מזהה ההדבקה שגוי.", - "Paste is not of burn-after-reading type.": "ההדבקה היא לא מסוג קוראים-שורפים.", - "Wrong deletion token. Paste was not deleted.": "אסימון מחיקה שגוי. ההדבקה לא נמחקה.", - "Paste was properly deleted.": "ההדבקה נמחקה כראוי.", + "Error saving document. Sorry.": "שגיאה בשמירת ההדבקה. סליחה.", + "Invalid document ID.": "מזהה ההדבקה שגוי.", + "Document is not of burn-after-reading type.": "ההדבקה היא לא מסוג קוראים-שורפים.", + "Wrong deletion token. Document was not deleted.": "אסימון מחיקה שגוי. ההדבקה לא נמחקה.", + "Document was properly deleted.": "ההדבקה נמחקה כראוי.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "צריך JavaScript כדי לאפשר ל־%s לפעול. סליחה על חוסר הנוחות.", "%s requires a modern browser to work.": "%s דורש דפדפן מודרני כדי לפעול.", "New": "חדש", - "Send": "שליחה", + "Create": "צור", "Clone": "שכפול", "Raw text": "טקסט גולמי", - "Expires": "Expires", + "Expires": "יפוג ב", "Burn after reading": "קוראים-שורפים", "Open discussion": "פתיחת דיון", "Password (recommended)": "ססמה (מומלץ)", @@ -53,11 +53,11 @@ ], "%d hours": [ "שעה אחת", - "%d hours (1st plural)", - "%d hours (2nd plural)", - "%d hours (3rd plural)", - "%d hours (4th plural)", - "%d hours (5th plural)" + "%d שעות", + "%d שעות", + "%d שעות", + "%d שעות", + "%d שעות" ], "%d days": [ "יום אחד", @@ -94,48 +94,48 @@ "Never": "לעולם לא", "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "הערה: זהו שירות בדקה: המידע לא ישמר.", "This document will expire in %d seconds.": [ - "This document will expire in %d second. (singular)", - "This document will expire in %d seconds. (1st plural)", - "This document will expire in %d seconds. (2nd plural)", - "This document will expire in %d seconds. (3rd plural)", - "This document will expire in %d seconds. (4th plural)", - "This document will expire in %d seconds. (5th plural)" + "מסמך זה יפוג בעוד שנייה אחת.", + "מסמך זה יפוג בעוד %d שניות.", + "מסמך זה יפוג בעוד %d שניות.", + "מסמך זה יפוג בעוד %d שניות.", + "מסמך זה יפוג בעוד %d שניות.", + "מסמך זה יפוג בעוד %d שניות." ], "This document will expire in %d minutes.": [ - "This document will expire in %d minute. (singular)", - "This document will expire in %d minutes. (1st plural)", - "This document will expire in %d minutes. (2nd plural)", - "This document will expire in %d minutes. (3rd plural)", - "This document will expire in %d minutes. (4th plural)", - "This document will expire in %d minutes. (5th plural)" + "מסמך זה יפוג בעוד דקה אחת.", + "מסמך זה יפוג בעוד %d דקות.", + "מסמך זה יפוג בעוד %d דקות.", + "מסמך זה יפוג בעוד %d דקות.", + "מסמך זה יפוג בעוד %d דקות.", + "מסמך זה יפוג בעוד %d דקות." ], "This document will expire in %d hours.": [ - "This document will expire in %d hour. (singular)", - "This document will expire in %d hours. (1st plural)", - "This document will expire in %d hours. (2nd plural)", - "This document will expire in %d hours. (3rd plural)", - "This document will expire in %d hours. (4th plural)", - "This document will expire in %d hours. (5th plural)" + "מסמך זה יפוג בעוד שעה אחת.", + "מסמך זה יפוג בעוד %d שעות.", + "מסמך זה יפוג בעוד %d שעות.", + "מסמך זה יפוג בעוד %d שעות.", + "מסמך זה יפוג בעוד %d שעות.", + "מסמך זה יפוג בעוד %d שעות." ], "This document will expire in %d days.": [ - "This document will expire in %d day. (singular)", - "This document will expire in %d days. (1st plural)", - "This document will expire in %d days. (2nd plural)", - "This document will expire in %d days. (3rd plural)", - "This document will expire in %d days. (4th plural)", - "This document will expire in %d days. (5th plural)" + "מסמך זה יפוג בעוד יום אחד.", + "מסמך זה יפוג בעוד %d ימים.", + "מסמך זה יפוג בעוד %d ימים.", + "מסמך זה יפוג בעוד %d ימים.", + "מסמך זה יפוג בעוד %d ימים.", + "מסמך זה יפוג בעוד %d ימים." ], "This document will expire in %d months.": [ - "This document will expire in %d month. (singular)", - "This document will expire in %d months. (1st plural)", - "This document will expire in %d months. (2nd plural)", - "This document will expire in %d months. (3rd plural)", - "This document will expire in %d months. (4th plural)", - "This document will expire in %d months. (5th plural)" + "מסמך זה יפוג בעוד חודש אחד.", + "מסמך זה יפוג בעוד %d חודשים.", + "מסמך זה יפוג בעוד %d חודשים.", + "מסמך זה יפוג בעוד %d חודשים.", + "מסמך זה יפוג בעוד %d חודשים.", + "מסמך זה יפוג בעוד %d חודשים." ], - "Please enter the password for this paste:": "נא למלא את הססמה להדבקה הזו:", + "Please enter the password for this document:": "נא למלא את הססמה להדבקה הזו:", "Could not decrypt data (Wrong key?)": "לא ניתן לפענח את הנתונים (מפתח שגוי?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "לא ניתן למחוק את ההדבקה, היא לא אוחסנה במצב קוראים-שורפים.", + "Could not delete the document, it was not stored in burn after reading mode.": "לא ניתן למחוק את ההדבקה, היא לא אוחסנה במצב קוראים-שורפים.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "לעיניך בלבד. לא לסגור את החלון הזה, ההודעה הזאת לא תופיע שוב.", "Could not decrypt comment; Wrong key?": "לא ניתן לפענח את ההערה, מפתח שגוי?", "Reply": "תגובה", @@ -150,49 +150,49 @@ "unknown status": "מצב לא ידוע", "server error or not responding": "שגיאת שרת או שהשרת לא מגיב", "Could not post comment: %s": "לא ניתן לפרסם תגובה: %s", - "Sending paste…": "ההדבקה נשלחת…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "ההדבקה שלך היא %s (יש ללחוץ [Ctrl]+[c] כדי להעתיק)", + "Sending document…": "ההדבקה נשלחת…", + "Your document is %s (Hit Ctrl+c to copy)": "ההדבקה שלך היא %s (יש ללחוץ Ctrl+c כדי להעתיק)", "Delete data": "מחיקת נתונים", - "Could not create paste: %s": "לא ניתן ליצור הדבקה: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "לא ניתן לפענח הדבקה: מפתח הפענוח חסר בכתובת (השתמשת במערכת הפנייה או מקצר כתובות שחותכים חלק מהכתובת?)", + "Could not create document: %s": "לא ניתן ליצור הדבקה: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "לא ניתן לפענח הדבקה: מפתח הפענוח חסר בכתובת (השתמשת במערכת הפנייה או מקצר כתובות שחותכים חלק מהכתובת?)", "B": "ב׳", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "פורמט", "Plain Text": "טקסט פשוט", "Source Code": "קוד מקור", "Markdown": "Markdown", "Download attachment": "הורדת קובץ מצורף", "Cloned: '%s'": "שוכפל: '%s'", - "The cloned file '%s' was attached to this paste.": "The cloned file '%s' was attached to this paste.", + "The cloned file '%s' was attached to this document.": "הקובץ '%s' שהועתק צורף להדבקה זו.", "Attach a file": "צירוף קובץ", - "alternatively drag & drop a file or paste an image from the clipboard": "alternatively drag & drop a file or paste an image from the clipboard", - "File too large, to display a preview. Please download the attachment.": "File too large, to display a preview. Please download the attachment.", - "Remove attachment": "Remove attachment", - "Your browser does not support uploading encrypted files. Please use a newer browser.": "Your browser does not support uploading encrypted files. Please use a newer browser.", + "alternatively drag & drop a file or paste an image from the clipboard": "לחלופין, ניתן לגרור ולשחרר קובץ או להדביק תמונה מהלוח.", + "File too large, to display a preview. Please download the attachment.": "הקובץ גדול מדי כדי להציג תצוגה מקדימה. אנא הורד את הקובץ המצורף.", + "Remove attachment": "הסר קובץ מצורף", + "Your browser does not support uploading encrypted files. Please use a newer browser.": "הדפדפן שלך אינו תומך בהעלאת קבצים מוצפנים. אנא השתמש בדפדפן עדכני יותר.", "Invalid attachment.": "קובץ מצורף שגוי.", "Options": "אפשרויות", "Shorten URL": "קיצור כתובת", "Editor": "עורך", "Preview": "תצוגה מקדימה", - "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.", + "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s דורש שה-PATH יסתיים ב-\"%s\". אנא עדכן את ה-PATH בקובץ index.php שלך.", "Decrypt": "פענוח", "Enter password": "נא למלא ססמה", "Loading…": "בטעינה…", - "Decrypting paste…": "ההדבקה מפוענחת…", - "Preparing new paste…": "ההדבקה החדשה בהכנות…", - "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "In case this message never disappears please have a look at this FAQ for information to troubleshoot.", - "+++ no paste text +++": "+++ אין טקסט להדבקה +++", - "Could not get paste data: %s": "לא ניתן לקבל את נתוני ההדבקה: %s", + "Decrypting document…": "ההדבקה מפוענחת…", + "Preparing new document…": "ההדבקה החדשה בהכנות…", + "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "אם הודעה זו לא נעלמת, אנא עיין ב- שאלות נפוצות אלה למידע לפתרון בעיות.", + "+++ no document text +++": "+++ אין טקסט להדבקה +++", + "Could not get document data: %s": "לא ניתן לקבל את נתוני ההדבקה: %s", "QR code": "קוד QR", "This website is using an insecure HTTP connection! Please use it only for testing.": "האתר הזה משתמש בחיבור HTTP בלתי מאובטח! נא להשתמש בזה לבדיקות בלבד.", - "For more information see this FAQ entry.": "יש מידע נוסף ברשומה הזאת בשו״ת.", + "For more information see this FAQ entry.": "לפרטים נוספים עיין ברשומת שאלות נפוצות זו.", "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": "יכול להיות שהדפדפן שלך ידרוש חיבור HTTPS כדי לתמוך ב־API של WebCrypto. כדי לנסות לעבור ל־HTTPS.", "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "הדפדפן שלך לא תומך ב־WebAssembly שמשמש לדחיסת zlib. אפשר ליצור מסמכים בלתי מוצפנים אך אין אפשרות לקרוא מסמכים מוצפנים.", "waiting on user to provide a password": "בהמתנה למילוי הססמה מצד המשתמש", @@ -209,12 +209,25 @@ "Close": "סגירה", "Encrypted note on %s": "%sהערה מוצפנת ב־", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "נא לבקר בקישור כדי לצפות בהערה. מסירת הקישור לאנשים כלשהם תאפשר גם להם לגשת להערה.", - "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.", - "Save paste": "Save paste", - "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.", - "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "URL shortener may expose your decrypt key in URL.": "שירות קיצור כתובת URL עשוי לחשוף את מפתח הפענוח שלך בכתובת ה-URL.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "שמור הדבקה", + "Your IP is not authorized to create documents.": "ה-IP שלך אינו מורשה ליצור הדבקות.", + "Trying to shorten a URL that isn't pointing at our instance.": "מנסים לקצר כתובת URL שאינה מצביעה על המערכת שלנו.", + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "שגיאה בעת קריאה ל-YOURLS. כנראה מדובר בבעיה בהגדרות, כמו \"apiurl\" או \"signature\" שגויים או חסרים.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "שגיאה בניתוח התגובה מ-YOURLS.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "ההודעה הסודית הזו יכולה להוצג רק פעם אחת. האם תרצה לראות אותה עכשיו?", + "Yes, see it": "כן, ראה אותה", + "Dark Mode": "מצב כהה", + "Error compressing document, due to missing WebAssembly support.": "שגיאה בדחיסת ההדבקה, עקב חוסר תמיכה ב-WebAssembly.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "שגיאה בהפקת ההדבקה, הדפדפן שלך לא תומך ב-WebAssembly. אנא השתמש בדפדפן אחר כדי לצפות בהדבקה זו.", + "Start over": "להתחיל מחדש", + "Document copied to clipboard": "ההדבקה הועתקה ללוח", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "על מנת להעתיק את ההדבקה, לחץ על כפתור ההעתקה או השתמש בקיצור הדרך ללוח Ctrl+c/Cmd+c", + "Copy link": "העתק קישור", + "Link copied to clipboard": "הקישור הועתק ללוח", + "Document text": "הדבק טקסט", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "משטח ה-tab פועל כמקש תו (לחץ על Ctrl+m או Esc להחלפה)", + "Theme": "נושא" } diff --git a/i18n/hi.json b/i18n/hi.json index 6ef3280b..c0d21fca 100644 --- a/i18n/hi.json +++ b/i18n/hi.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.", "More information on the project page.": "More information on the project page.", "Because ignorance is bliss": "Because ignorance is bliss", - "Paste does not exist, has expired or has been deleted.": "Paste does not exist, has expired or has been deleted.", + "Document does not exist, has expired or has been deleted.": "Document does not exist, has expired or has been deleted.", "%s requires php %s or above to work. Sorry.": "%s requires php %s or above to work. Sorry.", "%s requires configuration section [%s] to be present in configuration file.": "%s requires configuration section [%s] to be present in configuration file.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Please wait %d seconds between each post. (4th plural)", "Please wait %d seconds between each post. (5th plural)" ], - "Paste is limited to %s of encrypted data.": "Paste is limited to %s of encrypted data.", + "Document is limited to %s of encrypted data.": "Document is limited to %s of encrypted data.", "Invalid data.": "Invalid data.", "You are unlucky. Try again.": "You are unlucky. Try again.", "Error saving comment. Sorry.": "Error saving comment. Sorry.", - "Error saving paste. Sorry.": "Error saving paste. Sorry.", - "Invalid paste ID.": "Invalid paste ID.", - "Paste is not of burn-after-reading type.": "Paste is not of burn-after-reading type.", - "Wrong deletion token. Paste was not deleted.": "Wrong deletion token. Paste was not deleted.", - "Paste was properly deleted.": "Paste was properly deleted.", + "Error saving document. Sorry.": "Error saving document. Sorry.", + "Invalid document ID.": "Invalid document ID.", + "Document is not of burn-after-reading type.": "Document is not of burn-after-reading type.", + "Wrong deletion token. Document was not deleted.": "Wrong deletion token. Document was not deleted.", + "Document was properly deleted.": "Document was properly deleted.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript is required for %s to work. Sorry for the inconvenience.", "%s requires a modern browser to work.": "%s requires a modern browser to work.", "New": "New", - "Send": "Send", + "Create": "Create", "Clone": "Clone", "Raw text": "Raw text", "Expires": "Expires", @@ -133,9 +133,9 @@ "This document will expire in %d months. (4th plural)", "This document will expire in %d months. (5th plural)" ], - "Please enter the password for this paste:": "Please enter the password for this paste:", + "Please enter the password for this document:": "Please enter the password for this document:", "Could not decrypt data (Wrong key?)": "Could not decrypt data (Wrong key?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Could not delete the paste, it was not stored in burn after reading mode.", + "Could not delete the document, it was not stored in burn after reading mode.": "Could not delete the document, it was not stored in burn after reading mode.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.", "Could not decrypt comment; Wrong key?": "Could not decrypt comment; Wrong key?", "Reply": "Reply", @@ -150,27 +150,27 @@ "unknown status": "unknown status", "server error or not responding": "server error or not responding", "Could not post comment: %s": "Could not post comment: %s", - "Sending paste…": "Sending paste…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Your paste is %s (Hit [Ctrl]+[c] to copy)", + "Sending document…": "Sending document…", + "Your document is %s (Hit Ctrl+c to copy)": "Your document is %s (Hit Ctrl+c to copy)", "Delete data": "Delete data", - "Could not create paste: %s": "Could not create paste: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)", + "Could not create document: %s": "Could not create document: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Plain Text", "Source Code": "Source Code", "Markdown": "Markdown", "Download attachment": "Download attachment", "Cloned: '%s'": "Cloned: '%s'", - "The cloned file '%s' was attached to this paste.": "The cloned file '%s' was attached to this paste.", + "The cloned file '%s' was attached to this document.": "The cloned file '%s' was attached to this document.", "Attach a file": "Attach a file", "alternatively drag & drop a file or paste an image from the clipboard": "alternatively drag & drop a file or paste an image from the clipboard", "File too large, to display a preview. Please download the attachment.": "File too large, to display a preview. Please download the attachment.", @@ -185,11 +185,11 @@ "Decrypt": "Decrypt", "Enter password": "Enter password", "Loading…": "Loading…", - "Decrypting paste…": "Decrypting paste…", - "Preparing new paste…": "Preparing new paste…", + "Decrypting document…": "Decrypting document…", + "Preparing new document…": "Preparing new document…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "In case this message never disappears please have a look at this FAQ for information to troubleshoot.", - "+++ no paste text +++": "+++ no paste text +++", - "Could not get paste data: %s": "Could not get paste data: %s", + "+++ no document text +++": "+++ no document text +++", + "Could not get document data: %s": "Could not get document data: %s", "QR code": "QR code", "This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.", "For more information see this FAQ entry.": "For more information see this FAQ entry.", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Encrypted note on %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.", "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.", - "Save paste": "Save paste", - "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Save document", + "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.", "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?", + "Yes, see it": "Yes, see it", + "Dark Mode": "Dark Mode", + "Error compressing document, due to missing WebAssembly support.": "Error compressing document, due to missing WebAssembly support.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.", + "Start over": "Start over", + "Document copied to clipboard": "Document copied to clipboard", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/hu.json b/i18n/hu.json index d9161090..b451a789 100644 --- a/i18n/hu.json +++ b/i18n/hu.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "A %s egy minimalista, nyílt forráskódú adattároló szoftver, ahol a szerver semmilyen információt nem tárol a feltett adatról. Azt ugyanis a %sböngésződ%s segítségével titkosítja és oldja fel 256 bit hosszú titkosítási kulcsú AES-t használva.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "A %s egy minimalista, nyílt forráskódú adattároló szoftver, ahol a szerver semmilyen információt nem tárol a feltett adatról. Azt ugyanis a %sböngésződ%s segítségével titkosítja és oldja fel 256 bit hosszú titkosítási kulcsú AES-t használva.", "More information on the project page.": "További információt a projekt oldalán találsz.", "Because ignorance is bliss": "A titok egyfajta hatalom.", - "Paste does not exist, has expired or has been deleted.": "A bejegyzés nem létezik, lejárt vagy törölve lett.", + "Document does not exist, has expired or has been deleted.": "A bejegyzés nem létezik, lejárt vagy törölve lett.", "%s requires php %s or above to work. Sorry.": "Bocs, de a %s működéséhez %s vagy ezt meghaladó verziójú php-s környezet szükséges.", "%s requires configuration section [%s] to be present in configuration file.": "A %s megfelelő működéséhez a konfigurációs fájlban a [%s] résznek léteznie kell.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Kérlek várj %d másodpercet két beküldés között.", "Kérlek várj %d másodpercet két beküldés között." ], - "Paste is limited to %s of encrypted data.": "A bejegyzés maximális hossza: %s", + "Document is limited to %s of encrypted data.": "A bejegyzés maximális hossza: %s", "Invalid data.": "Érvénytelen adat.", "You are unlucky. Try again.": "Peched volt, próbáld újra.", "Error saving comment. Sorry.": "Nem sikerült menteni a hozzászólást. Bocs.", - "Error saving paste. Sorry.": "Nem sikerült menteni a bejegyzést. Bocs.", - "Invalid paste ID.": "Érvénytelen bejegyzésazonosító.", - "Paste is not of burn-after-reading type.": "A bejegyzés nem semmisül meg azonnal olvasás után.", - "Wrong deletion token. Paste was not deleted.": "Hibás törlési azonosító. A bejegyzés nem lett törölve.", - "Paste was properly deleted.": "A bejegyzés sikeresen törölve.", + "Error saving document. Sorry.": "Nem sikerült menteni a bejegyzést. Bocs.", + "Invalid document ID.": "Érvénytelen bejegyzésazonosító.", + "Document is not of burn-after-reading type.": "A bejegyzés nem semmisül meg azonnal olvasás után.", + "Wrong deletion token. Document was not deleted.": "Hibás törlési azonosító. A bejegyzés nem lett törölve.", + "Document was properly deleted.": "A bejegyzés sikeresen törölve.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript szükséges a %s működéséhez. Elnézést a fennakadásért.", "%s requires a modern browser to work.": "A %s működéséhez a jelenleginél újabb böngészőre van szükség.", "New": "Új", - "Send": "Beküldöm!", + "Create": "Létrehozás", "Clone": "Másol", "Raw text": "A nyers szöveg", "Expires": "Lejárati idő", @@ -133,9 +133,9 @@ "Ez a bejegyzés %d hónap múlva megsemmisül.", "Ez a bejegyzés %d hónap múlva megsemmisül." ], - "Please enter the password for this paste:": "Add meg a szükséges jelszót a bejegyzés megtekintéséhez:", + "Please enter the password for this document:": "Add meg a szükséges jelszót a bejegyzés megtekintéséhez:", "Could not decrypt data (Wrong key?)": "Nem tudtuk visszfejteni az adatot. Talán rossz kulcsot adtál meg?", - "Could not delete the paste, it was not stored in burn after reading mode.": "Nem tudtuk törölni a bejegyzést, mivel az olvasás után egyből megsemmisült. Így nem is volt tárolva.", + "Could not delete the document, it was not stored in burn after reading mode.": "Nem tudtuk törölni a bejegyzést, mivel az olvasás után egyből megsemmisült. Így nem is volt tárolva.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "EZT A BEJEGYZÉST CSAK TE LÁTHATOD!!! Ne csukd be ezt az ablakot, mivel nem tudod újra megnézni. Az ugyanis az első olvasás után rögtön megsemmisül.", "Could not decrypt comment; Wrong key?": "Nem tudtuk visszafejteni a hozzászólást. Talán rossz kulcsot adtál meg?", "Reply": "Válasz", @@ -150,27 +150,27 @@ "unknown status": "Ismeretlen státusz.", "server error or not responding": "A szerveren hiba lépett fel vagy nem válaszol.", "Could not post comment: %s": "Nem tudtuk beküldeni a hozzászólást: %s", - "Sending paste…": "Bejegyzés elküldése...", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "A bejegyzésed a %s címen elérhető. [Ctrl]+[c]-vel tudod vágólapra másolni.", + "Sending document…": "Bejegyzés elküldése...", + "Your document is %s (Hit Ctrl+c to copy)": "A bejegyzésed a %s címen elérhető. Ctrl+c-vel tudod vágólapra másolni.", "Delete data": "Adat törlése", - "Could not create paste: %s": "Nem tudtuk létrehozni a bejegyzést: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Nem tudjuk visszafejteni a bejegyzést: a dekódoláshoz szükséges kulcs hiányzik a címből. Talán URL rövidítőt használtál ami kivágta azt belőle?", + "Could not create document: %s": "Nem tudtuk létrehozni a bejegyzést: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Nem tudjuk visszafejteni a bejegyzést: a dekódoláshoz szükséges kulcs hiányzik a címből. Talán URL rövidítőt használtál ami kivágta azt belőle?", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Formátum", "Plain Text": "Egyszerű szöveg", "Source Code": "Forráskód", "Markdown": "Markdown", "Download attachment": "Csatolmány letöltése", "Cloned: '%s'": "'%s' másolva", - "The cloned file '%s' was attached to this paste.": "A másolt '%s' csatolmányt hozzáadtuk ehhez a bejegyzéshez.", + "The cloned file '%s' was attached to this document.": "A másolt '%s' csatolmányt hozzáadtuk ehhez a bejegyzéshez.", "Attach a file": "Fájl csatolása", "alternatively drag & drop a file or paste an image from the clipboard": "vagy húzz ide egy fájlt, netán illessz be egy képet a vágólapról.", "File too large, to display a preview. Please download the attachment.": "A fájl túl nagy ahhoz, hogy előnézete legyen. Töltsd le, hogy megtekinthesd.", @@ -185,11 +185,11 @@ "Decrypt": "Visszafejtés", "Enter password": "Jelszó", "Loading…": "Folyamatban...", - "Decrypting paste…": "Bejegyzés visszafejtése...", - "Preparing new paste…": "Új bejegyzés előkészítése...", + "Decrypting document…": "Bejegyzés visszafejtése...", + "Preparing new document…": "Új bejegyzés előkészítése...", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "Abban az esetben, ha ez az üzenet mindig látható lenne, látogass el a Gyakran Ismételt Kérdések szekcióba a megoldásához.", - "+++ no paste text +++": "+++ nincs beillesztett szöveg +++", - "Could not get paste data: %s": "Az adat megszerzése nem sikerült: %s", + "+++ no document text +++": "+++ nincs beillesztett szöveg +++", + "Could not get document data: %s": "Az adat megszerzése nem sikerült: %s", "QR code": "QR kód", "This website is using an insecure HTTP connection! Please use it only for testing.": "Ez a weboldal nem biztonságos HTTP kapcsolatot használ! Emiatt csak teszt célokra ajánljuk.", "For more information see this FAQ entry.": "További információ ebben a GyIK bejegyzésben található (angolul).", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Titkosított jegyzet a %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Látogasd meg ezt a hivatkozást a bejegyzés megtekintéséhez. Ha mások számára is megadod ezt a linket, azzal hozzáférnek ők is.", "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.", - "Save paste": "Save paste", - "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Save document", + "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.", "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?", + "Yes, see it": "Yes, see it", + "Dark Mode": "Sötét mód", + "Error compressing document, due to missing WebAssembly support.": "Error compressing document, due to missing WebAssembly support.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.", + "Start over": "Start over", + "Document copied to clipboard": "Document copied to clipboard", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/id.json b/i18n/id.json index a0e844e8..89212292 100644 --- a/i18n/id.json +++ b/i18n/id.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s adalah sebuah pastebin online sumber terbuka dan minimalis, dimana servernya tersebut tidak punya pengetahuan tentang data yang ditempelkan. Data tersebut di enkrip/dekrip %sdi dalam browser%s menggunakan metode enkrip AES 256 bit.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s adalah sebuah pastebin online sumber terbuka dan minimalis, dimana servernya tersebut tidak punya pengetahuan tentang data yang ditempelkan. Data tersebut di enkrip/dekrip %sdi dalam browser%s menggunakan metode enkrip AES 256 bit.", "More information on the project page.": "Infomasi lebih lanjut pada halaman proyek.", "Because ignorance is bliss": "Karena ketidaktahuan adalah kebahagiaan, gitu loh", - "Paste does not exist, has expired or has been deleted.": "Paste tidak ada, telah kedaluwarsa atau telah dihapus.", + "Document does not exist, has expired or has been deleted.": "Document tidak ada, telah kedaluwarsa atau telah dihapus.", "%s requires php %s or above to work. Sorry.": "%s memerlukan php %s atau versi diatasnya untuk dapat dijalankan. Maaf.", "%s requires configuration section [%s] to be present in configuration file.": "%s membutuhkan bagian konfigurasi [%s] untuk ada di file konfigurasi.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Silahkan menunggu %d detik antara masing-masing postingan.", "Silahkan menunggu %d detik antara masing-masing postingan." ], - "Paste is limited to %s of encrypted data.": "Paste dibatasi sampai %s dari data yang dienskripsi.", + "Document is limited to %s of encrypted data.": "Document dibatasi sampai %s dari data yang dienskripsi.", "Invalid data.": "Data tidak valid.", "You are unlucky. Try again.": "Anda belum beruntung. Coba kembali ya Kaka.", "Error saving comment. Sorry.": "Terjadi kesalahan saat menyimpan komentar. Maaf ya Kaka.", - "Error saving paste. Sorry.": "Terjadi kesalahan saat menyimpan paste. Maaf ya Kaka.", - "Invalid paste ID.": "ID paste tidak valid.", - "Paste is not of burn-after-reading type.": "Paste bukan tipe hapus-setelah-membaca.", - "Wrong deletion token. Paste was not deleted.": "Token penghapusan salah. Paste belum terhapus.", - "Paste was properly deleted.": "Paste telah dihapus dengan benar.", + "Error saving document. Sorry.": "Terjadi kesalahan saat menyimpan document. Maaf ya Kaka.", + "Invalid document ID.": "ID document tidak valid.", + "Document is not of burn-after-reading type.": "Document bukan tipe hapus-setelah-membaca.", + "Wrong deletion token. Document was not deleted.": "Token penghapusan salah. Document belum terhapus.", + "Document was properly deleted.": "Document telah dihapus dengan benar.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript diperlukan agar %s bekerja. Maaf untuk ketidaknyamanannya.", "%s requires a modern browser to work.": "%s memerlukan sebuah browser modern untuk bekerja.", "New": "Baru", - "Send": "Kirim", + "Create": "Buat baru", "Clone": "Klon", "Raw text": "Teks mentah", "Expires": "Kadaluarsa", @@ -133,9 +133,9 @@ "Dokumen ini akan kadaluarsa dalam %d bulan.", "Dokumen ini akan kadaluarsa dalam %d bulan." ], - "Please enter the password for this paste:": "Silahkan masukkan kata sandi untuk paste ini:", + "Please enter the password for this document:": "Silahkan masukkan kata sandi untuk document ini:", "Could not decrypt data (Wrong key?)": "Tidak dapat mendekrip data (Salah kunci?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Tidak dapat menghapus paste, ini dikarenakan data tidak tersimpan dalam mode hapus setelah membaca.", + "Could not delete the document, it was not stored in burn after reading mode.": "Tidak dapat menghapus document, ini dikarenakan data tidak tersimpan dalam mode hapus setelah membaca.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "HANYA UNTUK ANDA SAJA. Jangan tutup kolom jendela ini, pesan ini tidak akan dapat ditampilkan lagi.", "Could not decrypt comment; Wrong key?": "Tidak dapat mendekrip komentar; Salah kunci?", "Reply": "Balas", @@ -150,27 +150,27 @@ "unknown status": "status tidak diketahui", "server error or not responding": "kesalahan server atau server tidak merespon", "Could not post comment: %s": "Tidak dapat memposting komentar: %s", - "Sending paste…": "Mengirim paste…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Paste Anda adalah %s(Tekan [Ctrl]+[c] untuk menyalin)", + "Sending document…": "Mengirim document…", + "Your document is %s (Hit Ctrl+c to copy)": "Document Anda adalah %s(Tekan Ctrl+c untuk menyalin)", "Delete data": "Hapus data", - "Could not create paste: %s": "Tidak dapat membuat paste: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Tidak dapat mendekripsi paste: Kunci dekripsi tidak ada di URL (Apakah Anda menggunakan redirector atau penyingkat URL yang menghapus bagian dari URL?)", + "Could not create document: %s": "Tidak dapat membuat document: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Tidak dapat mendekripsi document: Kunci dekripsi tidak ada di URL (Apakah Anda menggunakan redirector atau penyingkat URL yang menghapus bagian dari URL?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Teks Biasa", "Source Code": "Kode Sumber", "Markdown": "Markdown", "Download attachment": "Unduh lampiran", "Cloned: '%s'": "Diklon: '%s'", - "The cloned file '%s' was attached to this paste.": "Berkas yang di-klon '%s' telah dilampirkan pada paste ini.", + "The cloned file '%s' was attached to this document.": "Berkas yang di-klon '%s' telah dilampirkan pada document ini.", "Attach a file": "Lampirkan sebuah berkas", "alternatively drag & drop a file or paste an image from the clipboard": "sebagai alternatif, seret & jatuhkan berkas atau tempel sebuah gambar dari papan klip", "File too large, to display a preview. Please download the attachment.": "File terlalu besar untuk menampilkan pratinjau. Silakan unduh lampirannya.", @@ -185,11 +185,11 @@ "Decrypt": "Dekrip", "Enter password": "Masukkan kata sandi", "Loading…": "Memuat…", - "Decrypting paste…": "Men-dekrip paste…", - "Preparing new paste…": "Menyiapkan paste baru…", + "Decrypting document…": "Men-dekrip document…", + "Preparing new document…": "Menyiapkan document baru…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "Jika pesan ini tidak pernah menghilang, silahkan kunjungi dan lihat pada FAQ ini untuk informasi bagaimana menyelesaikan masalah tersebut.", - "+++ no paste text +++": "+++ tidak ada teks paste +++", - "Could not get paste data: %s": "Tidak dapat mengambil/menampilkan data paste: %s", + "+++ no document text +++": "+++ tidak ada teks document +++", + "Could not get document data: %s": "Tidak dapat mengambil/menampilkan data document: %s", "QR code": "Kode QR", "This website is using an insecure HTTP connection! Please use it only for testing.": "Situs web ini menggunakan koneksi HTTP yang tidak aman! Silahkan gunakan hanya untuk pengujian.", "For more information see this FAQ entry.": "Untuk informasi lebih lanjut, lihat entri FAQ ini .", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Catatan ter-ekrip di %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Kunjungi tautan ini untuk melihat catatan. Memberikan alamat URL pada siapapun juga, akan mengizinkan mereka untuk mengakses catatan, so pasti gitu loh Kaka.", "URL shortener may expose your decrypt key in URL.": "Pemendek URL mungkin akan menampakkan kunci dekrip Anda dalam URL.", - "Save paste": "Simpan paste", - "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Simpan document", + "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.", "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?", + "Yes, see it": "Yes, see it", + "Dark Mode": "Mode Gelap", + "Error compressing document, due to missing WebAssembly support.": "Error compressing document, due to missing WebAssembly support.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.", + "Start over": "Start over", + "Document copied to clipboard": "Document copied to clipboard", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/it.json b/i18n/it.json index 37da153f..1d91186c 100644 --- a/i18n/it.json +++ b/i18n/it.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s è un sistema di tipo \"Pastebin\" online, open source, minimalista. Il server non possiede alcuna conoscenza (\"Zero Knowledge\") del contenuto dei dati inviati. I dati sono cifrati/decifrati %snel Browser%s con algoritmo AES a 256 Bit.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s è un sistema di tipo \"Pastebin\" online, open source, minimalista. Il server non possiede alcuna conoscenza (\"Zero Knowledge\") del contenuto dei dati inviati. I dati sono cifrati/decifrati %snel Browser%s con algoritmo AES a 256 Bit.", "More information on the project page.": "Per ulteriori informazioni, vedi Sito del progetto.", "Because ignorance is bliss": "Perché l'ignoranza è una benedizione (Because ignorance is bliss)", - "Paste does not exist, has expired or has been deleted.": "Questo messaggio non esiste, è scaduto o è stato cancellato.", + "Document does not exist, has expired or has been deleted.": "Questo messaggio non esiste, è scaduto o è stato cancellato.", "%s requires php %s or above to work. Sorry.": "%s richiede php %s o superiore per funzionare. Ci spiace.", "%s requires configuration section [%s] to be present in configuration file.": "%s richiede la presenza della sezione [%s] nei file di configurazione.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Attendi per favore %d secondi prima di ciascun invio.", "Attendi per favore %d secondi prima di ciascun invio." ], - "Paste is limited to %s of encrypted data.": "La dimensione del messaggio è limitata a %s di dati cifrati.", + "Document is limited to %s of encrypted data.": "La dimensione del messaggio è limitata a %s di dati cifrati.", "Invalid data.": "Dati non validi.", "You are unlucky. Try again.": "Ritenta, sarai più fortunato.", "Error saving comment. Sorry.": "Errore durante il salvataggio del commento.", - "Error saving paste. Sorry.": "Errore durante il salvataggio del messaggio.", - "Invalid paste ID.": "ID-Messaggio non valido.", - "Paste is not of burn-after-reading type.": "Il messaggio non è di tipo Distruggi-dopo-lettura.", - "Wrong deletion token. Paste was not deleted.": "Codice cancellazione errato. Il messaggio NON è stato cancellato.", - "Paste was properly deleted.": "Il messaggio è stato correttamente cancellato.", + "Error saving document. Sorry.": "Errore durante il salvataggio del messaggio.", + "Invalid document ID.": "ID-Messaggio non valido.", + "Document is not of burn-after-reading type.": "Il messaggio non è di tipo Distruggi-dopo-lettura.", + "Wrong deletion token. Document was not deleted.": "Codice cancellazione errato. Il messaggio NON è stato cancellato.", + "Document was properly deleted.": "Il messaggio è stato correttamente cancellato.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "%s funziona solo con JavaScript attivo. Ci dispiace per l'inconveniente.", "%s requires a modern browser to work.": "%s richiede un browser moderno e aggiornato per funzionare.", "New": "Nuovo", - "Send": "Invia", + "Create": "Crea", "Clone": "Clona", "Raw text": "Testo Raw", "Expires": "Scade", @@ -133,9 +133,9 @@ "Questo documento scadrà in %d mesi.", "Questo documento scadrà in %d mesi." ], - "Please enter the password for this paste:": "Inserisci la password per questo messaggio:", + "Please enter the password for this document:": "Inserisci la password per questo messaggio:", "Could not decrypt data (Wrong key?)": "Non riesco a decifrare i dati (chiave sbagliata?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Non riesco a cancellare il messaggio, non è stato salvato in modalità Distruggi-dopo-lettora.", + "Could not delete the document, it was not stored in burn after reading mode.": "Non riesco a cancellare il messaggio, non è stato salvato in modalità Distruggi-dopo-lettora.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "FOR YOUR EYES ONLY. Non chiudere questa finestra, il messaggio non può essere visualizzato una seconda volta.", "Could not decrypt comment; Wrong key?": "Non riesco a decifrare il commento (Chiave sbagliata?)", "Reply": "Rispondi", @@ -150,27 +150,27 @@ "unknown status": "stato sconosciuto", "server error or not responding": "errore o mancata risposta dal server", "Could not post comment: %s": "Impossibile inviare il commento: %s", - "Sending paste…": "Messaggio in fase di invio…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Il tuo messaggio è qui: %s (Premi [Ctrl]+[c] (Windows) o [Cmd]+[c] (Mac) per copiare il link)", + "Sending document…": "Messaggio in fase di invio…", + "Your document is %s (Hit Ctrl+c to copy)": "Il tuo messaggio è qui: %s (Premi Ctrl+c (Windows) o [Cmd]+[c] (Mac) per copiare il link)", "Delete data": "Cancella i dati", - "Could not create paste: %s": "Non riesco a creare il messaggio: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Non riesco a decifrare il messaggio: manca la chiave di decifrazione nell'URL (La chiave è parte integrante dell'URL. Per caso hai usato un Redirector o un altro servizio che ha rimosso una parte dell'URL?)", + "Could not create document: %s": "Non riesco a creare il messaggio: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Non riesco a decifrare il messaggio: manca la chiave di decifrazione nell'URL (La chiave è parte integrante dell'URL. Per caso hai usato un Redirector o un altro servizio che ha rimosso una parte dell'URL?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Formato", "Plain Text": "Solo Testo", "Source Code": "Codice Sorgente", "Markdown": "Markdown", "Download attachment": "Scarica Allegato", "Cloned: '%s'": "Clonato: '%s'", - "The cloned file '%s' was attached to this paste.": "Il file clonato '%s' era allegato a questo messaggio.", + "The cloned file '%s' was attached to this document.": "Il file clonato '%s' era allegato a questo messaggio.", "Attach a file": "Allega un file", "alternatively drag & drop a file or paste an image from the clipboard": "in alternativa trascina e rilascia un file o incolla un'immagine dagli appunti", "File too large, to display a preview. Please download the attachment.": "File troppo grande, per visualizzare un'anteprima. Sei pregato di scaricare l'allegato.", @@ -185,11 +185,11 @@ "Decrypt": "Decifra", "Enter password": "Inserisci la password", "Loading…": "Carico…", - "Decrypting paste…": "Decifro il messaggio…", - "Preparing new paste…": "Preparo il nuovo messaggio…", + "Decrypting document…": "Decifro il messaggio…", + "Preparing new document…": "Preparo il nuovo messaggio…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "Nel caso questo messaggio non scompaia, controlla questa FAQ per trovare informazioni su come risolvere il problema (in Inglese).", - "+++ no paste text +++": "+++ nessun testo nel messaggio +++", - "Could not get paste data: %s": "Impossibile ottenere i dati di incolla: %s", + "+++ no document text +++": "+++ nessun testo nel messaggio +++", + "Could not get document data: %s": "Impossibile ottenere i dati di incolla: %s", "QR code": "QR code", "This website is using an insecure HTTP connection! Please use it only for testing.": "Questo sito web sta usando una connessione HTTP non sicura! Si prega di usarlo solo per il test.", "For more information see this FAQ entry.": "Per ulteriori informazioni vedi questa voce della FAQ.", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Nota crittografata su %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visita questo collegamento per vedere la nota. Dare l'URL a chiunque consente anche a loro di accedere alla nota.", "URL shortener may expose your decrypt key in URL.": "URL shortener può esporre la tua chiave decrittografata nell'URL.", - "Save paste": "Salva il messagio", - "Your IP is not authorized to create pastes.": "Il tuo IP non è autorizzato a creare dei messaggi.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Salva il messagio", + "Your IP is not authorized to create documents.": "Il tuo IP non è autorizzato a creare dei messaggi.", "Trying to shorten a URL that isn't pointing at our instance.": "Tantativo in corso di accorciare un URL che non punta alla nostra istanza.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Errore nella chiamata a YOURLS. Probabilmente un problema di configurazione, come un \"apiurl\" o una \"signature\" sbagliati o mancanti.", - "Error parsing YOURLS response.": "Errore nell'analizzare la risposta YOURLS.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Messaggi di tipo Distruggi-dopo-lettura piovono essere visualizzata solo una volta al caricamento. Vuoi aprirle ora?", - "Yes, load it": "Sì, caricalo" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Errore nella chiamata a YOURLS. Probabilmente un problema di configurazione, come un \"apiurl\" o una \"signature\" sbagliati o mancanti.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Errore nell'analizzare la risposta YOURLS.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "Questo messaggio di tipo Distruggi-dopo-lettura può essere visualizzato solo una volta. Vuoi vederlo ora?", + "Yes, see it": "Sì, visualizzalo", + "Dark Mode": "Tema Scuro", + "Error compressing document, due to missing WebAssembly support.": "Errore nella compressione dell messaggio, a causa del supporto WebAssembly mancante.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Errore nella decompressione dell messaggio, il tuo browser non supporta WebAssembly. Utilizza un altro browser per visualizzare questo messaggio.", + "Start over": "Ricominciare", + "Document copied to clipboard": "Messaggio copiato", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copia il link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Testo del messaggio", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/ja.json b/i18n/ja.json index 07323772..54650f04 100644 --- a/i18n/ja.json +++ b/i18n/ja.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s はミニマリストで、オープンソースのオンラインデータ貼り付けサービスです。サーバーに、貼り付けられたデータの中身を読み取ることはできません。データは、256ビットのAESを用いて%sブラウザー上で%s暗号化、または復号化されます。", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s はミニマリストで、オープンソースのオンラインデータ貼り付けサービスです。サーバーに、貼り付けられたデータの中身を読み取ることはできません。データは、256ビットのAESを用いて%sブラウザー上で%s暗号化、または復号化されます。", "More information on the project page.": "詳細についてはプロジェクトのページをご覧ください。", "Because ignorance is bliss": "知らぬが仏", - "Paste does not exist, has expired or has been deleted.": "ペーストが存在しないか、期限切れ、または削除されました。", + "Document does not exist, has expired or has been deleted.": "ペーストが存在しないか、期限切れ、または削除されました。", "%s requires php %s or above to work. Sorry.": "%s の動作には php %s 以上が必要です。申し訳ありません。", "%s requires configuration section [%s] to be present in configuration file.": "%sには設定ファイルに[%s]の設定セクションが必要です。", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "投稿ごとに%d秒間お待ちください。", "投稿ごとに%d秒間お待ちください。" ], - "Paste is limited to %s of encrypted data.": "ペーストは暗号化されたデータの%sに制限されています。", + "Document is limited to %s of encrypted data.": "ペーストは暗号化されたデータの%sに制限されています。", "Invalid data.": "無効なデータです。", "You are unlucky. Try again.": "何か問題が発生しました。もう一度やり直してください。", "Error saving comment. Sorry.": "コメントの保存中にエラーが発生しました。申し訳ありません。", - "Error saving paste. Sorry.": "ペーストの保存中にエラーが発生しました。申し訳ありません。", - "Invalid paste ID.": "無効なペーストIDです。", - "Paste is not of burn-after-reading type.": "ペーストは、読み込んだ後に消去される種類のものではありません。", - "Wrong deletion token. Paste was not deleted.": "不正な削除トークンです。ペーストは削除されませんでした。", - "Paste was properly deleted.": "ペーストが正しく削除されました。", + "Error saving document. Sorry.": "ペーストの保存中にエラーが発生しました。申し訳ありません。", + "Invalid document ID.": "無効なペーストIDです。", + "Document is not of burn-after-reading type.": "ペーストは、読み込んだ後に消去される種類のものではありません。", + "Wrong deletion token. Document was not deleted.": "不正な削除トークンです。ペーストは削除されませんでした。", + "Document was properly deleted.": "ペーストが正しく削除されました。", "JavaScript is required for %s to work. Sorry for the inconvenience.": "%s の動作にはJavaScriptが必要です。ご迷惑をおかけして申し訳ありません。", "%s requires a modern browser to work.": "%s の動作には最近のブラウザが必要です。", "New": "新規", - "Send": "送信", + "Create": "作成", "Clone": "複製", "Raw text": "未加工テキスト", "Expires": "有効期限", @@ -133,9 +133,9 @@ "このドキュメントは%dか月後に失効します。", "このドキュメントは%dか月後に失効します。" ], - "Please enter the password for this paste:": "このペーストのパスワードを入力してください。", + "Please enter the password for this document:": "このペーストのパスワードを入力してください。", "Could not decrypt data (Wrong key?)": "データを復号することができませんでした(間違った鍵ですか?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "ペーストを削除できませんでした。このペーストは、読み込んだ後に消去するモードでは保存されませんでした。", + "Could not delete the document, it was not stored in burn after reading mode.": "ペーストを削除できませんでした。このペーストは、読み込んだ後に消去するモードでは保存されませんでした。", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "このウィンドウを閉じないでください。このメッセージはもう表示できません。", "Could not decrypt comment; Wrong key?": "コメントを復号することができませんでした。間違った鍵ですか?", "Reply": "返信", @@ -150,27 +150,27 @@ "unknown status": "不明な状態", "server error or not responding": "サーバーエラーまたは応答しません", "Could not post comment: %s": "コメントを投稿できませんでした:%s", - "Sending paste…": "ペーストを送信しています…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "ペーストは%sです(コピーするには[Ctrl]+[c]を押してください)", + "Sending document…": "ペーストを送信しています…", + "Your document is %s (Hit Ctrl+c to copy)": "ペーストは%sです(コピーするにはCtrl+cを押してください)", "Delete data": "データを削除", - "Could not create paste: %s": "ペーストを作成できませんでした:%s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "ペーストを復号化できません:復号化キーがURLにありません(URLの一部を削除するリダイレクト機能またはURLの短縮アプリケーションを使いましたか?)", + "Could not create document: %s": "ペーストを作成できませんでした:%s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "ペーストを復号化できません:復号化キーがURLにありません(URLの一部を削除するリダイレクト機能またはURLの短縮アプリケーションを使いましたか?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "形式", "Plain Text": "プレーンテキスト", "Source Code": "ソースコード", "Markdown": "Markdown", "Download attachment": "添付ファイルをダウンロード", "Cloned: '%s'": "複製済:'%s'", - "The cloned file '%s' was attached to this paste.": "複製されたファイル '%s' がこのペーストに添付されました。", + "The cloned file '%s' was attached to this document.": "複製されたファイル '%s' がこのペーストに添付されました。", "Attach a file": "ファイルを添付", "alternatively drag & drop a file or paste an image from the clipboard": "代わりに、ファイルをドラッグ&ドロップまたはクリップボードから画像を貼り付け", "File too large, to display a preview. Please download the attachment.": "ファイルが大きすぎるため、プレビューを表示できません。ダウンロードしてください。", @@ -185,11 +185,11 @@ "Decrypt": "復号化", "Enter password": "パスワードを入力", "Loading…": "読み込んでいます…", - "Decrypting paste…": "ペーストを復号化しています…", - "Preparing new paste…": "新しいペーストを準備しています…", + "Decrypting document…": "ペーストを復号化しています…", + "Preparing new document…": "新しいペーストを準備しています…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "このメッセージが消去されない場合、トラブルシュート用のFAQをご確認ください。", - "+++ no paste text +++": "+++ ペーストのテキストはありません +++", - "Could not get paste data: %s": "ペーストのデータを取得できませんでした:%s", + "+++ no document text +++": "+++ ペーストのテキストはありません +++", + "Could not get document data: %s": "ペーストのデータを取得できませんでした:%s", "QR code": "QRコード", "This website is using an insecure HTTP connection! Please use it only for testing.": "このウェブサイトは安全でない HTTP 接続を使用しています!テストにのみ使用してください。", "For more information see this FAQ entry.": "詳細については、こちらのFAQエントリーをご覧ください。", @@ -210,11 +210,24 @@ "Encrypted note on %s": "%sの暗号化されたメモ", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "メモを見るには、このリンクを参照してください。誰でもURLからこのメモにアクセスできます。", "URL shortener may expose your decrypt key in URL.": "URLの短縮アプリケーションを使うと、復号用のキーが漏洩するおそれがあります。", - "Save paste": "ペーストを保存", - "Your IP is not authorized to create pastes.": "あなたのIPアドレスにはペーストを作成する権限がありません。", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "ペーストを保存", + "Your IP is not authorized to create documents.": "あなたのIPアドレスにはペーストを作成する権限がありません。", "Trying to shorten a URL that isn't pointing at our instance.": "このインスタンスを指していないURLを短縮しようとしています。", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "YOURLSの呼び出し中にエラーが発生しました。\"apiurl\"または\"signature\"等の設定に問題がある可能性があります。", - "Error parsing YOURLS response.": "YOURLSレスポンスの解析中にエラーが発生しました。", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "YOURLSの呼び出し中にエラーが発生しました。\"apiurl\"または\"signature\"等の設定に問題がある可能性があります。", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "YOURLSレスポンスの解析中にエラーが発生しました。", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?", + "Yes, see it": "はい、使用します", + "Dark Mode": "ダークモード", + "Error compressing document, due to missing WebAssembly support.": "Error compressing document, due to missing WebAssembly support.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.", + "Start over": "Start over", + "Document copied to clipboard": "Document copied to clipboard", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/jbo.json b/i18n/jbo.json index f729f613..90160ecf 100644 --- a/i18n/jbo.json +++ b/i18n/jbo.json @@ -1,9 +1,9 @@ { "PrivateBin": "sivlolnitvanku'a", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": ".i la %s mupli lo sorcu lo'e se setca kibro .i ji'a zo'e se zancari gi'e fingubni .i lo samse'u na djuno lo datni selru'e cu .i ba'e %sle brauzero%s ku mipri le do datni ku fi la'oi AES poi bitni li 256", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": ".i la %s mupli lo sorcu lo'e se setca kibro .i ji'a zo'e se zancari gi'e fingubni .i lo samse'u na djuno lo datni selru'e cu .i ba'e %sle brauzero%s ku mipri le do datni ku fi la'oi AES poi bitni li 256", "More information on the project page.": "More information on the project page.", "Because ignorance is bliss": ".i ki'u le ka na djuno cu ka saxfri", - "Paste does not exist, has expired or has been deleted.": "Paste does not exist, has expired or has been deleted.", + "Document does not exist, has expired or has been deleted.": "Document does not exist, has expired or has been deleted.", "%s requires php %s or above to work. Sorry.": "%s requires php %s or above to work. Sorry.", "%s requires configuration section [%s] to be present in configuration file.": "%s requires configuration section [%s] to be present in configuration file.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Please wait %d seconds between each post. (4th plural)", "Please wait %d seconds between each post. (5th plural)" ], - "Paste is limited to %s of encrypted data.": "Paste is limited to %s of encrypted data.", + "Document is limited to %s of encrypted data.": "Document is limited to %s of encrypted data.", "Invalid data.": ".i le selru'e cu na drani", "You are unlucky. Try again.": "You are unlucky. Try again.", "Error saving comment. Sorry.": "Error saving comment. Sorry.", - "Error saving paste. Sorry.": "Error saving paste. Sorry.", - "Invalid paste ID.": "Invalid paste ID.", - "Paste is not of burn-after-reading type.": "Paste is not of burn-after-reading type.", - "Wrong deletion token. Paste was not deleted.": "Wrong deletion token. Paste was not deleted.", - "Paste was properly deleted.": "Paste was properly deleted.", + "Error saving document. Sorry.": "Error saving document. Sorry.", + "Invalid document ID.": "Invalid document ID.", + "Document is not of burn-after-reading type.": "Document is not of burn-after-reading type.", + "Wrong deletion token. Document was not deleted.": "Wrong deletion token. Document was not deleted.", + "Document was properly deleted.": "Document was properly deleted.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript is required for %s to work. Sorry for the inconvenience.", "%s requires a modern browser to work.": "%s requires a modern browser to work.", "New": "cnino", - "Send": "benji", + "Create": "benji", "Clone": "fukpi", "Raw text": "vlapoi nalselrucyzu'e", "Expires": "vimcu", @@ -133,9 +133,9 @@ "This document will expire in %d months. (4th plural)", "This document will expire in %d months. (5th plural)" ], - "Please enter the password for this paste:": "Please enter the password for this paste:", + "Please enter the password for this document:": "Please enter the password for this document:", "Could not decrypt data (Wrong key?)": "Could not decrypt data (Wrong key?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Could not delete the paste, it was not stored in burn after reading mode.", + "Could not delete the document, it was not stored in burn after reading mode.": "Could not delete the document, it was not stored in burn after reading mode.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.", "Could not decrypt comment; Wrong key?": "Could not decrypt comment; Wrong key?", "Reply": "Reply", @@ -150,27 +150,27 @@ "unknown status": "unknown status", "server error or not responding": "server error or not responding", "Could not post comment: %s": "Could not post comment: %s", - "Sending paste…": "Sending paste…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Your paste is %s (Hit [Ctrl]+[c] to copy)", + "Sending document…": "Sending document…", + "Your document is %s (Hit Ctrl+c to copy)": "Your document is %s (Hit Ctrl+c to copy)", "Delete data": "Delete data", - "Could not create paste: %s": "Could not create paste: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)", + "Could not create document: %s": "Could not create document: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Plain Text", "Source Code": "Source Code", "Markdown": "Markdown", "Download attachment": "Download attachment", "Cloned: '%s'": "Cloned: '%s'", - "The cloned file '%s' was attached to this paste.": "The cloned file '%s' was attached to this paste.", + "The cloned file '%s' was attached to this document.": "The cloned file '%s' was attached to this document.", "Attach a file": "Attach a file", "alternatively drag & drop a file or paste an image from the clipboard": "alternatively drag & drop a file or paste an image from the clipboard", "File too large, to display a preview. Please download the attachment.": "File too large, to display a preview. Please download the attachment.", @@ -185,11 +185,11 @@ "Decrypt": "Decrypt", "Enter password": "Enter password", "Loading…": "Loading…", - "Decrypting paste…": "Decrypting paste…", - "Preparing new paste…": "Preparing new paste…", + "Decrypting document…": "Decrypting document…", + "Preparing new document…": "Preparing new document…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "In case this message never disappears please have a look at this FAQ for information to troubleshoot.", - "+++ no paste text +++": "+++ no paste text +++", - "Could not get paste data: %s": "Could not get paste data: %s", + "+++ no document text +++": "+++ no document text +++", + "Could not get document data: %s": "Could not get document data: %s", "QR code": "ky.bu ry termifra", "This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.", "For more information see this FAQ entry.": "For more information see this FAQ entry.", @@ -210,11 +210,24 @@ "Encrypted note on %s": ".i lo lo notci ku mifra cu zvati %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.", "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.", - "Save paste": "rejgau fukpi", - "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "rejgau fukpi", + "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.", "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?", + "Yes, see it": "Yes, see it", + "Dark Mode": "Dark Mode", + "Error compressing document, due to missing WebAssembly support.": "Error compressing document, due to missing WebAssembly support.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.", + "Start over": "Start over", + "Document copied to clipboard": "Document copied to clipboard", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/ko.json b/i18n/ko.json new file mode 100644 index 00000000..c0d21fca --- /dev/null +++ b/i18n/ko.json @@ -0,0 +1,233 @@ +{ + "PrivateBin": "PrivateBin", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.", + "More information on the project page.": "More information on the project page.", + "Because ignorance is bliss": "Because ignorance is bliss", + "Document does not exist, has expired or has been deleted.": "Document does not exist, has expired or has been deleted.", + "%s requires php %s or above to work. Sorry.": "%s requires php %s or above to work. Sorry.", + "%s requires configuration section [%s] to be present in configuration file.": "%s requires configuration section [%s] to be present in configuration file.", + "Please wait %d seconds between each post.": [ + "Please wait %d second between each post. (singular)", + "Please wait %d seconds between each post. (1st plural)", + "Please wait %d seconds between each post. (2nd plural)", + "Please wait %d seconds between each post. (3rd plural)", + "Please wait %d seconds between each post. (4th plural)", + "Please wait %d seconds between each post. (5th plural)" + ], + "Document is limited to %s of encrypted data.": "Document is limited to %s of encrypted data.", + "Invalid data.": "Invalid data.", + "You are unlucky. Try again.": "You are unlucky. Try again.", + "Error saving comment. Sorry.": "Error saving comment. Sorry.", + "Error saving document. Sorry.": "Error saving document. Sorry.", + "Invalid document ID.": "Invalid document ID.", + "Document is not of burn-after-reading type.": "Document is not of burn-after-reading type.", + "Wrong deletion token. Document was not deleted.": "Wrong deletion token. Document was not deleted.", + "Document was properly deleted.": "Document was properly deleted.", + "JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript is required for %s to work. Sorry for the inconvenience.", + "%s requires a modern browser to work.": "%s requires a modern browser to work.", + "New": "New", + "Create": "Create", + "Clone": "Clone", + "Raw text": "Raw text", + "Expires": "Expires", + "Burn after reading": "Burn after reading", + "Open discussion": "Open discussion", + "Password (recommended)": "Password (recommended)", + "Discussion": "Discussion", + "Toggle navigation": "Toggle navigation", + "%d seconds": [ + "%d second (singular)", + "%d seconds (1st plural)", + "%d seconds (2nd plural)", + "%d seconds (3rd plural)", + "%d seconds (4th plural)", + "%d seconds (5th plural)" + ], + "%d minutes": [ + "%d minute (singular)", + "%d minutes (1st plural)", + "%d minutes (2nd plural)", + "%d minutes (3rd plural)", + "%d minutes (4th plural)", + "%d minutes (5th plural)" + ], + "%d hours": [ + "%d hour (singular)", + "%d hours (1st plural)", + "%d hours (2nd plural)", + "%d hours (3rd plural)", + "%d hours (4th plural)", + "%d hours (5th plural)" + ], + "%d days": [ + "%d day (singular)", + "%d days (1st plural)", + "%d days (2nd plural)", + "%d days (3rd plural)", + "%d days (4th plural)", + "%d days (5th plural)" + ], + "%d weeks": [ + "%d week (singular)", + "%d weeks (1st plural)", + "%d weeks (2nd plural)", + "%d weeks (3rd plural)", + "%d weeks (4th plural)", + "%d weeks (5th plural)" + ], + "%d months": [ + "%d month (singular)", + "%d months (1st plural)", + "%d months (2nd plural)", + "%d months (3rd plural)", + "%d months (4th plural)", + "%d months (5th plural)" + ], + "%d years": [ + "%d year (singular)", + "%d years (1st plural)", + "%d years (2nd plural)", + "%d years (3rd plural)", + "%d years (4th plural)", + "%d years (5th plural)" + ], + "Never": "Never", + "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.", + "This document will expire in %d seconds.": [ + "This document will expire in %d second. (singular)", + "This document will expire in %d seconds. (1st plural)", + "This document will expire in %d seconds. (2nd plural)", + "This document will expire in %d seconds. (3rd plural)", + "This document will expire in %d seconds. (4th plural)", + "This document will expire in %d seconds. (5th plural)" + ], + "This document will expire in %d minutes.": [ + "This document will expire in %d minute. (singular)", + "This document will expire in %d minutes. (1st plural)", + "This document will expire in %d minutes. (2nd plural)", + "This document will expire in %d minutes. (3rd plural)", + "This document will expire in %d minutes. (4th plural)", + "This document will expire in %d minutes. (5th plural)" + ], + "This document will expire in %d hours.": [ + "This document will expire in %d hour. (singular)", + "This document will expire in %d hours. (1st plural)", + "This document will expire in %d hours. (2nd plural)", + "This document will expire in %d hours. (3rd plural)", + "This document will expire in %d hours. (4th plural)", + "This document will expire in %d hours. (5th plural)" + ], + "This document will expire in %d days.": [ + "This document will expire in %d day. (singular)", + "This document will expire in %d days. (1st plural)", + "This document will expire in %d days. (2nd plural)", + "This document will expire in %d days. (3rd plural)", + "This document will expire in %d days. (4th plural)", + "This document will expire in %d days. (5th plural)" + ], + "This document will expire in %d months.": [ + "This document will expire in %d month. (singular)", + "This document will expire in %d months. (1st plural)", + "This document will expire in %d months. (2nd plural)", + "This document will expire in %d months. (3rd plural)", + "This document will expire in %d months. (4th plural)", + "This document will expire in %d months. (5th plural)" + ], + "Please enter the password for this document:": "Please enter the password for this document:", + "Could not decrypt data (Wrong key?)": "Could not decrypt data (Wrong key?)", + "Could not delete the document, it was not stored in burn after reading mode.": "Could not delete the document, it was not stored in burn after reading mode.", + "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.", + "Could not decrypt comment; Wrong key?": "Could not decrypt comment; Wrong key?", + "Reply": "Reply", + "Anonymous": "Anonymous", + "Avatar generated from IP address": "Avatar generated from IP address", + "Add comment": "Add comment", + "Optional nickname…": "Optional nickname…", + "Post comment": "Post comment", + "Sending comment…": "Sending comment…", + "Comment posted.": "Comment posted.", + "Could not refresh display: %s": "Could not refresh display: %s", + "unknown status": "unknown status", + "server error or not responding": "server error or not responding", + "Could not post comment: %s": "Could not post comment: %s", + "Sending document…": "Sending document…", + "Your document is %s (Hit Ctrl+c to copy)": "Your document is %s (Hit Ctrl+c to copy)", + "Delete data": "Delete data", + "Could not create document: %s": "Could not create document: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)", + "B": "B", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", + "Format": "Format", + "Plain Text": "Plain Text", + "Source Code": "Source Code", + "Markdown": "Markdown", + "Download attachment": "Download attachment", + "Cloned: '%s'": "Cloned: '%s'", + "The cloned file '%s' was attached to this document.": "The cloned file '%s' was attached to this document.", + "Attach a file": "Attach a file", + "alternatively drag & drop a file or paste an image from the clipboard": "alternatively drag & drop a file or paste an image from the clipboard", + "File too large, to display a preview. Please download the attachment.": "File too large, to display a preview. Please download the attachment.", + "Remove attachment": "Remove attachment", + "Your browser does not support uploading encrypted files. Please use a newer browser.": "Your browser does not support uploading encrypted files. Please use a newer browser.", + "Invalid attachment.": "Invalid attachment.", + "Options": "Options", + "Shorten URL": "Shorten URL", + "Editor": "Editor", + "Preview": "Preview", + "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.", + "Decrypt": "Decrypt", + "Enter password": "Enter password", + "Loading…": "Loading…", + "Decrypting document…": "Decrypting document…", + "Preparing new document…": "Preparing new document…", + "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "In case this message never disappears please have a look at this FAQ for information to troubleshoot.", + "+++ no document text +++": "+++ no document text +++", + "Could not get document data: %s": "Could not get document data: %s", + "QR code": "QR code", + "This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.", + "For more information see this FAQ entry.": "For more information see this FAQ entry.", + "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.", + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.", + "waiting on user to provide a password": "waiting on user to provide a password", + "Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.", + "Retry": "Retry", + "Showing raw text…": "Showing raw text…", + "Notice:": "Notice:", + "This link will expire after %s.": "This link will expire after %s.", + "This link can only be accessed once, do not use back or refresh button in your browser.": "This link can only be accessed once, do not use back or refresh button in your browser.", + "Link:": "Link:", + "Recipient may become aware of your timezone, convert time to UTC?": "Recipient may become aware of your timezone, convert time to UTC?", + "Use Current Timezone": "Use Current Timezone", + "Convert To UTC": "Convert To UTC", + "Close": "Close", + "Encrypted note on %s": "Encrypted note on %s", + "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.", + "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Save document", + "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.", + "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.", + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?", + "Yes, see it": "Yes, see it", + "Dark Mode": "Dark Mode", + "Error compressing document, due to missing WebAssembly support.": "Error compressing document, due to missing WebAssembly support.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.", + "Start over": "Start over", + "Document copied to clipboard": "Document copied to clipboard", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" +} diff --git a/i18n/ku.json b/i18n/ku.json index 6ef3280b..e72469d0 100644 --- a/i18n/ku.json +++ b/i18n/ku.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.", "More information on the project page.": "More information on the project page.", "Because ignorance is bliss": "Because ignorance is bliss", - "Paste does not exist, has expired or has been deleted.": "Paste does not exist, has expired or has been deleted.", + "Document does not exist, has expired or has been deleted.": "Document does not exist, has expired or has been deleted.", "%s requires php %s or above to work. Sorry.": "%s requires php %s or above to work. Sorry.", "%s requires configuration section [%s] to be present in configuration file.": "%s requires configuration section [%s] to be present in configuration file.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Please wait %d seconds between each post. (4th plural)", "Please wait %d seconds between each post. (5th plural)" ], - "Paste is limited to %s of encrypted data.": "Paste is limited to %s of encrypted data.", + "Document is limited to %s of encrypted data.": "Document is limited to %s of encrypted data.", "Invalid data.": "Invalid data.", "You are unlucky. Try again.": "You are unlucky. Try again.", "Error saving comment. Sorry.": "Error saving comment. Sorry.", - "Error saving paste. Sorry.": "Error saving paste. Sorry.", - "Invalid paste ID.": "Invalid paste ID.", - "Paste is not of burn-after-reading type.": "Paste is not of burn-after-reading type.", - "Wrong deletion token. Paste was not deleted.": "Wrong deletion token. Paste was not deleted.", - "Paste was properly deleted.": "Paste was properly deleted.", + "Error saving document. Sorry.": "Error saving document. Sorry.", + "Invalid document ID.": "Invalid document ID.", + "Document is not of burn-after-reading type.": "Document is not of burn-after-reading type.", + "Wrong deletion token. Document was not deleted.": "Wrong deletion token. Document was not deleted.", + "Document was properly deleted.": "Document was properly deleted.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript is required for %s to work. Sorry for the inconvenience.", "%s requires a modern browser to work.": "%s requires a modern browser to work.", "New": "New", - "Send": "Send", + "Create": "Create", "Clone": "Clone", "Raw text": "Raw text", "Expires": "Expires", @@ -133,9 +133,9 @@ "This document will expire in %d months. (4th plural)", "This document will expire in %d months. (5th plural)" ], - "Please enter the password for this paste:": "Please enter the password for this paste:", + "Please enter the password for this document:": "Please enter the password for this document:", "Could not decrypt data (Wrong key?)": "Could not decrypt data (Wrong key?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Could not delete the paste, it was not stored in burn after reading mode.", + "Could not delete the document, it was not stored in burn after reading mode.": "Could not delete the document, it was not stored in burn after reading mode.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.", "Could not decrypt comment; Wrong key?": "Could not decrypt comment; Wrong key?", "Reply": "Reply", @@ -150,27 +150,27 @@ "unknown status": "unknown status", "server error or not responding": "server error or not responding", "Could not post comment: %s": "Could not post comment: %s", - "Sending paste…": "Sending paste…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Your paste is %s (Hit [Ctrl]+[c] to copy)", + "Sending document…": "Sending document…", + "Your document is %s (Hit Ctrl+c to copy)": "Your document is %s (Hit Ctrl+c to copy)", "Delete data": "Delete data", - "Could not create paste: %s": "Could not create paste: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)", + "Could not create document: %s": "Could not create document: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Plain Text", "Source Code": "Source Code", "Markdown": "Markdown", "Download attachment": "Download attachment", "Cloned: '%s'": "Cloned: '%s'", - "The cloned file '%s' was attached to this paste.": "The cloned file '%s' was attached to this paste.", + "The cloned file '%s' was attached to this document.": "The cloned file '%s' was attached to this document.", "Attach a file": "Attach a file", "alternatively drag & drop a file or paste an image from the clipboard": "alternatively drag & drop a file or paste an image from the clipboard", "File too large, to display a preview. Please download the attachment.": "File too large, to display a preview. Please download the attachment.", @@ -185,11 +185,11 @@ "Decrypt": "Decrypt", "Enter password": "Enter password", "Loading…": "Loading…", - "Decrypting paste…": "Decrypting paste…", - "Preparing new paste…": "Preparing new paste…", + "Decrypting document…": "Decrypting document…", + "Preparing new document…": "Preparing new document…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "In case this message never disappears please have a look at this FAQ for information to troubleshoot.", - "+++ no paste text +++": "+++ no paste text +++", - "Could not get paste data: %s": "Could not get paste data: %s", + "+++ no document text +++": "+++ no document text +++", + "Could not get document data: %s": "Could not get document data: %s", "QR code": "QR code", "This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.", "For more information see this FAQ entry.": "For more information see this FAQ entry.", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Encrypted note on %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.", "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.", - "Save paste": "Save paste", - "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Save document", + "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.", "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?", + "Yes, see it": "Yes, see it", + "Dark Mode": "جۆری ڕەش", + "Error compressing document, due to missing WebAssembly support.": "Error compressing document, due to missing WebAssembly support.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.", + "Start over": "Start over", + "Document copied to clipboard": "Document copied to clipboard", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/la.json b/i18n/la.json index 895f0b02..081d551f 100644 --- a/i18n/la.json +++ b/i18n/la.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivatumVinariam", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.", "More information on the project page.": "More information on the project page.", "Because ignorance is bliss": "Because ignorance is bliss", - "Paste does not exist, has expired or has been deleted.": "Paste does not exist, has expired or has been deleted.", + "Document does not exist, has expired or has been deleted.": "Document does not exist, has expired or has been deleted.", "%s requires php %s or above to work. Sorry.": "%s requires php %s or above to work. Sorry.", "%s requires configuration section [%s] to be present in configuration file.": "%s requires configuration section [%s] to be present in configuration file.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Please wait %d seconds between each post. (4th plural)", "Please wait %d seconds between each post. (5th plural)" ], - "Paste is limited to %s of encrypted data.": "Paste is limited to %s of encrypted data.", + "Document is limited to %s of encrypted data.": "Document is limited to %s of encrypted data.", "Invalid data.": "Invalid data.", "You are unlucky. Try again.": "You are unlucky. Try again.", "Error saving comment. Sorry.": "Error saving comment. Sorry.", - "Error saving paste. Sorry.": "Error saving paste. Sorry.", - "Invalid paste ID.": "Invalid paste ID.", - "Paste is not of burn-after-reading type.": "Paste is not of burn-after-reading type.", - "Wrong deletion token. Paste was not deleted.": "Wrong deletion token. Paste was not deleted.", - "Paste was properly deleted.": "Paste was properly deleted.", + "Error saving document. Sorry.": "Error saving document. Sorry.", + "Invalid document ID.": "Invalid document ID.", + "Document is not of burn-after-reading type.": "Document is not of burn-after-reading type.", + "Wrong deletion token. Document was not deleted.": "Wrong deletion token. Document was not deleted.", + "Document was properly deleted.": "Document was properly deleted.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript is required for %s to work. Sorry for the inconvenience.", "%s requires a modern browser to work.": "%s requires a modern browser to work.", "New": "New", - "Send": "Send", + "Create": "Create", "Clone": "Clone", "Raw text": "Raw text", "Expires": "Expires", @@ -133,9 +133,9 @@ "This document will expire in %d months. (4th plural)", "This document will expire in %d months. (5th plural)" ], - "Please enter the password for this paste:": "Please enter the password for this paste:", + "Please enter the password for this document:": "Please enter the password for this document:", "Could not decrypt data (Wrong key?)": "Could not decrypt data (Wrong key?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Could not delete the paste, it was not stored in burn after reading mode.", + "Could not delete the document, it was not stored in burn after reading mode.": "Could not delete the document, it was not stored in burn after reading mode.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.", "Could not decrypt comment; Wrong key?": "Could not decrypt comment; Wrong key?", "Reply": "Reply", @@ -150,27 +150,27 @@ "unknown status": "unknown status", "server error or not responding": "server error or not responding", "Could not post comment: %s": "Could not post comment: %s", - "Sending paste…": "Sending paste…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Your paste is %s (Hit [Ctrl]+[c] to copy)", + "Sending document…": "Sending document…", + "Your document is %s (Hit Ctrl+c to copy)": "Your document is %s (Hit Ctrl+c to copy)", "Delete data": "Delete data", - "Could not create paste: %s": "Could not create paste: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)", + "Could not create document: %s": "Could not create document: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Plain Text", "Source Code": "Source Code", "Markdown": "Markdown", "Download attachment": "Download attachment", "Cloned: '%s'": "Cloned: '%s'", - "The cloned file '%s' was attached to this paste.": "The cloned file '%s' was attached to this paste.", + "The cloned file '%s' was attached to this document.": "The cloned file '%s' was attached to this document.", "Attach a file": "Attach a file", "alternatively drag & drop a file or paste an image from the clipboard": "alternatively drag & drop a file or paste an image from the clipboard", "File too large, to display a preview. Please download the attachment.": "File too large, to display a preview. Please download the attachment.", @@ -185,11 +185,11 @@ "Decrypt": "Decrypt", "Enter password": "Enter password", "Loading…": "Loading…", - "Decrypting paste…": "Decrypting paste…", - "Preparing new paste…": "Preparing new paste…", + "Decrypting document…": "Decrypting document…", + "Preparing new document…": "Preparing new document…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "In case this message never disappears please have a look at this FAQ for information to troubleshoot.", - "+++ no paste text +++": "+++ no paste text +++", - "Could not get paste data: %s": "Could not get paste data: %s", + "+++ no document text +++": "+++ no document text +++", + "Could not get document data: %s": "Could not get document data: %s", "QR code": "QR code", "This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.", "For more information see this FAQ entry.": "For more information see this FAQ entry.", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Encrypted note on %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.", "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.", - "Save paste": "Save paste", - "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Save document", + "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.", "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?", + "Yes, see it": "Yes, see it", + "Dark Mode": "Dark Mode", + "Error compressing document, due to missing WebAssembly support.": "Error compressing document, due to missing WebAssembly support.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.", + "Start over": "Start over", + "Document copied to clipboard": "Document copied to clipboard", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/lt.json b/i18n/lt.json index 81dfe123..02253d08 100644 --- a/i18n/lt.json +++ b/i18n/lt.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s yra minimalistinis, atvirojo kodo internetinis įdėjimų dėklas, kurį naudojant, serveris nieko nenutuokia apie įdėtus duomenis. Duomenys yra šifruojami/iššifruojami %snaršyklėje%s naudojant 256 bitų AES.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s yra minimalistinis, atvirojo kodo internetinis įdėjimų dėklas, kurį naudojant, serveris nieko nenutuokia apie įdėtus duomenis. Duomenys yra šifruojami/iššifruojami %snaršyklėje%s naudojant 256 bitų AES.", "More information on the project page.": "Daugiau informacijos rasite projekto puslapyje.", "Because ignorance is bliss": "Nes nežinojimas yra palaima", - "Paste does not exist, has expired or has been deleted.": "Įdėjimo nėra, jis nebegalioja arba buvo ištrintas.", + "Document does not exist, has expired or has been deleted.": "Įdėjimo nėra, jis nebegalioja arba buvo ištrintas.", "%s requires php %s or above to work. Sorry.": "%s savo darbui reikalauja php %s arba naujesnės versijos. Apgailestaujame.", "%s requires configuration section [%s] to be present in configuration file.": "%s reikalauja, kad konfigūracijos faile būtų [%s] konfigūracijos sekcija.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Tarp kiekvieno įrašo palaukite %d sekundžių.", "Tarp kiekvieno įrašo palaukite %d sekundžių." ], - "Paste is limited to %s of encrypted data.": "Įdėjimas yra apribotas iki %s šifruotų duomenų.", + "Document is limited to %s of encrypted data.": "Įdėjimas yra apribotas iki %s šifruotų duomenų.", "Invalid data.": "Neteisingi duomenys.", "You are unlucky. Try again.": "Jums nesiseka. Bandykite dar kartą.", "Error saving comment. Sorry.": "Klaida įrašant komentarą. Apgailestaujame.", - "Error saving paste. Sorry.": "Klaida įrašant įdėjimą. Apgailestaujame.", - "Invalid paste ID.": "Neteisingas įdėjimo ID.", - "Paste is not of burn-after-reading type.": "Įdėjimo tipas nėra „Perskaičius sudeginti“.", - "Wrong deletion token. Paste was not deleted.": "Neteisingas ištrynimo prieigos raktas. Įdėjimas nebuvo ištrintas.", - "Paste was properly deleted.": "Įdėjimas buvo tinkamai ištrintas.", + "Error saving document. Sorry.": "Klaida įrašant įdėjimą. Apgailestaujame.", + "Invalid document ID.": "Neteisingas įdėjimo ID.", + "Document is not of burn-after-reading type.": "Įdėjimo tipas nėra „Perskaičius sudeginti“.", + "Wrong deletion token. Document was not deleted.": "Neteisingas ištrynimo prieigos raktas. Įdėjimas nebuvo ištrintas.", + "Document was properly deleted.": "Įdėjimas buvo tinkamai ištrintas.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "%s darbui reikalinga JavaScript. Atsiprašome už nepatogumus.", "%s requires a modern browser to work.": "%s savo darbui reikalauja šiuolaikinės naršyklės.", "New": "Naujas", - "Send": "Siųsti", + "Create": "Sukurti", "Clone": "Dubliuoti", "Raw text": "Neapdorotas tekstas", "Expires": "Baigs galioti po", @@ -133,9 +133,9 @@ "Šis dokumentas nustos galioti po %d mėnesių.", "Šis dokumentas nustos galioti po %d mėnesių." ], - "Please enter the password for this paste:": "Įveskite šio įdėjimo slaptažodį:", + "Please enter the password for this document:": "Įveskite šio įdėjimo slaptažodį:", "Could not decrypt data (Wrong key?)": "Nepavyko iššifruoti duomenų (Neteisingas raktas?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Nepavyko ištrinti įdėjimo, jis nebuvo saugomas „Perskaičius sudeginti“ veiksenoje.", + "Could not delete the document, it was not stored in burn after reading mode.": "Nepavyko ištrinti įdėjimo, jis nebuvo saugomas „Perskaičius sudeginti“ veiksenoje.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "SKIRTA TIK JŪSŲ AKIMS. Neužverkite šio lango, šis pranešimas negalės būti rodomas dar kartą.", "Could not decrypt comment; Wrong key?": "Nepavyko iššifruoti komentaro; Neteisingas raktas?", "Reply": "Atsakyti", @@ -150,27 +150,27 @@ "unknown status": "nežinoma būsena", "server error or not responding": "serverio klaida arba jis neatsako", "Could not post comment: %s": "Nepavyko paskelbti komentaro: %s", - "Sending paste…": "Siunčiamas įdėjimas…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Jūsų įdėjimas yra %s (Paspauskite [Vald]+[c] norėdami nukopijuoti)", + "Sending document…": "Siunčiamas įdėjimas…", + "Your document is %s (Hit Ctrl+c to copy)": "Jūsų įdėjimas yra %s (Paspauskite Vald+c norėdami nukopijuoti)", "Delete data": "Ištrinti duomenis", - "Could not create paste: %s": "Nepavyko sukurti įdėjimo: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Nepavyksta iššifruoti įdėjimo: URL adrese trūksta iššifravimo rakto (Ar naudojote peradresavimo ar URL trumpinimo įrankį, kuris pašalina URL dalį?)", + "Could not create document: %s": "Nepavyko sukurti įdėjimo: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Nepavyksta iššifruoti įdėjimo: URL adrese trūksta iššifravimo rakto (Ar naudojote peradresavimo ar URL trumpinimo įrankį, kuris pašalina URL dalį?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Formatas", "Plain Text": "Grynasis tekstas", "Source Code": "Pirminis kodas", "Markdown": "„Markdown“", "Download attachment": "Atsisiųsti priedą", "Cloned: '%s'": "Dubliuota: „%s“", - "The cloned file '%s' was attached to this paste.": "Dubliuotas failas „%s“ buvo pridėtas į šį įdėjimą.", + "The cloned file '%s' was attached to this document.": "Dubliuotas failas „%s“ buvo pridėtas į šį įdėjimą.", "Attach a file": "Pridėti failą", "alternatively drag & drop a file or paste an image from the clipboard": "arba kitaip - tempkite failą arba įdėkite paveikslą iš iškarpinės", "File too large, to display a preview. Please download the attachment.": "Failas per didelis, kad būtų rodoma peržiūra. Atsisiųskite priedą.", @@ -185,11 +185,11 @@ "Decrypt": "Iššifruoti", "Enter password": "Įveskite slaptažodį", "Loading…": "Įkeliama…", - "Decrypting paste…": "Iššifruojamas įdėjimas…", - "Preparing new paste…": "Ruošiamas naujas įdėjimas…", + "Decrypting document…": "Iššifruojamas įdėjimas…", + "Preparing new document…": "Ruošiamas naujas įdėjimas…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "Jeigu šis pranešimas niekada nedingsta, pasižiūrėkite šį DUK skyrių, kuriame yra informacija apie nesklandumų šalinimą.", - "+++ no paste text +++": "+++ nėra įdėjimo teksto +++", - "Could not get paste data: %s": "Nepavyko gauti įdėjimo duomenų: %s", + "+++ no document text +++": "+++ nėra įdėjimo teksto +++", + "Could not get document data: %s": "Nepavyko gauti įdėjimo duomenų: %s", "QR code": "QR kodas", "This website is using an insecure HTTP connection! Please use it only for testing.": "Ši internetinė svetainė naudoja nesaugų HTTP ryšį! Naudokite ją tik bandymams.", "For more information see this FAQ entry.": "Išsamesnei informacijai, žiūrėkite šį DUK įrašą.", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Šifruoti užrašai ties %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Norėdami matyti užrašus, aplankykite šį tinklalapį. Pasidalinus šiuo URL adresu su kitais žmonėmis, jiems taip pat bus leidžiama prieiga prie šių užrašų.", "URL shortener may expose your decrypt key in URL.": "URL trumpinimo įrankis gali atskleisti URL adrese jūsų iššifravimo raktą.", - "Save paste": "Įrašyti įdėjimą", - "Your IP is not authorized to create pastes.": "Jūsų IP adresas neturi įgaliojimų kurti įdėjimų.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Įrašyti įdėjimą", + "Your IP is not authorized to create documents.": "Jūsų IP adresas neturi įgaliojimų kurti įdėjimų.", "Trying to shorten a URL that isn't pointing at our instance.": "Bandoma sutrumpinti URL adresą, kuris nenurodo į mūsų egzempliorių.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Klaida iškviečiant YOURLS. Tikriausiai, konfigūracijos klaida, pavyzdžiui, neteisingi „apiurl“ ar „signature“, arba jų nėra.", - "Error parsing YOURLS response.": "Klaida nagrinėjant YOURLS atsaką.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Klaida iškviečiant YOURLS. Tikriausiai, konfigūracijos klaida, pavyzdžiui, neteisingi „apiurl“ ar „signature“, arba jų nėra.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Klaida nagrinėjant YOURLS atsaką.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "Ši slapta žinutė gali būti parodyta tik vieną kartą. Ar norėtumėte ją dabar pamatyti?", + "Yes, see it": "Taip, pamatyti", + "Dark Mode": "Tamsi veiksena", + "Error compressing document, due to missing WebAssembly support.": "Klaida glaudinant įdėjimą, nes trūksta WebAssembly palaikymo.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Klaida išglaudinant įdėjimą, jūsų naršyklė nepalaiko WebAssembly. Norėdami peržiūrėti šį įdėjimą, naudokite kitą naršyklę.", + "Start over": "Start over", + "Document copied to clipboard": "Document copied to clipboard", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/nl.json b/i18n/nl.json index fc058a20..220ff9db 100644 --- a/i18n/nl.json +++ b/i18n/nl.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s is een minimalistische, open source online pastebin waarbij de server geen kennis heeft van de paste data zelf. Gegevens worden gecodeerd/gedecodeerd %s in de browser %s met behulp van 256-bits AES.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s is een minimalistische, open source online pastebin waarbij de server geen kennis heeft van de document data zelf. Gegevens worden gecodeerd/gedecodeerd %s in de browser %s met behulp van 256-bits AES.", "More information on the project page.": "Meer informatie is te vinden op de projectpagina.", "Because ignorance is bliss": "Onwetendheid is een zegen", - "Paste does not exist, has expired or has been deleted.": "Paste bestaat niet, is verlopen of verwijderd.", + "Document does not exist, has expired or has been deleted.": "Document bestaat niet, is verlopen of verwijderd.", "%s requires php %s or above to work. Sorry.": "%s vereist PHP %s of hoger om te kunnen werken. Sorry", "%s requires configuration section [%s] to be present in configuration file.": "%s vereist dat de configuratiesectie [%s] aanwezig is in het configuratiebestand", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Alstublieft %d seconden wachten tussen elk bericht.", "Alstublieft %d seconden wachten tussen elk bericht." ], - "Paste is limited to %s of encrypted data.": "Paste is beperkt tot %s aan versleutelde gegevens.", + "Document is limited to %s of encrypted data.": "Document is beperkt tot %s aan versleutelde gegevens.", "Invalid data.": "Ongeldige gegevens.", "You are unlucky. Try again.": "Helaas. Probeer het nog eens.", "Error saving comment. Sorry.": "Fout bij het opslaan van het commentaar. Sorry.", - "Error saving paste. Sorry.": "Fout bij het opslaan van de paste. Sorry.", - "Invalid paste ID.": "Ongeldige ID.", - "Paste is not of burn-after-reading type.": "Paste is geen 'vernietig na lezen' type.", - "Wrong deletion token. Paste was not deleted.": "Foutieve verwijdercode. Paste is niet verwijderd.", - "Paste was properly deleted.": "Paste is correct verwijderd.", + "Error saving document. Sorry.": "Fout bij het opslaan van het document. Sorry.", + "Invalid document ID.": "Ongeldige ID.", + "Document is not of burn-after-reading type.": "Document is geen 'vernietig na lezen' type.", + "Wrong deletion token. Document was not deleted.": "Foutieve verwijdercode. Document is niet verwijderd.", + "Document was properly deleted.": "Document is correct verwijderd.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript vereist om %s te laten werken. Sorry voor het ongemak.", "%s requires a modern browser to work.": "%s vereist een moderne browser om te kunnen werken.", "New": "Nieuw", - "Send": "Verzenden", + "Create": "Aanmaken", "Clone": "Klonen", "Raw text": "Onbewerkte tekst", "Expires": "Verloopt", @@ -133,9 +133,9 @@ "Dit document verloopt over %d maanden.", "Dit document verloopt over %d maanden." ], - "Please enter the password for this paste:": "Voer het wachtwoord in voor deze paste:", + "Please enter the password for this document:": "Voer het wachtwoord in voor dit document:", "Could not decrypt data (Wrong key?)": "Kon de gegevens niet decoderen (verkeerde sleutel?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Verwijderen van de paste niet mogelijk, deze werd niet opgeslagen in 'vernietig na lezen' modus.", + "Could not delete the document, it was not stored in burn after reading mode.": "Verwijderen van het document niet mogelijk, deze werd niet opgeslagen in 'vernietig na lezen' modus.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "ALLEEN VOOR JOUW OGEN BESTEMD. Sluit dit venster niet, dit bericht kan niet opnieuw worden weergegeven.", "Could not decrypt comment; Wrong key?": "Kon het commentaar niet decoderen; Verkeerde sleutel?", "Reply": "Beantwoorden", @@ -143,34 +143,34 @@ "Avatar generated from IP address": "Anonieme avatar (van het IP-adres)", "Add comment": "Commentaar toevoegen", "Optional nickname…": "Optionele bijnaam…", - "Post comment": "Plaats een commentaar", + "Post comment": "Plaats commentaar", "Sending comment…": "Commentaar verzenden…", "Comment posted.": "Commentaar geplaatst.", "Could not refresh display: %s": "Kon de weergave niet vernieuwen: %s", "unknown status": "Onbekende status", "server error or not responding": "Serverfout of server reageert niet", "Could not post comment: %s": "Kon het commentaar niet plaatsen: %s", - "Sending paste…": "Paste verzenden…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Je paste is %s (Druk [Ctrl]+[c] om te kopiëren)", + "Sending document…": "Document verzenden…", + "Your document is %s (Hit Ctrl+c to copy)": "Je document is %s (Druk Ctrl+c om te kopiëren)", "Delete data": "Gegevens wissen", - "Could not create paste: %s": "Kon de paste niet aanmaken: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Kon de paste niet decoderen: Decoderingssleutel ontbreekt in URL (Heb je een redirector of een URL-verkorter gebruikt die een deel van de URL verwijdert?)", + "Could not create document: %s": "Kon het document niet aanmaken: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Kon het document niet decoderen: Decoderingssleutel ontbreekt in URL (Heb je een doorverwijzer of een URL-verkorter gebruikt die een deel van de URL verwijdert?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Formaat", "Plain Text": "Platte tekst", "Source Code": "Broncode", "Markdown": "Markdown", "Download attachment": "Bijlage downloaden", "Cloned: '%s'": "Gekloond: '%s'", - "The cloned file '%s' was attached to this paste.": "Het gekloonde bestand '%s' is bijgevoegd aan de paste.", + "The cloned file '%s' was attached to this document.": "Het gekloonde bestand '%s' is bijgevoegd aan dit document.", "Attach a file": "Een bestand toevoegen", "alternatively drag & drop a file or paste an image from the clipboard": "Je kunt ook een bestand slepen en neerzetten of een afbeelding plakken van het klembord", "File too large, to display a preview. Please download the attachment.": "Het bestand is te groot om voorbeeld weer te geven. Aub de bijlage downloaden.", @@ -180,16 +180,16 @@ "Options": "Opties", "Shorten URL": "URL verkorten", "Editor": "Editor", - "Preview": "Preview", + "Preview": "Voorbeeld", "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s vereist dat PATH eindigt in een '%s'. a.u.b. PATH updaten in je index.php.", "Decrypt": "Decoderen", "Enter password": "Voer het wachtwoord in", "Loading…": "Laden…", - "Decrypting paste…": "Paste decoderen…", - "Preparing new paste…": "Nieuwe paste voorbereiden…", + "Decrypting document…": "Document decoderen…", + "Preparing new document…": "Nieuwe document voorbereiden…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "In het geval dat dit bericht nooit verdwijnt, kijkt dan eens naar veelgestelde vragen voor informatie over het oplossen van problemen.", - "+++ no paste text +++": "+++ geen paste tekst +++", - "Could not get paste data: %s": "Kon geen paste data verkrijgen: %s", + "+++ no document text +++": "+++ geen document tekst +++", + "Could not get document data: %s": "Kon geen documentdata verkrijgen: %s", "QR code": "QR-code", "This website is using an insecure HTTP connection! Please use it only for testing.": "Deze website gebruikt een onveilige HTTP-verbinding! Gelieve deze enkel te gebruiken om te testen.", "For more information see this FAQ entry.": "Voor meer informatie zie dit FAQ-artikel.", @@ -207,14 +207,27 @@ "Use Current Timezone": "Gebruik huidige tijdzone", "Convert To UTC": "Omzetten naar UTC", "Close": "Sluiten", - "Encrypted note on %s": "Versleutelde notitie op %s", - "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Bezoek deze link om de notitie te bekijken. Als je de URL aan iemand geeft, kan die de notitie ook bekijken.", + "Encrypted note on %s": "Versleuteld document op %s", + "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Bezoek deze link om het document te bekijken. Als je de URL aan iemand geeft, kan die het document ook bekijken.", "URL shortener may expose your decrypt key in URL.": "URL-verkorter kan je ontcijferingssleutel in URL blootleggen.", - "Save paste": "Notitie opslaan", - "Your IP is not authorized to create pastes.": "Je IP-adres is niet gemachtigd om pastes te maken.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Document opslaan", + "Your IP is not authorized to create documents.": "Je IP-adres is niet gemachtigd om documenten te maken.", "Trying to shorten a URL that isn't pointing at our instance.": "Proberen om een URL te verkorten dat niet naar ons systeem wijst.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Foutmelding ophalen YOURLS. Waarschijnlijk een configuratiefout, zoals een verkeerde of missende \"apiurl\" of \"signature\".", - "Error parsing YOURLS response.": "Foutmelding bij parsen van YOURLS respons.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Foutmelding ophalen YOURLS. Waarschijnlijk een configuratiefout, zoals een verkeerde of missende \"apiurl\" of \"signature\".", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Foutmelding bij parsen van YOURLS respons.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "Dit geheime bericht kan maar één keer worden weergegeven. Wil je het nu zien?", + "Yes, see it": "Ja, tonen", + "Dark Mode": "Donkere modus", + "Error compressing document, due to missing WebAssembly support.": "Fout bij het comprimeren van document door ontbrekende ondersteuning voor WebAssembly.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Fout bij het decomprimeren van het document, uw browser ondersteunt WebAssembly niet. Gebruik een andere browser om dit document te bekijken.", + "Start over": "Opnieuw beginnen", + "Document copied to clipboard": "Document gekopieerd naar klembord", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "Om te kopiëren en plakken druk je op de knop Kopiëren of gebruik je de sneltoets op het klembord Ctrl+c/Cmd+c", + "Copy link": "Kopieer link", + "Link copied to clipboard": "Link gekopieerd naar klembord", + "Document text": "Tekst plakken", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulatortoets dient als teken (gebruik Ctrl+m of Esc om te schakelen)", + "Theme": "Thema" } diff --git a/i18n/no.json b/i18n/no.json index 00417f24..538364ec 100644 --- a/i18n/no.json +++ b/i18n/no.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s er en minimalistisk, åpen kildekode, elektronisk tilgjengelig pastebin hvor serveren ikke har kunnskap om dataene som limes inn. Dataene krypteres/dekrypteres %si nettleseren%s ved hjelp av 256 bits AES.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s er en minimalistisk, åpen kildekode, elektronisk tilgjengelig pastebin hvor serveren ikke har kunnskap om dataene som limes inn. Dataene krypteres/dekrypteres %si nettleseren%s ved hjelp av 256 bits AES.", "More information on the project page.": "Mer informasjon om prosjektet på prosjektsiden.", "Because ignorance is bliss": "Fordi uvitenhet er lykke", - "Paste does not exist, has expired or has been deleted.": "Innlegget eksisterer ikke, er utløpt eller har blitt slettet.", + "Document does not exist, has expired or has been deleted.": "Innlegget eksisterer ikke, er utløpt eller har blitt slettet.", "%s requires php %s or above to work. Sorry.": "Beklager, %s krever php %s eller nyere for å kjøre.", "%s requires configuration section [%s] to be present in configuration file.": "%s krever konfigurasjonsdel [%s] å være til stede i konfigurasjonsfilen .", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Vennligst vent %d sekunder mellom hvert innlegg.", "Vennligst vent %d sekunder mellom hvert innlegg." ], - "Paste is limited to %s of encrypted data.": "Innlegg er begrenset til %s av kryptert data.", + "Document is limited to %s of encrypted data.": "Innlegg er begrenset til %s av kryptert data.", "Invalid data.": "Ugyldige data.", "You are unlucky. Try again.": "Du er uheldig. Prøv igjen.", "Error saving comment. Sorry.": "Beklager, det oppstod en feil ved lagring kommentar.", - "Error saving paste. Sorry.": "Beklager, det oppstod en feil ved lagring innlegg.", - "Invalid paste ID.": "Feil innlegg ID.", - "Paste is not of burn-after-reading type.": "Innlegg er ikke av typen slett etter lesing.", - "Wrong deletion token. Paste was not deleted.": "Feil slettingsnøkkel. Innlegg ble ikke fjernet.", - "Paste was properly deleted.": "Innlegget er slettet.", + "Error saving document. Sorry.": "Beklager, det oppstod en feil ved lagring innlegg.", + "Invalid document ID.": "Feil innlegg ID.", + "Document is not of burn-after-reading type.": "Innlegg er ikke av typen slett etter lesing.", + "Wrong deletion token. Document was not deleted.": "Feil slettingsnøkkel. Innlegg ble ikke fjernet.", + "Document was properly deleted.": "Innlegget er slettet.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "Javascript kreves for at %s skal fungere. Beklager.", "%s requires a modern browser to work.": "%s krever en moderne nettleser for å fungere.", "New": "Ny", - "Send": "Send", + "Create": "Opprette", "Clone": "Kopier", "Raw text": "Ren tekst", "Expires": "Utgår", @@ -133,9 +133,9 @@ "Dette dokumentet vil utløpe om %d måneder.", "Dette dokumentet vil utløpe om %d måneder." ], - "Please enter the password for this paste:": "Vennligst skriv inn passordet for dette innlegget:", + "Please enter the password for this document:": "Vennligst skriv inn passordet for dette innlegget:", "Could not decrypt data (Wrong key?)": "Kunne ikke dekryptere data (Feil nøkkel?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Kan ikke slette innlegget, det ble ikke lagret som 'slett etter les' type.", + "Could not delete the document, it was not stored in burn after reading mode.": "Kan ikke slette innlegget, det ble ikke lagret som 'slett etter les' type.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "KUN FOR DINE ØYNE. Ikke lukk dette vinduet, denne meldingen kan ikke bli vist igjen.", "Could not decrypt comment; Wrong key?": "Kan ikke dekryptere kommentar; Feil nøkkel?", "Reply": "Svar", @@ -150,27 +150,27 @@ "unknown status": "ukjent status", "server error or not responding": "tjener feilet eller svarer ikke", "Could not post comment: %s": "Kunne ikke sende kommentar: %s", - "Sending paste…": "Sender innlegg…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Ditt innlegg er %s (Trykk [Ctrl]+[c] for å kopiere)", + "Sending document…": "Sender innlegg…", + "Your document is %s (Hit Ctrl+c to copy)": "Ditt innlegg er %s (Trykk Ctrl+c for å kopiere)", "Delete data": "Slett data", - "Could not create paste: %s": "Kunne ikke opprette innlegg: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Kan ikke dekryptere innlegg: Dekrypteringsnøkkelen mangler i adressen (Har du bruket en redirector eller en URL forkorter som fjerner en del av addressen?)", + "Could not create document: %s": "Kunne ikke opprette innlegg: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Kan ikke dekryptere innlegg: Dekrypteringsnøkkelen mangler i adressen (Har du bruket en redirector eller en URL forkorter som fjerner en del av addressen?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Ren Tekst", "Source Code": "Kildekode", "Markdown": "Markdown", "Download attachment": "Last ned vedlegg", "Cloned: '%s'": "Kopiert: '%s'", - "The cloned file '%s' was attached to this paste.": "Den klonede filen '%s' var koblet til denne innlimingen.", + "The cloned file '%s' was attached to this document.": "Den klonede filen '%s' var koblet til denne innlimingen.", "Attach a file": "Legg til fil", "alternatively drag & drop a file or paste an image from the clipboard": "alternativt dra og slipp en fil, eller lim inn et bilde fra utklippstavlen", "File too large, to display a preview. Please download the attachment.": "Filen er for stor, for å vise en forhåndsvisning. Last ned vedlegget.", @@ -185,11 +185,11 @@ "Decrypt": "Dekrypter", "Enter password": "Skriv inn passord", "Loading…": "Laster…", - "Decrypting paste…": "Dekrypterer innlegg…", - "Preparing new paste…": "Klargjør nytt innlegg…", + "Decrypting document…": "Dekrypterer innlegg…", + "Preparing new document…": "Klargjør nytt innlegg…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "Hvis denne meldingen ikke forsvinner kan du ta en titt på siden med ofte stilte spørsmål for informasjon om feilsøking.", - "+++ no paste text +++": "+++ ingen innleggstekst +++", - "Could not get paste data: %s": "Kunne ikke hente utklippsdata: %s", + "+++ no document text +++": "+++ ingen innleggstekst +++", + "Could not get document data: %s": "Kunne ikke hente utklippsdata: %s", "QR code": "QR kode", "This website is using an insecure HTTP connection! Please use it only for testing.": "Denne websiden bruker usikker HTTP tilkobling! Bruk den kun for testing.", "For more information see this FAQ entry.": "For mer informasjon se ofte stilte spørsmål.", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Kryptert notat på %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Besøk denne lenken for å se notatet. Hvis lenken deles med andre, vil de også kunne se notatet.", "URL shortener may expose your decrypt key in URL.": "URL forkorter kan avsløre dekrypteringsnøkkelen.", - "Save paste": "Lagre utklipp", - "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.", - "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Lagre utklipp", + "Your IP is not authorized to create documents.": "Din IP er ikke autorisert til å opprette dokumenter.", + "Trying to shorten a URL that isn't pointing at our instance.": "Prøver å forkorte en URL som ikke peker i vår instans.", + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Feil ved å besøke YOURLS. Sannsynligvis et konfigurasjonsproblem, eksempelvis feil eller mangler, med \"apiurl\" eller \"signatur\".", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Feil ved analyse av YOURLS svar.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "Denne hemmelige meldingen kan bare vises én gang. Vil du se den nå?", + "Yes, see it": "Ja, se det", + "Dark Mode": "Mørk modus", + "Error compressing document, due to missing WebAssembly support.": "Error compressing document, due to missing WebAssembly support.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.", + "Start over": "Start over", + "Document copied to clipboard": "Document copied to clipboard", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/oc.json b/i18n/oc.json index 7553fb0e..5ba5af14 100644 --- a/i18n/oc.json +++ b/i18n/oc.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s es un 'pastebin' (o gestionari d’extrachs de tèxte e còdi font) minimalista e open source, dins lo qual lo servidor a pas cap de coneissença de las donadas mandadas. Las donadas son chifradas/deschifradas %sdins lo navigator%s per un chiframent AES 256 bits.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s es un 'pastebin' (o gestionari d’extrachs de tèxte e còdi font) minimalista e open source, dins lo qual lo servidor a pas cap de coneissença de las donadas mandadas. Las donadas son chifradas/deschifradas %sdins lo navigator%s per un chiframent AES 256 bits.", "More information on the project page.": "Mai informacions sus la pagina del projècte.", "Because ignorance is bliss": "Perque lo bonaür es l’ignorància", - "Paste does not exist, has expired or has been deleted.": "Lo tèxte existís pas, a expirat, o es estat suprimit.", + "Document does not exist, has expired or has been deleted.": "Lo tèxte existís pas, a expirat, o es estat suprimit.", "%s requires php %s or above to work. Sorry.": "O planhèm, %s necessita php %s o superior per foncionar.", "%s requires configuration section [%s] to be present in configuration file.": "%s fa besonh de la seccion de configuracion [%s] dins lo fichièr de configuracion per foncionar.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Mercés d'esperar %d segondas entre cada publicacion.", "Mercés d'esperar %d segondas entre cada publicacion." ], - "Paste is limited to %s of encrypted data.": "Lo tèxte es limitat a %s de donadas chifradas.", + "Document is limited to %s of encrypted data.": "Lo tèxte es limitat a %s de donadas chifradas.", "Invalid data.": "Donadas invalidas.", "You are unlucky. Try again.": "Pas cap de fortuna. Tornatz ensajar.", "Error saving comment. Sorry.": "Error al moment de salvagardar lo comentari. O planhèm.", - "Error saving paste. Sorry.": "Error al moment de salvagardar lo tèxte. O planhèm.", - "Invalid paste ID.": "ID del tèxte invalid.", - "Paste is not of burn-after-reading type.": "Lo tèxte es pas del tipe « Escafar aprèp lectura ».", - "Wrong deletion token. Paste was not deleted.": "Geton de supression incorrècte. Lo tèxte es pas estat suprimit.", - "Paste was properly deleted.": "Lo tèxte es estat corrèctament suprimit.", + "Error saving document. Sorry.": "Error al moment de salvagardar lo tèxte. O planhèm.", + "Invalid document ID.": "ID del tèxte invalid.", + "Document is not of burn-after-reading type.": "Lo tèxte es pas del tipe « Escafar aprèp lectura ».", + "Wrong deletion token. Document was not deleted.": "Geton de supression incorrècte. Lo tèxte es pas estat suprimit.", + "Document was properly deleted.": "Lo tèxte es estat corrèctament suprimit.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript es requesit per far foncionar %s. O planhèm per l’inconvenient.", "%s requires a modern browser to work.": "%s requerís un navigator modèrn per foncionar.", "New": "Nòu", - "Send": "Mandar", + "Create": "Mandar", "Clone": "Clonar", "Raw text": "Tèxte brut", "Expires": "Expira", @@ -133,9 +133,9 @@ "Aqueste document expirarà d’aquí %d meses.", "Aqueste document expirarà d’aquí %d meses." ], - "Please enter the password for this paste:": "Picatz lo senhal per aqueste tèxte :", + "Please enter the password for this document:": "Picatz lo senhal per aqueste tèxte :", "Could not decrypt data (Wrong key?)": "Impossible de deschifrar las donadas (marrida clau ?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Impossible de suprimir lo tèxte, perque es pas estat gardat en mòde \"Escafar aprèp lectura\".", + "Could not delete the document, it was not stored in burn after reading mode.": "Impossible de suprimir lo tèxte, perque es pas estat gardat en mòde \"Escafar aprèp lectura\".", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "PER VÒSTRES UÈLHS SOLAMENT. Tampetz pas aquesta fenèstra, aqueste tèxte poirà pas mai èsser afichat.", "Could not decrypt comment; Wrong key?": "Impossible de deschifrar lo comentari ; marrida clau ?", "Reply": "Respondre", @@ -150,27 +150,27 @@ "unknown status": "estatut desconegut", "server error or not responding": "lo servidor respond pas o a rescontrat una error", "Could not post comment: %s": "Impossible de mandar lo comentari : %s", - "Sending paste…": "Mandadís del tèxte…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Vòstre tèxte es disponible a l’adreça %s (Picatz sus [Ctrl]+[c] per copiar)", + "Sending document…": "Mandadís del tèxte…", + "Your document is %s (Hit Ctrl+c to copy)": "Vòstre tèxte es disponible a l’adreça %s (Picatz sus Ctrl+c per copiar)", "Delete data": "Supprimir las donadas del tèxte", - "Could not create paste: %s": "Impossible de crear lo tèxte : %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Impossible de deschifrar lo tèxte : clau de deschiframent absenta de l’URL (Avètz utilizat un redirector o un site de reduccion d’URL que suprimís una partida de l’URL ?)", + "Could not create document: %s": "Impossible de crear lo tèxte : %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Impossible de deschifrar lo tèxte : clau de deschiframent absenta de l’URL (Avètz utilizat un redirector o un site de reduccion d’URL que suprimís una partida de l’URL ?)", "B": "o", - "KiB": "Kio", - "MiB": "Mio", - "GiB": "Gio", - "TiB": "Tio", - "PiB": "Pio", - "EiB": "Eio", - "ZiB": "Zio", - "YiB": "Yio", + "kB": "ko", + "MB": "Mo", + "GB": "Go", + "TB": "To", + "PB": "Po", + "EB": "Eo", + "ZB": "Zo", + "YB": "Yo", "Format": "Format", "Plain Text": "Tèxte brut", "Source Code": "Còdi font", "Markdown": "Markdown", "Download attachment": "Telecargar la pèça junta", "Cloned: '%s'": "Clonar : '%s'", - "The cloned file '%s' was attached to this paste.": "Aqueste fichièr clonat '%s' es estat ajustat a aqueste tèxte.", + "The cloned file '%s' was attached to this document.": "Aqueste fichièr clonat '%s' es estat ajustat a aqueste tèxte.", "Attach a file": "Juntar un fichièr", "alternatively drag & drop a file or paste an image from the clipboard": "autrament lisatz lo fichièr o pegatz l’imatge del quichapapièrs", "File too large, to display a preview. Please download the attachment.": "Fichièr tròp pesuc per mostrar un apercebut. Telecargatz la pèca junta.", @@ -185,11 +185,11 @@ "Decrypt": "Deschifrar", "Enter password": "Picatz lo senhal", "Loading…": "Cargament…", - "Decrypting paste…": "Deschirament del tèxte…", - "Preparing new paste…": "Preparacion…", + "Decrypting document…": "Deschirament del tèxte…", + "Preparing new document…": "Preparacion…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "Se per cas aqueste messatge quite pas de s’afichar mercés de gaitar aquesta FAQ per las solucions (en anglés).", - "+++ no paste text +++": "+++ cap de tèxte pegat +++", - "Could not get paste data: %s": "Recuperacion impossibla de las donadas copiadas : %s", + "+++ no document text +++": "+++ cap de tèxte pegat +++", + "Could not get document data: %s": "Recuperacion impossibla de las donadas copiadas : %s", "QR code": "Còdi QR", "This website is using an insecure HTTP connection! Please use it only for testing.": "Aqueste site utiliza una connexion HTTP pas segura ! Mercés de l’utilizar pas que per d’ensages.", "For more information see this FAQ entry.": "Per mai d’informacions vejatz aqueste article de FAQ.", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Nòtas chifradas sus %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visitatz aqueste ligam per veire la nòta. Fornir lo ligam a qualqu’un mai li permet tanben d’accedir a la nòta.", "URL shortener may expose your decrypt key in URL.": "Los espleches d’acorchiment d’URL pòdon expausar la clau de deschiframent dins l’URL.", - "Save paste": "Enregistrar lo tèxt", - "Your IP is not authorized to create pastes.": "Vòstra adreça IP a pas l’autorizacion de crear de tèxtes.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Enregistrar lo tèxt", + "Your IP is not authorized to create documents.": "Vòstra adreça IP a pas l’autorizacion de crear de tèxtes.", "Trying to shorten a URL that isn't pointing at our instance.": "Ensag d’abracar una URL que mena pas a nòstra instància.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error en cridant YOURLS. Es probablament un problèma de configuracion, quicòm coma « apirul » o « signature » marrit o absent.", - "Error parsing YOURLS response.": "Error d'analisi de la responsa YOURLS.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Error en cridant YOURLS. Es probablament un problèma de configuracion, quicòm coma « apirul » o « signature » marrit o absent.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Error d'analisi de la responsa YOURLS.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "Aqueste messatge secrèt se pòt pas qu'afichar un còp. Lo volètz veire ara ?", + "Yes, see it": "Òc, afichatz-lo", + "Dark Mode": "Mòde escur", + "Error compressing document, due to missing WebAssembly support.": "Error al moment de la compression de l'empegatge, a causa de la manca de presa en carga de WebAssembly.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Error al moment de descompresar l'empegatge, vòstre navegador pren pas en carga WebAssembly. Mercés d'utilizar un autre navigador per visualizar aquesta pega.", + "Start over": "Start over", + "Document copied to clipboard": "Document copied to clipboard", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/pl.json b/i18n/pl.json index ec1930dd..68fcf2c6 100644 --- a/i18n/pl.json +++ b/i18n/pl.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s jest minimalistycznym, otwartoźródłowym serwisem typu pastebin, w którym serwer nie ma jakichkolwiek informacji o tym, co jest wklejane. Dane są szyfrowane i deszyfrowane %sw przeglądarce%s z użyciem 256-bitowego klucza AES.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s jest minimalistycznym, otwartoźródłowym serwisem typu pastebin, w którym serwer nie ma żadnej wiedzy o przechowywanych danych. Dane są szyfrowane i deszyfrowane %sw przeglądarce%s z użyciem 256-bitowego klucza AES.", "More information on the project page.": "Więcej informacji na stronie projektu.", "Because ignorance is bliss": "Ponieważ ignorancja jest cnotą", - "Paste does not exist, has expired or has been deleted.": "Wklejka nie istnieje, wygasła albo została usunięta.", + "Document does not exist, has expired or has been deleted.": "Dokument nie istnieje, wygasł lub został usunięty.", "%s requires php %s or above to work. Sorry.": "%s wymaga PHP w wersji %s lub nowszej. Przykro mi.", "%s requires configuration section [%s] to be present in configuration file.": "%s wymaga obecności sekcji [%s] w pliku konfiguracyjnym.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Poczekaj %d sekund pomiędzy każdą wklejką.", "Poczekaj %d sekund pomiędzy każdą wklejką." ], - "Paste is limited to %s of encrypted data.": "Wklejka jest limitowana do %s zaszyfrowanych danych.", + "Document is limited to %s of encrypted data.": "Dokument jest ograniczony do %s zaszyfrowanych danych.", "Invalid data.": "Nieprawidłowe dane.", "You are unlucky. Try again.": "Miałeś pecha. Spróbuj ponownie.", "Error saving comment. Sorry.": "Błąd przy zapisywaniu komentarza, sorry.", - "Error saving paste. Sorry.": "Błąd przy zapisywaniu wklejki, sorry.", - "Invalid paste ID.": "Nieprawidłowe ID wklejki.", - "Paste is not of burn-after-reading type.": "Ta wklejka nie ulega autodestrukcji po przeczytaniu.", - "Wrong deletion token. Paste was not deleted.": "Nieprawidłowy token usuwania. Wklejka nie została usunięta.", - "Paste was properly deleted.": "Wklejka usunięta poprawnie.", + "Error saving document. Sorry.": "Błąd podczas zapisywania dokumentu. Przepraszamy.", + "Invalid document ID.": "Nieprawidłowy ID dokumentu.", + "Document is not of burn-after-reading type.": "Dokument nie ulega autodestrukcji po przeczytaniu.", + "Wrong deletion token. Document was not deleted.": "Nieprawidłowy token usuwania. Dokument nie został usunięty.", + "Document was properly deleted.": "Dokument został prawidłowo usunięty.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "Do działania %sa jest wymagany JavaScript. Przepraszamy za tę niedogodność.", "%s requires a modern browser to work.": "%s wymaga do działania nowoczesnej przeglądarki.", "New": "Nowa", - "Send": "Wyślij", + "Create": "Dodaj", "Clone": "Sklonuj", "Raw text": "Czysty tekst", "Expires": "Wygasa za", @@ -133,9 +133,9 @@ "Ten dokument wygaśnie za %d miesięcy.", "Ten dokument wygaśnie za %d miesięcy." ], - "Please enter the password for this paste:": "Wpisz hasło dla tej wklejki:", + "Please enter the password for this document:": "Wprowadź hasło dla tego dokumentu:", "Could not decrypt data (Wrong key?)": "Nie udało się odszyfrować danych (zły klucz?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Nie udało się usunąć wklejki, nie została zapisana w trybie zniszczenia po przeczytaniu.", + "Could not delete the document, it was not stored in burn after reading mode.": "Nie można usunąć dokumentu, nie została zapisana w trybie zniszczenia po przeczytaniu.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "TYLKO DO TWOJEGO WGLĄDU. Nie zamykaj tego okna, ta wiadomość nie będzie mogła być wyświetlona ponownie.", "Could not decrypt comment; Wrong key?": "Nie udało się odszyfrować komentarza; zły klucz?", "Reply": "Odpowiedz", @@ -150,27 +150,27 @@ "unknown status": "nieznany status", "server error or not responding": "błąd serwera lub brak odpowiedzi", "Could not post comment: %s": "Nie udało się wysłać komentarza: %s", - "Sending paste…": "Wysyłanie wklejki…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Twoja wklejka to %s (wciśnij [Ctrl]+[c] aby skopiować)", + "Sending document…": "Wysyłanie dokumentu…", + "Your document is %s (Hit Ctrl+c to copy)": "Twój dokument to %s (wciśnij Ctrl+c aby skopiować)", "Delete data": "Skasuj dane", - "Could not create paste: %s": "Nie udało się utworzyć wklejki: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Nie udało się odszyfrować wklejki - brak klucza deszyfrującego w adresie (użyłeś skracacza linków, który ucina część adresu?)", + "Could not create document: %s": "Nie można utworzyć dokumentu: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Nie można odszyfrować dokumentu: Brak klucza deszyfrującego w adresie URL (Czy użyto przekierowania lub skracacza adresów URL, który usuwa część adresu URL?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Czysty tekst", "Source Code": "Kod źródłowy", - "Markdown": "Markdown", + "Markdown": "Znakowanie", "Download attachment": "Pobierz załącznik", "Cloned: '%s'": "Sklonowano: '%s'", - "The cloned file '%s' was attached to this paste.": "Sklonowany plik '%s' był dołączony do tej wklejki.", + "The cloned file '%s' was attached to this document.": "Sklonowany plik '%s' był dołączony do tego dokumentu.", "Attach a file": "Załącz plik", "alternatively drag & drop a file or paste an image from the clipboard": "Alternatywnie przeciągnij i upuść plik albo wklej obraz ze schowka", "File too large, to display a preview. Please download the attachment.": "Plik zbyt duży aby wyświetlić podgląd. Proszę pobrać załącznik.", @@ -181,40 +181,53 @@ "Shorten URL": "Skróć adres URL", "Editor": "Edytować", "Preview": "Podgląd", - "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.", + "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s wymaga zmiennej PATH zakończonej w \"%s\". Zaktualizuj zmienną PATH w index.php.", "Decrypt": "Odszyfruj", "Enter password": "Wpisz hasło", "Loading…": "Wczytywanie…", - "Decrypting paste…": "Odszyfrowywanie wklejki…", - "Preparing new paste…": "Przygotowywanie nowej wklejki…", + "Decrypting document…": "Odszyfrowywanie dokumentu…", + "Preparing new document…": "Przygotowywanie nowego dokumentu…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "W przypadku gdy ten komunikat nigdy nie znika, proszę spójrz na to FAQ aby rozwiązać problem (po angielsku).", - "+++ no paste text +++": "+++ brak wklejonego tekstu +++", - "Could not get paste data: %s": "Nie można było pobrać danych wklejki: %s", + "+++ no document text +++": "+++ brak tekstu dokumentu +++", + "Could not get document data: %s": "Nie można uzyskać danych dokumentu: %s", "QR code": "Kod QR", - "This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.", - "For more information see this FAQ entry.": "For more information see this FAQ entry.", - "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.", - "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.", - "waiting on user to provide a password": "waiting on user to provide a password", - "Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.", - "Retry": "Retry", - "Showing raw text…": "Showing raw text…", - "Notice:": "Notice:", - "This link will expire after %s.": "This link will expire after %s.", - "This link can only be accessed once, do not use back or refresh button in your browser.": "This link can only be accessed once, do not use back or refresh button in your browser.", - "Link:": "Link:", - "Recipient may become aware of your timezone, convert time to UTC?": "Recipient may become aware of your timezone, convert time to UTC?", - "Use Current Timezone": "Use Current Timezone", - "Convert To UTC": "Convert To UTC", - "Close": "Close", - "Encrypted note on %s": "Encrypted note on %s", - "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.", - "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.", - "Save paste": "Save paste", - "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.", - "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "This website is using an insecure HTTP connection! Please use it only for testing.": "Ta witryna używa niezabezpieczonego połączenia HTTP! Używaj jej wyłącznie do testowania.", + "For more information see this FAQ entry.": "Aby uzyskać więcej informacji, sprawdź to często zadawane pytanie.", + "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": "Twoja przeglądarka może wymagać połączenia HTTPS, aby obsługiwać API WebCrypto. Spróbuj przełączyć się na HTTPS.", + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "Twoja przeglądarka nie obsługuje WebAssembly używanego do kompresji zlib. Możesz utworzyć nieskompresowane dokumenty, ale nie możesz odczytać skompresowanych.", + "waiting on user to provide a password": "oczekiwanie na podanie hasła przez użytkownika", + "Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Błąd odszyfrowywania danych. Czy wprowadzono niepoprawne hasło? Spróbuj ponownie, używając przycisku na górze.", + "Retry": "Ponów", + "Showing raw text…": "Pokazywanie nieprzetworzonego tekstu…", + "Notice:": "Uwaga:", + "This link will expire after %s.": "Ten odnośnik wygaśnie po %s.", + "This link can only be accessed once, do not use back or refresh button in your browser.": "Tego odnośnika można użyć tylko jeden raz. Nie cofaj ani nie odświeżaj strony w przeglądarce.", + "Link:": "Odnośnik:", + "Recipient may become aware of your timezone, convert time to UTC?": "Odbiorca może uzyskać informację o twojej strefie czasowej. Zamienić czas na UTC?", + "Use Current Timezone": "Użyj bieżącej strefy czasowej", + "Convert To UTC": "Zamień na UTC", + "Close": "Zamknij", + "Encrypted note on %s": "Zaszyfrowana notatka na %s", + "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Naciśnij tej odnośnik, aby zobaczyć notatkę. Każda osoba z dostępem do tego adresu URL również może zobaczyć tę notatkę.", + "URL shortener may expose your decrypt key in URL.": "Skrócenie adresu URL może ujawnić Twój klucz odszyfrowujący w adresie URL.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Zapisz dokument", + "Your IP is not authorized to create documents.": "Twój adres IP nie jest autoryzowany do tworzenia dokumentów.", + "Trying to shorten a URL that isn't pointing at our instance.": "Próba skrócenia adresu URL wskazującego na inną instancję.", + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Błąd wywoływania YOURLS. Możliwy błąd konfiguracji, taki jak błędne lub brakujące \"apiurl\" lub \"signature\".", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Błąd przetwarzania odpowiedzi YOURLS.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "Tę tajną wiadomość możesz zobaczyć tylko jeden raz. Czy chcesz to zrobić teraz?", + "Yes, see it": "Tak, pokaż", + "Dark Mode": "Ciemny motyw", + "Error compressing document, due to missing WebAssembly support.": "Wystąpił błąd podczas kompresji dokumentu z powodu braku obsługi WebAssembly.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Wystąpił błąd podczas dekompresji dokumentu. Twoja przeglądarka nie obsługuje WebAssembly. Użyj innej przeglądarki, aby wyświetlić ten dokument.", + "Start over": "Zacznij od nowa", + "Document copied to clipboard": "Dokument został skopiowany do schowka", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "Aby skopiować dokument, naciśnij przycisk kopiowania lub użyj skrótu do schowka Ctrl+c/Cmd+c", + "Copy link": "Kopiuj link", + "Link copied to clipboard": "Link został skopiowany do schowka", + "Document text": "Tekst dokumentu", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Klawisz Tabulatora służy jako znak (przytrzymaj Ctrl+m lub Esc aby przełączać)", + "Theme": "Motyw" } diff --git a/i18n/pt.json b/i18n/pt.json index 3b7866db..91d8ea4b 100644 --- a/i18n/pt.json +++ b/i18n/pt.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s é um serviço minimalista e de código aberto do tipo \"pastebin\", em que o servidor tem zero conhecimento dos dados copiados. Os dados são cifrados e decifrados %sno navegador%s usando 256 bits AES.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s é um serviço minimalista e de código aberto do tipo \"pastebin\", em que o servidor tem zero conhecimento dos dados copiados. Os dados são cifrados e decifrados %sno navegador%s usando 256 bits AES.", "More information on the project page.": "Mais informações na página do projeto.", "Because ignorance is bliss": "Porque a ignorância é uma benção", - "Paste does not exist, has expired or has been deleted.": "A cópia não existe, expirou ou já foi excluída.", + "Document does not exist, has expired or has been deleted.": "A cópia não existe, expirou ou já foi excluída.", "%s requires php %s or above to work. Sorry.": "%s requer php %s ou superior para funcionar. Desculpa.", "%s requires configuration section [%s] to be present in configuration file.": "%s requer que a seção de configuração [% s] esteja no arquivo de configuração.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Por favor espere %d segundos entre cada publicação.", "Por favor espere %d segundos entre cada publicação." ], - "Paste is limited to %s of encrypted data.": "A cópia está limitada a %s de dados cifrados.", + "Document is limited to %s of encrypted data.": "A cópia está limitada a %s de dados cifrados.", "Invalid data.": "Dados inválidos.", "You are unlucky. Try again.": "Você é azarado. Tente novamente", "Error saving comment. Sorry.": "Erro ao salvar comentário. Desculpa.", - "Error saving paste. Sorry.": "Erro ao salvar cópia. Desculpa.", - "Invalid paste ID.": "ID de cópia inválido.", - "Paste is not of burn-after-reading type.": "Cópia não é do tipo \"queime após ler\".", - "Wrong deletion token. Paste was not deleted.": "Token de remoção inválido. A cópia não foi excluída.", - "Paste was properly deleted.": "A cópia foi devidamente excluída.", + "Error saving document. Sorry.": "Erro ao salvar cópia. Desculpa.", + "Invalid document ID.": "ID de cópia inválido.", + "Document is not of burn-after-reading type.": "Cópia não é do tipo \"queime após ler\".", + "Wrong deletion token. Document was not deleted.": "Token de remoção inválido. A cópia não foi excluída.", + "Document was properly deleted.": "A cópia foi devidamente excluída.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript é necessário para que %s funcione. Pedimos desculpas pela inconveniência.", "%s requires a modern browser to work.": "%s requer um navegador moderno para funcionar.", "New": "Novo", - "Send": "Enviar", + "Create": "Criar", "Clone": "Clonar", "Raw text": "Texto sem formato", "Expires": "Expirar em", @@ -133,9 +133,9 @@ "Este documento irá expirar em %d meses.", "Este documento irá expirar em %d meses." ], - "Please enter the password for this paste:": "Por favor, digite a senha para essa cópia:", + "Please enter the password for this document:": "Por favor, digite a senha para essa cópia:", "Could not decrypt data (Wrong key?)": "Não foi possível decifrar os dados (Chave errada?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Não foi possível excluir a cópia, ela não foi salva no modo de \"queime após ler\".", + "Could not delete the document, it was not stored in burn after reading mode.": "Não foi possível excluir a cópia, ela não foi salva no modo de \"queime após ler\".", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "APENAS PARA SEUS OLHOS. Não feche essa janela, essa mensagem não pode ser exibida novamente.", "Could not decrypt comment; Wrong key?": "Não foi possível decifrar o comentário; Chave errada?", "Reply": "Responder", @@ -150,27 +150,27 @@ "unknown status": "Estado desconhecido", "server error or not responding": "Servidor em erro ou não responsivo", "Could not post comment: %s": "Não foi possível publicar o comentário: %s", - "Sending paste…": "Enviando cópia…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Sua cópia é %s (Pressione [Ctrl]+[c] para copiar)", + "Sending document…": "Enviando cópia…", + "Your document is %s (Hit Ctrl+c to copy)": "Sua cópia é %s (Pressione Ctrl+c para copiar)", "Delete data": "Excluir dados", - "Could not create paste: %s": "Não foi possível criar cópia: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Não foi possível decifrar a cópia: chave de decriptografia ausente na URL (Você utilizou um redirecionador ou encurtador de URL que removeu parte dela?)", + "Could not create document: %s": "Não foi possível criar cópia: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Não foi possível decifrar a cópia: chave de decriptografia ausente na URL (Você utilizou um redirecionador ou encurtador de URL que removeu parte dela?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Formato", "Plain Text": "Texto sem formato", "Source Code": "Código fonte", "Markdown": "Markdown", "Download attachment": "Baixar anexo", "Cloned: '%s'": "Clonado: '%s'", - "The cloned file '%s' was attached to this paste.": "O arquivo clonado '%s' foi anexado a essa cópia.", + "The cloned file '%s' was attached to this document.": "O arquivo clonado '%s' foi anexado a essa cópia.", "Attach a file": "Anexar um arquivo", "alternatively drag & drop a file or paste an image from the clipboard": "alternativamente, arraste e solte um arquivo ou cole uma imagem da área de transferência", "File too large, to display a preview. Please download the attachment.": "Arquivo muito grande para exibir uma prévia. Por favor, faça o download do anexo.", @@ -185,11 +185,11 @@ "Decrypt": "Decifrar", "Enter password": "Digite a senha", "Loading…": "Carregando…", - "Decrypting paste…": "Decifrando cópia…", - "Preparing new paste…": "Preparando nova cópia…", + "Decrypting document…": "Decifrando cópia…", + "Preparing new document…": "Preparando nova cópia…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "Caso essa mensagem nunca desapareça, por favor veja este FAQ para saber como resolver os problemas.", - "+++ no paste text +++": "+++ sem texto de cópia +++", - "Could not get paste data: %s": "Não foi possível obter dados de cópia: %s", + "+++ no document text +++": "+++ sem texto de cópia +++", + "Could not get document data: %s": "Não foi possível obter dados de cópia: %s", "QR code": "Código QR", "This website is using an insecure HTTP connection! Please use it only for testing.": "Esse site usa uma conexão HTTP insegura! Use-o apenas para testes.", "For more information see this FAQ entry.": "Para mais informações veja esse item do FAQ.", @@ -209,12 +209,25 @@ "Close": "Fechar", "Encrypted note on %s": "Nota criptografada no %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visite esse link para ver a nota. Dar a URL para qualquer um permite que eles também acessem a nota.", - "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.", - "Save paste": "Salvar cópia", - "Your IP is not authorized to create pastes.": "Seu IP não está autorizado a criar cópias.", + "URL shortener may expose your decrypt key in URL.": "Encurtador de URL pode expor sua chave de descriptografia em URL.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Salvar cópia", + "Your IP is not authorized to create documents.": "Seu IP não está autorizado a criar cópias.", "Trying to shorten a URL that isn't pointing at our instance.": "Tentando encurtar uma URL que não aponta para a nossa instância.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Erro ao chamar YOURLS. Provavelmente um problema de configuração, como errado ou faltando \"apiurl\" ou \"signature\".", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Erro ao analisar a resposta do YOURLS.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "Esta mensagem secreta só pode ser exibida uma vez. Gostaria de vê-la agora?", + "Yes, see it": "Sim, veja", + "Dark Mode": "Modo Noturno", + "Error compressing document, due to missing WebAssembly support.": "Error compressing document, due to missing WebAssembly support.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.", + "Start over": "Start over", + "Document copied to clipboard": "Document copied to clipboard", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/ro.json b/i18n/ro.json index 89e6d1a7..aaf35e0d 100644 --- a/i18n/ro.json +++ b/i18n/ro.json @@ -1,32 +1,32 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s este un pastebin online, minimalist și cu sursă deschisă unde serverul are zero acces la datele introduse. Datele sunt criptate/decriptate %sîn browser%s folosind AES cu 256 de biți.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s este un pastebin online, minimalist și cu sursă deschisă unde serverul are zero acces la datele introduse. Datele sunt criptate/decriptate %sîn browser%s folosind AES cu 256 de biți.", "More information on the project page.": "Mai multe informații pe pagina proiectului.", "Because ignorance is bliss": "Ignoranța este o binecuvântare", - "Paste does not exist, has expired or has been deleted.": "Paste-ul nu există, a expirat sau a fost șters.", + "Document does not exist, has expired or has been deleted.": "Document-ul nu există, a expirat sau a fost șters.", "%s requires php %s or above to work. Sorry.": "%s necesită php %s sau mai nou pentru a funcționa. Scuze.", "%s requires configuration section [%s] to be present in configuration file.": "%s necesită ca secțiunea de configurare [%s] să fie prezentă în fișierul de configurare.", "Please wait %d seconds between each post.": [ "Vă rugăm să așteptați %d secundă între fiecare postare", "Vă rugăm să așteptați %d secunde între fiecare postare", "Vă rugăm să așteptați %d de secunde între fiecare postare", - "Please wait %d seconds between each post. (3rd plural)", - "Please wait %d seconds between each post. (4th plural)", - "Please wait %d seconds between each post. (5th plural)" + "Vă rugăm să așteptați %d de secunde între fiecare postare", + "Vă rugăm să așteptați %d de secunde între fiecare postare", + "Vă rugăm să așteptați %d de secunde între fiecare postare" ], - "Paste is limited to %s of encrypted data.": "Paste-ul este limitat la %s de date criptate.", + "Document is limited to %s of encrypted data.": "Document-ul este limitat la %s de date criptate.", "Invalid data.": "Date invalide.", "You are unlucky. Try again.": "Ați avut ghinion. Încercați din nou.", "Error saving comment. Sorry.": "Eroare la salvarea comentariului. Ne pare rău.", - "Error saving paste. Sorry.": "Eroare la salvarea paste-ului. Ne pare rău.", - "Invalid paste ID.": "ID paste invalid.", - "Paste is not of burn-after-reading type.": "Paste-ul nu se șterge după citire.", - "Wrong deletion token. Paste was not deleted.": "Token de ștergere incorect. Paste-ul nu a fost șters.", - "Paste was properly deleted.": "Paste-ul a fost șters cu succes.", + "Error saving document. Sorry.": "Eroare la salvarea document-ului. Ne pare rău.", + "Invalid document ID.": "ID document invalid.", + "Document is not of burn-after-reading type.": "Document-ul nu se șterge după citire.", + "Wrong deletion token. Document was not deleted.": "Token de ștergere incorect. Document-ul nu a fost șters.", + "Document was properly deleted.": "Document-ul a fost șters cu succes.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript este necesar pentru ca %s să funcționeze. Ne cerem scuze pentru neplăceri.", "%s requires a modern browser to work.": "%s necesită un browser modern pentru a funcționa.", "New": "Nou", - "Send": "Trimiteți", + "Create": "Creați", "Clone": "Clonați", "Raw text": "Text brut", "Expires": "Expiră", @@ -39,57 +39,57 @@ "%d secundă", "%d secunde", "%d de secunde", - "%d seconds (3rd plural)", - "%d seconds (4th plural)", - "%d seconds (5th plural)" + "%d de secunde", + "%d de secunde", + "%d de secunde" ], "%d minutes": [ "%d minut", "%d minute", "%d de minute", - "%d minutes (3rd plural)", - "%d minutes (4th plural)", - "%d minutes (5th plural)" + "%d de secunde", + "%d de secunde", + "%d de secunde" ], "%d hours": [ "%d oră", "%d ore", "%d de ore", - "%d hours (3rd plural)", - "%d hours (4th plural)", - "%d hours (5th plural)" + "%d de ore", + "%d de ore", + "%d de ore" ], "%d days": [ "%d zi", "%d zile", "%d de zile", - "%d days (3rd plural)", - "%d days (4th plural)", - "%d days (5th plural)" + "%d de zile", + "%d de zile", + "%d de zile" ], "%d weeks": [ - "%d week (singular)", + "%d săptămână", "%d săptămână", "%d săptămâni", "%d de săptămâni", - "%d weeks (4th plural)", - "%d weeks (5th plural)" + "%d de săptămâni", + "%d de săptămâni" ], "%d months": [ "%d lună", "%d luni", "%d de luni", - "%d months (3rd plural)", - "%d months (4th plural)", - "%d months (5th plural)" + "%d de luni", + "%d de luni", + "%d de luni" ], "%d years": [ "%d an", "%d ani", "%d de ani", - "%d years (3rd plural)", - "%d years (4th plural)", - "%d years (5th plural)" + "%d de ani", + "%d de ani", + "%d de ani" ], "Never": "Niciodată", "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "Notă: Acesta este un serviciu de test: Datele ar putea fi șterse oricând. Vor muri niște pisicuțe dacă abuzați acest serviciu.", @@ -97,45 +97,45 @@ "Acest document va expira în %d secundă.", "Acest document va expira în %d secunde.", "Acest document va expira în %d de secunde.", - "This document will expire in %d seconds. (3rd plural)", - "This document will expire in %d seconds. (4th plural)", - "This document will expire in %d seconds. (5th plural)" + "Acest document va expira în %d de secunde.", + "Acest document va expira în %d de secunde.", + "Acest document va expira în %d de secunde." ], "This document will expire in %d minutes.": [ - "This document will expire in %d minute. (singular)", - "This document will expire in %d minutes. (1st plural)", - "This document will expire in %d minutes. (2nd plural)", - "This document will expire in %d minutes. (3rd plural)", - "This document will expire in %d minutes. (4th plural)", - "This document will expire in %d minutes. (5th plural)" + "Acest document va expira în %d minut.", + "Acest document va expira în %d minute.", + "Acest document va expira în %d de minute.", + "Acest document va expira în %d de minute.", + "Acest document va expira în %d de minute.", + "Acest document va expira în %d de minute." ], "This document will expire in %d hours.": [ "Acest document va expira în %d oră.", "Acest document va expira în %d ore.", "Acest document va expira în %d de ore.", - "This document will expire in %d hours. (3rd plural)", - "This document will expire in %d hours. (4th plural)", - "This document will expire in %d hours. (5th plural)" + "Acest document va expira în %d de ore.", + "Acest document va expira în %d de ore.", + "Acest document va expira în %d de ore." ], "This document will expire in %d days.": [ "Acest document va expira în %d zi.", "Acest document va expira în %d zile.", "Acest document va expira în %d de zile.", - "This document will expire in %d days. (3rd plural)", - "This document will expire in %d days. (4th plural)", - "This document will expire in %d days. (5th plural)" + "Acest document va expira în %d de zile.", + "Acest document va expira în %d de zile.", + "Acest document va expira în %d de zile." ], "This document will expire in %d months.": [ "Acest document va expira în %d lună.", "Acest document va expira în %d luni.", "Acest document va expira în %d de luni.", - "This document will expire in %d months. (3rd plural)", - "This document will expire in %d months. (4th plural)", - "This document will expire in %d months. (5th plural)" + "Acest document va expira în %d de luni.", + "Acest document va expira în %d de luni.", + "Acest document va expira în %d de luni." ], - "Please enter the password for this paste:": "Va rugăm să introduceți parola pentru acest paste:", + "Please enter the password for this document:": "Va rugăm să introduceți parola pentru acest document:", "Could not decrypt data (Wrong key?)": "Nu s-au putut decripta datele (Cheie gresită?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Nu s-a putut șterge paste-ul, nu a fost stocat în modul de ștergere după citire.", + "Could not delete the document, it was not stored in burn after reading mode.": "Nu s-a putut șterge document-ul, nu a fost stocat în modul de ștergere după citire.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "NUMAI PENTRU OCHII DVS. Nu închideți această fereastră, acest mesaj nu poate fi afișat din nou.", "Could not decrypt comment; Wrong key?": "Nu s-a putut decripta comentariul; Cheie greșită?", "Reply": "Răspundeți", @@ -150,27 +150,27 @@ "unknown status": "stare necunoscută", "server error or not responding": "eroare de server sau nu răspunde", "Could not post comment: %s": "Nu s-a putut posta comentariul: %s", - "Sending paste…": "Se trimite paste-ul…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Paste-ul dvs. este %s (Apăsați [Ctrl]+[c] pentru a copia)", + "Sending document…": "Se trimite document-ul…", + "Your document is %s (Hit Ctrl+c to copy)": "Document-ul dvs. este %s (Apăsați Ctrl+c pentru a copia)", "Delete data": "Ștergeți datele", - "Could not create paste: %s": "Nu s-a putut crea paste-ul: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Nu s-a putut decripta paste-ul: Cheia de decriptare lipsește din URL (Ați folosit un redirector sau un scurtător de URL care a tăiat o parte din URL?)", + "Could not create document: %s": "Nu s-a putut crea document-ul: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Nu s-a putut decripta document-ul: Cheia de decriptare lipsește din URL (Ați folosit un redirector sau un scurtător de URL care a tăiat o parte din URL?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Formatare", "Plain Text": "Text neformatat", "Source Code": "Cod sursă", "Markdown": "Markdown", "Download attachment": "Descărcați fișierul atașat", "Cloned: '%s'": "S-a clonat: '%s'", - "The cloned file '%s' was attached to this paste.": "Fișierul clonat '%s' a fost atașat la acest paste.", + "The cloned file '%s' was attached to this document.": "Fișierul clonat '%s' a fost atașat la acest document.", "Attach a file": "Atașați un fișier", "alternatively drag & drop a file or paste an image from the clipboard": "alternativ, trageți și plasați un fișier sau lipiți o imagine din clipboard", "File too large, to display a preview. Please download the attachment.": "Fișierul este prea mare pentru a afișa o previzualizare. Vă rugăm să descărcaţi fișierul.", @@ -185,11 +185,11 @@ "Decrypt": "Decriptare", "Enter password": "Introduceţi parola", "Loading…": "Se încarcă…", - "Decrypting paste…": "Se decriptează paste-ul…", - "Preparing new paste…": "Se pregătește un paste nou…", + "Decrypting document…": "Se decriptează document-ul…", + "Preparing new document…": "Se pregătește un document nou…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "În cazul în care acest mesaj nu dispare niciodată, vă rugăm să aruncaţi o privire la acest FAQ pentru informații de depanare.", - "+++ no paste text +++": "+++ fără text +++", - "Could not get paste data: %s": "Nu s-a putut obține datele paste-ului: %s", + "+++ no document text +++": "+++ fără text +++", + "Could not get document data: %s": "Nu s-a putut obține datele document-ului: %s", "QR code": "Cod QR", "This website is using an insecure HTTP connection! Please use it only for testing.": "Acest website folosește o conexiune HTTP nesigură! Vă rugăm să îl folosiți doar pentru teste.", "For more information see this FAQ entry.": "Pentru mai multe informații a se vedea secțiunea FAQ.", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Notă criptată pe %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Accesați acest link pentru a vedea nota. Nota poate fi accesată de către oricine care are acest URL.", "URL shortener may expose your decrypt key in URL.": "Scurtătorul de URL ar putea să vă expună cheia de decriptare din URL.", - "Save paste": "Salvați paste-ul", - "Your IP is not authorized to create pastes.": "Adresa dvs. IP nu este autorizată să creeze paste-uri.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Salvați document-ul", + "Your IP is not authorized to create documents.": "Adresa dvs. IP nu este autorizată să creeze document-uri.", "Trying to shorten a URL that isn't pointing at our instance.": "Încercarea de a scurta un URL care nu direcționează spre instanța noastră.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Eroare la apelarea YOURLS. Probabil o problemă de configurare, cum ar fi \"apiurl\" sau \"signature\" greșite sau lipsă.", - "Error parsing YOURLS response.": "Eroare la analizarea răspunsului YOURLS.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Eroare la apelarea YOURLS. Probabil o problemă de configurare, cum ar fi \"apiurl\" sau \"signature\" greșite sau lipsă.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Eroare la analizarea răspunsului YOURLS.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "Acest mesaj secret poate fi afișat o singură dată. Doriți să îl vedeți acum?", + "Yes, see it": "Da, vezi", + "Dark Mode": "Mod întunecat", + "Error compressing document, due to missing WebAssembly support.": "Eroare la compresia document-ului din cauza incompatibilității cu WebAssembly.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Eroare la deschiderea document-ului, browserul dvs. nu acceptă WebAssembly. Vă rugăm să utilizați un alt browser pentru a vedea acest document.", + "Start over": "Start over", + "Document copied to clipboard": "Document copied to clipboard", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/ru.json b/i18n/ru.json index 00084dc8..ee4c4013 100644 --- a/i18n/ru.json +++ b/i18n/ru.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s это минималистичный Open Source проект для создания заметок, где сервер не знает ничего о сохраняемых данных. Данные шифруются/расшифровываются %sв браузере%s с использованием 256 битного шифрования AES.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s это минималистичный Open Source проект для создания заметок, где сервер не знает ничего о сохраняемых данных. Данные шифруются/расшифровываются %sв браузере%s с использованием 256 битного шифрования AES.", "More information on the project page.": "Подробнее можно узнать на сайте проекта.", "Because ignorance is bliss": "Потому что неведение - благо", - "Paste does not exist, has expired or has been deleted.": "Запись не существует, просрочена или была удалена.", + "Document does not exist, has expired or has been deleted.": "Запись не существует, просрочена или была удалена.", "%s requires php %s or above to work. Sorry.": "Для работы %s требуется php %s или выше. Извините.", "%s requires configuration section [%s] to be present in configuration file.": "%s необходимо наличие секции [%s] в конфигурационном файле.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Пожалуйста, ожидайте %d секунд между каждыми записями.", "Пожалуйста, ожидайте %d секунд между каждыми записями." ], - "Paste is limited to %s of encrypted data.": "Размер записи ограничен %s зашифрованных данных.", + "Document is limited to %s of encrypted data.": "Размер записи ограничен %s зашифрованных данных.", "Invalid data.": "Неверные данные.", "You are unlucky. Try again.": "Вам не повезло. Попробуйте еще раз.", "Error saving comment. Sorry.": "Ошибка при сохранении комментария. Извините.", - "Error saving paste. Sorry.": "Ошибка при сохранении записи. Извините.", - "Invalid paste ID.": "Неверный ID записи.", - "Paste is not of burn-after-reading type.": "Тип записи не \"Удалить после прочтения\".", - "Wrong deletion token. Paste was not deleted.": "Неверный ключ удаления записи. Запись не удалена.", - "Paste was properly deleted.": "Запись была успешно удалена.", + "Error saving document. Sorry.": "Ошибка при сохранении записи. Извините.", + "Invalid document ID.": "Неверный ID записи.", + "Document is not of burn-after-reading type.": "Тип записи не \"Удалить после прочтения\".", + "Wrong deletion token. Document was not deleted.": "Неверный ключ удаления записи. Запись не удалена.", + "Document was properly deleted.": "Запись была успешно удалена.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "Для работы %s требуется включенный JavaScript. Приносим извинения за неудобства.", "%s requires a modern browser to work.": "Для работы %s требуется более современный браузер.", "New": "Новая запись", - "Send": "Отправить", + "Create": "Создать", "Clone": "Дублировать", "Raw text": "Исходный текст", "Expires": "Удалить через", @@ -133,9 +133,9 @@ "Документ будет удален через %d месяцев.", "Документ будет удален через %d месяцев." ], - "Please enter the password for this paste:": "Пожалуйста, введите пароль от записи:", + "Please enter the password for this document:": "Пожалуйста, введите пароль от записи:", "Could not decrypt data (Wrong key?)": "Невозможно расшифровать данные (Неверный ключ?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Невозможно удалить запись, она не была сохранена в режиме удаления после прочтения.", + "Could not delete the document, it was not stored in burn after reading mode.": "Невозможно удалить запись, она не была сохранена в режиме удаления после прочтения.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "ТОЛЬКО ДЛЯ ВАШИХ ГЛАЗ. Не закрывайте это окно, это сообщение не может быть показано снова.", "Could not decrypt comment; Wrong key?": "Невозможно расшифровать комментарий; Неверный ключ?", "Reply": "Ответить", @@ -150,27 +150,27 @@ "unknown status": "неизвестная причина", "server error or not responding": "ошибка сервера или нет ответа", "Could not post comment: %s": "Не удалось опубликовать комментарий: %s", - "Sending paste…": "Отправка записи…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Ссылка на запись %s (Нажмите [Ctrl]+[c], чтобы скопировать ссылку)", + "Sending document…": "Отправка записи…", + "Your document is %s (Hit Ctrl+c to copy)": "Ссылка на запись %s (Нажмите Ctrl+c, чтобы скопировать ссылку)", "Delete data": "Удалить запись", - "Could not create paste: %s": "Не удалось опубликовать запись: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Невозможно расшифровать запись: Ключ расшифровки отсутствует в ссылке (Может быть, вы используете сокращатель ссылок, который удаляет часть ссылки?)", + "Could not create document: %s": "Не удалось опубликовать запись: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Невозможно расшифровать запись: Ключ расшифровки отсутствует в ссылке (Может быть, вы используете сокращатель ссылок, который удаляет часть ссылки?)", "B": "байт", - "KiB": "Кбайт", - "MiB": "Мбайт", - "GiB": "Гбайт", - "TiB": "Тбайт", - "PiB": "Пбайт", - "EiB": "Эбайт", - "ZiB": "Збайт", - "YiB": "Йбайт", + "kB": "кбайт", + "MB": "Мбайт", + "GB": "Гбайт", + "TB": "Тбайт", + "PB": "Пбайт", + "EB": "Эбайт", + "ZB": "Збайт", + "YB": "Йбайт", "Format": "Формат", "Plain Text": "Обычный текст", "Source Code": "Исходный код", "Markdown": "Язык разметки", "Download attachment": "Скачать прикрепленный файл", "Cloned: '%s'": "Дублировано: '%s'", - "The cloned file '%s' was attached to this paste.": "Дубликат файла '%s' был прикреплен к этой записи.", + "The cloned file '%s' was attached to this document.": "Дубликат файла '%s' был прикреплен к этой записи.", "Attach a file": "Прикрепить файл", "alternatively drag & drop a file or paste an image from the clipboard": "так же можно перенести файл в окно браузера или вставить изображение из буфера", "File too large, to display a preview. Please download the attachment.": "Файл слишком большой для отображения предпросмотра. Пожалуйста, скачайте прикрепленный файл.", @@ -185,11 +185,11 @@ "Decrypt": "Расшифровать", "Enter password": "Введите пароль", "Loading…": "Загрузка…", - "Decrypting paste…": "Расшифровка записи…", - "Preparing new paste…": "Подготовка новой записи…", + "Decrypting document…": "Расшифровка записи…", + "Preparing new document…": "Подготовка новой записи…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "Если данное сообщение не исчезает длительное время, посмотрите этот FAQ с информацией о возможном решении проблемы (на английском).", - "+++ no paste text +++": "+++ в записи нет текста +++", - "Could not get paste data: %s": "Не удалось получить данные записи: %s", + "+++ no document text +++": "+++ в записи нет текста +++", + "Could not get document data: %s": "Не удалось получить данные записи: %s", "QR code": "QR код", "This website is using an insecure HTTP connection! Please use it only for testing.": "Данный сайт использует незащищенное HTTP подключение! Пожалуйста используйте его только для тестирования.", "For more information see this FAQ entry.": "Для продробностей прочтите информацию в FAQ.", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Зашифрованная запись на %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Посетите эту ссылку чтобы просмотреть запись. Передача ссылки кому либо позволит им получить доступ к записи тоже.", "URL shortener may expose your decrypt key in URL.": "Сервис сокращения ссылок может получить ваш ключ расшифровки из ссылки.", - "Save paste": "Сохранить запись", - "Your IP is not authorized to create pastes.": "Вашему IP адресу не разрешено создавать записи.", - "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Сохранить запись", + "Your IP is not authorized to create documents.": "Вашему IP адресу не разрешено создавать записи.", + "Trying to shorten a URL that isn't pointing at our instance.": "Попытка сократить URL, который указывает не на наш сервер.", + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Ошибка обращения к YOURLS. Возможно в конфигурации допущена ошибка, например неверный или отсутствующий параметр \"apiurl\" или \"signature\".", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Ошибка разбора ответа от YOURLS.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "Записи, удаляемые после прочтения, могут быть отображены после загрузки только один раз. Вы хотите открыть её сейчас?", + "Yes, see it": "Да, загрузить", + "Dark Mode": "Тёмная", + "Error compressing document, due to missing WebAssembly support.": "Error compressing document, due to missing WebAssembly support.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.", + "Start over": "Start over", + "Document copied to clipboard": "Запись скопирована в буфер обмена", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "Чтобы скопировать запись нажмите на кнопку копирования или используйте комбинацию клавиш Ctrl+c/Cmd+c", + "Copy link": "Скопировать ссылку", + "Link copied to clipboard": "Ссылка скопирована в буфер обмена", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Тема" } diff --git a/i18n/sk.json b/i18n/sk.json index c73fe638..95dae475 100644 --- a/i18n/sk.json +++ b/i18n/sk.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s je minimalistický, open source online pastebin, kde server nemá žiadne znalosti o vložených údajoch. Údaje sú šifrované/dešifrované %sv prehliadači%s pomocou 256-bitového AES.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s je minimalistický, open source online pastebin, kde server nemá žiadne znalosti o vložených údajoch. Údaje sú šifrované/dešifrované %sv prehliadači%s pomocou 256-bitového AES.", "More information on the project page.": "Viac informácií na stránke projektu.", "Because ignorance is bliss": "Pretože nevedomosť je sladká", - "Paste does not exist, has expired or has been deleted.": "Vložený text neexistuje, jeho platnosť vypršala alebo bol vymazaný.", + "Document does not exist, has expired or has been deleted.": "Vložený text neexistuje, jeho platnosť vypršala alebo bol vymazaný.", "%s requires php %s or above to work. Sorry.": "%s vyžaduje php %s alebo vyššie. Prepáčte.", "%s requires configuration section [%s] to be present in configuration file.": "%s vyžaduje, aby bola v konfiguračnom súbore prítomná sekcia [%s].", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Počet sekúnd do ďalšieho príspevku: %d", "Počet sekúnd do ďalšieho príspevku: %d" ], - "Paste is limited to %s of encrypted data.": "Príspevok je obmedzený na %s zašifrovaných údajov.", + "Document is limited to %s of encrypted data.": "Príspevok je obmedzený na %s zašifrovaných údajov.", "Invalid data.": "Neplatné údaje.", "You are unlucky. Try again.": "Ľutujem. Skúste to znova.", "Error saving comment. Sorry.": "Pri ukladaní komentára sa vyskytla chyba.", - "Error saving paste. Sorry.": "Pri ukladaní príspevku sa vyskytla chyba.", - "Invalid paste ID.": "Chybne vložené ID.", - "Paste is not of burn-after-reading type.": "Príspevok nieje nastavený na zmazanie po prečítaní.", - "Wrong deletion token. Paste was not deleted.": "Nesprávny token odstránenia. Príspevok nebol odstránený.", - "Paste was properly deleted.": "Príspevok bol správne vymazaný.", + "Error saving document. Sorry.": "Pri ukladaní príspevku sa vyskytla chyba.", + "Invalid document ID.": "Chybne vložené ID.", + "Document is not of burn-after-reading type.": "Príspevok nieje nastavený na zmazanie po prečítaní.", + "Wrong deletion token. Document was not deleted.": "Nesprávny token odstránenia. Príspevok nebol odstránený.", + "Document was properly deleted.": "Príspevok bol správne vymazaný.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "Na fungovanie %s je potrebný JavaScript. Ospravedlňujeme sa za nepríjemnosti.", "%s requires a modern browser to work.": "%s vyžaduje na fungovanie moderný prehliadač.", "New": "Nový", - "Send": "Odoslať", + "Create": "Vytvoriť", "Clone": "Klonovať", "Raw text": "Surový text", "Expires": "Expirácia", @@ -133,9 +133,9 @@ "Platnosť tohto dokumentu vyprší o %d mesiacov.", "Platnosť tohto dokumentu vyprší o %d mesiacov." ], - "Please enter the password for this paste:": "Zadajte prosím heslo:", + "Please enter the password for this document:": "Zadajte prosím heslo:", "Could not decrypt data (Wrong key?)": "Nepodarilo sa dešifrovať údaje (nesprávny kľúč?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Nepodarilo sa odstrániť príspevok, nebol uložený v režime zmazania po prečítaní.", + "Could not delete the document, it was not stored in burn after reading mode.": "Nepodarilo sa odstrániť príspevok, nebol uložený v režime zmazania po prečítaní.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "IBA PRE VAŠE OČI. Toto okno nezatvárajte, táto správa sa nedá znova zobraziť.", "Could not decrypt comment; Wrong key?": "Nepodarilo sa dešifrovať komentár. Nesprávny kľúč?", "Reply": "Odpovedať", @@ -150,27 +150,27 @@ "unknown status": "neznámy stav", "server error or not responding": "chyba servera alebo server neodpovedá", "Could not post comment: %s": "Nepodarilo sa pridať komentár: %s", - "Sending paste…": "Odosiela sa príspevok…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Váš príspevok je %s (skopírujte stlačením [Ctrl]+[c])", + "Sending document…": "Odosiela sa príspevok…", + "Your document is %s (Hit Ctrl+c to copy)": "Váš príspevok je %s (skopírujte stlačením Ctrl+c)", "Delete data": "Odstrániť dáta", - "Could not create paste: %s": "Nepodarilo sa vytvoriť príspevok: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Nie je možné dešifrovať príspevok: V URL adrese chýba dešifrovací kľúč (Použili ste presmerovač alebo skracovač adresy, ktorý odstráni časť adresy URL?)", + "Could not create document: %s": "Nepodarilo sa vytvoriť príspevok: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Nie je možné dešifrovať príspevok: V URL adrese chýba dešifrovací kľúč (Použili ste presmerovač alebo skracovač adresy, ktorý odstráni časť adresy URL?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Formát", "Plain Text": "Čistý text", "Source Code": "Zdrojový kód", "Markdown": "Markdown", "Download attachment": "Stiahnuť prílohu", "Cloned: '%s'": "Naklonované: '%s'", - "The cloned file '%s' was attached to this paste.": "K tomuto príspevku bol pripojený klonovaný súbor '%s'.", + "The cloned file '%s' was attached to this document.": "K tomuto príspevku bol pripojený klonovaný súbor '%s'.", "Attach a file": "Priložiť súbor", "alternatively drag & drop a file or paste an image from the clipboard": "prípadne presuňte súbor myšou alebo vložte obrázok zo schránky", "File too large, to display a preview. Please download the attachment.": "Súbor je príliš veľký na zobrazenie ukážky. Stiahnite si prosím prílohu.", @@ -185,11 +185,11 @@ "Decrypt": "Dešifrovať", "Enter password": "Zadajte heslo", "Loading…": "Načítava sa…", - "Decrypting paste…": "Dešifrovanie príspevku…", - "Preparing new paste…": "Príprava nového príspevku…", + "Decrypting document…": "Dešifrovanie príspevku…", + "Preparing new document…": "Príprava nového príspevku…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "V prípade, že táto správa nezmizne, pozrite si tieto často kladené otázky, kde nájdete informácie na riešenie problémov.", - "+++ no paste text +++": "+++ žiadny vložený text +++", - "Could not get paste data: %s": "Nepodarilo sa načítať údaje príspevku: %s", + "+++ no document text +++": "+++ žiadny vložený text +++", + "Could not get document data: %s": "Nepodarilo sa načítať údaje príspevku: %s", "QR code": "QR kód", "This website is using an insecure HTTP connection! Please use it only for testing.": "Táto webová stránka používa nezabezpečené pripojenie HTTP! Používajte ju len na testovanie.", "For more information see this FAQ entry.": "Pre viac informácií si pozrite tento záznam FAQ.", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Zašifrovaná poznámka na %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Ak chcete zobraziť poznámku, navštívte tento odkaz. Poskytnutie adresy URL komukoľvek im umožní prístup aj k poznámke.", "URL shortener may expose your decrypt key in URL.": "Skracovač adries URL môže odhaliť váš dešifrovací kľúč v adrese URL.", - "Save paste": "Uložiť príspevok", - "Your IP is not authorized to create pastes.": "Vaša IP adresa nie je oprávnená vytvárať príspevky.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Uložiť príspevok", + "Your IP is not authorized to create documents.": "Vaša IP adresa nie je oprávnená vytvárať príspevky.", "Trying to shorten a URL that isn't pointing at our instance.": "Pokúšate sa skrátiť adresu URL, ktorá neukazuje na túto inštanciu.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?", + "Yes, see it": "Áno, zobraziť", + "Dark Mode": "Tmavý Režim", + "Error compressing document, due to missing WebAssembly support.": "Error compressing document, due to missing WebAssembly support.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.", + "Start over": "Začať odznova", + "Document copied to clipboard": "Kópia vložená do schránky", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Kopírovať odkaz", + "Link copied to clipboard": "Odkaz vložený do schránky", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/sl.json b/i18n/sl.json index f3baab91..8098381b 100644 --- a/i18n/sl.json +++ b/i18n/sl.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s je minimalističen, odprtokodni spletni 'pastebin', kjer server ne ve ničesar o prilepljenih podatkih. Podatki so zakodirani/odkodirani %sv brskalniku%s z uporabo 256 bitnega AES.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s je minimalističen, odprtokodni spletni 'pastebin', kjer server ne ve ničesar o prilepljenih podatkih. Podatki so zakodirani/odkodirani %sv brskalniku%s z uporabo 256 bitnega AES.", "More information on the project page.": "Več informacij na spletni strani projekta..", "Because ignorance is bliss": "Ker kar ne veš ne boli.", - "Paste does not exist, has expired or has been deleted.": "Prilepek ne obstaja, mu je potekla življenjska doba, ali pa je izbrisan.", + "Document does not exist, has expired or has been deleted.": "Prilepek ne obstaja, mu je potekla življenjska doba, ali pa je izbrisan.", "%s requires php %s or above to work. Sorry.": "Oprosti, %s za delovanje potrebuje vsaj php %s.", "%s requires configuration section [%s] to be present in configuration file.": "%s potrebuje sekcijo konfiguracij [%s] v konfiguracijski datoteki.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Prosim počakaj vsaj %d sekund pred vsako naslednjo objavo.", "Prosim počakaj vsaj %d sekund pred vsako naslednjo objavo." ], - "Paste is limited to %s of encrypted data.": "Velikost prilepka je omejena na %s zakodiranih podatkov.", + "Document is limited to %s of encrypted data.": "Velikost prilepka je omejena na %s zakodiranih podatkov.", "Invalid data.": "Neveljavni podatki.", "You are unlucky. Try again.": "Nimaš sreče, poskusi ponovno.", "Error saving comment. Sorry.": "Nekaj je šlo narobe pri shranjevanju komentarja. Oprosti.", - "Error saving paste. Sorry.": "Nekaj je šlo narobe pri shranjevanju prilepka. Oprosti.", - "Invalid paste ID.": "Napačen ID prilepka.", - "Paste is not of burn-after-reading type.": "Prilepek ni tipa zažgi-po-branju.", - "Wrong deletion token. Paste was not deleted.": "Napačen token za izbris. Prilepek ni bil izbrisan..", - "Paste was properly deleted.": "Prilepek je uspešno izbrisan.", + "Error saving document. Sorry.": "Nekaj je šlo narobe pri shranjevanju prilepka. Oprosti.", + "Invalid document ID.": "Napačen ID prilepka.", + "Document is not of burn-after-reading type.": "Prilepek ni tipa zažgi-po-branju.", + "Wrong deletion token. Document was not deleted.": "Napačen token za izbris. Prilepek ni bil izbrisan..", + "Document was properly deleted.": "Prilepek je uspešno izbrisan.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "Da %s deluje, moraš vklopiti JavaScript. Oprosti za povročene nevšečnosti.", "%s requires a modern browser to work.": "%s za svoje delovanje potrebuje moderen brskalnik.", "New": "Nov prilepek", - "Send": "Pošlji", + "Create": "Ustvari", "Clone": "Kloniraj", "Raw text": "Surov tekst", "Expires": "Poteče", @@ -133,9 +133,9 @@ "Ta dokument bo potekel čez %d mesecev.", "Ta dokument bo potekel čez %d mesecev." ], - "Please enter the password for this paste:": "Prosim vnesi geslo tega prilepka:", + "Please enter the password for this document:": "Prosim vnesi geslo tega prilepka:", "Could not decrypt data (Wrong key?)": "Nemogoče odkodirati podakte (Imaš napačen ključ?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Prilepek je nemogoče izbrisati, ni bil shranjen v načinu \"zažgi po branju\".", + "Could not delete the document, it was not stored in burn after reading mode.": "Prilepek je nemogoče izbrisati, ni bil shranjen v načinu \"zažgi po branju\".", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "SAMO ZA TVOJE OČI. Ne zapri tega okna (zavihka), to sporočilo ne bo prikazano nikoli več.", "Could not decrypt comment; Wrong key?": "Ne morem odkodirati komentarja: Imaš napačen ključ?", "Reply": "Odgovori", @@ -150,27 +150,27 @@ "unknown status": "neznan status", "server error or not responding": "napaka na strežniku, ali pa se strežnik ne odziva", "Could not post comment: %s": "Komentarja ni bilo mogoče objaviti : %s", - "Sending paste…": "Pošiljam prilepek…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Tvoj prilepek je dostopen na naslovu: %s (Pritisni [Ctrl]+[c] ali [Cmd] + [c] in skopiraj)", + "Sending document…": "Pošiljam prilepek…", + "Your document is %s (Hit Ctrl+c to copy)": "Tvoj prilepek je dostopen na naslovu: %s (Pritisni Ctrl+c ali [Cmd] + [c] in skopiraj)", "Delete data": "Izbriši podatke", - "Could not create paste: %s": "Ne morem ustvariti prilepka: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Ne morem odkodirati prilepka: V URL-ju manjka ključ (A si uporabil krajšalnik URL-jev, ki odstrani del URL-ja?)", + "Could not create document: %s": "Ne morem ustvariti prilepka: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Ne morem odkodirati prilepka: V URL-ju manjka ključ (A si uporabil krajšalnik URL-jev, ki odstrani del URL-ja?)", "B": "o", - "KiB": "KB", - "MiB": "MB", - "GiB": "GB", - "TiB": "TB", - "PiB": "PB", - "EiB": "EB", - "ZiB": "ZB", - "YiB": "YB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Surov tekst", "Source Code": "Odprta koda", "Markdown": "Markdown", "Download attachment": "Pretoči priponko", "Cloned: '%s'": "'%s' klonirana", - "The cloned file '%s' was attached to this paste.": "The cloned file '%s' was attached to this paste.", + "The cloned file '%s' was attached to this document.": "The cloned file '%s' was attached to this document.", "Attach a file": "Pripni datoteko", "alternatively drag & drop a file or paste an image from the clipboard": "alternatively drag & drop a file or paste an image from the clipboard", "File too large, to display a preview. Please download the attachment.": "File too large, to display a preview. Please download the attachment.", @@ -185,11 +185,11 @@ "Decrypt": "Decrypt", "Enter password": "Prosim vnesi geslo", "Loading…": "Loading…", - "Decrypting paste…": "Decrypting paste…", - "Preparing new paste…": "Preparing new paste…", + "Decrypting document…": "Decrypting document…", + "Preparing new document…": "Preparing new document…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "In case this message never disappears please have a look at this FAQ for information to troubleshoot (in English).", - "+++ no paste text +++": "+++ no paste text +++", - "Could not get paste data: %s": "Could not get paste data: %s", + "+++ no document text +++": "+++ no document text +++", + "Could not get document data: %s": "Could not get document data: %s", "QR code": "QR code", "This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.", "For more information see this FAQ entry.": "For more information see this FAQ entry.", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Encrypted note on %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.", "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.", - "Save paste": "Save paste", - "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Save document", + "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.", "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?", + "Yes, see it": "Yes, see it", + "Dark Mode": "Temni način", + "Error compressing document, due to missing WebAssembly support.": "Error compressing document, due to missing WebAssembly support.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.", + "Start over": "Start over", + "Document copied to clipboard": "Document copied to clipboard", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/sv.json b/i18n/sv.json index 6ef3280b..8e9ac275 100644 --- a/i18n/sv.json +++ b/i18n/sv.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.", "More information on the project page.": "More information on the project page.", "Because ignorance is bliss": "Because ignorance is bliss", - "Paste does not exist, has expired or has been deleted.": "Paste does not exist, has expired or has been deleted.", + "Document does not exist, has expired or has been deleted.": "Document does not exist, has expired or has been deleted.", "%s requires php %s or above to work. Sorry.": "%s requires php %s or above to work. Sorry.", "%s requires configuration section [%s] to be present in configuration file.": "%s requires configuration section [%s] to be present in configuration file.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Please wait %d seconds between each post. (4th plural)", "Please wait %d seconds between each post. (5th plural)" ], - "Paste is limited to %s of encrypted data.": "Paste is limited to %s of encrypted data.", + "Document is limited to %s of encrypted data.": "Document is limited to %s of encrypted data.", "Invalid data.": "Invalid data.", "You are unlucky. Try again.": "You are unlucky. Try again.", "Error saving comment. Sorry.": "Error saving comment. Sorry.", - "Error saving paste. Sorry.": "Error saving paste. Sorry.", - "Invalid paste ID.": "Invalid paste ID.", - "Paste is not of burn-after-reading type.": "Paste is not of burn-after-reading type.", - "Wrong deletion token. Paste was not deleted.": "Wrong deletion token. Paste was not deleted.", - "Paste was properly deleted.": "Paste was properly deleted.", + "Error saving document. Sorry.": "Error saving document. Sorry.", + "Invalid document ID.": "Invalid document ID.", + "Document is not of burn-after-reading type.": "Document is not of burn-after-reading type.", + "Wrong deletion token. Document was not deleted.": "Wrong deletion token. Document was not deleted.", + "Document was properly deleted.": "Document was properly deleted.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript is required for %s to work. Sorry for the inconvenience.", "%s requires a modern browser to work.": "%s requires a modern browser to work.", "New": "New", - "Send": "Send", + "Create": "Skapa", "Clone": "Clone", "Raw text": "Raw text", "Expires": "Expires", @@ -133,9 +133,9 @@ "This document will expire in %d months. (4th plural)", "This document will expire in %d months. (5th plural)" ], - "Please enter the password for this paste:": "Please enter the password for this paste:", + "Please enter the password for this document:": "Please enter the password for this document:", "Could not decrypt data (Wrong key?)": "Could not decrypt data (Wrong key?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Could not delete the paste, it was not stored in burn after reading mode.", + "Could not delete the document, it was not stored in burn after reading mode.": "Could not delete the document, it was not stored in burn after reading mode.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.", "Could not decrypt comment; Wrong key?": "Could not decrypt comment; Wrong key?", "Reply": "Reply", @@ -150,27 +150,27 @@ "unknown status": "unknown status", "server error or not responding": "server error or not responding", "Could not post comment: %s": "Could not post comment: %s", - "Sending paste…": "Sending paste…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Your paste is %s (Hit [Ctrl]+[c] to copy)", + "Sending document…": "Sending document…", + "Your document is %s (Hit Ctrl+c to copy)": "Your document is %s (Hit Ctrl+c to copy)", "Delete data": "Delete data", - "Could not create paste: %s": "Could not create paste: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)", + "Could not create document: %s": "Could not create document: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Plain Text", "Source Code": "Source Code", "Markdown": "Markdown", "Download attachment": "Download attachment", "Cloned: '%s'": "Cloned: '%s'", - "The cloned file '%s' was attached to this paste.": "The cloned file '%s' was attached to this paste.", + "The cloned file '%s' was attached to this document.": "The cloned file '%s' was attached to this document.", "Attach a file": "Attach a file", "alternatively drag & drop a file or paste an image from the clipboard": "alternatively drag & drop a file or paste an image from the clipboard", "File too large, to display a preview. Please download the attachment.": "File too large, to display a preview. Please download the attachment.", @@ -185,11 +185,11 @@ "Decrypt": "Decrypt", "Enter password": "Enter password", "Loading…": "Loading…", - "Decrypting paste…": "Decrypting paste…", - "Preparing new paste…": "Preparing new paste…", + "Decrypting document…": "Decrypting document…", + "Preparing new document…": "Preparing new document…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "In case this message never disappears please have a look at this FAQ for information to troubleshoot.", - "+++ no paste text +++": "+++ no paste text +++", - "Could not get paste data: %s": "Could not get paste data: %s", + "+++ no document text +++": "+++ no document text +++", + "Could not get document data: %s": "Could not get document data: %s", "QR code": "QR code", "This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.", "For more information see this FAQ entry.": "For more information see this FAQ entry.", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Encrypted note on %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.", "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.", - "Save paste": "Save paste", - "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Save document", + "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.", "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?", + "Yes, see it": "Yes, see it", + "Dark Mode": "Mörkt Läge", + "Error compressing document, due to missing WebAssembly support.": "Error compressing document, due to missing WebAssembly support.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.", + "Start over": "Start over", + "Document copied to clipboard": "Document copied to clipboard", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/th.json b/i18n/th.json index 4325ab1d..d7d2a133 100644 --- a/i18n/th.json +++ b/i18n/th.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s เป็น pastebin ออนไลน์แบบโอเพ่นซอร์สที่มีรูปแบบการใช้งานที่เรียบง่าย เซิร์ฟเวอร์ไม่สามารถรู้ได้ว่าข้อมูลโค้ดที่มาฝากนั้นเป็นข้อมูลอะไร โดยจะถูกเข้ารหัส/ถอดรหัสด้วยกระบวนการ AES จำนวน 256 บิต%sผ่านเบราว์เซอร์%s", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s เป็น pastebin ออนไลน์แบบโอเพ่นซอร์สที่มีรูปแบบการใช้งานที่เรียบง่าย เซิร์ฟเวอร์ไม่สามารถรู้ได้ว่าข้อมูลโค้ดที่มาฝากนั้นเป็นข้อมูลอะไร โดยจะถูกเข้ารหัส/ถอดรหัสด้วยกระบวนการ AES จำนวน 256 บิต%sผ่านเบราว์เซอร์%s", "More information on the project page.": "ข้อมูลเพิ่มเติม ดูได้ที่หน้าโครงการ", "Because ignorance is bliss": "ไม่รู้ไม่ชี้ดีที่สุด", - "Paste does not exist, has expired or has been deleted.": "การฝากโค้ดไม่มีอยู่ อาจจะหมดอายุหรือถูกลบไปแล้ว", + "Document does not exist, has expired or has been deleted.": "การฝากโค้ดไม่มีอยู่ อาจจะหมดอายุหรือถูกลบไปแล้ว", "%s requires php %s or above to work. Sorry.": "ขออภัย %s ต้องใช้ PHP %s ขึ้นไปจึงจะใช้งานได้", "%s requires configuration section [%s] to be present in configuration file.": "%s จำเป็นต้องตั้งค่าตัวแปร [%s] ในไฟล์กำหนดค่า", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "กรุณาเว้นระยะเวลาการส่งข้อมูลอย่างน้อย %d วินาที", "กรุณาเว้นระยะเวลาการส่งข้อมูลอย่างน้อย %d วินาที" ], - "Paste is limited to %s of encrypted data.": "การฝากโค้ดแบบเข้ารหัส ขีดจำกัดสูงสุดคือ %s", + "Document is limited to %s of encrypted data.": "การฝากโค้ดแบบเข้ารหัส ขีดจำกัดสูงสุดคือ %s", "Invalid data.": "ข้อมูลไม่ถูกต้อง", "You are unlucky. Try again.": "วันนี้คุณดวงไม่เฮงเลย ลองใหม่อีกครั้งนะ", "Error saving comment. Sorry.": "ขออภัย เกิดข้อผิดพลาดในระหว่างบันทึกความคิดเห็น", - "Error saving paste. Sorry.": "ขออภัย เกิดข้อผิดพลาดในระหว่างบันทึกการฝากโค้ด", - "Invalid paste ID.": "ID การฝากโค้ดไม่ถูกต้อง", - "Paste is not of burn-after-reading type.": "ข้อมูลการฝากโค้ดนี้ไม่ได้เป็นรูปแบบลบทันทีเมื่อเปิดอ่าน", - "Wrong deletion token. Paste was not deleted.": "โทเค็นการลบไม่ถูกต้อง ข้อมูลการฝากโค้ดไม่ถูกลบ", - "Paste was properly deleted.": "ข้อมูลการฝากโค้ดถูกลบออกเรียบร้อยแล้ว", + "Error saving document. Sorry.": "ขออภัย เกิดข้อผิดพลาดในระหว่างบันทึกการฝากโค้ด", + "Invalid document ID.": "ID การฝากโค้ดไม่ถูกต้อง", + "Document is not of burn-after-reading type.": "ข้อมูลการฝากโค้ดนี้ไม่ได้เป็นรูปแบบลบทันทีเมื่อเปิดอ่าน", + "Wrong deletion token. Document was not deleted.": "โทเค็นการลบไม่ถูกต้อง ข้อมูลการฝากโค้ดไม่ถูกลบ", + "Document was properly deleted.": "ข้อมูลการฝากโค้ดถูกลบออกเรียบร้อยแล้ว", "JavaScript is required for %s to work. Sorry for the inconvenience.": "จำเป็นต้องใช้ JavaScript เพื่อให้ %s สามารถทำงานได้ ขออภัยในความไม่สะดวก", "%s requires a modern browser to work.": "%s ต้องใช้เบราว์เซอร์สมัยใหม่ถึงจะสามารถใช้งานได้", "New": "ใหม่", - "Send": "ส่ง", + "Create": "สร้าง", "Clone": "โคลน", "Raw text": "ข้อความล้วน", "Expires": "หมดอายุ", @@ -133,9 +133,9 @@ "เอกสารนี้จะหมดอายุใน %d เดือน", "เอกสารนี้จะหมดอายุใน %d เดือน" ], - "Please enter the password for this paste:": "กรุณากรอกรหัสผ่านเพื่อเปิดข้อมูลการฝากโค้ดนี้:", + "Please enter the password for this document:": "กรุณากรอกรหัสผ่านเพื่อเปิดข้อมูลการฝากโค้ดนี้:", "Could not decrypt data (Wrong key?)": "ไม่สามารถถอดรหัสข้อมูลได้ (คีย์ไม่ถูกต้องหรือไม่)", - "Could not delete the paste, it was not stored in burn after reading mode.": "ไม่สามารถลบการฝากโค้ดนี้ได้ เนื่องจากว่าไม่ได้ถูกเก็บไว้ในโหมดลบทันทีเมื่อเปิดอ่าน", + "Could not delete the document, it was not stored in burn after reading mode.": "ไม่สามารถลบการฝากโค้ดนี้ได้ เนื่องจากว่าไม่ได้ถูกเก็บไว้ในโหมดลบทันทีเมื่อเปิดอ่าน", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "เก็บไว้ดูคนเดียวนะ อย่าปิดหน้าต่างนี้ ข้อความนี้จะไม่สามารถแสดงได้อีก", "Could not decrypt comment; Wrong key?": "ไม่สามารถถอดรหัสความคิดเห็นได้ คีย์ไม่ถูกต้องหรือไม่", "Reply": "ตอบกลับ", @@ -150,27 +150,27 @@ "unknown status": "ไม่ทราบสถานะ", "server error or not responding": "เซิร์ฟเวอร์มีข้อผิดพลาดหรือไม่ตอบสนอง", "Could not post comment: %s": "ไม่สามารถส่งความคิดเห็นได้: %s", - "Sending paste…": "กำลังส่งข้อมูล…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "การฝากโค้ดของคุณอยู่ที่ %s (กดปุ่ม [Ctrl]+[c] เพื่อคัดลอก)", + "Sending document…": "กำลังส่งข้อมูล…", + "Your document is %s (Hit Ctrl+c to copy)": "การฝากโค้ดของคุณอยู่ที่ %s (กดปุ่ม Ctrl+c เพื่อคัดลอก)", "Delete data": "ลบข้อมูล", - "Could not create paste: %s": "ไม่สามารถสร้างข้อมูลการฝากโค้ดได้: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "ไม่สามารถถอดรหัสข้อมูลการฝากโค้ดได้: คีย์ถอดรหัสที่อยู่ใน URL หายไป (คุณได้ใช้ตัวเปลี่ยนเส้นทางหรือตัวย่อ URL ที่มีการตัดส่วนของ URL ออกหรือไม่)", + "Could not create document: %s": "ไม่สามารถสร้างข้อมูลการฝากโค้ดได้: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "ไม่สามารถถอดรหัสข้อมูลการฝากโค้ดได้: คีย์ถอดรหัสที่อยู่ใน URL หายไป (คุณได้ใช้ตัวเปลี่ยนเส้นทางหรือตัวย่อ URL ที่มีการตัดส่วนของ URL ออกหรือไม่)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "รูปแบบ", "Plain Text": "ข้อความล้วน", "Source Code": "ซอร์สโค้ด", "Markdown": "Markdown", "Download attachment": "ดาวน์โหลดไฟล์แนบ", "Cloned: '%s'": "โคลนแล้ว: '%s'", - "The cloned file '%s' was attached to this paste.": "การโคลนข้อมูลการฝากโค้ด มีไฟล์ '%s' แนบมาด้วย", + "The cloned file '%s' was attached to this document.": "การโคลนข้อมูลการฝากโค้ด มีไฟล์ '%s' แนบมาด้วย", "Attach a file": "แนบไฟล์", "alternatively drag & drop a file or paste an image from the clipboard": "หรือสามารถลากและวางไฟล์หรือวางรูปภาพจากคลิปบอร์ดได้", "File too large, to display a preview. Please download the attachment.": "ไฟล์มีขนาดใหญ่เกินไปที่จะแสดงตัวอย่าง กรุณาดาวน์โหลดเป็นไฟล์แนบแทน", @@ -185,11 +185,11 @@ "Decrypt": "ถอดรหัส", "Enter password": "กรอกรหัสผ่าน", "Loading…": "กำลังโหลด…", - "Decrypting paste…": "กำลังถอดรหัสข้อมูลการฝากโค้ด…", - "Preparing new paste…": "กำลังเตรียมข้อมูลการฝากโค้ดใหม่…", + "Decrypting document…": "กำลังถอดรหัสข้อมูลการฝากโค้ด…", + "Preparing new document…": "กำลังเตรียมข้อมูลการฝากโค้ดใหม่…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "ในกรณีที่ข้อความนี้ยังปรากฎให้เห็นอยู่ กรุณาดูคำถามที่พบบ่อยนี้เพื่อใช้แก้ไขปัญหา", - "+++ no paste text +++": "+++ ไม่มีข้อความการฝากโค้ด +++", - "Could not get paste data: %s": "ไม่สามารถดึงข้อมูลการฝากโค้ดได้: %s", + "+++ no document text +++": "+++ ไม่มีข้อความการฝากโค้ด +++", + "Could not get document data: %s": "ไม่สามารถดึงข้อมูลการฝากโค้ดได้: %s", "QR code": "คิวอาร์โค้ด", "This website is using an insecure HTTP connection! Please use it only for testing.": "เว็บไซต์นี้ใช้การเชื่อมต่อแบบ HTTP ที่ไม่ปลอดภัย! กรุณาใช้เพื่อการทดสอบเท่านั้น", "For more information see this FAQ entry.": "สำหรับข้อมูลเพิ่มเติม กรุณาดูรายการคำถามที่พบบ่อยนี้", @@ -210,11 +210,24 @@ "Encrypted note on %s": "เขารหัสบันทึกย่อบน %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "ไปที่ลิงก์นี้เพื่อดูบันทึกย่อทั้งหมด ส่ง URL นี้ให้ใครก็ได้เพื่อให้สามารถเข้าถึงบันทึกย่อได้", "URL shortener may expose your decrypt key in URL.": "เครื่องมือสร้างลิงก์ย่ออาจเปิดเผยคีย์ถอดรหัสของคุณใน URL ได้", - "Save paste": "ดาวน์โหลดข้อมูลการฝากโค้ด", - "Your IP is not authorized to create pastes.": "IP ของคุณไม่ได้รับอนุญาตให้สร้างการฝากโค้ด", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "ดาวน์โหลดข้อมูลการฝากโค้ด", + "Your IP is not authorized to create documents.": "IP ของคุณไม่ได้รับอนุญาตให้สร้างการฝากโค้ด", "Trying to shorten a URL that isn't pointing at our instance.": "กำลังพยายามใช้เครื่องมือสร้างลิงก์ย่อ ที่ไม่ได้ชี้ไปที่อินสแตนซ์ของเรา", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "เกิดข้อผิดพลาดในการเรียก YOURLS อาจเป็นปัญหามาจากการกำหนดค่า เช่น \"apiurl\" หรือ \"signature\" ไม่ถูกต้องหรือขาดหายไป", - "Error parsing YOURLS response.": "เกิดข้อผิดพลาดในการแยกวิเคราะห์การตอบสนองของ YOURLS", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "เกิดข้อผิดพลาดในการเรียก YOURLS อาจเป็นปัญหามาจากการกำหนดค่า เช่น \"apiurl\" หรือ \"signature\" ไม่ถูกต้องหรือขาดหายไป", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "เกิดข้อผิดพลาดในการแยกวิเคราะห์การตอบสนองของ YOURLS", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "ข้อความลับนี้จะแสดงได้เพียงครั้งเดียวเท่านั้น คุณต้องการดูข้อความนี้ตอนนี้เลยใช่หรือไม่", + "Yes, see it": "ใช่ ดูเลย", + "Dark Mode": "โหมดสีเข้ม", + "Error compressing document, due to missing WebAssembly support.": "ไม่สามารถบีบอัดข้อมูลที่คุณต้องการฝากโค้ดได้ เนื่องจากอุปกรณ์ของคุณขาดการรองรับ WebAssembly", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "ไม่สามารถอ่านข้อมูลที่คุณได้ฝากโค้ดไว้ เบราว์เซอร์ของคุณไม่รองรับ WebAssembly กรุณาลองเปลี่ยนใช้เบราว์เซอร์ตัวอื่นเพื่อดูการฝากโค้ดนี้อีกครั้ง", + "Start over": "เริ่มใหม่", + "Document copied to clipboard": "คัดลอกการฝากโค้ดไปที่คลิปบอร์ดแล้ว", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "หากต้องการคัดลอกและวาง กรุณากดปุ่มคัดลอก หรือใช้ปุ่มลัด Ctrl+c/Cmd+c สำหรับคลิปบอร์ด", + "Copy link": "คัดลอกลิงก์", + "Link copied to clipboard": "คัดลอกลิงก์ไปที่คลิปบอร์ดแล้ว", + "Document text": "ฝากข้อความ", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "ปุ่ม Tabulator ใช้เป็นอักขระ (กด Ctrl+m หรือ Esc เพื่อสลับ)", + "Theme": "ธีม" } diff --git a/i18n/tr.json b/i18n/tr.json index 5164aee6..c5f6ab21 100644 --- a/i18n/tr.json +++ b/i18n/tr.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s sunucunun burada paylaştığınız veriyi görmediği, minimal, açık kaynak bir pastebindir. Veriler tarayıcıda 256 bit AES kullanılarak şifrelenir/çözülür.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s sunucunun burada paylaştığınız veriyi görmediği, minimal, açık kaynak bir pastebindir. Veriler tarayıcıda 256 bit AES kullanılarak şifrelenir/çözülür.", "More information on the project page.": "Daha fazla bilgi için proje sayfası'na göz atabilirsiniz.", "Because ignorance is bliss": "Çünkü, cehalet mutluluktur", - "Paste does not exist, has expired or has been deleted.": "Paste does not exist, has expired or has been deleted.", + "Document does not exist, has expired or has been deleted.": "Bu mevcut değil, süresi dolmuş veya silinmiş.", "%s requires php %s or above to work. Sorry.": "%s PHP %s veya daha üstünü gerektirir.", "%s requires configuration section [%s] to be present in configuration file.": "%s konfigürasyon bölümünün [%s] bulunmasını gerektir.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Lütfen paylaşımlar arasında %d saniye bekleyiniz.", "Lütfen paylaşımlar arasında %d saniye bekleyiniz." ], - "Paste is limited to %s of encrypted data.": "Yazılar %s şifreli veriyle sınırlıdır.", + "Document is limited to %s of encrypted data.": "Yazılar %s şifreli veriyle sınırlıdır.", "Invalid data.": "Geçersiz veri.", "You are unlucky. Try again.": "Lütfen tekrar deneyiniz.", "Error saving comment. Sorry.": "Yorum kaydedilemedi.", - "Error saving paste. Sorry.": "Yazı kaydedilemedi. Üzgünüz.", - "Invalid paste ID.": "Geçersiz yazı ID'si.", - "Paste is not of burn-after-reading type.": "Yazı okunduğunda silinmeyecek şekilde ayarlanmış.", - "Wrong deletion token. Paste was not deleted.": "Yanlış silme anahtarı. Yazı silinemedi.", - "Paste was properly deleted.": "Yazı başarıyla silindi.", + "Error saving document. Sorry.": "Yazı kaydedilemedi. Üzgünüz.", + "Invalid document ID.": "Geçersiz yazı ID'si.", + "Document is not of burn-after-reading type.": "Yazı okunduğunda silinmeyecek şekilde ayarlanmış.", + "Wrong deletion token. Document was not deleted.": "Yanlış silme anahtarı. Yazı silinemedi.", + "Document was properly deleted.": "Yazı başarıyla silindi.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript %s 'in çalışması için gereklidir. Rahatsızlıktan dolayı özür dileriz.", "%s requires a modern browser to work.": "%s çalışmak için çağdaş bir tarayıcı gerektirir.", "New": "Yeni", - "Send": "Gönder", + "Create": "Oluştur", "Clone": "Kopyala", "Raw text": "Açık yazı", "Expires": "Süre Sonu", @@ -69,7 +69,7 @@ ], "%d weeks": [ "%d hafta", - "%d haftalar", + "%d hafta", "%d hafta", "%d hafta", "%d hafta", @@ -92,7 +92,7 @@ "%d yıl" ], "Never": "Asla", - "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.", + "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "Not: Bu bir test hizmetidir: Veriler herhangi bir zamanda silinebilir. Bu hizmeti kötüye kullanırsanız, kedicikler ölebilir.", "This document will expire in %d seconds.": [ "Bu belge %d saniyede silinecektir.", "Bu belge %d saniyede silinecektir.", @@ -133,9 +133,9 @@ "Bu belge %d ayda silinecektir.", "Bu belge %d ayda silinecektir." ], - "Please enter the password for this paste:": "Lütfen bu yazı için şifrenizi girin:", + "Please enter the password for this document:": "Lütfen bu yazı için şifrenizi girin:", "Could not decrypt data (Wrong key?)": "Şifre çözülemedi (Yanlış anahtar mı kullandınız?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Yazı silinemedi, okunduktan sonra silinmek için ayarlanmadı.", + "Could not delete the document, it was not stored in burn after reading mode.": "Yazı silinemedi, okunduktan sonra silinmek için ayarlanmadı.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "BU DOSYAYI SADECE SİZ GÖRÜNTÜLEYEBİLİRSİNİZ. Bu pencereyi kapatmayın, yazıyı tekrar görüntüleyemeyeceksiniz.", "Could not decrypt comment; Wrong key?": "Dosya şifresi çözülemedi, doğru anahtarı girdiğinizden emin misiniz?", "Reply": "Cevapla", @@ -150,71 +150,84 @@ "unknown status": "bilinmeyen durum", "server error or not responding": "sunucu hatası veya yanıt vermiyor", "Could not post comment: %s": "Yorum paylaşılamadı: %s", - "Sending paste…": "Yazı gönderiliyor…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Yazınız: %s ([Ctrl]+[c] tuşlarına basarak kopyalayın.)", + "Sending document…": "Yazı gönderiliyor…", + "Your document is %s (Hit Ctrl+c to copy)": "Yazınız: %s (Ctrl+c tuşlarına basarak kopyalayın.)", "Delete data": "Veriyi sil", - "Could not create paste: %s": "Yazı oluşturulamadı: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Yazı şifresi çözülemedi, çözme anahtarı URL'de bulunamadı. (Buraya bir yönlendirici veya URL kısaltıcı kullanarak gelmiş olabilirsiniz.)", + "Could not create document: %s": "Yazı oluşturulamadı: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Yazı şifresi çözülemedi, çözme anahtarı URL'de bulunamadı. (Buraya bir yönlendirici veya URL kısaltıcı kullanarak gelmiş olabilirsiniz.)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Düz Yazı", "Source Code": "Kaynak Kodu", "Markdown": "Markdown", "Download attachment": "Eki indir", "Cloned: '%s'": "Klonlandı: '%s'", - "The cloned file '%s' was attached to this paste.": "Klonlanmış dosya '%s' bu yazıya eklendi.", + "The cloned file '%s' was attached to this document.": "Klonlanmış dosya '%s' bu yazıya eklendi.", "Attach a file": "Dosya ekle", - "alternatively drag & drop a file or paste an image from the clipboard": "alternatif olarak dosyasyı yapıştırabilir veya sürükleyip bırakabilirsin", + "alternatively drag & drop a file or paste an image from the clipboard": "alternatif olarak dosyayı yapıştırabilir veya sürükleyip bırakabilirsiniz", "File too large, to display a preview. Please download the attachment.": "Dosya önizleme için çok büyük. Lütfen eki indirin.", "Remove attachment": "Eki sil", - "Your browser does not support uploading encrypted files. Please use a newer browser.": "Tarayıcınız şifreli dosyaları desteklemiyor.", + "Your browser does not support uploading encrypted files. Please use a newer browser.": "Tarayıcınız şifreli dosyaları yüklemeyi desteklemiyor. Lütfen daha yeni bir tarayıcı kullanın.", "Invalid attachment.": "Geçersiz ek.", "Options": "Seçenekler", "Shorten URL": "URL kısaltma", "Editor": "Düzenleyici", "Preview": "Ön izleme", - "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.", + "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s, PATH'in \"%s\" ile bitmesini gerektirir. Lütfen index.php dosyanızdaki PATH'i güncelleyin.", "Decrypt": "Şifreyi çöz", "Enter password": "Şifreyi girin", "Loading…": "Yükleniyor…", - "Decrypting paste…": "Yazı şifresi çözülüyor…", - "Preparing new paste…": "Yeni yazı hazırlanıyor…", - "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "In case this message never disappears please have a look at this FAQ for information to troubleshoot.", - "+++ no paste text +++": "+++ no paste text +++", - "Could not get paste data: %s": "Yazı verisi alınamıyor: %s", + "Decrypting document…": "Yazı şifresi çözülüyor…", + "Preparing new document…": "Yeni yazı hazırlanıyor…", + "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "Bu mesaj hiç kaybolmazsa, sorun giderme bilgileri için bu SSS'ye göz atın.", + "+++ no document text +++": "+++ yazı içeriği yok +++", + "Could not get document data: %s": "Yazı verisi alınamıyor: %s", "QR code": "QR kodu", - "This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.", - "For more information see this FAQ entry.": "For more information see this FAQ entry.", - "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.", - "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.", - "waiting on user to provide a password": "waiting on user to provide a password", - "Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Dosya şifresi çözülemedi, doğru şifreyi kullandığınıza emin misiniz? Üstteki buton ile tekrar deneyin.", + "This website is using an insecure HTTP connection! Please use it only for testing.": "Bu web sitesi güvensiz bir HTTP bağlantısı kullanıyor! Lütfen bunu yalnızca test için kullanın.", + "For more information see this FAQ entry.": "Daha fazla bilgi için bu SSS girişine bakın.", + "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": "Tarayıcınızın WebCrypto API'sini desteklemesi için HTTPS bağlantısına ihtiyacı olabilir. HTTPS'ye geçmeyi deneyin.", + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "Tarayıcınız zlib sıkıştırma için kullanılan WebAssembly'i desteklemiyor. Sıkıştırılmamış belgeler oluşturabilirsiniz, ancak sıkıştırılmış olanları okuyamazsınız.", + "waiting on user to provide a password": "kullanıcının şifre girmesi bekleniyor", + "Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Şifre çözülemedi, yanlış şifre mi girdiniz? Üstteki butonla tekrar deneyin.", "Retry": "Yeniden Dene", "Showing raw text…": "Açık yazı gösteriliyor…", "Notice:": "Bildirim:", - "This link will expire after %s.": "Bu bağlantı şu kadar zaman sonra etkisiz kalacaktır: %s.", - "This link can only be accessed once, do not use back or refresh button in your browser.": "Bu bağlantı sadece bir kere erişilebilir, lütfen sayfayı yenilemeyiniz.", + "This link will expire after %s.": "Bu bağlantı %s sonra geçersiz hale gelecektir.", + "This link can only be accessed once, do not use back or refresh button in your browser.": "Bu bağlantıya yalnızca bir kez erişilebilir, tarayıcınızda geri veya yenile butonunu kullanmayın.", "Link:": "Bağlantı:", - "Recipient may become aware of your timezone, convert time to UTC?": "Alıcı zaman dilmini öğrenebilir, zaman dilimini UTC'ye çevirmek ister misin?", - "Use Current Timezone": "Şuanki zaman dilimini kullan", - "Convert To UTC": "UTC zaman dilimine çevir", + "Recipient may become aware of your timezone, convert time to UTC?": "Alıcı zaman diliminizi öğrenebilir, zamanı UTC'ye çevirmek ister misiniz?", + "Use Current Timezone": "Mevcut Zaman Dilimini Kullan", + "Convert To UTC": "UTC'ye Dönüştür", "Close": "Kapat", "Encrypted note on %s": "%s üzerinde şifrelenmiş not", - "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Notu görmek için bu bağlantıyı ziyaret et. Bağlantıya sahip olan birisi notu görebilir.", - "URL shortener may expose your decrypt key in URL.": "URL kısaltıcı şifreleme anahtarınızı URL içerisinde gösterebilir.", - "Save paste": "Yazıyı kaydet", - "Your IP is not authorized to create pastes.": "IP adresinizin yazı oluşturmaya yetkisi yoktur.", - "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Notu görmek için bu bağlantıyı ziyaret edin. URL'yi birine vermek, onların da nota erişmesini sağlar.", + "URL shortener may expose your decrypt key in URL.": "URL kısaltıcı, şifre çözme anahtarınızı URL içinde gösterebilir.", + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Yazıyı kaydet", + "Your IP is not authorized to create documents.": "IP adresinizin yazı oluşturmaya yetkisi yoktur.", + "Trying to shorten a URL that isn't pointing at our instance.": "URL'yi kısaltmaya çalışırken, bizim sunucumuza işaret etmeyen bir URL kullanıyorsunuz.", + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "YOURLS çağrısı başarısız oldu. Muhtemelen \"apiurl\" veya \"signature\" gibi yanlış veya eksik yapılandırma hatası.", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "YOURLS yanıtı ayrıştırılamadı.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "Bu gizli mesaj yalnızca bir kez görüntülenebilir. Şimdi görmek ister misiniz?", + "Yes, see it": "Evet, gör", + "Dark Mode": "Koyu Mod", + "Error compressing document, due to missing WebAssembly support.": "WebAssembly desteği eksik olduğundan yazı sıkıştırılamadı.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Yazı açılırken hata oluştu, tarayıcınız WebAssembly'i desteklemiyor. Lütfen bu yazıyı görüntülemek için başka bir tarayıcı kullanın.", + "Start over": "Baştan başla", + "Document copied to clipboard": "Document copied to clipboard", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/uk.json b/i18n/uk.json index 0d514b5a..efdbc89e 100644 --- a/i18n/uk.json +++ b/i18n/uk.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s це мінімалістичний Open Source проєкт для створення нотаток, де сервер не знає нічого про дані, що зберігаються. Дані шифруються/розшифровуються %sу переглядачі%s з використанням 256-бітного шифрувания AES.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s це мінімалістичний Open Source проєкт для створення нотаток, де сервер не знає нічого про дані, що зберігаються. Дані шифруються/розшифровуються %sу браузері%s з використанням 256-бітного шифрування AES.", "More information on the project page.": "Подробиці можна дізнатися на сайті проєкту.", "Because ignorance is bliss": "Бо незнання - благо", - "Paste does not exist, has expired or has been deleted.": "Допис не існує, протермінований чи був видалений.", + "Document does not exist, has expired or has been deleted.": "Допис не існує, протермінований чи був видалений.", "%s requires php %s or above to work. Sorry.": "Для роботи %s потрібен php %s и вище. Вибачте.", "%s requires configuration section [%s] to be present in configuration file.": "%s потрібна секція [%s] в конфігураційному файлі.", "Please wait %d seconds between each post.": [ @@ -14,19 +14,19 @@ "Будь ласка, зачекайте %d секунд між створеннями.", "Будь ласка, зачекайте %d секунд між створеннями." ], - "Paste is limited to %s of encrypted data.": "Розмір допису обмежений %s зашифрованих даних.", + "Document is limited to %s of encrypted data.": "Розмір допису обмежений %s зашифрованих даних.", "Invalid data.": "Неправильні дані.", - "You are unlucky. Try again.": "Вам не пощастило. Спробуйте ще раз.", + "You are unlucky. Try again.": "Якась халепа! Спробуйте ще раз.", "Error saving comment. Sorry.": "Помилка при збереженні коментаря. Вибачте.", - "Error saving paste. Sorry.": "Помилка при збереженні допису. Вибачте.", - "Invalid paste ID.": "Неправильний ID допису.", - "Paste is not of burn-after-reading type.": "Тип допису не \"Знищити після прочитання\".", - "Wrong deletion token. Paste was not deleted.": "Неправильний ключ вилучення допису. Допис не вилучено.", - "Paste was properly deleted.": "Допис був вилучений повністю.", + "Error saving document. Sorry.": "Помилка при збереженні допису. Вибачте.", + "Invalid document ID.": "Неправильний ID допису.", + "Document is not of burn-after-reading type.": "Тип допису не \"Знищити після прочитання\".", + "Wrong deletion token. Document was not deleted.": "Неправильний жетон вилучення допису. Допис не вилучено.", + "Document was properly deleted.": "Допис був вилучений повністю.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "Для роботи %s потрібен увімкнутий JavaScript. Вибачте.", - "%s requires a modern browser to work.": "Для роботи %s потрібен більш сучасний переглядач.", + "%s requires a modern browser to work.": "Для роботи %s потрібен більш сучасний браузер.", "New": "Новий допис", - "Send": "Відправити", + "Create": "Створити", "Clone": "Дублювати", "Raw text": "Початковий текст", "Expires": "Вилучити через", @@ -36,8 +36,8 @@ "Discussion": "Обговорення", "Toggle navigation": "Перемкнути навігацію", "%d seconds": [ - "%d секунду", - "%d секунди", + "%d секунд", + "%d секунд", "%d секунд", "%d секунд", "%d секунд", @@ -133,9 +133,9 @@ "Документ буде вилучений через %d місяців.", "Документ буде вилучений через %d місяців." ], - "Please enter the password for this paste:": "Будь ласка, введіть пароль від допису:", - "Could not decrypt data (Wrong key?)": "Неможливо розшифрувати дані (Неправильний ключ?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Неможливо вилучити допис, він не був збережений в режимі знищити після прочитання.", + "Please enter the password for this document:": "Будь ласка, введіть пароль від допису:", + "Could not decrypt data (Wrong key?)": "Неможливо розшифрувати дані (можливо, невірний ключ?)", + "Could not delete the document, it was not stored in burn after reading mode.": "Неможливо вилучити допис, він не був збережений в режимі знищити після прочитання.", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "ЛИШЕ ДЛЯ ВАШИХ ОЧЕЙ. Не закривайте це вікно, це повідомлення не може бути показано знову.", "Could not decrypt comment; Wrong key?": "Неможливо розшифрувати коментар; Неправильний ключ?", "Reply": "Відповісти", @@ -150,27 +150,27 @@ "unknown status": "невідома причина", "server error or not responding": "помилка на сервері чи немає відповіді", "Could not post comment: %s": "Не вдалося опублікувати коментар: %s", - "Sending paste…": "Відправка допису…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Посилання на допис %s (Тисніть [Ctrl]+[c], щоб скопіювати посилання)", + "Sending document…": "Відправка допису…", + "Your document is %s (Hit Ctrl+c to copy)": "Посилання на допис %s (Тисніть Ctrl+c, щоб скопіювати посилання)", "Delete data": "Видалити допис", - "Could not create paste: %s": "Не вдалося опублікувати допис: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Неможливо розшифрувати запис: Ключ дешифрування відсутній в посиланні (Можливо, ви використовуєте скорочувач посилань, що видаляє частину посилання?)", + "Could not create document: %s": "Не вдалося опублікувати допис: %s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Неможливо розшифрувати запис: Ключ дешифрування відсутній в посиланні (Можливо, ви використовуєте скорочувач посилань, що видаляє частину посилання?)", "B": "байт", - "KiB": "Кбайт", - "MiB": "Мбайт", - "GiB": "Гбайт", - "TiB": "Тбайт", - "PiB": "Пбайт", - "EiB": "Ебайт", - "ZiB": "Збайт", - "YiB": "Йбайт", + "kB": "кбайт", + "MB": "Мбайт", + "GB": "Гбайт", + "TB": "Тбайт", + "PB": "Пбайт", + "EB": "Ебайт", + "ZB": "Збайт", + "YB": "Йбайт", "Format": "Формат", "Plain Text": "Звичайний текст", - "Source Code": "Джерельний код", + "Source Code": "Вихідний код", "Markdown": "Мова розмітки", "Download attachment": "Звантажити прикріплений файл", "Cloned: '%s'": "Дубльовано: '%s'", - "The cloned file '%s' was attached to this paste.": "Дублікат файлу '%s' був прикріплений до цього запису.", + "The cloned file '%s' was attached to this document.": "Дублікат файлу '%s' був прикріплений до цього запису.", "Attach a file": "Прикріпити файл", "alternatively drag & drop a file or paste an image from the clipboard": "також можна перенести файл у вікно переглядача чи вставити зображення з буфера", "File too large, to display a preview. Please download the attachment.": "Файл завеликий для відображення передогляду. Будь ласка, звантажте прикріплений файл.", @@ -185,11 +185,11 @@ "Decrypt": "Розшифрувати", "Enter password": "Введіть пароль", "Loading…": "Завантаження…", - "Decrypting paste…": "Розшифровування допису…", - "Preparing new paste…": "Приготування нового допису…", + "Decrypting document…": "Розшифровування допису…", + "Preparing new document…": "Приготування нового допису…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "Якщо це повідомлення не зникатиме тривалий час, подивіться цей FAQ з інформацією про можливе вирішення проблеми.", - "+++ no paste text +++": "+++ у дописі немає тексту +++", - "Could not get paste data: %s": "Не вдалося отримати дані допису: %s", + "+++ no document text +++": "+++ у дописі немає тексту +++", + "Could not get document data: %s": "Не вдалося отримати дані допису: %s", "QR code": "QR код", "This website is using an insecure HTTP connection! Please use it only for testing.": "Цей сайт використовує незахищене HTTP підключення! Будь ласка, використовуйте його лише для тестування.", "For more information see this FAQ entry.": "Для подробиць дивіться інформацію в FAQ.", @@ -210,11 +210,24 @@ "Encrypted note on %s": "Зашифрована нотатка на %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Відвідайте посилання, щоб переглянути нотатку. Передача посилання будь-кому дозволить їм переглянути нотатку.", "URL shortener may expose your decrypt key in URL.": "Сервіс скорочення посилань може викрити ваш ключ дешифрування з URL.", - "Save paste": "Зберегти вставку", - "Your IP is not authorized to create pastes.": "Вашому IP не дозволено створювати вставки.", - "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response.", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "URL shortener is enabled by default.": "URL shortener is enabled by default.", + "Save document": "Зберегти вставку", + "Your IP is not authorized to create documents.": "Вашому IP не дозволено створювати вставки.", + "Trying to shorten a URL that isn't pointing at our instance.": "Спроба скоротити URL, який не вказує на наш екземпляр.", + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Помилка виклику YOURLS. Ймовірно проблема з налаштуванням, наприклад \"apiurl\" чи \"signature\".", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Помилка розбору відповіді YOURLS.", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.", + "This secret message can only be displayed once. Would you like to see it now?": "Це таємне повідомлення можна надіслати лише один раз. Хочете переглянути його зараз?", + "Yes, see it": "Так, побачити", + "Dark Mode": "Темний режим", + "Error compressing document, due to missing WebAssembly support.": "Помилка при стисканні допису, через відсутність підтримки WebAssembly сервера.", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Помилка при розпакуванні допису, бо ваш браузер не підтримує WebAssembly. Будь ласка, відкрийте в іншому браузері для перегляду цього допису.", + "Start over": "Почати знову", + "Document copied to clipboard": "Document copied to clipboard", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Document text": "Document text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/zh.json b/i18n/zh.json index 421622f5..12aa7d71 100644 --- a/i18n/zh.json +++ b/i18n/zh.json @@ -1,32 +1,32 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s 是一个极简、开源、对粘贴内容毫不知情的在线粘贴板,数据%s在浏览器内%s进行 AES-256 加密和解密。", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s 是一个极简、开源、对粘贴内容毫不知情的在线粘贴板,数据%s在浏览器内%s进行 AES-256 加密和解密。", "More information on the project page.": "更多信息请查看项目主页。", "Because ignorance is bliss": "以不知为幸", - "Paste does not exist, has expired or has been deleted.": "粘贴内容不存在、已过期或已被删除。", + "Document does not exist, has expired or has been deleted.": "粘贴内容不存在、已过期或已被删除。", "%s requires php %s or above to work. Sorry.": "抱歉,%s 需要 PHP %s 及以上版本才能运行。", "%s requires configuration section [%s] to be present in configuration file.": "%s 需要设置配置文件中的 [%s] 部分。", "Please wait %d seconds between each post.": [ - "每 %d 秒只能粘贴一次。", - "每 %d 秒只能粘贴一次。", - "每 %d 秒只能粘贴一次。", - "每 %d 秒只能粘贴一次。", - "每 %d 秒只能粘贴一次。", - "每 %d 秒只能粘贴一次。" + "每 %d 秒只能创建一次粘贴。", + "每 %d 秒只能创建一次粘贴。", + "每 %d 秒只能创建一次粘贴。", + "每 %d 秒只能创建一次粘贴。", + "每 %d 秒只能创建一次粘贴。", + "每 %d 秒只能创建一次粘贴。" ], - "Paste is limited to %s of encrypted data.": "对于加密数据,上限为 %s。", + "Document is limited to %s of encrypted data.": "对于加密数据,上限为 %s。", "Invalid data.": "无效的数据。", "You are unlucky. Try again.": "请再试一次。", "Error saving comment. Sorry.": "保存评论时出现错误,抱歉。", - "Error saving paste. Sorry.": "保存粘贴内容时出现错误,抱歉。", - "Invalid paste ID.": "无效的 ID。", - "Paste is not of burn-after-reading type.": "粘贴内容不是阅后即焚类型。", - "Wrong deletion token. Paste was not deleted.": "错误的删除token,粘贴内容没有被删除。", - "Paste was properly deleted.": "粘贴内容已被正确删除。", + "Error saving document. Sorry.": "保存粘贴内容时出现错误,抱歉。", + "Invalid document ID.": "无效的 ID。", + "Document is not of burn-after-reading type.": "粘贴内容不是阅后即焚类型。", + "Wrong deletion token. Document was not deleted.": "错误的删除token,粘贴内容没有被删除。", + "Document was properly deleted.": "粘贴内容已被正确删除。", "JavaScript is required for %s to work. Sorry for the inconvenience.": "%s 需要 JavaScript 来进行加解密。 给你带来的不便敬请谅解。", "%s requires a modern browser to work.": "%s 需要在现代浏览器上工作。", "New": "新建", - "Send": "送出", + "Create": "创建", "Clone": "复制", "Raw text": "纯文本", "Expires": "有效期", @@ -46,10 +46,10 @@ "%d minutes": [ "%d 分钟", "%d 分钟", - "%d 秒", - "%d 秒", - "%d 秒", - "%d 秒" + "%d 分钟", + "%d 分钟", + "%d 分钟", + "%d 分钟" ], "%d hours": [ "%d 小时", @@ -94,7 +94,7 @@ "Never": "永不过期", "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "注意:这是一个测试服务,数据随时可能被删除。如果你滥用这个服务的话,小猫咪会死的。", "This document will expire in %d seconds.": [ - "这份文档将在一秒后过期。", + "这份文档将在 %d 秒后过期。", "这份文档将在 %d 秒后过期。", "这份文档将在 %d 秒后过期。", "这份文档将在 %d 秒后过期。", @@ -102,7 +102,7 @@ "这份文档将在 %d 秒后过期。" ], "This document will expire in %d minutes.": [ - "这份文档将在一分钟后过期。", + "这份文档将在 %d 分钟后过期。", "这份文档将在 %d 分钟后过期。", "这份文档将在 %d 分钟后过期。", "这份文档将在 %d 分钟后过期。", @@ -110,7 +110,7 @@ "这份文档将在 %d 分钟后过期。" ], "This document will expire in %d hours.": [ - "这份文档将在一小时后过期。", + "这份文档将在 %d 小时后过期。", "这份文档将在 %d 小时后过期。", "这份文档将在 %d 小时后过期。", "这份文档将在 %d 小时后过期。", @@ -118,7 +118,7 @@ "这份文档将在 %d 小时后过期。" ], "This document will expire in %d days.": [ - "这份文档将在一天后过期。", + "这份文档将在 %d 天后过期。", "这份文档将在 %d 天后过期。", "这份文档将在 %d 天后过期。", "这份文档将在 %d 天后过期。", @@ -126,17 +126,17 @@ "这份文档将在 %d 天后过期。" ], "This document will expire in %d months.": [ - "这份文档将在一个月后过期。", + "这份文档将在 %d 个月后过期。", "这份文档将在 %d 个月后过期。", "这份文档将在 %d 个月后过期。", "这份文档将在 %d 个月后过期。", "这份文档将在 %d 个月后过期。", "这份文档将在 %d 个月后过期。" ], - "Please enter the password for this paste:": "请输入这份粘贴内容的密码:", + "Please enter the password for this document:": "请输入这份粘贴内容的密码:", "Could not decrypt data (Wrong key?)": "无法解密数据(密钥错误?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "无法删除此粘贴内容,它没有以阅后即焚模式保存。", - "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "看!仔!细!了!不要关闭窗口,否则你再也见不到这条消息了。", + "Could not delete the document, it was not stored in burn after reading mode.": "无法删除此粘贴内容,它没有以阅后即焚模式保存。", + "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "睁大眼睛看清楚!不要关闭窗口,否则你再也见不到这条消息了。", "Could not decrypt comment; Wrong key?": "无法解密评论;密钥错误?", "Reply": "回复", "Anonymous": "匿名", @@ -150,27 +150,27 @@ "unknown status": "未知状态", "server error or not responding": "服务器错误或无回应", "Could not post comment: %s": "无法发送评论: %s", - "Sending paste…": "粘贴内容提交中…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "您粘贴内容的链接是 %s (按下 [Ctrl]+[C] 以复制)", + "Sending document…": "正在发送粘贴内容…", + "Your document is %s (Hit Ctrl+c to copy)": "您粘贴内容的链接是 %s (按下 Ctrl+c 以复制)", "Delete data": "删除数据", - "Could not create paste: %s": "无法创建粘贴:%s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "无法解密粘贴:URL中缺失解密密钥(是否使用了重定向或者短链接导致密钥丢失?)", + "Could not create document: %s": "无法创建粘贴:%s", + "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "无法解密粘贴:URL中缺失解密密钥(是否使用了重定向或者短链接导致密钥丢失?)", "B": "B", - "KiB": "KiB", - "MiB": "MiB", - "GiB": "GiB", - "TiB": "TiB", - "PiB": "PiB", - "EiB": "EiB", - "ZiB": "ZiB", - "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "格式", "Plain Text": "纯文本", "Source Code": "源代码", "Markdown": "Markdown", "Download attachment": "下载附件", "Cloned: '%s'": "副本:“%s”", - "The cloned file '%s' was attached to this paste.": "副本“%s”已附加到此粘贴内容。", + "The cloned file '%s' was attached to this document.": "副本“%s”已附加到此粘贴内容。", "Attach a file": "添加一个附件", "alternatively drag & drop a file or paste an image from the clipboard": "拖放文件或从剪贴板粘贴图片", "File too large, to display a preview. Please download the attachment.": "文件过大,无法显示预览。请下载附件。", @@ -185,11 +185,11 @@ "Decrypt": "解密", "Enter password": "输入密码", "Loading…": "载入中…", - "Decrypting paste…": "正在解密", - "Preparing new paste…": "正在准备新的粘贴内容", + "Decrypting document…": "正在解密…", + "Preparing new document…": "正在准备新的粘贴内容…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "如果此消息一直存在,请参考 这里的 FAQ(英文版)排除故障。", - "+++ no paste text +++": "+++ 无粘贴内容 +++", - "Could not get paste data: %s": "无法获取粘贴数据:%s", + "+++ no document text +++": "+++ 无粘贴内容 +++", + "Could not get document data: %s": "无法获取粘贴数据:%s", "QR code": "二维码", "This website is using an insecure HTTP connection! Please use it only for testing.": "该网站使用了不安全的 HTTP 连接!请仅将其用于测试。", "For more information see this FAQ entry.": "有关更多信息,请参阅此常见问题解答。", @@ -200,7 +200,7 @@ "Retry": "重试", "Showing raw text…": "显示原始文字…", "Notice:": "注意:", - "This link will expire after %s.": "这个链接将会在 %s 过期。", + "This link will expire after %s.": "此链接将会在 %s 过期。", "This link can only be accessed once, do not use back or refresh button in your browser.": "此链接只能被访问一次,请勿使用浏览器中的返回和刷新按钮。", "Link:": "链接:", "Recipient may become aware of your timezone, convert time to UTC?": "收件人可能会知道您的时区,将时间转换为 UTC?", @@ -210,11 +210,24 @@ "Encrypted note on %s": "%s 上的加密笔记", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "访问此链接来查看该笔记。将此 URL 发送给任何人即可允许其访问该笔记。", "URL shortener may expose your decrypt key in URL.": "短链接服务可能会暴露您在 URL 中的解密密钥。", - "Save paste": "保存内容", - "Your IP is not authorized to create pastes.": "您的 IP 无权创建粘贴。", + "URL shortener is enabled by default.": "默认已启用 URL 缩短功能。", + "Save document": "保存内容", + "Your IP is not authorized to create documents.": "您的 IP 无权创建粘贴。", "Trying to shorten a URL that isn't pointing at our instance.": "尝试缩短一个不指向我们实例的URL。", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "调用 YOURLS 时出错。可能是配置问题,例如“apiurl”或“signature”错误或缺失。", - "Error parsing YOURLS response.": "解析 YOURLS 响应时出错。", - "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?", - "Yes, load it": "Yes, load it" + "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "调用 YOURLS 时出错。可能是配置问题,例如“apiurl”或“signature”错误或缺失。", + "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "解析 YOURLS 响应时出错。", + "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "代理错误:响应无效。这可能是配置问题,例如配置密钥错误或丢失,或者临时中断。", + "This secret message can only be displayed once. Would you like to see it now?": "读取粘贴后只能在加载时显示一次。您想现在打开吗?", + "Yes, see it": "是的,加载它", + "Dark Mode": "夜间模式", + "Error compressing document, due to missing WebAssembly support.": "由于缺少 WebAssembly 支持,在压缩粘贴时出错。", + "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "解压粘贴时出错,您的浏览器不支持 WebAssembly。请使用其他浏览器查看此粘贴。", + "Start over": "重新开始", + "Document copied to clipboard": "粘贴内容已复制到剪贴板", + "To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "要复制粘贴内容,请点击复制按钮或使用快捷键 Ctrl+c/Cmd+c。", + "Copy link": "复制链接", + "Link copied to clipboard": "链接已复制到剪贴板", + "Document text": "粘贴文本", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tab 键可作为字符(按 Ctrl+mEsc 切换开关)", + "Theme": "主题" } diff --git a/img/android-chrome-192x192.png b/img/android-chrome-192x192.png index 42baf753..6f417b9b 100644 Binary files a/img/android-chrome-192x192.png and b/img/android-chrome-192x192.png differ diff --git a/img/android-chrome-512x512.png b/img/android-chrome-512x512.png index 48e6608b..6294b81c 100644 Binary files a/img/android-chrome-512x512.png and b/img/android-chrome-512x512.png differ diff --git a/img/apple-touch-icon.png b/img/apple-touch-icon.png index aa6e2b04..00d9f373 100644 Binary files a/img/apple-touch-icon.png and b/img/apple-touch-icon.png differ diff --git a/img/bootstrap-icons.svg b/img/bootstrap-icons.svg new file mode 100644 index 00000000..18390345 --- /dev/null +++ b/img/bootstrap-icons.svg @@ -0,0 +1 @@ + diff --git a/img/favicon-32x32.png b/img/favicon-32x32.png index be42cb39..3e20546d 100644 Binary files a/img/favicon-32x32.png and b/img/favicon-32x32.png differ diff --git a/img/icon_clone.png b/img/icon_clone.png index 455b82f9..a0afc1d8 100644 Binary files a/img/icon_clone.png and b/img/icon_clone.png differ diff --git a/img/icon_email.png b/img/icon_email.png index cd3fdf42..3a404dfb 100644 Binary files a/img/icon_email.png and b/img/icon_email.png differ diff --git a/img/icon_new.png b/img/icon_new.png index dd96fa2b..f311d869 100644 Binary files a/img/icon_new.png and b/img/icon_new.png differ diff --git a/img/icon_qr.png b/img/icon_qr.png index 28d10ca7..53e7373f 100644 Binary files a/img/icon_qr.png and b/img/icon_qr.png differ diff --git a/img/icon_raw.png b/img/icon_raw.png index 41b586f0..d4677775 100644 Binary files a/img/icon_raw.png and b/img/icon_raw.png differ diff --git a/img/icon_send.png b/img/icon_send.png index a6e62ebd..78c617a5 100644 Binary files a/img/icon_send.png and b/img/icon_send.png differ diff --git a/img/icon_shorten.png b/img/icon_shorten.png index 009c2e10..ad393037 100644 Binary files a/img/icon_shorten.png and b/img/icon_shorten.png differ diff --git a/img/mstile-144x144.png b/img/mstile-144x144.png index 81953077..872741fa 100644 Binary files a/img/mstile-144x144.png and b/img/mstile-144x144.png differ diff --git a/img/mstile-150x150.png b/img/mstile-150x150.png index 9b9d36d1..ac4704c9 100644 Binary files a/img/mstile-150x150.png and b/img/mstile-150x150.png differ diff --git a/img/mstile-310x150.png b/img/mstile-310x150.png index 14dbf533..2c77221e 100644 Binary files a/img/mstile-310x150.png and b/img/mstile-310x150.png differ diff --git a/img/mstile-310x310.png b/img/mstile-310x310.png index 47264533..ff1ebec5 100644 Binary files a/img/mstile-310x310.png and b/img/mstile-310x310.png differ diff --git a/img/mstile-70x70.png b/img/mstile-70x70.png index 02b11be0..f2c07187 100644 Binary files a/img/mstile-70x70.png and b/img/mstile-70x70.png differ diff --git a/index.php b/index.php index 131fb17a..154eb6ee 100644 --- a/index.php +++ b/index.php @@ -1,4 +1,4 @@ -= 255) { throw new TypeError('Alphabet too long') } - var BASE_MAP = new Uint8Array(256) - for (var j = 0; j < BASE_MAP.length; j++) { + const BASE_MAP = new Uint8Array(256) + for (let j = 0; j < BASE_MAP.length; j++) { BASE_MAP[j] = 255 } - for (var i = 0; i < ALPHABET.length; i++) { - var x = ALPHABET.charAt(i) - var xc = x.charCodeAt(0) + for (let i = 0; i < ALPHABET.length; i++) { + const x = ALPHABET.charAt(i) + const xc = x.charCodeAt(0) if (BASE_MAP[xc] !== 255) { throw new TypeError(x + ' is ambiguous') } BASE_MAP[xc] = i } - var BASE = ALPHABET.length - var LEADER = ALPHABET.charAt(0) - var FACTOR = Math.log(BASE) / Math.log(256) // log(BASE) / log(256), rounded up - var iFACTOR = Math.log(256) / Math.log(BASE) // log(256) / log(BASE), rounded up + const BASE = ALPHABET.length + const LEADER = ALPHABET.charAt(0) + const FACTOR = Math.log(BASE) / Math.log(256) // log(BASE) / log(256), rounded up + const iFACTOR = Math.log(256) / Math.log(BASE) // log(256) / log(BASE), rounded up function encode (source) { - if (source instanceof Uint8Array) { - } else if (ArrayBuffer.isView(source)) { + // eslint-disable-next-line no-empty + if (source instanceof Uint8Array) { } else if (ArrayBuffer.isView(source)) { source = new Uint8Array(source.buffer, source.byteOffset, source.byteLength) } else if (Array.isArray(source)) { source = Uint8Array.from(source) } if (!(source instanceof Uint8Array)) { throw new TypeError('Expected Uint8Array') } if (source.length === 0) { return '' } - // Skip & count leading zeroes. - var zeroes = 0 - var length = 0 - var pbegin = 0 - var pend = source.length + // Skip & count leading zeroes. + let zeroes = 0 + let length = 0 + let pbegin = 0 + const pend = source.length while (pbegin !== pend && source[pbegin] === 0) { pbegin++ zeroes++ } - // Allocate enough space in big-endian base58 representation. - var size = ((pend - pbegin) * iFACTOR + 1) >>> 0 - var b58 = new Uint8Array(size) - // Process the bytes. + // Allocate enough space in big-endian base58 representation. + const size = ((pend - pbegin) * iFACTOR + 1) >>> 0 + const b58 = new Uint8Array(size) + // Process the bytes. while (pbegin !== pend) { - var carry = source[pbegin] - // Apply "b58 = b58 * 256 + ch". - var i = 0 - for (var it1 = size - 1; (carry !== 0 || i < length) && (it1 !== -1); it1--, i++) { + let carry = source[pbegin] + // Apply "b58 = b58 * 256 + ch". + let i = 0 + for (let it1 = size - 1; (carry !== 0 || i < length) && (it1 !== -1); it1--, i++) { carry += (256 * b58[it1]) >>> 0 b58[it1] = (carry % BASE) >>> 0 carry = (carry / BASE) >>> 0 @@ -56,38 +56,42 @@ this.baseX = function base (ALPHABET) { length = i pbegin++ } - // Skip leading zeroes in base58 result. - var it2 = size - length + // Skip leading zeroes in base58 result. + let it2 = size - length while (it2 !== size && b58[it2] === 0) { it2++ } - // Translate the result into a string. - var str = LEADER.repeat(zeroes) + // Translate the result into a string. + let str = LEADER.repeat(zeroes) for (; it2 < size; ++it2) { str += ALPHABET.charAt(b58[it2]) } return str } function decodeUnsafe (source) { if (typeof source !== 'string') { throw new TypeError('Expected String') } if (source.length === 0) { return new Uint8Array() } - var psz = 0 - // Skip and count leading '1's. - var zeroes = 0 - var length = 0 + let psz = 0 + // Skip and count leading '1's. + let zeroes = 0 + let length = 0 while (source[psz] === LEADER) { zeroes++ psz++ } - // Allocate enough space in big-endian base256 representation. - var size = (((source.length - psz) * FACTOR) + 1) >>> 0 // log(58) / log(256), rounded up. - var b256 = new Uint8Array(size) - // Process the characters. - while (source[psz]) { - // Decode character - var carry = BASE_MAP[source.charCodeAt(psz)] - // Invalid character + // Allocate enough space in big-endian base256 representation. + const size = (((source.length - psz) * FACTOR) + 1) >>> 0 // log(58) / log(256), rounded up. + const b256 = new Uint8Array(size) + // Process the characters. + while (psz < source.length) { + // Find code of next character + const charCode = source.charCodeAt(psz) + // Base map can not be indexed using char code + if (charCode > 255) { return } + // Decode character + let carry = BASE_MAP[charCode] + // Invalid character if (carry === 255) { return } - var i = 0 - for (var it3 = size - 1; (carry !== 0 || i < length) && (it3 !== -1); it3--, i++) { + let i = 0 + for (let it3 = size - 1; (carry !== 0 || i < length) && (it3 !== -1); it3--, i++) { carry += (BASE * b256[it3]) >>> 0 b256[it3] = (carry % 256) >>> 0 carry = (carry / 256) >>> 0 @@ -96,27 +100,27 @@ this.baseX = function base (ALPHABET) { length = i psz++ } - // Skip leading zeroes in b256. - var it4 = size - length + // Skip leading zeroes in b256. + let it4 = size - length while (it4 !== size && b256[it4] === 0) { it4++ } - var vch = new Uint8Array(zeroes + (size - it4)) - var j = zeroes + const vch = new Uint8Array(zeroes + (size - it4)) + let j = zeroes while (it4 !== size) { vch[j++] = b256[it4++] } return vch } function decode (string) { - var buffer = decodeUnsafe(string) + const buffer = decodeUnsafe(string) if (buffer) { return buffer } throw new Error('Non-base' + BASE + ' character') } return { - encode: encode, - decodeUnsafe: decodeUnsafe, - decode: decode + encode, + decodeUnsafe, + decode } } }).call(this); diff --git a/js/base64-1.7.js b/js/base64-1.7.js deleted file mode 100644 index 5dfa05ae..00000000 --- a/js/base64-1.7.js +++ /dev/null @@ -1,237 +0,0 @@ -/* - * $Id: base64.js,v 1.7 2012/08/23 10:30:18 dankogai Exp dankogai $ - * - * Licensed under the MIT license. - * https://www.opensource.org/licenses/mit-license.php - * - * References: - * https://en.wikipedia.org/wiki/Base64 - */ - -(function(global){ - -var b64chars - = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - -var b64charcodes = function(){ - var a = []; - var codeA = 'A'.charCodeAt(0); - var codea = 'a'.charCodeAt(0); - var code0 = '0'.charCodeAt(0); - for (var i = 0; i < 26; i ++) a.push(codeA + i); - for (var i = 0; i < 26; i ++) a.push(codea + i); - for (var i = 0; i < 10; i ++) a.push(code0 + i); - a.push('+'.charCodeAt(0)); - a.push('/'.charCodeAt(0)); - return a; -}(); - -var b64tab = function(bin){ - var t = {}; - for (var i = 0, l = bin.length; i < l; i++) t[bin.charAt(i)] = i; - return t; -}(b64chars); - -var stringToArray = function(s){ - var a = []; - for (var i = 0, l = s.length; i < l; i ++) a[i] = s.charCodeAt(i); - return a; -}; - -var convertUTF8ArrayToBase64 = function(bin){ - var padlen = 0; - while (bin.length % 3){ - bin.push(0); - padlen++; - }; - var b64 = []; - for (var i = 0, l = bin.length; i < l; i += 3){ - var c0 = bin[i], c1 = bin[i+1], c2 = bin[i+2]; - if (c0 >= 256 || c1 >= 256 || c2 >= 256) - throw 'unsupported character found'; - var n = (c0 << 16) | (c1 << 8) | c2; - b64.push( - b64charcodes[ n >>> 18], - b64charcodes[(n >>> 12) & 63], - b64charcodes[(n >>> 6) & 63], - b64charcodes[ n & 63] - ); - } - while (padlen--) b64[b64.length - padlen - 1] = '='.charCodeAt(0); - return chunkStringFromCharCodeApply(b64); -}; - -var convertBase64ToUTF8Array = function(b64){ - b64 = b64.replace(/[^A-Za-z0-9+\/]+/g, ''); - var bin = []; - var padlen = b64.length % 4; - for (var i = 0, l = b64.length; i < l; i += 4){ - var n = ((b64tab[b64.charAt(i )] || 0) << 18) - | ((b64tab[b64.charAt(i+1)] || 0) << 12) - | ((b64tab[b64.charAt(i+2)] || 0) << 6) - | ((b64tab[b64.charAt(i+3)] || 0)); - bin.push( - ( n >> 16 ), - ( (n >> 8) & 0xff ), - ( n & 0xff ) - ); - } - bin.length -= [0,0,2,1][padlen]; - return bin; -}; - -var convertUTF16ArrayToUTF8Array = function(uni){ - var bin = []; - for (var i = 0, l = uni.length; i < l; i++){ - var n = uni[i]; - if (n < 0x80) - bin.push(n); - else if (n < 0x800) - bin.push( - 0xc0 | (n >>> 6), - 0x80 | (n & 0x3f)); - else - bin.push( - 0xe0 | ((n >>> 12) & 0x0f), - 0x80 | ((n >>> 6) & 0x3f), - 0x80 | (n & 0x3f)); - } - return bin; -}; - -var convertUTF8ArrayToUTF16Array = function(bin){ - var uni = []; - for (var i = 0, l = bin.length; i < l; i++){ - var c0 = bin[i]; - if (c0 < 0x80){ - uni.push(c0); - }else{ - var c1 = bin[++i]; - if (c0 < 0xe0){ - uni.push(((c0 & 0x1f) << 6) | (c1 & 0x3f)); - }else{ - var c2 = bin[++i]; - uni.push( - ((c0 & 0x0f) << 12) | ((c1 & 0x3f) << 6) | (c2 & 0x3f) - ); - } - } - } - return uni; -}; - -var convertUTF8StringToBase64 = function(bin){ - return convertUTF8ArrayToBase64(stringToArray(bin)); -}; - -var convertBase64ToUTF8String = function(b64){ - return chunkStringFromCharCodeApply(convertBase64ToUTF8Array(b64)); -}; - -var convertUTF8StringToUTF16Array = function(bin){ - return convertUTF8ArrayToUTF16Array(stringToArray(bin)); -}; - -var convertUTF8ArrayToUTF16String = function(bin){ - return chunkStringFromCharCodeApply(convertUTF8ArrayToUTF16Array(bin)); -}; - -var convertUTF8StringToUTF16String = function(bin){ - return chunkStringFromCharCodeApply( - convertUTF8ArrayToUTF16Array(stringToArray(bin)) - ); -}; - -var convertUTF16StringToUTF8Array = function(uni){ - return convertUTF16ArrayToUTF8Array(stringToArray(uni)); -}; - -var convertUTF16ArrayToUTF8String = function(uni){ - return chunkStringFromCharCodeApply(convertUTF16ArrayToUTF8Array(uni)); -}; - -var convertUTF16StringToUTF8String = function(uni){ - return chunkStringFromCharCodeApply( - convertUTF16ArrayToUTF8Array(stringToArray(uni)) - ); -}; - -/* - * String.fromCharCode.apply will only handle arrays as big as 65536, - * after that it'll return a truncated string with no warning. - */ -var chunkStringFromCharCodeApply = function(arr){ - var strs = [], i; - for (i = 0; i < arr.length; i += 65536){ - strs.push(String.fromCharCode.apply(String, arr.slice(i, i+65536))); - } - return strs.join(''); -}; - -if (global.btoa){ - var btoa = global.btoa; - var convertUTF16StringToBase64 = function (uni){ - return btoa(convertUTF16StringToUTF8String(uni)); - }; -} -else { - var btoa = convertUTF8StringToBase64; - var convertUTF16StringToBase64 = function (uni){ - return convertUTF8ArrayToBase64(convertUTF16StringToUTF8Array(uni)); - }; -} - -if (global.atob){ - var atob = global.atob; - var convertBase64ToUTF16String = function (b64){ - return convertUTF8StringToUTF16String(atob(b64)); - }; -} -else { - var atob = convertBase64ToUTF8String; - var convertBase64ToUTF16String = function (b64){ - return convertUTF8ArrayToUTF16String(convertBase64ToUTF8Array(b64)); - }; -} - -global.Base64 = { - convertUTF8ArrayToBase64:convertUTF8ArrayToBase64, - convertByteArrayToBase64:convertUTF8ArrayToBase64, - convertBase64ToUTF8Array:convertBase64ToUTF8Array, - convertBase64ToByteArray:convertBase64ToUTF8Array, - convertUTF16ArrayToUTF8Array:convertUTF16ArrayToUTF8Array, - convertUTF16ArrayToByteArray:convertUTF16ArrayToUTF8Array, - convertUTF8ArrayToUTF16Array:convertUTF8ArrayToUTF16Array, - convertByteArrayToUTF16Array:convertUTF8ArrayToUTF16Array, - convertUTF8StringToBase64:convertUTF8StringToBase64, - convertBase64ToUTF8String:convertBase64ToUTF8String, - convertUTF8StringToUTF16Array:convertUTF8StringToUTF16Array, - convertUTF8ArrayToUTF16String:convertUTF8ArrayToUTF16String, - convertByteArrayToUTF16String:convertUTF8ArrayToUTF16String, - convertUTF8StringToUTF16String:convertUTF8StringToUTF16String, - convertUTF16StringToUTF8Array:convertUTF16StringToUTF8Array, - convertUTF16StringToByteArray:convertUTF16StringToUTF8Array, - convertUTF16ArrayToUTF8String:convertUTF16ArrayToUTF8String, - convertUTF16StringToUTF8String:convertUTF16StringToUTF8String, - convertUTF16StringToBase64:convertUTF16StringToBase64, - convertBase64ToUTF16String:convertBase64ToUTF16String, - fromBase64:convertBase64ToUTF8String, - toBase64:convertUTF8StringToBase64, - atob:atob, - btoa:btoa, - utob:convertUTF16StringToUTF8String, - btou:convertUTF8StringToUTF16String, - encode:convertUTF16StringToBase64, - encodeURI:function(u){ - return convertUTF16StringToBase64(u).replace(/[+\/]/g, function(m0){ - return m0 == '+' ? '-' : '_'; - }).replace(/=+$/, ''); - }, - decode:function(a){ - return convertBase64ToUTF16String(a.replace(/[-_]/g, function(m0){ - return m0 == '-' ? '+' : '/'; - })); - } -}; - -})(this); diff --git a/js/bootstrap-5.3.7.js b/js/bootstrap-5.3.7.js new file mode 100644 index 00000000..7139fbe5 --- /dev/null +++ b/js/bootstrap-5.3.7.js @@ -0,0 +1,6 @@ +/*! + * Bootstrap v5.3.7 (https://getbootstrap.com/) + * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!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).bootstrap=e()}(this,(function(){"use strict";const t=new Map,e={set(e,i,n){t.has(e)||t.set(e,new Map);const s=t.get(e);s.has(i)||0===s.size?s.set(i,n):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(s.keys())[0]}.`)},get:(e,i)=>t.has(e)&&t.get(e).get(i)||null,remove(e,i){if(!t.has(e))return;const n=t.get(e);n.delete(i),0===n.size&&t.delete(e)}},i="transitionend",n=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),s=t=>{t.dispatchEvent(new Event(i))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(n(t)):null,a=t=>{if(!o(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},l=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),c=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?c(t.parentNode):null},h=()=>{},d=t=>{t.offsetHeight},u=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,f=[],p=()=>"rtl"===document.documentElement.dir,m=t=>{var e;e=()=>{const e=u();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(f.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of f)t()})),f.push(e)):e()},g=(t,e=[],i=t)=>"function"==typeof t?t.call(...e):i,_=(t,e,n=!0)=>{if(!n)return void g(t);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let r=!1;const a=({target:n})=>{n===e&&(r=!0,e.removeEventListener(i,a),g(t))};e.addEventListener(i,a),setTimeout((()=>{r||s(e)}),o)},b=(t,e,i,n)=>{const s=t.length;let o=t.indexOf(e);return-1===o?!i&&n?t[s-1]:t[0]:(o+=i?1:-1,n&&(o=(o+s)%s),t[Math.max(0,Math.min(o,s-1))])},v=/[^.]*(?=\..*)\.|.*/,y=/\..*/,w=/::\d+$/,A={};let E=1;const T={mouseenter:"mouseover",mouseleave:"mouseout"},C=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function O(t,e){return e&&`${e}::${E++}`||t.uidEvent||E++}function x(t){const e=O(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function k(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function L(t,e,i){const n="string"==typeof e,s=n?i:e||i;let o=I(t);return C.has(o)||(o=t),[n,s,o]}function S(t,e,i,n,s){if("string"!=typeof e||!t)return;let[o,r,a]=L(e,i,n);if(e in T){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=x(t),c=l[a]||(l[a]={}),h=k(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=O(r,e.replace(v,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return P(s,{delegateTarget:r}),n.oneOff&&N.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return P(n,{delegateTarget:t}),i.oneOff&&N.off(t,n.type,e),e.apply(t,[n])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function D(t,e,i,n,s){const o=k(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function $(t,e,i,n){const s=e[i]||{};for(const[o,r]of Object.entries(s))o.includes(n)&&D(t,e,i,r.callable,r.delegationSelector)}function I(t){return t=t.replace(y,""),T[t]||t}const N={on(t,e,i,n){S(t,e,i,n,!1)},one(t,e,i,n){S(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=L(e,i,n),a=r!==e,l=x(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))$(t,l,i,e.slice(1));for(const[i,n]of Object.entries(c)){const s=i.replace(w,"");a&&!e.includes(s)||D(t,l,r,n.callable,n.delegationSelector)}}else{if(!Object.keys(c).length)return;D(t,l,r,o,s?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=u();let s=null,o=!0,r=!0,a=!1;e!==I(e)&&n&&(s=n.Event(e,i),n(t).trigger(s),o=!s.isPropagationStopped(),r=!s.isImmediatePropagationStopped(),a=s.isDefaultPrevented());const l=P(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&s&&s.preventDefault(),l}};function P(t,e={}){for(const[i,n]of Object.entries(e))try{t[i]=n}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>n})}return t}function j(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function M(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const F={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${M(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${M(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter((t=>t.startsWith("bs")&&!t.startsWith("bsConfig")));for(const n of i){let i=n.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1),e[i]=j(t.dataset[n])}return e},getDataAttribute:(t,e)=>j(t.getAttribute(`data-bs-${M(e)}`))};class H{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=o(e)?F.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...o(e)?F.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[n,s]of Object.entries(e)){const e=t[n],r=o(e)?"element":null==(i=e)?`${i}`:Object.prototype.toString.call(i).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(s).test(r))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${n}" provided type "${r}" but expected type "${s}".`)}var i}}class W extends H{constructor(t,i){super(),(t=r(t))&&(this._element=t,this._config=this._getConfig(i),e.set(this._element,this.constructor.DATA_KEY,this))}dispose(){e.remove(this._element,this.constructor.DATA_KEY),N.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){_(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return e.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.7"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const B=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e?e.split(",").map((t=>n(t))).join(","):null},z={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode.closest(e);for(;n;)i.push(n),n=n.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(",");return this.find(e,t).filter((t=>!l(t)&&a(t)))},getSelectorFromElement(t){const e=B(t);return e&&z.findOne(e)?e:null},getElementFromSelector(t){const e=B(t);return e?z.findOne(e):null},getMultipleElementsFromSelector(t){const e=B(t);return e?z.find(e):[]}},R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,n=t.NAME;N.on(document,i,`[data-bs-dismiss="${n}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),l(this))return;const s=z.getElementFromSelector(this)||this.closest(`.${n}`);t.getOrCreateInstance(s)[e]()}))},q=".bs.alert",V=`close${q}`,K=`closed${q}`;class Q extends W{static get NAME(){return"alert"}close(){if(N.trigger(this._element,V).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),N.trigger(this._element,K),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=Q.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(Q,"close"),m(Q);const X='[data-bs-toggle="button"]';class Y extends W{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=Y.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}N.on(document,"click.bs.button.data-api",X,(t=>{t.preventDefault();const e=t.target.closest(X);Y.getOrCreateInstance(e).toggle()})),m(Y);const U=".bs.swipe",G=`touchstart${U}`,J=`touchmove${U}`,Z=`touchend${U}`,tt=`pointerdown${U}`,et=`pointerup${U}`,it={endCallback:null,leftCallback:null,rightCallback:null},nt={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class st extends H{constructor(t,e){super(),this._element=t,t&&st.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return it}static get DefaultType(){return nt}static get NAME(){return"swipe"}dispose(){N.off(this._element,U)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),g(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&g(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(N.on(this._element,tt,(t=>this._start(t))),N.on(this._element,et,(t=>this._end(t))),this._element.classList.add("pointer-event")):(N.on(this._element,G,(t=>this._start(t))),N.on(this._element,J,(t=>this._move(t))),N.on(this._element,Z,(t=>this._end(t))))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const ot=".bs.carousel",rt=".data-api",at="ArrowLeft",lt="ArrowRight",ct="next",ht="prev",dt="left",ut="right",ft=`slide${ot}`,pt=`slid${ot}`,mt=`keydown${ot}`,gt=`mouseenter${ot}`,_t=`mouseleave${ot}`,bt=`dragstart${ot}`,vt=`load${ot}${rt}`,yt=`click${ot}${rt}`,wt="carousel",At="active",Et=".active",Tt=".carousel-item",Ct=Et+Tt,Ot={[at]:ut,[lt]:dt},xt={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},kt={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class Lt extends W{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=z.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===wt&&this.cycle()}static get Default(){return xt}static get DefaultType(){return kt}static get NAME(){return"carousel"}next(){this._slide(ct)}nextWhenVisible(){!document.hidden&&a(this._element)&&this.next()}prev(){this._slide(ht)}pause(){this._isSliding&&s(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?N.one(this._element,pt,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void N.one(this._element,pt,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const n=t>i?ct:ht;this._slide(n,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&N.on(this._element,mt,(t=>this._keydown(t))),"hover"===this._config.pause&&(N.on(this._element,gt,(()=>this.pause())),N.on(this._element,_t,(()=>this._maybeEnableCycle()))),this._config.touch&&st.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of z.find(".carousel-item img",this._element))N.on(t,bt,(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(dt)),rightCallback:()=>this._slide(this._directionToOrder(ut)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new st(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=Ot[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=z.findOne(Et,this._indicatorsElement);e.classList.remove(At),e.removeAttribute("aria-current");const i=z.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(At),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),n=t===ct,s=e||b(this._getItems(),i,n,this._config.wrap);if(s===i)return;const o=this._getItemIndex(s),r=e=>N.trigger(this._element,e,{relatedTarget:s,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(ft).defaultPrevented)return;if(!i||!s)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=s;const l=n?"carousel-item-start":"carousel-item-end",c=n?"carousel-item-next":"carousel-item-prev";s.classList.add(c),d(s),i.classList.add(l),s.classList.add(l),this._queueCallback((()=>{s.classList.remove(l,c),s.classList.add(At),i.classList.remove(At,c,l),this._isSliding=!1,r(pt)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return z.findOne(Ct,this._element)}_getItems(){return z.find(Tt,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return p()?t===dt?ht:ct:t===dt?ct:ht}_orderToDirection(t){return p()?t===ht?dt:ut:t===ht?ut:dt}static jQueryInterface(t){return this.each((function(){const e=Lt.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)}))}}N.on(document,yt,"[data-bs-slide], [data-bs-slide-to]",(function(t){const e=z.getElementFromSelector(this);if(!e||!e.classList.contains(wt))return;t.preventDefault();const i=Lt.getOrCreateInstance(e),n=this.getAttribute("data-bs-slide-to");return n?(i.to(n),void i._maybeEnableCycle()):"next"===F.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),N.on(window,vt,(()=>{const t=z.find('[data-bs-ride="carousel"]');for(const e of t)Lt.getOrCreateInstance(e)})),m(Lt);const St=".bs.collapse",Dt=`show${St}`,$t=`shown${St}`,It=`hide${St}`,Nt=`hidden${St}`,Pt=`click${St}.data-api`,jt="show",Mt="collapse",Ft="collapsing",Ht=`:scope .${Mt} .${Mt}`,Wt='[data-bs-toggle="collapse"]',Bt={parent:null,toggle:!0},zt={parent:"(null|element)",toggle:"boolean"};class Rt extends W{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=z.find(Wt);for(const t of i){const e=z.getSelectorFromElement(t),i=z.find(e).filter((t=>t===this._element));null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return Bt}static get DefaultType(){return zt}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter((t=>t!==this._element)).map((t=>Rt.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(N.trigger(this._element,Dt).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(Mt),this._element.classList.add(Ft),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(Ft),this._element.classList.add(Mt,jt),this._element.style[e]="",N.trigger(this._element,$t)}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(N.trigger(this._element,It).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,d(this._element),this._element.classList.add(Ft),this._element.classList.remove(Mt,jt);for(const t of this._triggerArray){const e=z.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(Ft),this._element.classList.add(Mt),N.trigger(this._element,Nt)}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(jt)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=r(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Wt);for(const e of t){const t=z.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=z.find(Ht,this._config.parent);return z.find(t,this._config.parent).filter((t=>!e.includes(t)))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each((function(){const i=Rt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}N.on(document,Pt,Wt,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of z.getMultipleElementsFromSelector(this))Rt.getOrCreateInstance(t,{toggle:!1}).toggle()})),m(Rt);var qt="top",Vt="bottom",Kt="right",Qt="left",Xt="auto",Yt=[qt,Vt,Kt,Qt],Ut="start",Gt="end",Jt="clippingParents",Zt="viewport",te="popper",ee="reference",ie=Yt.reduce((function(t,e){return t.concat([e+"-"+Ut,e+"-"+Gt])}),[]),ne=[].concat(Yt,[Xt]).reduce((function(t,e){return t.concat([e,e+"-"+Ut,e+"-"+Gt])}),[]),se="beforeRead",oe="read",re="afterRead",ae="beforeMain",le="main",ce="afterMain",he="beforeWrite",de="write",ue="afterWrite",fe=[se,oe,re,ae,le,ce,he,de,ue];function pe(t){return t?(t.nodeName||"").toLowerCase():null}function me(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function ge(t){return t instanceof me(t).Element||t instanceof Element}function _e(t){return t instanceof me(t).HTMLElement||t instanceof HTMLElement}function be(t){return"undefined"!=typeof ShadowRoot&&(t instanceof me(t).ShadowRoot||t instanceof ShadowRoot)}const ve={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];_e(s)&&pe(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});_e(n)&&pe(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function ye(t){return t.split("-")[0]}var we=Math.max,Ae=Math.min,Ee=Math.round;function Te(){var t=navigator.userAgentData;return null!=t&&t.brands&&Array.isArray(t.brands)?t.brands.map((function(t){return t.brand+"/"+t.version})).join(" "):navigator.userAgent}function Ce(){return!/^((?!chrome|android).)*safari/i.test(Te())}function Oe(t,e,i){void 0===e&&(e=!1),void 0===i&&(i=!1);var n=t.getBoundingClientRect(),s=1,o=1;e&&_e(t)&&(s=t.offsetWidth>0&&Ee(n.width)/t.offsetWidth||1,o=t.offsetHeight>0&&Ee(n.height)/t.offsetHeight||1);var r=(ge(t)?me(t):window).visualViewport,a=!Ce()&&i,l=(n.left+(a&&r?r.offsetLeft:0))/s,c=(n.top+(a&&r?r.offsetTop:0))/o,h=n.width/s,d=n.height/o;return{width:h,height:d,top:c,right:l+h,bottom:c+d,left:l,x:l,y:c}}function xe(t){var e=Oe(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function ke(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&be(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function Le(t){return me(t).getComputedStyle(t)}function Se(t){return["table","td","th"].indexOf(pe(t))>=0}function De(t){return((ge(t)?t.ownerDocument:t.document)||window.document).documentElement}function $e(t){return"html"===pe(t)?t:t.assignedSlot||t.parentNode||(be(t)?t.host:null)||De(t)}function Ie(t){return _e(t)&&"fixed"!==Le(t).position?t.offsetParent:null}function Ne(t){for(var e=me(t),i=Ie(t);i&&Se(i)&&"static"===Le(i).position;)i=Ie(i);return i&&("html"===pe(i)||"body"===pe(i)&&"static"===Le(i).position)?e:i||function(t){var e=/firefox/i.test(Te());if(/Trident/i.test(Te())&&_e(t)&&"fixed"===Le(t).position)return null;var i=$e(t);for(be(i)&&(i=i.host);_e(i)&&["html","body"].indexOf(pe(i))<0;){var n=Le(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function Pe(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}function je(t,e,i){return we(t,Ae(e,i))}function Me(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function Fe(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const He={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=ye(i.placement),l=Pe(a),c=[Qt,Kt].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return Me("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:Fe(t,Yt))}(s.padding,i),d=xe(o),u="y"===l?qt:Qt,f="y"===l?Vt:Kt,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=Ne(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,A=je(v,w,y),E=l;i.modifiersData[n]=((e={})[E]=A,e.centerOffset=A-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&ke(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function We(t){return t.split("-")[1]}var Be={top:"auto",right:"auto",bottom:"auto",left:"auto"};function ze(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=t.isFixed,u=r.x,f=void 0===u?0:u,p=r.y,m=void 0===p?0:p,g="function"==typeof h?h({x:f,y:m}):{x:f,y:m};f=g.x,m=g.y;var _=r.hasOwnProperty("x"),b=r.hasOwnProperty("y"),v=Qt,y=qt,w=window;if(c){var A=Ne(i),E="clientHeight",T="clientWidth";A===me(i)&&"static"!==Le(A=De(i)).position&&"absolute"===a&&(E="scrollHeight",T="scrollWidth"),(s===qt||(s===Qt||s===Kt)&&o===Gt)&&(y=Vt,m-=(d&&A===w&&w.visualViewport?w.visualViewport.height:A[E])-n.height,m*=l?1:-1),s!==Qt&&(s!==qt&&s!==Vt||o!==Gt)||(v=Kt,f-=(d&&A===w&&w.visualViewport?w.visualViewport.width:A[T])-n.width,f*=l?1:-1)}var C,O=Object.assign({position:a},c&&Be),x=!0===h?function(t,e){var i=t.x,n=t.y,s=e.devicePixelRatio||1;return{x:Ee(i*s)/s||0,y:Ee(n*s)/s||0}}({x:f,y:m},me(i)):{x:f,y:m};return f=x.x,m=x.y,l?Object.assign({},O,((C={})[y]=b?"0":"",C[v]=_?"0":"",C.transform=(w.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",C)):Object.assign({},O,((e={})[y]=b?m+"px":"",e[v]=_?f+"px":"",e.transform="",e))}const Re={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:ye(e.placement),variation:We(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s,isFixed:"fixed"===e.options.strategy};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,ze(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,ze(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var qe={passive:!0};const Ve={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=me(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,qe)})),a&&l.addEventListener("resize",i.update,qe),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,qe)})),a&&l.removeEventListener("resize",i.update,qe)}},data:{}};var Ke={left:"right",right:"left",bottom:"top",top:"bottom"};function Qe(t){return t.replace(/left|right|bottom|top/g,(function(t){return Ke[t]}))}var Xe={start:"end",end:"start"};function Ye(t){return t.replace(/start|end/g,(function(t){return Xe[t]}))}function Ue(t){var e=me(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Ge(t){return Oe(De(t)).left+Ue(t).scrollLeft}function Je(t){var e=Le(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ze(t){return["html","body","#document"].indexOf(pe(t))>=0?t.ownerDocument.body:_e(t)&&Je(t)?t:Ze($e(t))}function ti(t,e){var i;void 0===e&&(e=[]);var n=Ze(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=me(n),r=s?[o].concat(o.visualViewport||[],Je(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(ti($e(r)))}function ei(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function ii(t,e,i){return e===Zt?ei(function(t,e){var i=me(t),n=De(t),s=i.visualViewport,o=n.clientWidth,r=n.clientHeight,a=0,l=0;if(s){o=s.width,r=s.height;var c=Ce();(c||!c&&"fixed"===e)&&(a=s.offsetLeft,l=s.offsetTop)}return{width:o,height:r,x:a+Ge(t),y:l}}(t,i)):ge(e)?function(t,e){var i=Oe(t,!1,"fixed"===e);return i.top=i.top+t.clientTop,i.left=i.left+t.clientLeft,i.bottom=i.top+t.clientHeight,i.right=i.left+t.clientWidth,i.width=t.clientWidth,i.height=t.clientHeight,i.x=i.left,i.y=i.top,i}(e,i):ei(function(t){var e,i=De(t),n=Ue(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=we(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=we(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+Ge(t),l=-n.scrollTop;return"rtl"===Le(s||i).direction&&(a+=we(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(De(t)))}function ni(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?ye(s):null,r=s?We(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case qt:e={x:a,y:i.y-n.height};break;case Vt:e={x:a,y:i.y+i.height};break;case Kt:e={x:i.x+i.width,y:l};break;case Qt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?Pe(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case Ut:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Gt:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function si(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.strategy,r=void 0===o?t.strategy:o,a=i.boundary,l=void 0===a?Jt:a,c=i.rootBoundary,h=void 0===c?Zt:c,d=i.elementContext,u=void 0===d?te:d,f=i.altBoundary,p=void 0!==f&&f,m=i.padding,g=void 0===m?0:m,_=Me("number"!=typeof g?g:Fe(g,Yt)),b=u===te?ee:te,v=t.rects.popper,y=t.elements[p?b:u],w=function(t,e,i,n){var s="clippingParents"===e?function(t){var e=ti($e(t)),i=["absolute","fixed"].indexOf(Le(t).position)>=0&&_e(t)?Ne(t):t;return ge(i)?e.filter((function(t){return ge(t)&&ke(t,i)&&"body"!==pe(t)})):[]}(t):[].concat(e),o=[].concat(s,[i]),r=o[0],a=o.reduce((function(e,i){var s=ii(t,i,n);return e.top=we(s.top,e.top),e.right=Ae(s.right,e.right),e.bottom=Ae(s.bottom,e.bottom),e.left=we(s.left,e.left),e}),ii(t,r,n));return a.width=a.right-a.left,a.height=a.bottom-a.top,a.x=a.left,a.y=a.top,a}(ge(y)?y:y.contextElement||De(t.elements.popper),l,h,r),A=Oe(t.elements.reference),E=ni({reference:A,element:v,placement:s}),T=ei(Object.assign({},v,E)),C=u===te?T:A,O={top:w.top-C.top+_.top,bottom:C.bottom-w.bottom+_.bottom,left:w.left-C.left+_.left,right:C.right-w.right+_.right},x=t.modifiersData.offset;if(u===te&&x){var k=x[s];Object.keys(O).forEach((function(t){var e=[Kt,Vt].indexOf(t)>=0?1:-1,i=[qt,Vt].indexOf(t)>=0?"y":"x";O[t]+=k[i]*e}))}return O}function oi(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?ne:l,h=We(n),d=h?a?ie:ie.filter((function(t){return We(t)===h})):Yt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=si(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[ye(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const ri={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=ye(g),b=l||(_!==g&&p?function(t){if(ye(t)===Xt)return[];var e=Qe(t);return[Ye(t),e,Ye(e)]}(g):[Qe(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(ye(i)===Xt?oi(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,A=new Map,E=!0,T=v[0],C=0;C=0,S=L?"width":"height",D=si(e,{placement:O,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),$=L?k?Kt:Qt:k?Vt:qt;y[S]>w[S]&&($=Qe($));var I=Qe($),N=[];if(o&&N.push(D[x]<=0),a&&N.push(D[$]<=0,D[I]<=0),N.every((function(t){return t}))){T=O,E=!1;break}A.set(O,N)}if(E)for(var P=function(t){var e=v.find((function(e){var i=A.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},j=p?3:1;j>0&&"break"!==P(j);j--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function ai(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function li(t){return[qt,Kt,Vt,Qt].some((function(e){return t[e]>=0}))}const ci={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=si(e,{elementContext:"reference"}),a=si(e,{altBoundary:!0}),l=ai(r,n),c=ai(a,s,o),h=li(l),d=li(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},hi={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=ne.reduce((function(t,i){return t[i]=function(t,e,i){var n=ye(t),s=[Qt,qt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[Qt,Kt].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},di={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=ni({reference:e.rects.reference,element:e.rects.popper,placement:e.placement})},data:{}},ui={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=si(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=ye(e.placement),b=We(e.placement),v=!b,y=Pe(_),w="x"===y?"y":"x",A=e.modifiersData.popperOffsets,E=e.rects.reference,T=e.rects.popper,C="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,O="number"==typeof C?{mainAxis:C,altAxis:C}:Object.assign({mainAxis:0,altAxis:0},C),x=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,k={x:0,y:0};if(A){if(o){var L,S="y"===y?qt:Qt,D="y"===y?Vt:Kt,$="y"===y?"height":"width",I=A[y],N=I+g[S],P=I-g[D],j=f?-T[$]/2:0,M=b===Ut?E[$]:T[$],F=b===Ut?-T[$]:-E[$],H=e.elements.arrow,W=f&&H?xe(H):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},z=B[S],R=B[D],q=je(0,E[$],W[$]),V=v?E[$]/2-j-q-z-O.mainAxis:M-q-z-O.mainAxis,K=v?-E[$]/2+j+q+R+O.mainAxis:F+q+R+O.mainAxis,Q=e.elements.arrow&&Ne(e.elements.arrow),X=Q?"y"===y?Q.clientTop||0:Q.clientLeft||0:0,Y=null!=(L=null==x?void 0:x[y])?L:0,U=I+K-Y,G=je(f?Ae(N,I+V-Y-X):N,I,f?we(P,U):P);A[y]=G,k[y]=G-I}if(a){var J,Z="x"===y?qt:Qt,tt="x"===y?Vt:Kt,et=A[w],it="y"===w?"height":"width",nt=et+g[Z],st=et-g[tt],ot=-1!==[qt,Qt].indexOf(_),rt=null!=(J=null==x?void 0:x[w])?J:0,at=ot?nt:et-E[it]-T[it]-rt+O.altAxis,lt=ot?et+E[it]+T[it]-rt-O.altAxis:st,ct=f&&ot?function(t,e,i){var n=je(t,e,i);return n>i?i:n}(at,et,lt):je(f?at:nt,et,f?lt:st);A[w]=ct,k[w]=ct-et}e.modifiersData[n]=k}},requiresIfExists:["offset"]};function fi(t,e,i){void 0===i&&(i=!1);var n,s,o=_e(e),r=_e(e)&&function(t){var e=t.getBoundingClientRect(),i=Ee(e.width)/t.offsetWidth||1,n=Ee(e.height)/t.offsetHeight||1;return 1!==i||1!==n}(e),a=De(e),l=Oe(t,r,i),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&(("body"!==pe(e)||Je(a))&&(c=(n=e)!==me(n)&&_e(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:Ue(n)),_e(e)?((h=Oe(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=Ge(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}function pi(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var mi={placement:"bottom",modifiers:[],strategy:"absolute"};function gi(){for(var t=arguments.length,e=new Array(t),i=0;iNumber.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(F.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...g(this._config.popperConfig,[void 0,t])}}_selectMenuItem({key:t,target:e}){const i=z.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter((t=>a(t)));i.length&&b(i,e,t===Oi,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=Ki.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=z.find(ji);for(const i of e){const e=Ki.getInstance(i);if(!e||!1===e._config.autoClose)continue;const n=t.composedPath(),s=n.includes(e._menu);if(n.includes(e._element)||"inside"===e._config.autoClose&&!s||"outside"===e._config.autoClose&&s)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,n=[Ci,Oi].includes(t.key);if(!n&&!i)return;if(e&&!i)return;t.preventDefault();const s=this.matches(Pi)?this:z.prev(this,Pi)[0]||z.next(this,Pi)[0]||z.findOne(Pi,t.delegateTarget.parentNode),o=Ki.getOrCreateInstance(s);if(n)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),s.focus())}}N.on(document,$i,Pi,Ki.dataApiKeydownHandler),N.on(document,$i,Mi,Ki.dataApiKeydownHandler),N.on(document,Di,Ki.clearMenus),N.on(document,Ii,Ki.clearMenus),N.on(document,Di,Pi,(function(t){t.preventDefault(),Ki.getOrCreateInstance(this).toggle()})),m(Ki);const Qi="backdrop",Xi="show",Yi=`mousedown.bs.${Qi}`,Ui={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},Gi={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class Ji extends H{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return Ui}static get DefaultType(){return Gi}static get NAME(){return Qi}show(t){if(!this._config.isVisible)return void g(t);this._append();const e=this._getElement();this._config.isAnimated&&d(e),e.classList.add(Xi),this._emulateAnimation((()=>{g(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(Xi),this._emulateAnimation((()=>{this.dispose(),g(t)}))):g(t)}dispose(){this._isAppended&&(N.off(this._element,Yi),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=r(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),N.on(t,Yi,(()=>{g(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){_(t,this._getElement(),this._config.isAnimated)}}const Zi=".bs.focustrap",tn=`focusin${Zi}`,en=`keydown.tab${Zi}`,nn="backward",sn={autofocus:!0,trapElement:null},on={autofocus:"boolean",trapElement:"element"};class rn extends H{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return sn}static get DefaultType(){return on}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),N.off(document,Zi),N.on(document,tn,(t=>this._handleFocusin(t))),N.on(document,en,(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,N.off(document,Zi))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=z.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===nn?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?nn:"forward")}}const an=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",ln=".sticky-top",cn="padding-right",hn="margin-right";class dn{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,cn,(e=>e+t)),this._setElementAttributes(an,cn,(e=>e+t)),this._setElementAttributes(ln,hn,(e=>e-t))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,cn),this._resetElementAttributes(an,cn),this._resetElementAttributes(ln,hn)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(s))}px`)}))}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&F.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=F.getDataAttribute(t,e);null!==i?(F.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(o(t))e(t);else for(const i of z.find(t,this._element))e(i)}}const un=".bs.modal",fn=`hide${un}`,pn=`hidePrevented${un}`,mn=`hidden${un}`,gn=`show${un}`,_n=`shown${un}`,bn=`resize${un}`,vn=`click.dismiss${un}`,yn=`mousedown.dismiss${un}`,wn=`keydown.dismiss${un}`,An=`click${un}.data-api`,En="modal-open",Tn="show",Cn="modal-static",On={backdrop:!0,focus:!0,keyboard:!0},xn={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class kn extends W{constructor(t,e){super(t,e),this._dialog=z.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new dn,this._addEventListeners()}static get Default(){return On}static get DefaultType(){return xn}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||N.trigger(this._element,gn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(En),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(N.trigger(this._element,fn).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(Tn),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){N.off(window,un),N.off(this._dialog,un),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Ji({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new rn({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=z.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),d(this._element),this._element.classList.add(Tn),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,N.trigger(this._element,_n,{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){N.on(this._element,wn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())})),N.on(window,bn,(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),N.on(this._element,yn,(t=>{N.one(this._element,vn,(e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())}))}))}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(En),this._resetAdjustments(),this._scrollBar.reset(),N.trigger(this._element,mn)}))}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(N.trigger(this._element,pn).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(Cn)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(Cn),this._queueCallback((()=>{this._element.classList.remove(Cn),this._queueCallback((()=>{this._element.style.overflowY=e}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=p()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=p()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=kn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}N.on(document,An,'[data-bs-toggle="modal"]',(function(t){const e=z.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),N.one(e,gn,(t=>{t.defaultPrevented||N.one(e,mn,(()=>{a(this)&&this.focus()}))}));const i=z.findOne(".modal.show");i&&kn.getInstance(i).hide(),kn.getOrCreateInstance(e).toggle(this)})),R(kn),m(kn);const Ln=".bs.offcanvas",Sn=".data-api",Dn=`load${Ln}${Sn}`,$n="show",In="showing",Nn="hiding",Pn=".offcanvas.show",jn=`show${Ln}`,Mn=`shown${Ln}`,Fn=`hide${Ln}`,Hn=`hidePrevented${Ln}`,Wn=`hidden${Ln}`,Bn=`resize${Ln}`,zn=`click${Ln}${Sn}`,Rn=`keydown.dismiss${Ln}`,qn={backdrop:!0,keyboard:!0,scroll:!1},Vn={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class Kn extends W{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return qn}static get DefaultType(){return Vn}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||N.trigger(this._element,jn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new dn).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(In),this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add($n),this._element.classList.remove(In),N.trigger(this._element,Mn,{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(N.trigger(this._element,Fn).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add(Nn),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove($n,Nn),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new dn).reset(),N.trigger(this._element,Wn)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new Ji({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():N.trigger(this._element,Hn)}:null})}_initializeFocusTrap(){return new rn({trapElement:this._element})}_addEventListeners(){N.on(this._element,Rn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():N.trigger(this._element,Hn))}))}static jQueryInterface(t){return this.each((function(){const e=Kn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}N.on(document,zn,'[data-bs-toggle="offcanvas"]',(function(t){const e=z.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this))return;N.one(e,Wn,(()=>{a(this)&&this.focus()}));const i=z.findOne(Pn);i&&i!==e&&Kn.getInstance(i).hide(),Kn.getOrCreateInstance(e).toggle(this)})),N.on(window,Dn,(()=>{for(const t of z.find(Pn))Kn.getOrCreateInstance(t).show()})),N.on(window,Bn,(()=>{for(const t of z.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&Kn.getOrCreateInstance(t).hide()})),R(Kn),m(Kn);const Qn={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],dd:[],div:[],dl:[],dt:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},Xn=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Yn=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,Un=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!Xn.has(i)||Boolean(Yn.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},Gn={allowList:Qn,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"
"},Jn={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},Zn={entry:"(string|element|function|null)",selector:"(string|element)"};class ts extends H{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return Gn}static get DefaultType(){return Jn}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map((t=>this._resolvePossibleFunction(t))).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},Zn)}_setContent(t,e,i){const n=z.findOne(i,t);n&&((e=this._resolvePossibleFunction(e))?o(e)?this._putElementInTemplate(r(e),n):this._config.html?n.innerHTML=this._maybeSanitize(e):n.textContent=e:n.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const n=(new window.DOMParser).parseFromString(t,"text/html"),s=[].concat(...n.body.querySelectorAll("*"));for(const t of s){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const n=[].concat(...t.attributes),s=[].concat(e["*"]||[],e[i]||[]);for(const e of n)Un(e,s)||t.removeAttribute(e.nodeName)}return n.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return g(t,[void 0,this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const es=new Set(["sanitize","allowList","sanitizeFn"]),is="fade",ns="show",ss=".tooltip-inner",os=".modal",rs="hide.bs.modal",as="hover",ls="focus",cs="click",hs={AUTO:"auto",TOP:"top",RIGHT:p()?"left":"right",BOTTOM:"bottom",LEFT:p()?"right":"left"},ds={allowList:Qn,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'',title:"",trigger:"hover focus"},us={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class fs extends W{constructor(t,e){if(void 0===wi)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org/docs/v2/)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return ds}static get DefaultType(){return us}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),N.off(this._element.closest(os),rs,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=N.trigger(this._element,this.constructor.eventName("show")),e=(c(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:n}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(n.append(i),N.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(ns),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.on(t,"mouseover",h);this._queueCallback((()=>{N.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1}),this.tip,this._isAnimated())}hide(){if(this._isShown()&&!N.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(ns),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.off(t,"mouseover",h);this._activeTrigger[cs]=!1,this._activeTrigger[ls]=!1,this._activeTrigger[as]=!1,this._isHovered=null,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),N.trigger(this._element,this.constructor.eventName("hidden")))}),this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(is,ns),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add(is),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new ts({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{[ss]:this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(is)}_isShown(){return this.tip&&this.tip.classList.contains(ns)}_createPopper(t){const e=g(this._config.placement,[this,t,this._element]),i=hs[e.toUpperCase()];return yi(this._element,t,this._getPopperConfig(i))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return g(t,[this._element,this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,...g(this._config.popperConfig,[void 0,e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)N.on(this._element,this.constructor.eventName("click"),this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger[cs]=!(e._isShown()&&e._activeTrigger[cs]),e.toggle()}));else if("manual"!==e){const t=e===as?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===as?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");N.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?ls:as]=!0,e._enter()})),N.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?ls:as]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},N.on(this._element.closest(os),rs,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout((()=>{this._isHovered&&this.show()}),this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout((()=>{this._isHovered||this.hide()}),this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=F.getDataAttributes(this._element);for(const t of Object.keys(e))es.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each((function(){const e=fs.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(fs);const ps=".popover-header",ms=".popover-body",gs={...fs.Default,content:"",offset:[0,8],placement:"right",template:'',trigger:"click"},_s={...fs.DefaultType,content:"(null|string|element|function)"};class bs extends fs{static get Default(){return gs}static get DefaultType(){return _s}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{[ps]:this._getTitle(),[ms]:this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=bs.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(bs);const vs=".bs.scrollspy",ys=`activate${vs}`,ws=`click${vs}`,As=`load${vs}.data-api`,Es="active",Ts="[href]",Cs=".nav-link",Os=`${Cs}, .nav-item > ${Cs}, .list-group-item`,xs={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},ks={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class Ls extends W{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return xs}static get DefaultType(){return ks}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=r(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map((t=>Number.parseFloat(t)))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(N.off(this._config.target,ws),N.on(this._config.target,ws,Ts,(t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,n=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:n,behavior:"smooth"});i.scrollTop=n}})))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver((t=>this._observerCallback(t)),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},n=(this._rootElement||document.documentElement).scrollTop,s=n>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=n;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(s&&t){if(i(o),!n)return}else s||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=z.find(Ts,this._config.target);for(const e of t){if(!e.hash||l(e))continue;const t=z.findOne(decodeURI(e.hash),this._element);a(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(Es),this._activateParents(t),N.trigger(this._element,ys,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))z.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(Es);else for(const e of z.parents(t,".nav, .list-group"))for(const t of z.prev(e,Os))t.classList.add(Es)}_clearActiveClass(t){t.classList.remove(Es);const e=z.find(`${Ts}.${Es}`,t);for(const t of e)t.classList.remove(Es)}static jQueryInterface(t){return this.each((function(){const e=Ls.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(window,As,(()=>{for(const t of z.find('[data-bs-spy="scroll"]'))Ls.getOrCreateInstance(t)})),m(Ls);const Ss=".bs.tab",Ds=`hide${Ss}`,$s=`hidden${Ss}`,Is=`show${Ss}`,Ns=`shown${Ss}`,Ps=`click${Ss}`,js=`keydown${Ss}`,Ms=`load${Ss}`,Fs="ArrowLeft",Hs="ArrowRight",Ws="ArrowUp",Bs="ArrowDown",zs="Home",Rs="End",qs="active",Vs="fade",Ks="show",Qs=".dropdown-toggle",Xs=`:not(${Qs})`,Ys='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',Us=`.nav-link${Xs}, .list-group-item${Xs}, [role="tab"]${Xs}, ${Ys}`,Gs=`.${qs}[data-bs-toggle="tab"], .${qs}[data-bs-toggle="pill"], .${qs}[data-bs-toggle="list"]`;class Js extends W{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),N.on(this._element,js,(t=>this._keydown(t))))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?N.trigger(e,Ds,{relatedTarget:t}):null;N.trigger(t,Is,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(qs),this._activate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),N.trigger(t,Ns,{relatedTarget:e})):t.classList.add(Ks)}),t,t.classList.contains(Vs)))}_deactivate(t,e){t&&(t.classList.remove(qs),t.blur(),this._deactivate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),N.trigger(t,$s,{relatedTarget:e})):t.classList.remove(Ks)}),t,t.classList.contains(Vs)))}_keydown(t){if(![Fs,Hs,Ws,Bs,zs,Rs].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter((t=>!l(t)));let i;if([zs,Rs].includes(t.key))i=e[t.key===zs?0:e.length-1];else{const n=[Hs,Bs].includes(t.key);i=b(e,t.target,n,!0)}i&&(i.focus({preventScroll:!0}),Js.getOrCreateInstance(i).show())}_getChildren(){return z.find(Us,this._parent)}_getActiveElem(){return this._getChildren().find((t=>this._elemIsActive(t)))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=z.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const n=(t,n)=>{const s=z.findOne(t,i);s&&s.classList.toggle(n,e)};n(Qs,qs),n(".dropdown-menu",Ks),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(qs)}_getInnerElement(t){return t.matches(Us)?t:z.findOne(Us,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each((function(){const e=Js.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(document,Ps,Ys,(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this)||Js.getOrCreateInstance(this).show()})),N.on(window,Ms,(()=>{for(const t of z.find(Gs))Js.getOrCreateInstance(t)})),m(Js);const Zs=".bs.toast",to=`mouseover${Zs}`,eo=`mouseout${Zs}`,io=`focusin${Zs}`,no=`focusout${Zs}`,so=`hide${Zs}`,oo=`hidden${Zs}`,ro=`show${Zs}`,ao=`shown${Zs}`,lo="hide",co="show",ho="showing",uo={animation:"boolean",autohide:"boolean",delay:"number"},fo={animation:!0,autohide:!0,delay:5e3};class po extends W{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return fo}static get DefaultType(){return uo}static get NAME(){return"toast"}show(){N.trigger(this._element,ro).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(lo),d(this._element),this._element.classList.add(co,ho),this._queueCallback((()=>{this._element.classList.remove(ho),N.trigger(this._element,ao),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(N.trigger(this._element,so).defaultPrevented||(this._element.classList.add(ho),this._queueCallback((()=>{this._element.classList.add(lo),this._element.classList.remove(ho,co),N.trigger(this._element,oo)}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(co),super.dispose()}isShown(){return this._element.classList.contains(co)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){N.on(this._element,to,(t=>this._onInteraction(t,!0))),N.on(this._element,eo,(t=>this._onInteraction(t,!1))),N.on(this._element,io,(t=>this._onInteraction(t,!0))),N.on(this._element,no,(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=po.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(po),m(po),{Alert:Q,Button:Y,Carousel:Lt,Collapse:Rt,Dropdown:Ki,Modal:kn,Offcanvas:Kn,Popover:bs,ScrollSpy:Ls,Tab:Js,Toast:po,Tooltip:fs}})); diff --git a/js/common.js b/js/common.js index 4519030f..ea4c6e00 100644 --- a/js/common.js +++ b/js/common.js @@ -5,22 +5,19 @@ global.assert = require('assert'); global.jsc = require('jsverify'); global.jsdom = require('jsdom-global'); global.cleanup = global.jsdom(); -global.URL = require('jsdom-url').URL; global.fs = require('fs'); global.WebCrypto = require('@peculiar/webcrypto').Crypto; // application libraries to test -global.$ = global.jQuery = require('./jquery-3.7.0'); -global.RawDeflate = require('./rawinflate-0.3').RawDeflate; -global.zlib = require('./zlib-1.3.1').zlib; +global.$ = global.jQuery = require('./jquery-3.7.1'); +global.zlib = require('./zlib-1.3.1-1').zlib; require('./prettify'); global.prettyPrint = window.PR.prettyPrint; global.prettyPrintOne = window.PR.prettyPrintOne; global.showdown = require('./showdown-2.1.0'); -global.DOMPurify = require('./purify-3.0.8'); -global.baseX = require('./base-x-4.0.0').baseX; +global.DOMPurify = require('./purify-3.2.6'); +global.baseX = require('./base-x-5.0.1').baseX; global.Legacy = require('./legacy').Legacy; -require('./bootstrap-3.4.1'); require('./privatebin'); // internal variables @@ -79,8 +76,16 @@ function parseMime(line) { } // common testing helper functions -exports.atob = atob; -exports.btoa = btoa; +// as of jsDOM 22 the base64 functions provided in the DOM are more restrictive +// than browser implementation and throw when being passed invalid unicode +// codepoints - as we use these in the encryption with binary data, we need +// these to be character encoding agnostic +exports.atob = function(encoded) { + return Buffer.from(encoded, 'base64').toString('binary'); +} +exports.btoa = function(text) { + return Buffer.from(text, 'binary').toString('base64'); +} // provides random lowercase characters from a to z exports.jscA2zString = function() { @@ -127,7 +132,7 @@ exports.jscMimeTypes = function() { return jsc.elements(mimeTypes); }; -// provides a random PrivateBin paste formatter +// provides a random PrivateBin document formatter exports.jscFormats = function() { return jsc.elements(formats); }; @@ -152,3 +157,22 @@ exports.urlToString = function (url) { encodeURI(url.query.join('').replace(/^&+|&+$/gm,'')) : '') + (url.fragment ? '#' + encodeURI(url.fragment) : ''); }; + +exports.enableClipboard = function () { + navigator.clipboard = (function () { + let savedText = ""; + + async function writeText(text) { + savedText = text; + }; + + async function readText() { + return savedText; + }; + + return { + writeText, + readText, + }; + })(); +}; diff --git a/js/dark-mode-switch.js b/js/dark-mode-switch.js new file mode 100644 index 00000000..e60bedb5 --- /dev/null +++ b/js/dark-mode-switch.js @@ -0,0 +1,82 @@ +/*! + * Color mode toggler for Bootstrap's docs (https://getbootstrap.com/) + * Copyright 2011-2024 The Bootstrap Authors + * Licensed under the Creative Commons Attribution 3.0 Unported License. + * Modified to work with a simpler checkbox toggle & support prettify CSS themes + */ + +(() => { + 'use strict' + + const getStoredTheme = () => localStorage.getItem('theme') + const setStoredTheme = theme => localStorage.setItem('theme', theme) + const getPreferredTheme = () => window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' + + const getStoredPreferredTheme = () => { + const storedTheme = getStoredTheme() + if (storedTheme) { + return storedTheme + } + return getPreferredTheme() + } + + const delStoredPrettifyTheme = () => localStorage.removeItem('themePrettify') + const getStoredPrettifyTheme = () => localStorage.getItem('themePrettify') + const setStoredPrettifyTheme = theme => localStorage.setItem('themePrettify', theme) + + const getPrettifyThemeLink = () => { + for (const sheet of document.getElementsByTagName('link')) { + if (sheet.rel === 'stylesheet' && sheet.href.includes('css/prettify/') && !sheet.href.includes('css/prettify/prettify.css')) { + return sheet + } + } + return null + } + + const setTheme = theme => { + const preferredTheme = theme === 'auto' ? getPreferredTheme() : theme + document.documentElement.setAttribute('data-bs-theme', preferredTheme) + const sheetPrettify = getPrettifyThemeLink() + if (sheetPrettify) { + sheetPrettify.remove() + } + const link = document.createElement('link') + link.rel = 'stylesheet' + if (preferredTheme === 'dark') { + link.href = 'css/prettify/sons-of-obsidian.css' + document.head.appendChild(link) + } else { + const themePrettify = getStoredPrettifyTheme() + if (themePrettify) { + link.href = themePrettify + document.head.appendChild(link) + } + } + } + + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { + const storedTheme = getStoredTheme() + if (storedTheme !== 'light' && storedTheme !== 'dark') { + setTheme(getStoredPreferredTheme()) + } + }) + + window.addEventListener('DOMContentLoaded', () => { + const sheetPrettify = getPrettifyThemeLink() + if (sheetPrettify) { + setStoredPrettifyTheme(sheetPrettify.href) + } else { + delStoredPrettifyTheme() + } + const toggle = document.getElementById('bd-theme') + const theme = getStoredPreferredTheme() + setTheme(theme) + toggle.checked = (theme === 'dark') + toggle.addEventListener('change', (event) => { + const theme = event.currentTarget.checked ? 'dark' : 'light' + setStoredTheme(theme) + setTheme(theme) + event.currentTarget.focus() + }) + }) +})() diff --git a/js/jquery-3.7.0.js b/js/jquery-3.7.0.js deleted file mode 100644 index e7e29d5b..00000000 --- a/js/jquery-3.7.0.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! jQuery v3.7.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ -!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.0",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},R=function(){V()},M=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&z(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function X(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&M(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function U(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function z(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",R),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Me(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return R(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return R(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0{"object"==typeof exports&&"object"==typeof module?module.exports=r():"function"==typeof define&&define.amd?define("kjua",[],r):"object"==typeof exports?exports.kjua=r():t.kjua=r()})("undefined"!=typeof self?self:this,()=>{return n=[(t,r,e)=>{function n(t){var t=Object.assign({},o,t),r=i(t.text,t.ecLevel,t.minVersion,t.quiet);return"svg"===t.render?u(r,t):a(r,t,"image"===t.render)}var o=e(1),i=e(2),a=e(4),u=e(8);t.exports=n;try{jQuery.fn.kjua=function(e){return this.each(function(t,r){return r.appendChild(n(e))})}}catch(t){}},t=>{t.exports={render:"image",crisp:!0,minVersion:1,ecLevel:"L",size:200,ratio:null,fill:"#333",back:"#fff",text:"no text",rounded:0,quiet:0,mode:"plain",mSize:30,mPosX:50,mPosY:50,label:"no label",fontname:"sans",fontcolor:"#333",image:null}},(t,r,e)=>{function i(t,r){for(var e,n=2{try{var e=u(o,r),n=(e.addData(t),e.make(),e.getModuleCount());return{v:{text:t,level:r,version:o,module_count:n,is_dark:function(t,r){return 0<=t&&t{z.stringToBytes=(z.stringToBytesFuncs={default:function(t){for(var r=[],e=0;e{for(var r=y(f),t=function(){var t=r.read();if(-1==t)throw"eof";return t},e=0,n={};;){var o=r.read();if(-1==o)break;var i=t(),a=t(),u=t();n[String.fromCharCode(o<<8|i)]=a<<8|u,e+=1}if(e!=l)throw e+" != "+l;return n})(),i="?".charCodeAt(0);return function(t){for(var r=[],e=0;e>>8),r.push(255&n)):r.push(i)}return r}},u=8,k={L:a=1,M:0,Q:3,H:i=2},o=0,f=1,l=2,c=3,s=n=4,g=5,d=7,e=[[],[h=6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],(w={}).getBCHTypeInfo=function(t){for(var r=t<<10;0<=T(r)-T(1335);)r^=1335<{for(var r=new Array(256),e=new Array(256),t=0;t<8;t+=1)r[t]=1<{switch(r){case k.L:return p[4*(t-1)+0];case k.M:return p[4*(t-1)+1];case k.Q:return p[4*(t-1)+2];case k.H:return p[4*(t-1)+3];default:return}})(t,r);if(void 0===e)throw"bad rs block @ typeNumber:"+t+"/errorCorrectionLevel:"+r;for(var n,o,i=e.length/3,a=[],u=0;u>>7-t%8&1)},put:function(t,r){for(var e=0;e>>r-e-1&1))},getLengthInBits:function(){return n},putBit:function(t){var r=Math.floor(n/8);e.length<=r&&e.push(0),t&&(e[r]|=128>>>n%8),n+=1}};return o},C=function(t){var r=a,n=t,t={getMode:function(){return r},getLength:function(t){return n.length},write:function(t){for(var r=n,e=0;e+2>>8&255)+(255&n),13),e+=2}if(e>>8)},writeBytes:function(t,r,e){r=r||0,e=e||t.length;for(var n=0;n=e.length){if(0==i)return-1;throw"unexpected end of file./"+i}var t=e.charAt(n);if(n+=1,"="==t)return i=0,-1;t.match(/^\s$/)||(o=o<<6|a(t.charCodeAt(0)),i+=6)}var r=o>>>i-8&255;return i-=8,r}},a=function(t){if(65<=t&&t<=90)return t-65;if(97<=t&&t<=122)return t-97+26;if(48<=t&&t<=57)return t-48+52;if(43==t)return 62;if(47==t)return 63;throw"c:"+t};return t},D=function(t,r,e){for(var n=j(t,r),o=0;o{for(var r=new Array(t),e=0;e>e&1);s[Math.floor(e/3)][e%3+g-8-3]=n}for(e=0;e<18;e+=1){n=!t&&1==(r>>e&1);s[e%3+g-8-3][Math.floor(e/3)]=n}},v=function(t,r){for(var r=c<<3|r,e=x.getBCHTypeInfo(r),n=0;n<15;n+=1){var o=!t&&1==(e>>n&1);n<6?s[n][8]=o:n<8?s[n+1][8]=o:s[g-15+n][8]=o}for(n=0;n<15;n+=1){o=!t&&1==(e>>n&1);n<8?s[8][g-n-1]=o:n<9?s[8][15-n-1+1]=o:s[8][15-n-1]=o}s[g-8][8]=!t},p=function(t,r){for(var e=-1,n=g-1,o=7,i=0,a=x.getMaskFunction(r),u=g-1;0>>o&1)),l=a(n,u-c),s[n][u-c]=f=l?!f:f,-1==--o)&&(i+=1,o=7);if((n+=e)<0||g<=n){n-=e,e=-e;break}}},w=function(t,r){for(var e=0,n=0,o=0,i=new Array(r.length),a=new Array(r.length),u=0;u8*u)throw"code length overflow. ("+o.getLengthInBits()+">"+8*u+")";for(o.getLengthInBits()+4<=8*u&&o.put(0,4);o.getLengthInBits()%8!=0;)o.putBit(!1);for(;;){if(o.getLengthInBits()>=8*u)break;if(o.put(f,8),o.getLengthInBits()>=8*u)break;o.put(l,8)}return w(o,n)},y=(A.addData=function(t,r){var e=null;switch(r=r||"Byte"){case"Numeric":e=C(t);break;case"Alphanumeric":e=M(t);break;case"Byte":e=S(t);break;case"Kanji":e=L(t);break;default:throw"mode:"+r}h.push(e),n=null},A.isDark=function(t,r){if(t<0||g<=t||r<0||g<=r)throw t+","+r;return s[t][r]},A.getModuleCount=function(){return g},A.make=function(){if(u<1){for(var t=1;t<40;t++){for(var r=b.getRSBlocks(t,c),e=B(),n=0;n{for(var t=0,r=0,e=0;e<8;e+=1){a(!0,e);var n=x.getLostPoint(A);(0==e||n'+"",n=0;n";for(var o=0;o';e+=""}return e=e+""+""},A.createSvgTag=function(t,r,e,n){for(var o,i,a={},u=("object"==typeof arguments[0]&&(t=(a=arguments[0]).cellSize,r=a.margin,e=a.alt,n=a.title),t=t||2,r=void 0===r?4*t:r,(e="string"==typeof e?{text:e}:e||{}).text=e.text||null,e.id=e.text?e.id||"qrcode-description":null,(n="string"==typeof n?{text:n}:n||{}).text=n.text||null,n.id=n.text?n.id||"qrcode-title":null,A.getModuleCount()*t+2*r),f="l"+t+",0 0,"+t+" -"+t+",0 0,-"+t+"z ",l=(l=(l=(l=(l=(l=(l="")+'")+(n.text?''+y(n.text)+"":""))+(e.text?''+y(e.text)+"":""))+''+''+""},A.createDataURL=function(e,t){e=e||2,t=void 0===t?4*e:t;var r=A.getModuleCount()*e+2*t,n=t,o=r-t;return D(r,r,function(t,r){return n<=t&&t":r+=">";break;case"&":r+="&";break;case'"':r+=""";break;default:r+=n}}return r});return A.createASCII=function(t,r){if((t=t||1)<2){var e=r;e=void 0===e?2:e;for(var n,o,i,a,u=+A.getModuleCount()+2*e,f=e,l=u-e,c={"██":"█","█ ":"▀"," █":"▄"," ":" "},s={"██":"▀","█ ":"▀"," █":" "," ":" "},g="",h=0;h>>=1;return r}function _(n,o){if(void 0===n.length)throw n.length+"/"+o;var r=(()=>{for(var t=0;t{if(!(t<0)){if(t<26)return 65+t;if(t<52)return t-26+97;if(t<62)return t-52+48;if(62==t)return 43;if(63==t)return 47}throw"n:"+t})(63&t))}var n=0,o=0,i=0,a="",t={writeByte:function(t){for(n=n<<8|255&t,o+=8,i+=1;6<=o;)e(n>>>o-6),o-=6},flush:function(){if(0>>r!=0)throw"length over";for(;8<=u+r;)a.writeByte(255&(t<>>=8-u,u=f=0;f|=t<>6,128|63&o):o<55296||57344<=o?e.push(224|o>>12,128|o>>6&63,128|63&o):(n++,o=65536+((1023&o)<<10|1023&r.charCodeAt(n)),e.push(240|o>>18,128|o>>12&63,128|o>>6&63,128|63&o))}return e},void 0!==(r="function"==typeof(w=function(){return A})?w.apply(r,[]):w)&&(t.exports=r)},(t,r,e)=>{var a=e(5),l=e(6),u=e(7),f=function(t,r){r.back&&(t.fillStyle=r.back,t.fillRect(0,0,r.size,r.size))},c=function(t,r,e,n,o,i){t.is_dark(o,i)&&r.rect(i*n,o*n,n,n)},s=function(t,r,e){if(t){var n=0{function e(t,r){return t.getAttribute(r)}function n(r,e){return Object.keys(e||{}).forEach(function(t){r.setAttribute(t,e[t])}),r}function o(t,r){return n(i.createElement(t),r)}var r=window,i=r.document,a="http://www.w3.org/2000/svg";t.exports={dpr:r.devicePixelRatio||1,SVG_NS:a,get_attr:e,create_el:o,create_svg_el:function(t,r){return n(i.createElementNS(a,t),r)},create_canvas:function(t,r){r=o("canvas",{width:t*r,height:t*r});return r.style.width="".concat(t,"px"),r.style.height="".concat(t,"px"),r},canvas_to_img:function(t){var r=o("img",{crossOrigin:"anonymous",src:t.toDataURL("image/png"),width:e(t,"width"),height:e(t,"height")});return r.style.width=t.style.width,r.style.height=t.style.height,r}}},t=>{t.exports=function(t,r,e,n,o,i){var a,u,f,l,c,s,g,h,d=i*n,v=o*n,p=d+n,w=v+n,e=.005*e.rounded*n,n=t.is_dark,t=o-1,m=o+1,y=i-1,k=i+1,x=n(o,i),b=n(t,y),B=n(t,i),t=n(t,k),C=n(o,k),k=n(m,k),i=n(m,i),m=n(m,y),n=n(o,y),o=(a=r,{m:function(t,r){return a.moveTo(t,r),this},l:function(t,r){return a.lineTo(t,r),this},a:function(){return a.arcTo.apply(a,arguments),this}});x?(y=o,r=d,x=v,u=p,f=w,l=e,s=!B&&!C,g=!i&&!C,h=!i&&!n,(c=!B&&!n)?y.m(r+l,x):y.m(r,x),s?y.l(u-l,x).a(u,x,u,f,l):y.l(u,x),g?y.l(u,f-l).a(u,f,r,f,l):y.l(u,f),h?y.l(r+l,f).a(r,f,r,x,l):y.l(r,f),c?y.l(r,x+l).a(r,x,u,x,l):y.l(r,x)):(s=o,g=d,h=v,f=p,c=w,u=e,l=B&&C&&t,y=i&&C&&k,r=i&&n&&m,B&&n&&b&&s.m(g+u,h).l(g,h).l(g,h+u).a(g,h,g+u,h,u),l&&s.m(f-u,h).l(f,h).l(f,h+u).a(f,h,f-u,h,u),y&&s.m(f-u,c).l(f,c).l(f,c-u).a(f,c,f-u,c,u),r&&s.m(g+u,c).l(g,c).l(g,c-u).a(g,c,g+u,c,u))}},t=>{t.exports=function(t,r){var e,n,o,i,a,u=r.mode;"label"===u?(e=t,o=(n=r).size,i="bold "+.01*n.mSize*o+"px "+n.fontname,e.strokeStyle=n.back,e.lineWidth=.01*n.mSize*o*.1,e.fillStyle=n.fontcolor,e.font=i,i=e.measureText(n.label).width,a=.01*n.mSize,i=(1-i/o)*n.mPosX*.01*o,a=(1-a)*n.mPosY*.01*o+.75*n.mSize*.01*o,e.strokeText(n.label,i,a),e.fillText(n.label,i,a)):"image"===u&&(o=r.size,e=r.image.naturalWidth||1,n=r.image.naturalHeight||1,e=(i=.01*r.mSize)*e/n,t.drawImage(r.image,(1-e)*r.mPosX*.01*o,(1-i)*r.mPosY*.01*o,e*o,i*o))}},(t,r,c)=>{var e=c(5),s=e.SVG_NS,g=e.get_attr,h=e.create_svg_el,d=function(n){function o(t){return Math.round(10*t)/10}function i(t){return Math.round(10*t)/10+n.o}return{m:function(t,r){return n.p+="M ".concat(i(t)," ").concat(i(r)," "),this},l:function(t,r){return n.p+="L ".concat(i(t)," ").concat(i(r)," "),this},a:function(t,r,e){return n.p+="A ".concat(o(e)," ").concat(o(e)," 0 0 1 ").concat(i(t)," ").concat(i(r)," "),this}}},w=function(t,r,e,n,o,i,a,u,f,l){a?t.m(r+i,e):t.m(r,e),u?t.l(n-i,e).a(n,e+i,i):t.l(n,e),f?t.l(n,o-i).a(n-i,o,i):t.l(n,o),l?t.l(r+i,o).a(r,o-i,i):t.l(r,o),a?t.l(r,e+i).a(r+i,e,i):t.l(r,e)},m=function(t,r,e,n,o,i,a,u,f,l){a&&t.m(r+i,e).l(r,e).l(r,e+i).a(r+i,e,i),u&&t.m(n,e+i).l(n,e).l(n-i,e).a(n,e+i,i),f&&t.m(n-i,o).l(n,o).l(n,o-i).a(n-i,o,i),l&&t.m(r,o-i).l(r,o).l(r+i,o).a(r,o-i,i)},v=function(t,r,e,n,o,i){var a=i*n,u=o*n,f=a+n,l=u+n,e=.005*e.rounded*n,n=t.is_dark,t=o-1,c=o+1,s=i-1,g=i+1,h=n(o,i),d=n(t,s),v=n(t,i),t=n(t,g),p=n(o,g),g=n(c,g),i=n(c,i),c=n(c,s),n=n(o,s);h?w(r,a,u,f,l,e,!v&&!n,!v&&!p,!i&&!p,!i&&!n):m(r,a,u,f,l,e,v&&n&&d,v&&p&&t,i&&p&&g,i&&n&&c)};t.exports=function(t,r){var e,n,o,i,a,u=r.size,f=r.mode,l=h("svg",{xmlns:s,width:u,height:u,viewBox:"0 0 ".concat(u," ").concat(u)});return l.style.width="".concat(u,"px"),l.style.height="".concat(u,"px"),r.back&&l.appendChild(h("rect",{x:0,y:0,width:u,height:u,fill:r.back})),l.appendChild(h("path",{d:((t,r)=>{if(!t)return"";for(var e={p:"",o:0},n=t.module_count,o=r.size/n,i=(r.crisp&&(o=Math.floor(o),e.o=Math.floor((r.size-o*n)/2)),d(e)),a=0;a>e&1);l[Math.floor(e/3)][e%3+s-8-3]=n}for(e=0;e<18;e+=1){n=!t&&1==(r>>e&1);l[e%3+s-8-3][Math.floor(e/3)]=n}},d=function(t,r){for(var e=f<<3|r,n=m.getBCHTypeInfo(e),o=0;o<15;o+=1){var i=!t&&1==(n>>o&1);o<6?l[o][8]=i:o<8?l[o+1][8]=i:l[s-15+o][8]=i}for(o=0;o<15;o+=1){i=!t&&1==(n>>o&1);o<8?l[8][s-o-1]=i:o<9?l[8][15-o-1+1]=i:l[8][15-o-1]=i}l[s-8][8]=!t},v=function(t,r){for(var e=-1,n=s-1,o=7,i=0,a=m.getMaskFunction(r),u=s-1;0>>o&1)),a(n,u-c)&&(f=!f),l[n][u-c]=f,-1==--o&&(i+=1,o=7))}if((n+=e)<0||s<=n){n-=e,e=-e;break}}},p=function(t,r,e){for(var n=S.getRSBlocks(t,r),o=M(),i=0;i8*u)throw"code length overflow. ("+o.getLengthInBits()+">"+8*u+")";for(o.getLengthInBits()+4<=8*u&&o.put(0,4);o.getLengthInBits()%8!=0;)o.putBit(!1);for(;!(o.getLengthInBits()>=8*u||(o.put(236,8),o.getLengthInBits()>=8*u));)o.put(17,8);return function(t,r){for(var e=0,n=0,o=0,i=new Array(r.length),a=new Array(r.length),u=0;u',e+="";for(var n=0;n";for(var o=0;o';e+=""}return e+="",e+=""},h.createSvgTag=function(t,r,e,n){var o={};"object"==typeof arguments[0]&&(t=(o=arguments[0]).cellSize,r=o.margin,e=o.alt,n=o.title),t=t||2,r=void 0===r?4*t:r,(e="string"==typeof e?{text:e}:e||{}).text=e.text||null,e.id=e.text?e.id||"qrcode-description":null,(n="string"==typeof n?{text:n}:n||{}).text=n.text||null,n.id=n.text?n.id||"qrcode-title":null;var i,a,u,f=h.getModuleCount()*t+2*r,c="",l="l"+t+",0 0,"+t+" -"+t+",0 0,-"+t+"z ";for(c+=''+y(n.text)+"":"",c+=e.text?''+y(e.text)+"":"",c+='',c+='":r+=">";break;case"&":r+="&";break;case'"':r+=""";break;default:r+=n}}return r};return h.createASCII=function(t,r){if((t=t||1)<2)return function(t){t=void 0===t?2:t;for(var r,e,n,o,i=+h.getModuleCount()+2*t,a=t,u=i-t,f={"██":"█","█ ":"▀"," █":"▄"," ":" "},c={"██":"▀","█ ":"▀"," █":" "," ":" "},l="",s=0;s>>8),r.push(255&n)):r.push(a)}return r}};var r,t,a=1,u=2,o=4,f=8,w={L:1,M:0,Q:3,H:2},e=0,n=1,c=2,l=3,s=4,g=5,h=6,d=7,m=(r=[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],(t={}).getBCHTypeInfo=function(t){for(var r=t<<10;0<=v(r)-v(1335);)r^=1335<>>=1;return r}var p=function(){for(var r=new Array(256),e=new Array(256),t=0;t<8;t+=1)r[t]=1<>>8)},writeBytes:function(t,r,e){r=r||0,e=e||t.length;for(var n=0;n>>o-6),o-=6},t.flush=function(){if(0>>r!=0)throw"length over";for(;8<=u+r;)a.writeByte(255&(t<>>=8-u,u=f=0;f|=t<>>7-t%8&1)},put:function(t,r){for(var e=0;e>>r-e-1&1))},getLengthInBits:function(){return n},putBit:function(t){var r=Math.floor(n/8);e.length<=r&&e.push(0),t&&(e[r]|=128>>>n%8),n+=1}};return o},A=function(t){var r=a,n=t,e={getMode:function(){return r},getLength:function(t){return n.length},write:function(t){for(var r=n,e=0;e+2>>8&255)+(255&n),t.put(n,13),e+=2}if(e=e.length){if(0==i)return-1;throw"unexpected end of file./"+i}var t=e.charAt(n);if(n+=1,"="==t)return i=0,-1;t.match(/^\s$/)||(o=o<<6|a(t.charCodeAt(0)),i+=6)}var r=o>>>i-8&255;return i-=8,r}},a=function(t){if(65<=t&&t<=90)return t-65;if(97<=t&&t<=122)return t-97+26;if(48<=t&&t<=57)return t-48+52;if(43==t)return 62;if(47==t)return 63;throw"c:"+t};return r},P=function(t,r,e){for(var n=k(t,r),o=0;o>6,128|63&n):n<55296||57344<=n?r.push(224|n>>12,128|n>>6&63,128|63&n):(e++,n=65536+((1023&n)<<10|1023&t.charCodeAt(e)),r.push(240|n>>18,128|n>>12&63,128|n>>6&63,128|63&n))}return r}(t)},o=[],void 0===(i="function"==typeof(n=function(){return a})?n.apply(r,o):n)||(t.exports=i)},function(t,r,e){function c(t,r,e,n,o,i){t.is_dark(o,i)&&r.rect(i*n,o*n,n,n)}function a(t,r,e){var n,o;n=r,(o=e).back&&(n.fillStyle=o.back,n.fillRect(0,0,o.size,o.size)),function(t,r,e){if(t){var n=0 {}'); - } catch (e) { - if (e instanceof SyntaxError) { - return true; - } else { - throw e; // throws CSP error - } - } - return false; } @@ -238,7 +225,7 @@ { return init; }; - + /** * returns the current status of the check * @@ -250,7 +237,7 @@ { return status; }; - + /** * init on application start, returns an all-clear signal * @@ -259,7 +246,7 @@ */ me.init = function() { - // prevent bots from viewing a paste and potentially deleting data + // prevent bots from viewing a document and potentially deleting data // when burn-after-reading is set if (isBadBot()) { showError('I love you too, bot…'); @@ -308,4 +295,4 @@ this.Legacy = { Check: Check }; -}).call(this); \ No newline at end of file +}).call(this); diff --git a/js/package-lock.json b/js/package-lock.json index ed57b711..41a4c92f 100644 --- a/js/package-lock.json +++ b/js/package-lock.json @@ -1,30 +1,152 @@ { "name": "privatebin", - "version": "1.6.2", + "version": "2.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "privatebin", - "version": "1.6.2", + "version": "2.0.0", "license": "zlib-acknowledgement", "devDependencies": { - "@peculiar/webcrypto": "^1.1.1", - "jsdom": "^9.12.0", - "jsdom-global": "^2.1.1", - "jsdom-url": "^2.2.1", + "@peculiar/webcrypto": "^1.5.0", + "jsdom": "^26.0.0", + "jsdom-global": "^3.0.2", "jsverify": "^0.8.3" } }, + "node_modules/@asamuzakjp/css-color": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-2.8.3.tgz", + "integrity": "sha512-GIc76d9UI1hCvOATjZPyHFmE5qhRccp3/zGfMPapK3jBi+yocEzp6BBB0UnfRYP9NP4FANqUZYb0hnfs3TM3hw==", + "dev": true, + "dependencies": { + "@csstools/css-calc": "^2.1.1", + "@csstools/css-color-parser": "^3.0.7", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.1.tgz", + "integrity": "sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.1.tgz", + "integrity": "sha512-rL7kaUnTkL9K+Cvo2pnCieqNpTKgQzy5f+N+5Iuko9HAoasP+xgprVh7KN/MaJVvVL1l0EzQq2MoqBHKSrDrag==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.7.tgz", + "integrity": "sha512-nkMp2mTICw32uE5NN+EsJ4f5N+IGFeCFu4bGpiKgb2Pq/7J/MpyLBeQ5ry4KKtRFZaYs6sTmcMYrSRIyj5DFKA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/color-helpers": "^5.0.1", + "@csstools/css-calc": "^2.1.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz", + "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz", + "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@peculiar/asn1-schema": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.2.0.tgz", - "integrity": "sha512-1ENEJNY7Lwlua/1wvzpYP194WtjQBfFxvde2FlzfBFh/ln6wvChrtxlORhbKEnYswzn6fOC4c7HdC5izLPMTJg==", + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.15.tgz", + "integrity": "sha512-QPeD8UA8axQREpgR5UTAfu2mqQmm97oUqahDtNdBcfj3qAnoXzFdQW+aNf/tD2WVXF8Fhmftxoj0eMIT++gX2w==", "dev": true, "dependencies": { "asn1js": "^3.0.5", - "pvtsutils": "^1.3.2", - "tslib": "^2.4.0" + "pvtsutils": "^1.3.6", + "tslib": "^2.8.1" } }, "node_modules/@peculiar/json-schema": { @@ -40,77 +162,28 @@ } }, "node_modules/@peculiar/webcrypto": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.0.tgz", - "integrity": "sha512-U58N44b2m3OuTgpmKgf0LPDOmP3bhwNz01vAnj1mBwxBASRhptWYK+M3zG+HBkDqGQM+bFsoIihTW8MdmPXEqg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.5.0.tgz", + "integrity": "sha512-BRs5XUAwiyCDQMsVA9IDvDa7UBR9gAvPHgugOeGng3YN6vJ9JYonyDc0lNczErgtCWtucjR5N7VtaonboD/ezg==", "dev": true, "dependencies": { - "@peculiar/asn1-schema": "^2.1.6", + "@peculiar/asn1-schema": "^2.3.8", "@peculiar/json-schema": "^1.1.12", - "pvtsutils": "^1.3.2", - "tslib": "^2.4.0", - "webcrypto-core": "^1.7.4" + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2", + "webcrypto-core": "^1.8.0" }, "engines": { "node": ">=10.12.0" } }, - "node_modules/abab": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz", - "integrity": "sha512-I+Wi+qiE2kUXyrRhNsWv6XsjUTBJjSoVSctKNBfLG5zG/Xe7Rjbxf13+vqYHNTwHaFU+FtSlVxOCTiMEVtPv0A==", - "dev": true - }, - "node_modules/acorn": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha512-fu2ygVGuMmlzG8ZeRJ0bvR41nsAkxxhbyk8bZ1SS521Z7vmgJFTQQlfz/Mp/nJexGBz+v8sC9bM6+lNgskt4Ug==", + "node_modules/agent-base": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", "dev": true, - "bin": { - "acorn": "bin/acorn" - }, "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-globals": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz", - "integrity": "sha512-uWttZCk96+7itPxK8xCzY86PnxKTMrReKDqrHzv42VQY0K30PUO8WY13WMOuI+cOdX4EIdzdvQ8k6jkuGRFMYw==", - "dev": true, - "dependencies": { - "acorn": "^4.0.4" - } - }, - "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, - "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/array-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha512-H3LU5RLiSsGXPhN+Nipar0iR0IofH+8r89G2y1tBKxQ/agagKyAjhkAFDRBfodP2caPrNKHpAWNIM/c9yeL7uA==", - "dev": true - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "dependencies": { - "safer-buffer": "~2.1.0" + "node": ">= 14" } }, "node_modules/asn1js": { @@ -127,57 +200,25 @@ "node": ">=12.0.0" } }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true - }, - "node_modules/bcrypt-pbkdf": { + "node_modules/call-bind-apply-helpers": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, "dependencies": { - "tweetnacl": "^0.14.3" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true - }, - "node_modules/class-proxy": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/class-proxy/-/class-proxy-1.1.2.tgz", - "integrity": "sha512-kowpC1EGn0b5ZxOMbF8f7IO03gg6dtI1rwBIHMfG5dEAeOVpZpukN9cT4K9cxv+IG8JihVdsqPr0V5bitB+pqQ==", - "dev": true - }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -190,49 +231,87 @@ "node": ">= 0.8" } }, - "node_modules/content-type-parser": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.2.tgz", - "integrity": "sha512-lM4l4CnMEwOLHAHr/P6MEZwZFPJFtAAKgL6pogbXmVZggIqXhdB6RbBtPOTsw2FcXwYhehRGERJmRrjOiIB8pQ==", - "dev": true - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true - }, - "node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, "node_modules/cssstyle": { - "version": "0.2.37", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz", - "integrity": "sha512-FUpKc+1FNBsHUr9IsfSGCovr8VuGOiiuzlgCyppKBjJi2jYTOFLN3oiiNRMIvYqbFzF38mqKj4BgcevzU5/kIA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.2.1.tgz", + "integrity": "sha512-9+vem03dMXG7gDmZ62uqmRiMRNtinIZ9ZyuF6BdxzfOD+FdN5hretzynkn0ReS2DO2GSw76RWHs0UmJPI2zUjw==", "dev": true, "dependencies": { - "cssom": "0.3.x" - } - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" + "@asamuzakjp/css-color": "^2.8.2", + "rrweb-cssom": "^0.8.0" }, "engines": { - "node": ">=0.10" + "node": ">=18" } }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls/node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dev": true, + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz", + "integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==", + "dev": true, + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "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, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", + "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", "dev": true }, "node_modules/delayed-stream": { @@ -244,305 +323,327 @@ "node": ">=0.4.0" } }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "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==", "dev": true, "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "dev": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" }, "engines": { - "node": ">=4.0" + "node": ">= 0.4" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" }, - "optionalDependencies": { - "source-map": "~0.6.1" + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "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==", "dev": true, "engines": { - "node": ">=4.0" + "node": ">= 0.4" } }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "node_modules/extsprintf": { + "node_modules/es-errors": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true, - "engines": [ - "node >=0.6.0" - ] - }, - "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==", - "dev": true - }, - "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 - }, - "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 - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, "engines": { - "node": "*" + "node": ">= 0.4" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", "dev": true, "dependencies": { "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { - "node": ">= 0.12" + "node": ">= 6" } }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "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==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", "dev": true, "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dev": true, - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" + "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": ">=6" + "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==", + "dev": true, + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/html-encoding-sniffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", - "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", "dev": true, "dependencies": { - "whatwg-encoding": "^1.0.1" - } - }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "whatwg-encoding": "^3.1.1" }, "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" + "node": ">=18" + } + }, + "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==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "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==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" } }, "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==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true }, "node_modules/jsdom": { - "version": "9.12.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-9.12.0.tgz", - "integrity": "sha512-Qw4oqNxo4LyzkSqVIyCnEltTc4xV3g1GBaI88AvYTesWzmWHUSoMNmhBjUBa+6ldXIBJS9xoeLNJPfUAykTyxw==", + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.0.0.tgz", + "integrity": "sha512-BZYDGVAIriBWTpIxYzrXjv3E/4u8+/pSG5bQdIYCbNCGOvsPkDQfTVLAIXAf9ETdCpduCVTkDe2NNZ8NIwUVzw==", "dev": true, "dependencies": { - "abab": "^1.0.3", - "acorn": "^4.0.4", - "acorn-globals": "^3.1.0", - "array-equal": "^1.0.0", - "content-type-parser": "^1.0.1", - "cssom": ">= 0.3.2 < 0.4.0", - "cssstyle": ">= 0.2.37 < 0.3.0", - "escodegen": "^1.6.1", - "html-encoding-sniffer": "^1.0.1", - "nwmatcher": ">= 1.3.9 < 2.0.0", - "parse5": "^1.5.1", - "request": "^2.79.0", - "sax": "^1.2.1", - "symbol-tree": "^3.2.1", - "tough-cookie": "^2.3.2", - "webidl-conversions": "^4.0.0", - "whatwg-encoding": "^1.0.1", - "whatwg-url": "^4.3.0", - "xml-name-validator": "^2.0.1" + "cssstyle": "^4.2.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.1", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.16", + "parse5": "^7.2.1", + "rrweb-cssom": "^0.8.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.0.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.1.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } } }, "node_modules/jsdom-global": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/jsdom-global/-/jsdom-global-2.1.1.tgz", - "integrity": "sha512-nVZiKQhXZzmkFSF+AfpvErIYuzPEuBV684gYpWagtwWTLiy0p5EgQbP7gmNNA6/qxFb8l1E5w1NjES5nSBCw5A==", - "dev": true - }, - "node_modules/jsdom-url": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/jsdom-url/-/jsdom-url-2.2.1.tgz", - "integrity": "sha512-+wha7QGq/vPR97R/wz5+213pyWP1362/xmAMmesyVgxyTFOfAeKtwPah+f2znabdNdcqOPbyM7j/xWHbXAqhmg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsdom-global/-/jsdom-global-3.0.2.tgz", + "integrity": "sha512-t1KMcBkz/pT5JrvcJbpUR2u/w1kO9jXctaaGJ0vZDzwFnIvGWw9IDSRciT83kIs8Bnw4qpOl8bQK08V01YgMPg==", "dev": true, - "dependencies": { - "class-proxy": "^1.1.1", - "whatwg-url": "^7.0.0" + "peerDependencies": { + "jsdom": ">=10.0.0" } }, - "node_modules/jsdom-url/node_modules/tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "node_modules/jsdom/node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", "dev": true, "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/jsdom-url/node_modules/whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dev": true, - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true - }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dev": true, - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" + "punycode": "^2.3.1" }, "engines": { - "node": ">=0.6.0" + "node": ">=18" + } + }, + "node_modules/jsdom/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/jsdom/node_modules/whatwg-url": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz", + "integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==", + "dev": true, + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" } }, "node_modules/jsverify": { @@ -569,25 +670,21 @@ "node": ">= 0.10.0" } }, - "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true }, + "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==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -609,81 +706,46 @@ "node": ">= 0.6" } }, - "node_modules/nwmatcher": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.4.tgz", - "integrity": "sha512-3iuY4N5dhgMpCUrOVnuAdGrgxVqV2cJpM+XNccjR2DKOB1RUP0aA+wGXEiNziG/UKboFyGBIoKOaNlJxx8bciQ==", + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } + "node_modules/nwsapi": { + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.16.tgz", + "integrity": "sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==", + "dev": true }, "node_modules/parse5": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz", - "integrity": "sha512-w2jx/0tJzvgKwZa58sj2vAYq/S/K1QJfIB3cWYea/Iu1scFPDQQ3IQiVZTHWtRBwAjv2Yd7S/xeZf3XqLDb3bA==", - "dev": true - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true - }, - "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", "dev": true, - "engines": { - "node": ">= 0.8.0" + "dependencies": { + "entities": "^4.5.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" } }, "node_modules/pvtsutils": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.2.tgz", - "integrity": "sha512-+Ipe2iNUyrZz+8K/2IOo+kKikdtfhRKzNpQbruF2URmqPtoqAs8g3xS7TJvFF2GcPXjh7DkqMnpVveRFq4PgEQ==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", "dev": true, "dependencies": { - "tslib": "^2.4.0" + "tslib": "^2.8.1" } }, "node_modules/pvutils": { @@ -695,15 +757,6 @@ "node": ">=6.0.0" } }, - "node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, "node_modules/rc4": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/rc4/-/rc4-0.1.5.tgz", @@ -713,57 +766,11 @@ "node": ">=0.10.0" } }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dev": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "dev": true }, "node_modules/safer-buffer": { "version": "2.1.2", @@ -771,45 +778,16 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dev": true, "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" + "xmlchars": "^2.2.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=v12.22.7" } }, "node_modules/symbol-tree": { @@ -818,25 +796,36 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, - "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "node_modules/tldts": { + "version": "6.1.77", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.77.tgz", + "integrity": "sha512-lBpoWgy+kYmuXWQ83+R7LlJCnsd9YW8DGpZSHhrMl4b8Ly/1vzOie3OdtmUJDkKxcgRGOehDu5btKkty+JEe+g==", "dev": true, "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "tldts-core": "^6.1.77" }, - "engines": { - "node": ">=0.8" + "bin": { + "tldts": "bin/cli.js" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "node_modules/tldts-core": { + "version": "6.1.77", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.77.tgz", + "integrity": "sha512-bCaqm24FPk8OgBkM0u/SrEWJgHnhBWYqeBo6yUmcZJDCHt/IfyWBb+14CXdGi4RInMv4v7eUAin15W0DoA+Ytg==", "dev": true }, + "node_modules/tough-cookie": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.1.tgz", + "integrity": "sha512-Ek7HndSVkp10hmHP9V4qZO1u+pn1RU5sI0Fw+jCU3lyvuMZcgqsNgc6CmJJZyByK4Vm/qotGRJlfgAX8q+4JiA==", + "dev": true, + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/trampa": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trampa/-/trampa-1.0.1.tgz", @@ -844,41 +833,11 @@ "dev": true }, "node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/typify-parser": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/typify-parser/-/typify-parser-1.1.0.tgz", @@ -888,109 +847,148 @@ "node": ">= 0.10.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==", + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", "dev": true, "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" } }, "node_modules/webcrypto-core": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.5.tgz", - "integrity": "sha512-gaExY2/3EHQlRNNNVSrbG2Cg94Rutl7fAaKILS1w8ZDhGxdFOaw6EbCfHIxPy9vt/xwp5o0VQAx9aySPF6hU1A==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.8.1.tgz", + "integrity": "sha512-P+x1MvlNCXlKbLSOY4cYrdreqPG5hbzkmawbcXLKN/mf6DZW0SdNNkZ+sjwsqVkI4A4Ko2sPZmkZtCKY58w83A==", "dev": true, "dependencies": { - "@peculiar/asn1-schema": "^2.1.6", + "@peculiar/asn1-schema": "^2.3.13", "@peculiar/json-schema": "^1.1.12", - "asn1js": "^3.0.1", - "pvtsutils": "^1.3.2", - "tslib": "^2.4.0" + "asn1js": "^3.0.5", + "pvtsutils": "^1.3.5", + "tslib": "^2.7.0" } }, - "node_modules/webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, "node_modules/whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", "dev": true, "dependencies": { - "iconv-lite": "0.4.24" + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" } }, - "node_modules/whatwg-url": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-4.8.0.tgz", - "integrity": "sha512-nUvUPuenPFtPfy/X+dAYh/TfRbTBlnXTM5iIfLseJFkkQewmpG9pGR6i87E9qL+lZaJzv+99kkQWoGOtLfkZQQ==", - "dev": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/whatwg-url/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - }, - "node_modules/word-wrap": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", - "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=18" + } + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, "node_modules/xml-name-validator": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz", - "integrity": "sha512-jRKe/iQYMyVJpzPH+3HL97Lgu5HrCfii+qSo+TfjKHtOnvbnvdVfMYrn9Q34YV81M2e5sviJlI6Ko9y+nByzvA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true } }, "dependencies": { + "@asamuzakjp/css-color": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-2.8.3.tgz", + "integrity": "sha512-GIc76d9UI1hCvOATjZPyHFmE5qhRccp3/zGfMPapK3jBi+yocEzp6BBB0UnfRYP9NP4FANqUZYb0hnfs3TM3hw==", + "dev": true, + "requires": { + "@csstools/css-calc": "^2.1.1", + "@csstools/css-color-parser": "^3.0.7", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "@csstools/color-helpers": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.1.tgz", + "integrity": "sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA==", + "dev": true + }, + "@csstools/css-calc": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.1.tgz", + "integrity": "sha512-rL7kaUnTkL9K+Cvo2pnCieqNpTKgQzy5f+N+5Iuko9HAoasP+xgprVh7KN/MaJVvVL1l0EzQq2MoqBHKSrDrag==", + "dev": true, + "requires": {} + }, + "@csstools/css-color-parser": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.7.tgz", + "integrity": "sha512-nkMp2mTICw32uE5NN+EsJ4f5N+IGFeCFu4bGpiKgb2Pq/7J/MpyLBeQ5ry4KKtRFZaYs6sTmcMYrSRIyj5DFKA==", + "dev": true, + "requires": { + "@csstools/color-helpers": "^5.0.1", + "@csstools/css-calc": "^2.1.1" + } + }, + "@csstools/css-parser-algorithms": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz", + "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==", + "dev": true, + "requires": {} + }, + "@csstools/css-tokenizer": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz", + "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==", + "dev": true + }, "@peculiar/asn1-schema": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.2.0.tgz", - "integrity": "sha512-1ENEJNY7Lwlua/1wvzpYP194WtjQBfFxvde2FlzfBFh/ln6wvChrtxlORhbKEnYswzn6fOC4c7HdC5izLPMTJg==", + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.15.tgz", + "integrity": "sha512-QPeD8UA8axQREpgR5UTAfu2mqQmm97oUqahDtNdBcfj3qAnoXzFdQW+aNf/tD2WVXF8Fhmftxoj0eMIT++gX2w==", "dev": true, "requires": { "asn1js": "^3.0.5", - "pvtsutils": "^1.3.2", - "tslib": "^2.4.0" + "pvtsutils": "^1.3.6", + "tslib": "^2.8.1" } }, "@peculiar/json-schema": { @@ -1003,66 +1001,24 @@ } }, "@peculiar/webcrypto": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.0.tgz", - "integrity": "sha512-U58N44b2m3OuTgpmKgf0LPDOmP3bhwNz01vAnj1mBwxBASRhptWYK+M3zG+HBkDqGQM+bFsoIihTW8MdmPXEqg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.5.0.tgz", + "integrity": "sha512-BRs5XUAwiyCDQMsVA9IDvDa7UBR9gAvPHgugOeGng3YN6vJ9JYonyDc0lNczErgtCWtucjR5N7VtaonboD/ezg==", "dev": true, "requires": { - "@peculiar/asn1-schema": "^2.1.6", + "@peculiar/asn1-schema": "^2.3.8", "@peculiar/json-schema": "^1.1.12", - "pvtsutils": "^1.3.2", - "tslib": "^2.4.0", - "webcrypto-core": "^1.7.4" + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2", + "webcrypto-core": "^1.8.0" } }, - "abab": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz", - "integrity": "sha512-I+Wi+qiE2kUXyrRhNsWv6XsjUTBJjSoVSctKNBfLG5zG/Xe7Rjbxf13+vqYHNTwHaFU+FtSlVxOCTiMEVtPv0A==", + "agent-base": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", "dev": true }, - "acorn": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha512-fu2ygVGuMmlzG8ZeRJ0bvR41nsAkxxhbyk8bZ1SS521Z7vmgJFTQQlfz/Mp/nJexGBz+v8sC9bM6+lNgskt4Ug==", - "dev": true - }, - "acorn-globals": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz", - "integrity": "sha512-uWttZCk96+7itPxK8xCzY86PnxKTMrReKDqrHzv42VQY0K30PUO8WY13WMOuI+cOdX4EIdzdvQ8k6jkuGRFMYw==", - "dev": true, - "requires": { - "acorn": "^4.0.4" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "array-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha512-H3LU5RLiSsGXPhN+Nipar0iR0IofH+8r89G2y1tBKxQ/agagKyAjhkAFDRBfodP2caPrNKHpAWNIM/c9yeL7uA==", - "dev": true - }, - "asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, "asn1js": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", @@ -1074,51 +1030,22 @@ "tslib": "^2.4.0" } }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true - }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true - }, - "aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true - }, - "bcrypt-pbkdf": { + "call-bind-apply-helpers": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, "requires": { - "tweetnacl": "^0.14.3" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" } }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true - }, - "class-proxy": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/class-proxy/-/class-proxy-1.1.2.tgz", - "integrity": "sha512-kowpC1EGn0b5ZxOMbF8f7IO03gg6dtI1rwBIHMfG5dEAeOVpZpukN9cT4K9cxv+IG8JihVdsqPr0V5bitB+pqQ==", - "dev": true - }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -1128,46 +1055,66 @@ "delayed-stream": "~1.0.0" } }, - "content-type-parser": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.2.tgz", - "integrity": "sha512-lM4l4CnMEwOLHAHr/P6MEZwZFPJFtAAKgL6pogbXmVZggIqXhdB6RbBtPOTsw2FcXwYhehRGERJmRrjOiIB8pQ==", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true - }, - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, "cssstyle": { - "version": "0.2.37", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz", - "integrity": "sha512-FUpKc+1FNBsHUr9IsfSGCovr8VuGOiiuzlgCyppKBjJi2jYTOFLN3oiiNRMIvYqbFzF38mqKj4BgcevzU5/kIA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.2.1.tgz", + "integrity": "sha512-9+vem03dMXG7gDmZ62uqmRiMRNtinIZ9ZyuF6BdxzfOD+FdN5hretzynkn0ReS2DO2GSw76RWHs0UmJPI2zUjw==", "dev": true, "requires": { - "cssom": "0.3.x" + "@asamuzakjp/css-color": "^2.8.2", + "rrweb-cssom": "^0.8.0" } }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", "dev": true, "requires": { - "assert-plus": "^1.0.0" + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "dependencies": { + "tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dev": true, + "requires": { + "punycode": "^2.3.1" + } + }, + "webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true + }, + "whatwg-url": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz", + "integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==", + "dev": true, + "requires": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + } + } } }, - "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==", + "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, + "requires": { + "ms": "^2.1.3" + } + }, + "decimal.js": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", + "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", "dev": true }, "delayed-stream": { @@ -1176,260 +1123,239 @@ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "dev": true, "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" } }, - "escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "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==", "dev": true }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extsprintf": { + "es-errors": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "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==", + "dev": true, + "requires": { + "es-errors": "^1.3.0" + } }, - "fast-json-stable-stringify": { + "es-set-tostringtag": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "requires": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + } }, "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", "dev": true, "requires": { "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" + "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" + } + }, + "get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "requires": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + } + }, + "gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true + }, + "has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true + }, + "has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.3" + } + }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" } }, "html-encoding-sniffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", - "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", "dev": true, "requires": { - "whatwg-encoding": "^1.0.1" + "whatwg-encoding": "^3.1.1" } }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "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==", "dev": true, "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, + "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==", + "dev": true, + "requires": { + "agent-base": "^7.1.2", + "debug": "4" } }, "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" } }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true }, "jsdom": { - "version": "9.12.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-9.12.0.tgz", - "integrity": "sha512-Qw4oqNxo4LyzkSqVIyCnEltTc4xV3g1GBaI88AvYTesWzmWHUSoMNmhBjUBa+6ldXIBJS9xoeLNJPfUAykTyxw==", + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.0.0.tgz", + "integrity": "sha512-BZYDGVAIriBWTpIxYzrXjv3E/4u8+/pSG5bQdIYCbNCGOvsPkDQfTVLAIXAf9ETdCpduCVTkDe2NNZ8NIwUVzw==", "dev": true, "requires": { - "abab": "^1.0.3", - "acorn": "^4.0.4", - "acorn-globals": "^3.1.0", - "array-equal": "^1.0.0", - "content-type-parser": "^1.0.1", - "cssom": ">= 0.3.2 < 0.4.0", - "cssstyle": ">= 0.2.37 < 0.3.0", - "escodegen": "^1.6.1", - "html-encoding-sniffer": "^1.0.1", - "nwmatcher": ">= 1.3.9 < 2.0.0", - "parse5": "^1.5.1", - "request": "^2.79.0", - "sax": "^1.2.1", - "symbol-tree": "^3.2.1", - "tough-cookie": "^2.3.2", - "webidl-conversions": "^4.0.0", - "whatwg-encoding": "^1.0.1", - "whatwg-url": "^4.3.0", - "xml-name-validator": "^2.0.1" - } - }, - "jsdom-global": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/jsdom-global/-/jsdom-global-2.1.1.tgz", - "integrity": "sha512-nVZiKQhXZzmkFSF+AfpvErIYuzPEuBV684gYpWagtwWTLiy0p5EgQbP7gmNNA6/qxFb8l1E5w1NjES5nSBCw5A==", - "dev": true - }, - "jsdom-url": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/jsdom-url/-/jsdom-url-2.2.1.tgz", - "integrity": "sha512-+wha7QGq/vPR97R/wz5+213pyWP1362/xmAMmesyVgxyTFOfAeKtwPah+f2znabdNdcqOPbyM7j/xWHbXAqhmg==", - "dev": true, - "requires": { - "class-proxy": "^1.1.1", - "whatwg-url": "^7.0.0" + "cssstyle": "^4.2.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.1", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.16", + "parse5": "^7.2.1", + "rrweb-cssom": "^0.8.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.0.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.1.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" }, "dependencies": { "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", "dev": true, "requires": { - "punycode": "^2.1.0" + "punycode": "^2.3.1" } }, + "webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true + }, "whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz", + "integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==", "dev": true, "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" } } } }, - "json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true - }, - "jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "jsdom-global": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsdom-global/-/jsdom-global-3.0.2.tgz", + "integrity": "sha512-t1KMcBkz/pT5JrvcJbpUR2u/w1kO9jXctaaGJ0vZDzwFnIvGWw9IDSRciT83kIs8Bnw4qpOl8bQK08V01YgMPg==", "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } + "requires": {} }, "jsverify": { "version": "0.8.4", @@ -1449,20 +1375,16 @@ "integrity": "sha512-AQ4vRcnULa7FX6R6YTAjKQAE1MuEThidVQm0TEtTpedaBpnOwid5k6go16E5NDkafel1xAsZL73WkwdG03IzhA==", "dev": true }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } + "lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", + "math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "dev": true }, "mime-db": { @@ -1480,69 +1402,40 @@ "mime-db": "1.52.0" } }, - "nwmatcher": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.4.tgz", - "integrity": "sha512-3iuY4N5dhgMpCUrOVnuAdGrgxVqV2cJpM+XNccjR2DKOB1RUP0aA+wGXEiNziG/UKboFyGBIoKOaNlJxx8bciQ==", + "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 }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "nwsapi": { + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.16.tgz", + "integrity": "sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==", "dev": true }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, "parse5": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz", - "integrity": "sha512-w2jx/0tJzvgKwZa58sj2vAYq/S/K1QJfIB3cWYea/Iu1scFPDQQ3IQiVZTHWtRBwAjv2Yd7S/xeZf3XqLDb3bA==", - "dev": true - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true - }, - "psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "dev": true, + "requires": { + "entities": "^4.5.0" + } }, "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true }, "pvtsutils": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.2.tgz", - "integrity": "sha512-+Ipe2iNUyrZz+8K/2IOo+kKikdtfhRKzNpQbruF2URmqPtoqAs8g3xS7TJvFF2GcPXjh7DkqMnpVveRFq4PgEQ==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", "dev": true, "requires": { - "tslib": "^2.4.0" + "tslib": "^2.8.1" } }, "pvutils": { @@ -1551,50 +1444,16 @@ "integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==", "dev": true }, - "qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true - }, "rc4": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/rc4/-/rc4-0.1.5.tgz", "integrity": "sha512-xdDTNV90z5x5u25Oc871Xnvu7yAr4tV7Eluh0VSvrhUkry39q1k+zkz7xroqHbRq+8PiazySHJPArqifUvz9VA==", "dev": true }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, - "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==", + "rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", "dev": true }, "safer-buffer": { @@ -1603,34 +1462,13 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true - }, - "sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dev": true, "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" + "xmlchars": "^2.2.0" } }, "symbol-tree": { @@ -1639,22 +1477,30 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "tldts": { + "version": "6.1.77", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.77.tgz", + "integrity": "sha512-lBpoWgy+kYmuXWQ83+R7LlJCnsd9YW8DGpZSHhrMl4b8Ly/1vzOie3OdtmUJDkKxcgRGOehDu5btKkty+JEe+g==", "dev": true, "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "tldts-core": "^6.1.77" } }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "tldts-core": { + "version": "6.1.77", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.77.tgz", + "integrity": "sha512-bCaqm24FPk8OgBkM0u/SrEWJgHnhBWYqeBo6yUmcZJDCHt/IfyWBb+14CXdGi4RInMv4v7eUAin15W0DoA+Ytg==", "dev": true }, + "tough-cookie": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.1.tgz", + "integrity": "sha512-Ek7HndSVkp10hmHP9V4qZO1u+pn1RU5sI0Fw+jCU3lyvuMZcgqsNgc6CmJJZyByK4Vm/qotGRJlfgAX8q+4JiA==", + "dev": true, + "requires": { + "tldts": "^6.1.32" + } + }, "trampa": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trampa/-/trampa-1.0.1.tgz", @@ -1662,123 +1508,71 @@ "dev": true }, "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, "typify-parser": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/typify-parser/-/typify-parser-1.1.0.tgz", "integrity": "sha512-p5+L1sc6Al3bcStMwiZNxDh4ii4JxL+famEbSIUuOUMVoNn9Nz27AT1jL3x7poMHxqKK0UQIUAp5lGkKbyKkFA==", "dev": true }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", "dev": true, "requires": { - "punycode": "^2.1.0" - } - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "xml-name-validator": "^5.0.0" } }, "webcrypto-core": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.5.tgz", - "integrity": "sha512-gaExY2/3EHQlRNNNVSrbG2Cg94Rutl7fAaKILS1w8ZDhGxdFOaw6EbCfHIxPy9vt/xwp5o0VQAx9aySPF6hU1A==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.8.1.tgz", + "integrity": "sha512-P+x1MvlNCXlKbLSOY4cYrdreqPG5hbzkmawbcXLKN/mf6DZW0SdNNkZ+sjwsqVkI4A4Ko2sPZmkZtCKY58w83A==", "dev": true, "requires": { - "@peculiar/asn1-schema": "^2.1.6", + "@peculiar/asn1-schema": "^2.3.13", "@peculiar/json-schema": "^1.1.12", - "asn1js": "^3.0.1", - "pvtsutils": "^1.3.2", - "tslib": "^2.4.0" + "asn1js": "^3.0.5", + "pvtsutils": "^1.3.5", + "tslib": "^2.7.0" } }, - "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", "dev": true, "requires": { - "iconv-lite": "0.4.24" + "iconv-lite": "0.6.3" } }, - "whatwg-url": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-4.8.0.tgz", - "integrity": "sha512-nUvUPuenPFtPfy/X+dAYh/TfRbTBlnXTM5iIfLseJFkkQewmpG9pGR6i87E9qL+lZaJzv+99kkQWoGOtLfkZQQ==", - "dev": true, - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - }, - "dependencies": { - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - } - } - }, - "word-wrap": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", - "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", + "whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", "dev": true }, + "ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "requires": {} + }, "xml-name-validator": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz", - "integrity": "sha512-jRKe/iQYMyVJpzPH+3HL97Lgu5HrCfii+qSo+TfjKHtOnvbnvdVfMYrn9Q34YV81M2e5sviJlI6Ko9y+nByzvA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true } } diff --git a/js/package.json b/js/package.json index a0b4899b..eaa7b8b4 100644 --- a/js/package.json +++ b/js/package.json @@ -1,21 +1,20 @@ { "name": "privatebin", - "version": "1.7.1", - "description": "PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted in the browser using 256 bit AES in Galois Counter mode (GCM).", + "version": "2.0.0", + "description": "PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted in the browser using 256 bit AES in Galois Counter mode (GCM).", "main": "privatebin.js", "directories": { "test": "test" }, - "dependencies": {}, "devDependencies": { - "jsdom": "^9.12.0", - "jsdom-global": "^2.1.1", - "jsdom-url": "^2.2.1", - "jsverify": "^0.8.3", - "@peculiar/webcrypto": "^1.1.1" + "@peculiar/webcrypto": "^1.5.0", + "jsdom": "^26.0.0", + "jsdom-global": "^3.0.2", + "jsverify": "^0.8.3" }, "scripts": { - "test": "mocha" + "test": "mocha", + "ci-test": "mocha --reporter xunit --reporter-option output=mocha-results.xml" }, "repository": { "type": "git", diff --git a/js/privatebin.js b/js/privatebin.js index c3888ad6..4e765db3 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -6,12 +6,11 @@ * @see {@link https://github.com/PrivateBin/PrivateBin} * @copyright 2012 Sébastien SAUVAGE ({@link http://sebsauvage.net}) * @license {@link https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License} - * @version 1.7.1 * @name PrivateBin * @namespace */ -// global Base64, DOMPurify, FileReader, RawDeflate, history, navigator, prettyPrint, prettyPrintOne, showdown, kjua +// global Base64, DOMPurify, FileReader, baseX, bootstrap, history, navigator, prettyPrint, prettyPrintOne, showdown, kjua jQuery.fn.draghover = function() { 'use strict'; @@ -42,7 +41,7 @@ jQuery(document).ready(function() { $.PrivateBin.Controller.init(); }); -jQuery.PrivateBin = (function($, RawDeflate) { +jQuery.PrivateBin = (function($) { 'use strict'; /** @@ -59,7 +58,6 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ const purifyHtmlConfig = { ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|magnet):)/i, - SAFE_FOR_JQUERY: true, USE_PROFILES: { html: true } @@ -87,13 +85,12 @@ jQuery.PrivateBin = (function($, RawDeflate) { /** * CryptoData class * - * bundles helper functions used in both paste and comment formats + * bundles helper functions used in both document and comment formats * * @name CryptoData * @class */ function CryptoData(data) { - this.v = 1; // store all keys in the default locations for drop-in replacement for (let key in data) { this[key] = data[key]; @@ -104,18 +101,18 @@ jQuery.PrivateBin = (function($, RawDeflate) { * * @name CryptoData.getCipherData * @function - * @return {Array}|{string} + * @return {Array} */ this.getCipherData = function() { - return this.v === 1 ? this.data : [this.ct, this.adata]; + return [this.ct, this.adata]; } } /** * Paste class * - * bundles helper functions around the paste formats + * bundles helper functions around the document formats * * @name Paste * @class @@ -133,11 +130,11 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ this.getFormat = function() { - return this.v === 1 ? this.meta.formatter : this.adata[1]; + return this.adata[1]; } /** - * gets the remaining seconds before the paste expires + * gets the remaining seconds before the document expires * * returns 0 if there is no expiration * @@ -147,7 +144,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ this.getTimeToLive = function() { - return (this.v === 1 ? this.meta.remaining_time : this.meta.time_to_live) || 0; + return this.meta.time_to_live || 0; } /** @@ -159,7 +156,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ this.isBurnAfterReadingEnabled = function() { - return (this.v === 1 ? this.meta.burnafterreading : this.adata[3]); + return this.adata[3]; } /** @@ -171,7 +168,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ this.isDiscussionEnabled = function() { - return (this.v === 1 ? this.meta.opendiscussion : this.adata[2]); + return this.adata[2]; } } @@ -196,7 +193,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ this.getCreated = function() { - return this.meta[this.v === 1 ? 'postdate' : 'created']; + return this.meta['created'] || 0; } /** @@ -208,7 +205,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ this.getIcon = function() { - return this.meta[this.v === 1 ? 'vizhash' : 'icon'] || ''; + return this.meta['icon'] || ''; } } @@ -593,6 +590,35 @@ jQuery.PrivateBin = (function($, RawDeflate) { return expirationDate; }; + /** + * Convert Bytes to kB/MB/GB/TB/PB/EB/ZB/YB + * + * @name Helper.formatBytes + * @function + * + * @param {number} bytes + * @return {string} + */ + me.formatBytes = function (bytes) + { + let result = ''; + const kilobyte = 1000; + const decimalPoint = 2; + const sizes = [ + I18n._('B'), I18n._('kB'), I18n._('MB'), I18n._('GB'), I18n._('TB'), + I18n._('PB'), I18n._('EB'), I18n._('ZB'), I18n._('YB') + ]; + const index = Math.floor(Math.log(bytes) / Math.log(kilobyte)); + + if (bytes > 0) { + result = parseFloat((bytes / Math.pow(kilobyte, index)).toFixed(decimalPoint)) + ' ' + sizes[index]; + } else { + result = `0 ${I18n._('B')}`; + } + + return result; + } + /** * resets state, used for unit testing * @@ -604,6 +630,17 @@ jQuery.PrivateBin = (function($, RawDeflate) { baseUri = null; }; + /** + * check if bootstrap5 object detected + * + * @name Helper.isBootstrap5 + * @returns {Boolean} + */ + me.isBootstrap5 = function () + { + return typeof bootstrap !== 'undefined'; + }; + return me; })(); @@ -758,14 +795,14 @@ jQuery.PrivateBin = (function($, RawDeflate) { args[0] = translations[messageId]; } - // messageID may contain links, but should be from a trusted source (code or translation JSON files) - let containsLinks = args[0].indexOf(' 0) may never contain HTML as they may come from untrusted parties - if ((containsLinks ? i > 1 : i > 0) || !containsLinks) { + if ((containsHtml ? i > 1 : i > 0) || !containsHtml) { args[i] = Helper.htmlEntities(args[i]); } } @@ -773,11 +810,11 @@ jQuery.PrivateBin = (function($, RawDeflate) { // format string let output = Helper.sprintf.apply(this, args); - if (containsLinks) { + if (containsHtml) { // only allow tags/attributes we actually use in translations output = DOMPurify.sanitize( output, { - ALLOWED_TAGS: ['a', 'i', 'span'], + ALLOWED_TAGS: ['a', 'i', 'span', 'kbd'], ALLOWED_ATTR: ['href', 'id'] } ); @@ -785,7 +822,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { // if $element is given, insert translation if ($element !== null) { - if (containsLinks) { + if (containsHtml) { $element.html(output); } else { // text node takes care of entity encoding @@ -893,7 +930,8 @@ jQuery.PrivateBin = (function($, RawDeflate) { } // load strings from JSON - $.getJSON('i18n/' + newLanguage + '.json', function(data) { + const cacheBreaker = document.querySelector('script[src^="js/privatebin.js"]').getAttribute("src").split(".js")[1] || ""; + $.getJSON('i18n/' + newLanguage + '.json' + cacheBreaker, function(data) { language = newLanguage; translations = data; $(document).triggerHandler(languageLoadedEvent); @@ -915,6 +953,25 @@ jQuery.PrivateBin = (function($, RawDeflate) { translations = mockTranslations || {}; }; + /** + * Check if string contains valid HTML code + * + * @name I18n.isStringContainsHtml + * @function + * @private + * @param {string} messageId + * @returns {boolean} + */ + function isStringContainsHtml(messageId) { + // An integer which specifies the type of the node. An Element node like

or

. + const elementNodeType = 1; + + const div = document.createElement('div'); + div.innerHTML = messageId; + + return Array.from(div.childNodes).some(node => node.nodeType === elementNodeType); + } + return me; })(); @@ -932,7 +989,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { * * @private */ - let base58 = new baseX('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'); + const base58 = new baseX('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'); /** * convert UTF-8 string stored in a DOMString to a standard UTF-16 DOMString @@ -1043,7 +1100,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { ); if (mode === 'zlib') { if (typeof zlib === 'undefined') { - throw 'Error compressing paste, due to missing WebAssembly support.' + throw 'Error compressing document, due to missing WebAssembly support.' } return zlib.deflate(message).buffer; } @@ -1065,39 +1122,17 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ async function decompress(data, mode, zlib) { - if (mode === 'zlib' || mode === 'none') { - if (mode === 'zlib') { - if (typeof zlib === 'undefined') { - throw 'Error decompressing paste, due to missing WebAssembly support.' - } - data = zlib.inflate( - new Uint8Array(data) - ).buffer; + if (mode === 'zlib') { + if (typeof zlib === 'undefined') { + throw 'Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.' } - return utf8To16( - arraybufferToString(data) - ); - } - // detect presence of Base64.js, indicating legacy ZeroBin paste - if (typeof Base64 === 'undefined') { - return utf8To16( - RawDeflate.inflate( - utf8To16( - atob( - arraybufferToString(data) - ) - ) - ) - ); - } else { - return Base64.btou( - RawDeflate.inflate( - Base64.fromBase64( - arraybufferToString(data) - ) - ) - ); + data = zlib.inflate( + new Uint8Array(data) + ).buffer; } + return utf8To16( + arraybufferToString(data) + ); } /** @@ -1137,19 +1172,6 @@ jQuery.PrivateBin = (function($, RawDeflate) { { let keyArray = stringToArraybuffer(key); if (password.length > 0) { - // version 1 pastes did append the passwords SHA-256 hash in hex - if (spec[7] === 'rawdeflate') { - let passwordBuffer = await window.crypto.subtle.digest( - {name: 'SHA-256'}, - stringToArraybuffer( - utf16To8(password) - ) - ).catch(Alert.showError); - password = Array.prototype.map.call( - new Uint8Array(passwordBuffer), - x => ('00' + x.toString(16)).slice(-2) - ).join(''); - } let passwordArray = stringToArraybuffer(password), newKeyArray = new Uint8Array(keyArray.length + passwordArray.length); newKeyArray.set(keyArray, 0); @@ -1283,21 +1305,6 @@ jQuery.PrivateBin = (function($, RawDeflate) { // clone the array instead of passing the reference spec = (data[1][0] instanceof Array ? data[1][0] : data[1]).slice(); cipherMessage = data[0]; - } else if (typeof data === 'string') { - // version 1 - let object = JSON.parse(data); - adataString = atob(object.adata); - spec = [ - object.iv, - object.salt, - object.iter, - object.ks, - object.ts, - object.cipher, - object.mode, - 'rawdeflate' - ]; - cipherMessage = object.ct; } else { throw 'unsupported message format'; } @@ -1305,7 +1312,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { spec[1] = atob(spec[1]); if (spec[7] === 'zlib') { if (typeof zlib === 'undefined') { - throw 'Error decompressing paste, due to missing WebAssembly support.' + throw 'Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.' } } try { @@ -1415,7 +1422,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { }; /** - * returns the paste data (including the cipher data) + * returns the document data (including the cipher data) * * @name Model.getPasteData * @function @@ -1447,7 +1454,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { TopNav.showViewButtons(); // show error message - Alert.showError(ServerInteraction.parseUploadError(status, data, 'get paste data')); + Alert.showError(ServerInteraction.parseUploadError(status, data, 'get document data')); }); ServerInteraction.setSuccess(function (status, data) { pasteData = new Paste(data); @@ -1460,7 +1467,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { }; /** - * get the pastes unique identifier from the URL, + * get the documents unique identifier from the URL, * eg. https://example.com/path/?c05354954c49a487#dfdsdgdgdfgdf returns c05354954c49a487 * * @name Model.getPasteId @@ -1492,14 +1499,14 @@ jQuery.PrivateBin = (function($, RawDeflate) { } if (id === null) { - throw 'no paste id given'; + throw 'no document id given'; } return id; } /** - * returns true, when the URL has a delete token and the current call was used for deleting a paste. + * returns true, when the URL has a delete token and the current call was used for deleting a document. * * @name Model.hasDeleteToken * @function @@ -1544,7 +1551,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { // string, so we re-add them if necessary symmetricKey = CryptTool.base58decode(newKey).padStart(32, '\u0000'); } catch(e) { - symmetricKey = newKey; + throw 'encryption key of unsupported format given or incomplete, mangled URL'; } } @@ -2064,7 +2071,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { } /** - * Forces opening the paste if the link does not do this automatically. + * Forces opening the document if the link does not do this automatically. * * This is necessary as browsers will not reload the page when it is * already loaded (which is fake as it is set via history.pushState()). @@ -2082,7 +2089,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { } /** - * creates a notification after a successfull paste upload + * creates a notification after a successful document upload * * @name PasteStatus.createPasteNotification * @function @@ -2093,7 +2100,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { { I18n._( $('#pastelink'), - 'Your paste is %s (Hit [Ctrl]+[c] to copy)', + 'Your document is %s (Hit Ctrl+c to copy)', url, url ); // save newly created element @@ -2102,8 +2109,8 @@ jQuery.PrivateBin = (function($, RawDeflate) { $pasteUrl.click(pasteLinkClick); // delete link - $('#deletelink').html(''); - I18n._($('#deletelink a').first(), 'Delete data'); + $('#deletelink').attr('href', deleteUrl); + I18n._($('#deletelink span').not('.glyphicon').first(), 'Delete data'); // enable shortener button $shortenButton.removeClass('buttondisabled'); @@ -2114,11 +2121,26 @@ jQuery.PrivateBin = (function($, RawDeflate) { Helper.selectText($pasteUrl[0]); }; + /** + * Checks if auto-shortening is enabled and sends the link to the shortener if it is. + * + * @name PasteStatus.checkAutoShorten + * @function + */ + me.checkAutoShorten = function() { + // check if auto-shortening is enabled + if ($shortenButton.data('autoshorten') === true) { + // if so, we send the link to the shortener + // we do not remove the button, in case shortener fails + sendToShortener(); + } + } + /** * extracts URLs from given string * * if at least one is found, it disables the shortener button and - * replaces the paste URL + * replaces the document URL * * @name PasteStatus.extractUrl * @function @@ -2152,6 +2174,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { $pasteUrl.prop('href', shortUrl); // we pre-select the link so that the user only has to [Ctrl]+[c] the link Helper.selectText($pasteUrl[0]); + CopyToClipboard.setUrl(shortUrl); return; } } @@ -2168,15 +2191,15 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.showRemainingTime = function(paste) { if (paste.isBurnAfterReadingEnabled()) { - // display paste "for your eyes only" if it is deleted + // display document "for your eyes only" if it is deleted - // the paste has been deleted when the JSON with the ciphertext + // the document has been deleted when the JSON with the ciphertext // has been downloaded Alert.showRemaining('FOR YOUR EYES ONLY. Don\'t close this window, this message can\'t be displayed again.'); $remainingTime.addClass('foryoureyesonly'); } else if (paste.getTimeToLive() > 0) { - // display paste expiration + // display document expiration let expiration = Helper.secondsToHuman(paste.getTimeToLive()), expirationLabel = [ 'This document will expire in %d ' + expiration[1] + '.', @@ -2238,8 +2261,8 @@ jQuery.PrivateBin = (function($, RawDeflate) { const me = {}; let $passwordDecrypt, - $passwordForm, $passwordModal, + bootstrap5PasswordModal = null, password = ''; /** @@ -2258,13 +2281,17 @@ jQuery.PrivateBin = (function($, RawDeflate) { password = $passwordDecrypt.val(); // hide modal - $passwordModal.modal('hide'); + if (bootstrap5PasswordModal) { + bootstrap5PasswordModal.hide(); + } else { + $passwordModal.modal('hide'); + } PasteDecrypter.run(); } /** - * Request users confirmation to load possibly burn after reading paste + * Request users confirmation to load possibly burn after reading document * * @name Prompt.requestLoadConfirmation * @function @@ -2272,22 +2299,19 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.requestLoadConfirmation = function() { const $loadconfirmmodal = $('#loadconfirmmodal'); - if ($loadconfirmmodal.length > 0) { - const $loadconfirmOpenNow = $loadconfirmmodal.find('#loadconfirm-open-now'); - $loadconfirmOpenNow.off('click.loadPaste'); - $loadconfirmOpenNow.on('click.loadPaste', PasteDecrypter.run); - const $loadconfirmClose = $loadconfirmmodal.find('.close'); - $loadconfirmClose.off('click.close'); - $loadconfirmClose.on('click.close', Controller.newPaste); - $loadconfirmmodal.modal('show'); + + const $loadconfirmOpenNow = $loadconfirmmodal.find('#loadconfirm-open-now'); + $loadconfirmOpenNow.off('click.loadPaste'); + $loadconfirmOpenNow.on('click.loadPaste', PasteDecrypter.run); + + const $loadconfirmClose = $loadconfirmmodal.find('.close'); + $loadconfirmClose.off('click.close'); + $loadconfirmClose.on('click.close', Controller.newPaste); + + if (typeof bootstrap !== 'undefined' && bootstrap.Tooltip.VERSION) { + (new bootstrap.Modal($loadconfirmmodal[0])).show(); } else { - if (window.confirm( - I18n._('Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?') - )) { - PasteDecrypter.run(); - } else { - Controller.newPaste(); - } + $loadconfirmmodal.modal('show'); } } @@ -2301,28 +2325,14 @@ jQuery.PrivateBin = (function($, RawDeflate) { { // show new bootstrap method (if available) if ($passwordModal.length !== 0) { - $passwordModal.modal({ - backdrop: 'static', - keyboard: false - }); - // focus password input - $passwordDecrypt.focus(); - // then re-focus it, when modal causes it to loose focus again - setTimeout(function () { - $passwordDecrypt.focus(); - }, 500); + if (bootstrap5PasswordModal) { + bootstrap5PasswordModal.show(); + } else { + $passwordModal.modal('show'); + } return; } - // fallback to old method for page template - password = prompt(I18n._('Please enter the password for this paste:'), ''); - if (password === null) { - throw 'password prompt canceled'; - } - if (password.length === 0) { - // recurse… - return me.requestPassword(); - } PasteDecrypter.run(); }; @@ -2354,7 +2364,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { // and also reset UI $passwordDecrypt.val(''); - } + }; /** * init status manager @@ -2367,11 +2377,26 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.init = function() { $passwordDecrypt = $('#passworddecrypt'); - $passwordForm = $('#passwordform'); $passwordModal = $('#passwordmodal'); // bind events - handle Model password submission - $passwordForm.submit(submitPasswordModal); + if ($passwordModal.length !== 0) { + $('#passwordform').submit(submitPasswordModal); + + const disableClosingConfig = { + backdrop: 'static', + keyboard: false, + show: false + }; + if (typeof bootstrap !== 'undefined' && bootstrap.Tooltip.VERSION) { + bootstrap5PasswordModal = new bootstrap.Modal($passwordModal[0], disableClosingConfig); + } else { + $passwordModal.modal(disableClosingConfig); + } + $passwordModal.on('shown.bs.modal', () => { + $passwordDecrypt.focus(); + }); + } }; return me; @@ -2390,9 +2415,14 @@ jQuery.PrivateBin = (function($, RawDeflate) { let $editorTabs, $messageEdit, + $messageEditParent, $messagePreview, + $messagePreviewParent, + $messageTab, + $messageTabParent, $message, - isPreview = false; + isPreview = false, + isTabSupported = true; /** * support input of tab character @@ -2404,9 +2434,13 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ function supportTabs(event) { - const keyCode = event.keyCode || event.which; - // tab was pressed - if (keyCode === 9) { + // support disabling tab support using [Esc] and [Ctrl]+[m] + if (event.key === 'Escape' || (event.ctrlKey && event.key === 'm')) { + toggleTabSupport(); + $messageTab[0].checked = isTabSupported; + event.preventDefault(); + } + else if (isTabSupported && event.key === 'Tab') { // get caret position & selection const val = this.value, start = this.selectionStart, @@ -2420,6 +2454,18 @@ jQuery.PrivateBin = (function($, RawDeflate) { } } + /** + * toggle tab support in message textarea + * + * @name Editor.toggleTabSupport + * @private + * @function + */ + function toggleTabSupport() + { + isTabSupported = !isTabSupported; + } + /** * view the Editor tab * @@ -2431,15 +2477,18 @@ jQuery.PrivateBin = (function($, RawDeflate) { { // toggle buttons $messageEdit.addClass('active'); + $messageEditParent.addClass('active'); $messagePreview.removeClass('active'); + $messagePreviewParent.removeClass('active'); - $('#messageedit').attr('aria-selected','true'); - $('#messagepreview').attr('aria-selected','false'); + $messageEdit.attr('aria-selected','true'); + $messagePreview.attr('aria-selected','false'); PasteViewer.hide(); // reshow input $message.removeClass('hidden'); + $messageTabParent.removeClass('hidden'); me.focusInput(); @@ -2463,22 +2512,32 @@ jQuery.PrivateBin = (function($, RawDeflate) { { // toggle buttons $messageEdit.removeClass('active'); + $messageEditParent.removeClass('active'); $messagePreview.addClass('active'); + $messagePreviewParent.addClass('active'); - $('#messageedit').attr('aria-selected','false'); - $('#messagepreview').attr('aria-selected','true'); + $messageEdit.attr('aria-selected','false'); + $messagePreview.attr('aria-selected','true'); // hide input as now preview is shown $message.addClass('hidden'); + $messageTabParent.addClass('hidden'); // show preview PasteViewer.setText($message.val()); if (AttachmentViewer.hasAttachmentData()) { - const attachment = AttachmentViewer.getAttachment(); - AttachmentViewer.handleBlobAttachmentPreview( - AttachmentViewer.getAttachmentPreview(), - attachment[0], attachment[1] - ); + const attachmentsData = AttachmentViewer.getAttachmentsData(); + + attachmentsData.forEach(attachmentData => { + const mimeType = AttachmentViewer.getAttachmentMimeType(attachmentData); + + AttachmentViewer.handleBlobAttachmentPreview( + AttachmentViewer.getAttachmentPreview(), + attachmentData, mimeType + ); + }); + + AttachmentViewer.showAttachment(); } PasteViewer.run(); @@ -2528,6 +2587,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.show = function() { $message.removeClass('hidden'); + $messageTabParent.removeClass('hidden'); $editorTabs.removeClass('hidden'); }; @@ -2540,6 +2600,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.hide = function() { $message.addClass('hidden'); + $messageTabParent.addClass('hidden'); $editorTabs.addClass('hidden'); }; @@ -2579,7 +2640,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { }; /** - * init status manager + * init editor * * preloads jQuery elements * @@ -2590,21 +2651,25 @@ jQuery.PrivateBin = (function($, RawDeflate) { { $editorTabs = $('#editorTabs'); $message = $('#message'); + $messageTab = $('#messagetab'); + $messageTabParent = $messageTab.parent(); // bind events $message.keydown(supportTabs); + $messageTab.change(toggleTabSupport); - // bind click events to tab switchers (a), but save parent of them - // (li) - $messageEdit = $('#messageedit').click(viewEditor).parent(); - $messagePreview = $('#messagepreview').click(viewPreview).parent(); + // bind click events to tab switchers (a), and save parents (li) + $messageEdit = $('#messageedit').click(viewEditor); + $messageEditParent = $messageEdit.parent(); + $messagePreview = $('#messagepreview').click(viewPreview); + $messagePreviewParent = $messagePreview.parent(); }; return me; })(); /** - * (view) Parse and show paste. + * (view) Parse and show document. * * @name PasteViewer * @class @@ -2612,7 +2677,8 @@ jQuery.PrivateBin = (function($, RawDeflate) { const PasteViewer = (function () { const me = {}; - let $placeholder, + let $messageTabParent, + $placeholder, $prettyMessage, $prettyPrint, $plainText, @@ -2677,7 +2743,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { } /** - * displays the paste + * displays the document * * @name PasteViewer.showPaste * @private @@ -2692,16 +2758,14 @@ jQuery.PrivateBin = (function($, RawDeflate) { } // otherwise hide the placeholder $placeholder.addClass('hidden'); + $messageTabParent.addClass('hidden'); - switch (format) { - case 'markdown': - $plainText.removeClass('hidden'); - $prettyMessage.addClass('hidden'); - break; - default: - $plainText.addClass('hidden'); - $prettyMessage.removeClass('hidden'); - break; + if (format === 'markdown') { + $plainText.removeClass('hidden'); + $prettyMessage.addClass('hidden'); + } else { + $plainText.addClass('hidden'); + $prettyMessage.removeClass('hidden'); } } @@ -2726,6 +2790,11 @@ jQuery.PrivateBin = (function($, RawDeflate) { format = newFormat; isChanged = true; + + // update preview + if (Editor.isPreview()) { + PasteViewer.run(); + } }; /** @@ -2828,6 +2897,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ me.init = function() { + $messageTabParent = $('#messagetab').parent(); $placeholder = $('#placeholder'); $plainText = $('#plaintext'); $prettyMessage = $('#prettymessage'); @@ -2852,14 +2922,12 @@ jQuery.PrivateBin = (function($, RawDeflate) { const AttachmentViewer = (function () { const me = {}; - let $attachmentLink, - $attachmentPreview, + let $attachmentPreview, $attachment, - attachmentData, - file, + attachmentsData = [], + files, $fileInput, - $dragAndDropFileName, - attachmentHasPreview = false, + $dragAndDropFileNames, $dropzone; /** @@ -2901,26 +2969,30 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.setAttachment = function(attachmentData, fileName) { // skip, if attachments got disabled - if (!$attachmentLink || !$attachmentPreview) return; + if (!$attachment || !$attachmentPreview) return; // data URI format: data:[][;base64], + const template = Model.getTemplate('attachment'); + const attachmentLink = template.find('a'); + // position in data URI string of where data begins const base64Start = attachmentData.indexOf(',') + 1; - // position in data URI string of where mimeType ends - const mimeTypeEnd = attachmentData.indexOf(';'); - // extract mimeType - const mimeType = attachmentData.substring(5, mimeTypeEnd); + const mimeType = me.getAttachmentMimeType(attachmentData); + // extract data and convert to binary const rawData = attachmentData.substring(base64Start); const decodedData = rawData.length > 0 ? atob(rawData) : ''; let blobUrl = getBlobUrl(decodedData, mimeType); - $attachmentLink.attr('href', blobUrl); + attachmentLink.attr('href', blobUrl); if (typeof fileName !== 'undefined') { - $attachmentLink.attr('download', fileName); + attachmentLink.attr('download', fileName); + + const fileSize = Helper.formatBytes(decodedData.length); + template.append(`(${fileName}, ${fileSize})`); } // sanitize SVG preview @@ -2935,6 +3007,9 @@ jQuery.PrivateBin = (function($, RawDeflate) { blobUrl = getBlobUrl(sanitizedData, mimeType); } + template.removeClass('hidden'); + $attachment.append(template); + me.handleBlobAttachmentPreview($attachmentPreview, blobUrl, mimeType); }; @@ -2951,7 +3026,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { $attachment.removeClass('hidden'); - if (attachmentHasPreview) { + if (me.hasAttachmentPreview()) { $attachmentPreview.removeClass('hidden'); } }; @@ -2972,11 +3047,9 @@ jQuery.PrivateBin = (function($, RawDeflate) { } me.hideAttachment(); me.hideAttachmentPreview(); - $attachmentLink.removeAttr('href'); - $attachmentLink.removeAttr('download'); - $attachmentLink.off('click'); + $attachment.html(''); $attachmentPreview.html(''); - $dragAndDropFileName.text(''); + $dragAndDropFileNames.html(''); AttachmentViewer.removeAttachmentData(); }; @@ -2991,8 +3064,8 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ me.removeAttachmentData = function() { - file = undefined; - attachmentData = undefined; + files = undefined; + attachmentsData = []; }; /** @@ -3003,9 +3076,21 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ me.clearDragAndDrop = function() { - $dragAndDropFileName.text(''); + $dragAndDropFileNames.html(''); }; + /** + * Print file names added via drag & drop + * + * @name AttachmentViewer.printDragAndDropFileNames + * @private + * @function + * @param {array} fileNames + */ + function printDragAndDropFileNames(fileNames) { + $dragAndDropFileNames.html(fileNames.join("
")); + } + /** * hides the attachment * @@ -3034,6 +3119,18 @@ jQuery.PrivateBin = (function($, RawDeflate) { } }; + /** + * checks if has any attachment preview + * + * @name AttachmentViewer.hasAttachmentPreview + * @function + * @return {JQuery} + */ + me.hasAttachmentPreview = function() + { + return $attachmentPreview.children().length > 0; + } + /** * checks if there is an attachment displayed * @@ -3045,8 +3142,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { if (!$attachment.length) { return false; } - const link = $attachmentLink.prop('href'); - return (typeof link !== 'undefined' && link !== ''); + return [...$attachment.children()].length > 0; }; /** @@ -3066,20 +3162,38 @@ jQuery.PrivateBin = (function($, RawDeflate) { }; /** - * return the attachment + * return the attachments * - * @name AttachmentViewer.getAttachment + * @name AttachmentViewer.getAttachments * @function * @returns {array} */ - me.getAttachment = function() + me.getAttachments = function() { - return [ - $attachmentLink.prop('href'), - $attachmentLink.prop('download') - ]; + return [...$attachment.find('a')].map(link => ( + [ + $(link).prop('href'), + $(link).prop('download') + ] + )); }; + /** + * Get attachment mime type + * + * @name AttachmentViewer.getAttachmentMimeType + * @function + * @param {string} attachmentData - Base64 string + */ + me.getAttachmentMimeType = function(attachmentData) + { + // position in data URI string of where mimeType ends + const mimeTypeEnd = attachmentData.indexOf(';'); + + // extract mimeType + return attachmentData.substring(5, mimeTypeEnd); + } + /** * moves the attachment link to another element * @@ -3088,27 +3202,36 @@ jQuery.PrivateBin = (function($, RawDeflate) { * @name AttachmentViewer.moveAttachmentTo * @function * @param {jQuery} $element - the wrapper/container element where this should be moved to + * @param {array} attachment - attachment data * @param {string} label - the text to show (%s will be replaced with the file name), will automatically be translated */ - me.moveAttachmentTo = function($element, label) + me.moveAttachmentTo = function($element, attachment, label) { + const attachmentLink = $(document.createElement('a')) + .addClass('alert-link') + .prop('href', attachment[0]) + .prop('download', attachment[1]); + // move elemement to new place - $attachmentLink.appendTo($element); + attachmentLink.appendTo($element); // update text - ensuring no HTML is inserted into the text node - I18n._($attachmentLink, label, $attachmentLink.attr('download')); + I18n._(attachmentLink, label, attachment[1]); }; /** - * read file data as data URL using the FileReader API + * read files data as data URL using the FileReader API * * @name AttachmentViewer.readFileData * @private * @function - * @param {object} loadedFile (optional) loaded file object + * @param {FileList[]} loadedFiles (optional) loaded files array * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/FileReader#readAsDataURL()} */ - function readFileData(loadedFile) { + function readFileData(loadedFiles) { + // Clear old cache + me.removeAttachmentData(); + if (typeof FileReader === 'undefined') { // revert loading status… me.hideAttachment(); @@ -3117,28 +3240,35 @@ jQuery.PrivateBin = (function($, RawDeflate) { return; } - const fileReader = new FileReader(); - if (loadedFile === undefined) { - loadedFile = $fileInput[0].files[0]; - $dragAndDropFileName.text(''); + if (loadedFiles === undefined) { + loadedFiles = [...$fileInput[0].files]; + me.clearDragAndDrop(); } else { - $dragAndDropFileName.text(loadedFile.name); + const fileNames = loadedFiles.map((loadedFile => loadedFile.name)); + printDragAndDropFileNames(fileNames); } - if (typeof loadedFile !== 'undefined') { - file = loadedFile; - fileReader.onload = function (event) { - const dataURL = event.target.result; - attachmentData = dataURL; + if (typeof loadedFiles !== 'undefined') { + files = loadedFiles; + loadedFiles.forEach((loadedFile, index) => { + const fileReader = new FileReader(); - if (Editor.isPreview()) { - me.handleAttachmentPreview($attachmentPreview, dataURL); - $attachmentPreview.removeClass('hidden'); - } + fileReader.onload = function (event) { + const dataURL = event.target.result; + if (dataURL) { + attachmentsData[index] = dataURL; + } - TopNav.highlightFileupload(); - }; - fileReader.readAsDataURL(loadedFile); + if (Editor.isPreview()) { + me.handleAttachmentPreview($attachmentPreview, dataURL); + $attachmentPreview.removeClass('hidden'); + } + + TopNav.highlightFileupload(); + }; + + fileReader.readAsDataURL(loadedFile); + }); } else { me.removeAttachmentData(); } @@ -3154,16 +3284,17 @@ jQuery.PrivateBin = (function($, RawDeflate) { * @argument {string} mime type */ me.handleBlobAttachmentPreview = function ($targetElement, blobUrl, mimeType) { - if (blobUrl) { - attachmentHasPreview = true; + const alreadyIncludesCurrentAttachment = $targetElement.find(`[src='${blobUrl}']`).length > 0; + + if (blobUrl && !alreadyIncludesCurrentAttachment) { if (mimeType.match(/^image\//i)) { - $targetElement.html( + $targetElement.append( $(document.createElement('img')) .attr('src', blobUrl) .attr('class', 'img-thumbnail') ); } else if (mimeType.match(/^video\//i)) { - $targetElement.html( + $targetElement.append( $(document.createElement('video')) .attr('controls', 'true') .attr('autoplay', 'true') @@ -3174,7 +3305,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { .attr('src', blobUrl)) ); } else if (mimeType.match(/^audio\//i)) { - $targetElement.html( + $targetElement.append( $(document.createElement('audio')) .attr('controls', 'true') .attr('autoplay', 'true') @@ -3187,15 +3318,13 @@ jQuery.PrivateBin = (function($, RawDeflate) { // Fallback for browsers, that don't support the vh unit const clientHeight = $(window).height(); - $targetElement.html( + $targetElement.append( $(document.createElement('embed')) .attr('src', blobUrl) .attr('type', 'application/pdf') .attr('class', 'pdfPreview') .css('height', clientHeight) ); - } else { - attachmentHasPreview = false; } } }; @@ -3228,14 +3357,14 @@ jQuery.PrivateBin = (function($, RawDeflate) { } if ($fileInput) { - const file = evt.dataTransfer.files[0]; + const files = [...evt.dataTransfer.files]; //Clear the file input: $fileInput.wrap('
').closest('form').get(0).reset(); $fileInput.unwrap(); //Only works in Chrome: //fileInput[0].files = e.dataTransfer.files; - readFileData(file); + readFileData(files); } }; @@ -3270,18 +3399,19 @@ jQuery.PrivateBin = (function($, RawDeflate) { * @function */ function addClipboardEventHandler() { - $(document).on('paste', function (event) { + $('#message').on('paste', function (event) { const items = (event.clipboardData || event.originalEvent.clipboardData).items; - const lastItem = items[items.length - 1]; - if (lastItem.kind === 'file') { - if (TopNav.isAttachmentReadonly()) { - event.stopPropagation(); - event.preventDefault(); - return false; - } else { - readFileData(lastItem.getAsFile()); - } + const files = [...items] + .filter(item => item.kind === 'file') + .map(item => item.getAsFile()); + + if (TopNav.isAttachmentReadonly()) { + event.stopPropagation(); + event.preventDefault(); + return false; } + + readFileData(files); }); } @@ -3289,23 +3419,12 @@ jQuery.PrivateBin = (function($, RawDeflate) { /** * getter for attachment data * - * @name AttachmentViewer.getAttachmentData + * @name AttachmentViewer.getAttachmentsData * @function - * @return {jQuery} + * @return {string[]} */ - me.getAttachmentData = function () { - return attachmentData; - }; - - /** - * getter for attachment link - * - * @name AttachmentViewer.getAttachmentLink - * @function - * @return {jQuery} - */ - me.getAttachmentLink = function () { - return $attachmentLink; + me.getAttachmentsData = function () { + return attachmentsData; }; /** @@ -3320,14 +3439,14 @@ jQuery.PrivateBin = (function($, RawDeflate) { }; /** - * getter for file data, returns the file contents + * getter for files data, returns the file list * - * @name AttachmentViewer.getFile + * @name AttachmentViewer.getFiles * @function - * @return {string} + * @return {FileList[]} */ - me.getFile = function () { - return file; + me.getFiles = function () { + return files; }; /** @@ -3341,9 +3460,8 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.init = function() { $attachment = $('#attachment'); - $dragAndDropFileName = $('#dragAndDropFileName'); + $dragAndDropFileNames = $('#dragAndDropFileName'); $dropzone = $('#dropzone'); - $attachmentLink = $('#attachment a') || $(''); if($attachment.length) { $attachmentPreview = $('#attachmentPreview'); @@ -3404,6 +3522,12 @@ jQuery.PrivateBin = (function($, RawDeflate) { { const $source = $(event.target); + // show all reply buttons + $commentContainer.find('button').removeClass('hidden'); + + // hide the current reply button + $source.addClass('hidden'); + // clear input $replyMessage.val(''); $replyNickname.val(''); @@ -3484,9 +3608,11 @@ jQuery.PrivateBin = (function($, RawDeflate) { } // set date + const created = comment.getCreated(); + const commentDate = created == 0 ? '' : ' (' + (new Date(created * 1000).toLocaleString()) + ')'; $commentEntry.find('span.commentdate') - .text(' (' + (new Date(comment.getCreated() * 1000).toLocaleString()) + ')') - .attr('title', 'CommentID: ' + comment.id); + .text(commentDate) + .attr('title', 'CommentID: ' + comment.id); // if an avatar is available, display it const icon = comment.getIcon(); @@ -3712,11 +3838,6 @@ jQuery.PrivateBin = (function($, RawDeflate) { $('#pasteFormatterDisplay').text($target.text()); PasteViewer.setFormat(newFormat); - // update preview - if (Editor.isPreview()) { - PasteViewer.run(); - } - event.preventDefault(); } @@ -3760,6 +3881,18 @@ jQuery.PrivateBin = (function($, RawDeflate) { } } + /** + * Clear the password input in the top navigation + * + * @name TopNav.clearPasswordInput + * @function + */ + + function clearPasswordInput() + { + $passwordInput.val(''); + } + /** * Clear the attachment input in the top navigation. @@ -3791,7 +3924,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { history.pushState( {type: 'raw'}, document.title, - // recreate paste URL + // recreate document URL Helper.baseUri() + '?' + Model.getPasteId() + '#' + CryptTool.base58encode(Model.getPasteKey()) ); @@ -3824,10 +3957,11 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ function downloadText() { - var filename='paste-' + Model.getPasteId() + '.txt'; - var text = PasteViewer.getText(); + const fileFormat = PasteViewer.getFormat() === 'markdown' ? '.md' : '.txt'; + const filename = 'document-' + Model.getPasteId() + fileFormat; + const text = PasteViewer.getText(); - var element = document.createElement('a'); + const element = document.createElement('a'); element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); element.setAttribute('download', filename); @@ -3849,13 +3983,32 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ function setLanguage(event) { - document.cookie = 'lang=' + $(event.target).data('lang') + ';secure'; - UiHelper.reloadHome(); + let lang = $(event.target).data('lang') || event.target.value; + + document.cookie = 'lang=' + lang + '; SameSite=Lax; Secure'; + window.location.reload(); event.preventDefault(); } /** - * hides all messages and creates a new paste + * save the template in a cookie and reloads the page + * + * @name TopNav.setTemplate + * @private + * @function + * @param {Event} event + */ + function setTemplate(event) + { + let template = $(event.target).data('template') || event.target.value; + + document.cookie = 'template=' + template + '; SameSite=Lax; Secure'; + window.location.reload(); + event.preventDefault(); + } + + /** + * hides all messages and creates a new document * * @name TopNav.clickNewPaste * @private @@ -3908,7 +4061,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { } /** - * Shows the QR code of the current paste (URL). + * Shows the QR code of the current document (URL). * * @name TopNav.displayQrCode * @private @@ -3965,7 +4118,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { } emailBody += I18n._('Link:'); emailBody += EOL; - emailBody += `${window.location.href}`; + emailBody += $('#pasteurl').attr('href') || window.location.href; // href is tried first as it might have been shortened return emailBody; } @@ -3986,7 +4139,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { } /** - * Send Email with current paste (URL). + * Send Email with current document (URL). * * @name TopNav.sendEmail * @private @@ -4005,50 +4158,47 @@ jQuery.PrivateBin = (function($, RawDeflate) { expirationDateRoundedToSecond.setUTCSeconds(0); const $emailconfirmmodal = $('#emailconfirmmodal'); - if ($emailconfirmmodal.length > 0) { - if (expirationDate !== null) { - const $emailconfirmTimezoneCurrent = $emailconfirmmodal.find('#emailconfirm-timezone-current'); - const $emailconfirmTimezoneUtc = $emailconfirmmodal.find('#emailconfirm-timezone-utc'); - $emailconfirmTimezoneCurrent.off('click.sendEmailCurrentTimezone'); - $emailconfirmTimezoneCurrent.on('click.sendEmailCurrentTimezone', () => { - const emailBody = templateEmailBody(expirationDateRoundedToSecond.toLocaleString(), isBurnafterreading); + if (expirationDate !== null) { + const $emailconfirmTimezoneCurrent = $emailconfirmmodal.find('#emailconfirm-timezone-current'); + const $emailconfirmTimezoneUtc = $emailconfirmmodal.find('#emailconfirm-timezone-utc'); + let localeConfiguration = { dateStyle: 'long', timeStyle: 'long' }; + const bootstrap5EmailConfirmModal = typeof bootstrap !== 'undefined' && bootstrap.Tooltip.VERSION ? + new bootstrap.Modal($emailconfirmmodal[0]) : null; + + function sendEmailAndHideModal() { + const emailBody = templateEmailBody( + // we don't use Date.prototype.toUTCString() because we would like to avoid GMT + expirationDateRoundedToSecond.toLocaleString( + [], localeConfiguration + ), isBurnafterreading + ); + if (bootstrap5EmailConfirmModal) { + bootstrap5EmailConfirmModal.hide(); + } else { $emailconfirmmodal.modal('hide'); - triggerEmailSend(emailBody); - }); - $emailconfirmTimezoneUtc.off('click.sendEmailUtcTimezone'); - $emailconfirmTimezoneUtc.on('click.sendEmailUtcTimezone', () => { - const emailBody = templateEmailBody(expirationDateRoundedToSecond.toLocaleString( - undefined, - // we don't use Date.prototype.toUTCString() because we would like to avoid GMT - { timeZone: 'UTC', dateStyle: 'long', timeStyle: 'long' } - ), isBurnafterreading); - $emailconfirmmodal.modal('hide'); - triggerEmailSend(emailBody); - }); - $emailconfirmmodal.modal('show'); + } + triggerEmailSend(emailBody); + }; + + $emailconfirmTimezoneCurrent.off('click.sendEmailCurrentTimezone'); + $emailconfirmTimezoneCurrent.on('click.sendEmailCurrentTimezone', sendEmailAndHideModal); + $emailconfirmTimezoneUtc.off('click.sendEmailUtcTimezone'); + $emailconfirmTimezoneUtc.on('click.sendEmailUtcTimezone', () => { + localeConfiguration.timeZone = 'UTC'; + sendEmailAndHideModal(); + }); + if (bootstrap5EmailConfirmModal) { + bootstrap5EmailConfirmModal.show(); } else { - triggerEmailSend(templateEmailBody(null, isBurnafterreading)); + $emailconfirmmodal.modal('show'); } } else { - let emailBody = ''; - if (expirationDate !== null) { - const expirationDateString = window.confirm( - I18n._('Recipient may become aware of your timezone, convert time to UTC?') - ) ? expirationDateRoundedToSecond.toLocaleString( - undefined, - // we don't use Date.prototype.toUTCString() because we would like to avoid GMT - { timeZone: 'UTC', dateStyle: 'long', timeStyle: 'long' } - ) : expirationDateRoundedToSecond.toLocaleString(); - emailBody = templateEmailBody(expirationDateString, isBurnafterreading); - } else { - emailBody = templateEmailBody(null, isBurnafterreading); - } - triggerEmailSend(emailBody); + triggerEmailSend(templateEmailBody(null, isBurnafterreading)); } } /** - * Shows all navigation elements for viewing an existing paste + * Shows all navigation elements for viewing an existing document * * @name TopNav.showViewButtons * @function @@ -4069,7 +4219,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { }; /** - * Hides all navigation elements for viewing an existing paste + * Hides all navigation elements for viewing an existing document * * @name TopNav.hideViewButtons * @function @@ -4091,7 +4241,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { }; /** - * Hides all elements belonging to existing pastes + * Hides all elements belonging to existing documents * * @name TopNav.hideAllButtons * @function @@ -4103,7 +4253,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { }; /** - * shows all elements needed when creating a new paste + * shows all elements needed when creating a new document * * @name TopNav.showCreateButtons * @function @@ -4127,7 +4277,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { }; /** - * shows all elements needed when creating a new paste + * shows all elements needed when creating a new document * * @name TopNav.hideCreateButtons * @function @@ -4151,7 +4301,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { }; /** - * only shows the "new paste" button + * only shows the "new document" button * * @name TopNav.showNewPasteButton * @function @@ -4268,7 +4418,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { } /** - * hide all irrelevant buttons when viewing burn after reading paste + * hide irrelevant buttons when viewing burn after reading document * * @name TopNav.hideBurnAfterReadingButtons * @function @@ -4337,6 +4487,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.resetInput = function() { clearAttachmentInput(); + clearPasswordInput(); $burnAfterReading.prop('checked', burnAfterReadingDefault); $openDiscussion.prop('checked', openDiscussionDefault); if (openDiscussionDefault || !burnAfterReadingDefault) $openDiscussionOption.removeClass('buttondisabled'); @@ -4461,7 +4612,11 @@ jQuery.PrivateBin = (function($, RawDeflate) { // visually indicate file uploaded const $attachDropdownToggle = $attach.children('.dropdown-toggle'); if ($attachDropdownToggle.attr('aria-expanded') === 'false') { - $attachDropdownToggle.click(); + if (Helper.isBootstrap5()) { + new bootstrap.Dropdown($attachDropdownToggle).toggle(); + } else { + $attachDropdownToggle.click(); + } } $fileWrap.addClass('highlight'); setTimeout(function () { @@ -4525,8 +4680,9 @@ jQuery.PrivateBin = (function($, RawDeflate) { // bootstrap template drop down $('#language ul.dropdown-menu li a').click(setLanguage); - // page template drop down - $('#language select option').click(setLanguage); + + // bootstrap template drop down + $('#template ul.dropdown-menu li a').click(setTemplate); // bind events $burnAfterReading.change(changeBurnAfterReading); @@ -4543,6 +4699,13 @@ jQuery.PrivateBin = (function($, RawDeflate) { // bootstrap template drop downs $('ul.dropdown-menu li a', $('#expiration').parent()).click(updateExpiration); $('ul.dropdown-menu li a', $('#formatter').parent()).click(updateFormat); + // bootstrap5 & page drop downs + $('#pasteExpiration').on('change', function() { + pasteExpiration = Model.getExpirationDefault(); + }); + $('#pasteFormatter').on('change', function() { + PasteViewer.setFormat(Model.getFormatDefault()); + }); // initiate default state of checkboxes changeBurnAfterReading(); @@ -4551,7 +4714,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { // get default values from template or fall back to set value burnAfterReadingDefault = me.getBurnAfterReading(); openDiscussionDefault = me.getOpenDiscussion(); - pasteExpiration = Model.getExpirationDefault() || pasteExpiration; + pasteExpiration = Model.getExpirationDefault(); createButtonsDisplayed = false; viewButtonsDisplayed = false; @@ -4598,7 +4761,10 @@ jQuery.PrivateBin = (function($, RawDeflate) { * @readonly * @enum {Object} */ - const ajaxHeaders = {'X-Requested-With': 'JSONHttpRequest'}; + const ajaxHeaders = { + 'X-Requested-With': 'JSONHttpRequest', + 'Content-Type': 'application/json' + }; /** * called after successful upload @@ -4836,7 +5002,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { })(); /** - * (controller) Responsible for encrypting paste and sending it to server. + * (controller) Responsible for encrypting document and sending it to server. * * Does upload, encryption is done transparently by ServerInteraction. * @@ -4847,7 +5013,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { const me = {}; /** - * called after successful paste upload + * called after successful document upload * * @name PasteEncrypter.showCreatedPaste * @private @@ -4870,6 +5036,9 @@ jQuery.PrivateBin = (function($, RawDeflate) { TopNav.showViewButtons(); + CopyToClipboard.setUrl(url); + CopyToClipboard.showKeyboardShortcutHint(); + // this cannot be grouped with showViewButtons due to remaining time calculation TopNav.showEmailButton(); @@ -4877,6 +5046,8 @@ jQuery.PrivateBin = (function($, RawDeflate) { TopNav.hideDownloadButton(); Editor.hide(); + PasteStatus.checkAutoShorten(); + // parse and show text // (preparation already done in me.sendPaste()) PasteViewer.run(); @@ -4895,7 +5066,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { // show success message Alert.showStatus('Comment posted.'); - // reload paste + // reload document Controller.refreshPaste(function () { // highlight sent comment DiscussionViewer.highlightComment(data.id, true); @@ -4958,7 +5129,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { ServerInteraction.setUnencryptedData('pasteid', Model.getPasteId()); if (typeof parentid === 'undefined') { // if parent id is not set, this is the top-most comment, so use - // paste id as parent, as the root element of the discussion tree + // document id as parent, as the root element of the discussion tree ServerInteraction.setUnencryptedData('parentid', Model.getPasteId()); } else { ServerInteraction.setUnencryptedData('parentid', parentid); @@ -4977,7 +5148,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { }; /** - * sends a new paste to server + * sends a new document to server * * @name PasteEncrypter.sendPaste * @async @@ -4990,14 +5161,14 @@ jQuery.PrivateBin = (function($, RawDeflate) { // UI loading state TopNav.hideAllButtons(); - Alert.showLoading('Sending paste…', 'cloud-upload'); + Alert.showLoading('Sending document…', 'cloud-upload'); TopNav.collapseBar(); // get data const plainText = Editor.getText(), format = PasteViewer.getFormat(), // the methods may return different values if no files are attached (null, undefined or false) - files = TopNav.getFileList() || AttachmentViewer.getFile() || AttachmentViewer.hasAttachment(); + files = TopNav.getFileList() || AttachmentViewer.getFiles() || AttachmentViewer.hasAttachment(); // do not send if there is no data if (plainText.length === 0 && !files) { @@ -5020,7 +5191,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { // show error message Alert.showError( - ServerInteraction.parseUploadError(status, data, 'create paste') + ServerInteraction.parseUploadError(status, data, 'create document') ); }); @@ -5037,62 +5208,64 @@ jQuery.PrivateBin = (function($, RawDeflate) { PasteViewer.setFormat(format); // prepare cypher message - let file = AttachmentViewer.getAttachmentData(), + let attachmentsData = AttachmentViewer.getAttachmentsData(), cipherMessage = { 'paste': plainText }; - if (typeof file !== 'undefined' && file !== null) { - cipherMessage['attachment'] = file; - cipherMessage['attachment_name'] = AttachmentViewer.getFile().name; + if (attachmentsData.length) { + cipherMessage['attachment'] = attachmentsData; + cipherMessage['attachment_name'] = AttachmentViewer.getFiles().map((fileInfo => fileInfo.name)); } else if (AttachmentViewer.hasAttachment()) { // fall back to cloned part - let attachment = AttachmentViewer.getAttachment(); - cipherMessage['attachment'] = attachment[0]; - cipherMessage['attachment_name'] = attachment[1]; + let attachments = AttachmentViewer.getAttachments(); + cipherMessage['attachment'] = attachments.map(attachment => attachment[0]); + cipherMessage['attachment_name'] = attachments.map(attachment => attachment[1]); - // we need to retrieve data from blob if browser already parsed it in memory - if (typeof attachment[0] === 'string' && attachment[0].startsWith('blob:')) { - Alert.showStatus( - [ - 'Retrieving cloned file \'%s\' from memory...', - attachment[1] - ], - 'copy' - ); - try { - const blobData = await $.ajax({ - type: 'GET', - url: `${attachment[0]}`, - processData: false, - timeout: 10000, - xhrFields: { - withCredentials: false, - responseType: 'blob' - } - }); - if (blobData instanceof window.Blob) { - const fileReading = new Promise(function(resolve, reject) { - const fileReader = new FileReader(); - fileReader.onload = function (event) { - resolve(event.target.result); - }; - fileReader.onerror = function (error) { - reject(error); + cipherMessage['attachment'] = await Promise.all(cipherMessage['attachment'].map(async (attachment) => { + // we need to retrieve data from blob if browser already parsed it in memory + if (typeof attachment === 'string' && attachment.startsWith('blob:')) { + Alert.showStatus( + [ + 'Retrieving cloned file \'%s\' from memory...', + attachment[1] + ], + 'copy' + ); + try { + const blobData = await $.ajax({ + type: 'GET', + url: `${attachment}`, + processData: false, + timeout: 10000, + xhrFields: { + withCredentials: false, + responseType: 'blob' } - fileReader.readAsDataURL(blobData); }); - cipherMessage['attachment'] = await fileReading; - } else { - const error = 'Cannot process attachment data.'; - Alert.showError(error); - throw new TypeError(error); + if (blobData instanceof window.Blob) { + const fileReading = new Promise(function(resolve, reject) { + const fileReader = new FileReader(); + fileReader.onload = function (event) { + resolve(event.target.result); + }; + fileReader.onerror = function (error) { + reject(error); + } + fileReader.readAsDataURL(blobData); + }); + + return await fileReading; + } else { + const error = 'Cannot process attachment data.'; + Alert.showError(error); + throw new TypeError(error); + } + } catch (error) { + Alert.showError('Cannot retrieve attachment.'); + throw error; } - } catch (error) { - console.error(error); - Alert.showError('Cannot retrieve attachment.'); - throw error; } - } + })); } // encrypt message @@ -5153,13 +5326,13 @@ jQuery.PrivateBin = (function($, RawDeflate) { } /** - * decrypt the actual paste text + * decrypt the actual document text * * @name PasteDecrypter.decryptPaste * @private * @async * @function - * @param {Paste} paste - paste data in object form + * @param {Paste} paste - document data in object form * @param {string} key * @param {string} password * @throws {string} @@ -5167,7 +5340,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ async function decryptPaste(paste, key, password) { - let pastePlain = await decryptOrPromptPassword( + const pastePlain = await decryptOrPromptPassword( key, password, paste.getCipherData() ); @@ -5183,28 +5356,21 @@ jQuery.PrivateBin = (function($, RawDeflate) { } } - if (paste.v > 1) { - // version 2 paste - const pasteMessage = JSON.parse(pastePlain); - if (pasteMessage.hasOwnProperty('attachment') && pasteMessage.hasOwnProperty('attachment_name')) { - AttachmentViewer.setAttachment(pasteMessage.attachment, pasteMessage.attachment_name); - AttachmentViewer.showAttachment(); - } - pastePlain = pasteMessage.paste; - } else { - // version 1 paste - if (paste.hasOwnProperty('attachment') && paste.hasOwnProperty('attachmentname')) { - Promise.all([ - CryptTool.decipher(key, password, paste.attachment), - CryptTool.decipher(key, password, paste.attachmentname) - ]).then((attachment) => { - AttachmentViewer.setAttachment(attachment[0], attachment[1]); - AttachmentViewer.showAttachment(); + const pasteMessage = JSON.parse(pastePlain); + if (pasteMessage.hasOwnProperty('attachment') && pasteMessage.hasOwnProperty('attachment_name')) { + if (Array.isArray(pasteMessage.attachment) && Array.isArray(pasteMessage.attachment_name)) { + pasteMessage.attachment.forEach((attachment, key) => { + const attachment_name = pasteMessage.attachment_name[key]; + AttachmentViewer.setAttachment(attachment, attachment_name); }); + } else { + // Continue to process attachment parameters as strings to ensure backward compatibility + AttachmentViewer.setAttachment(pasteMessage.attachment, pasteMessage.attachment_name); } + AttachmentViewer.showAttachment(); } PasteViewer.setFormat(paste.getFormat()); - PasteViewer.setText(pastePlain); + PasteViewer.setText(pasteMessage.paste); PasteViewer.run(); } @@ -5215,7 +5381,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { * @private * @async * @function - * @param {Paste} paste - paste data in object form + * @param {Paste} paste - document data in object form * @param {string} key * @param {string} password * @return {Promise} @@ -5231,28 +5397,15 @@ jQuery.PrivateBin = (function($, RawDeflate) { const comment = new Comment(paste.comments[i]), commentPromise = CryptTool.decipher(key, password, comment.getCipherData()); paste.comments[i] = comment; - if (comment.v > 1) { - // version 2 comment - commentDecryptionPromises.push( - commentPromise.then(function (commentJson) { - const commentMessage = JSON.parse(commentJson); - return [ - commentMessage.comment || '', - commentMessage.nickname || '' - ]; - }) - ); - } else { - // version 1 comment - commentDecryptionPromises.push( - Promise.all([ - commentPromise, - paste.comments[i].meta.hasOwnProperty('nickname') ? - CryptTool.decipher(key, password, paste.comments[i].meta.nickname) : - Promise.resolve('') - ]) - ); - } + commentDecryptionPromises.push( + commentPromise.then(function (commentJson) { + const commentMessage = JSON.parse(commentJson); + return [ + commentMessage.comment || '', + commentMessage.nickname || '' + ]; + }) + ); } return Promise.all(commentDecryptionPromises).then(function (plaintexts) { for (let i = 0; i < paste.comments.length; ++i) { @@ -5278,7 +5431,8 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.run = function(paste) { Alert.hideMessages(); - Alert.showLoading('Decrypting paste…', 'cloud-download'); + Alert.setCustomHandler(null); + Alert.showLoading('Decrypting document…', 'cloud-download'); if (typeof paste === 'undefined' || paste.type === 'click') { // get cipher data and wait until it is available @@ -5295,10 +5449,13 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.run(paste); }); + // Clear attachments to prevent duplicates + AttachmentViewer.removeAttachment(); + // decrypt paste & attachments decryptionPromises.push(decryptPaste(paste, key, password)); - // if the discussion is opened on this paste, display it + // if the discussion is opened on this document, display it if (paste.isDiscussionEnabled()) { decryptionPromises.push(decryptComments(paste, key, password)); } @@ -5306,6 +5463,8 @@ jQuery.PrivateBin = (function($, RawDeflate) { // shows the remaining time (until) deletion PasteStatus.showRemainingTime(paste); + CopyToClipboard.showKeyboardShortcutHint(); + Promise.all(decryptionPromises) .then(() => { Alert.hideLoading(); @@ -5319,7 +5478,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { TopNav.showEmailButton(paste.getTimeToLive()); } - // only offer adding comments, after paste was successfully decrypted + // only offer adding comments, after document was successfully decrypted if (paste.isDiscussionEnabled()) { DiscussionViewer.finishDiscussion(); } @@ -5335,6 +5494,187 @@ jQuery.PrivateBin = (function($, RawDeflate) { return me; })(); + /** + * + * @name CopyToClipboard + * @class + */ + const CopyToClipboard = (function () { + const me = {}; + + let copyButton, + copyLinkButton, + copyIcon, + successIcon, + shortcutHint, + url; + + /** + * Handle copy to clipboard button click + * + * @name CopyToClipboard.handleCopyButtonClick + * @private + * @function + */ + function handleCopyButtonClick() { + $(copyButton).click(function() { + const text = PasteViewer.getText(); + saveToClipboard(text); + + toggleSuccessIcon(); + showAlertMessage('Document copied to clipboard'); + }); + }; + + /** + * Handle copy link to clipboard button click + * + * @name CopyToClipboard.handleCopyLinkButtonClick + * @private + * @function + */ + function handleCopyLinkButtonClick() { + $(copyLinkButton).click(function () { + saveToClipboard(url); + + showAlertMessage('Link copied to clipboard'); + }); + } + + /** + * Handle CTRL+C/CMD+C keyboard shortcut + * + * @name CopyToClipboard.handleKeyboardShortcut + * @private + * @function + */ + function handleKeyboardShortcut() { + $(document).bind('copy', function () { + if (!isUserSelectedTextToCopy()) { + const text = PasteViewer.getText(); + saveToClipboard(text); + + showAlertMessage('Document copied to clipboard'); + } + }); + }; + + /** + * Check if user selected some text on the page to copy it + * + * @name CopyToClipboard.isUserSelectedTextToCopy + * @private + * @function + * @returns {boolean} + */ + function isUserSelectedTextToCopy() { + let text = ''; + + if (window.getSelection) { + text = window.getSelection().toString(); + } else if (document.selection && document.selection.type != 'Control') { + text = document.selection.createRange().text; + } + + return text.length > 0; + }; + + /** + * Save text to the clipboard + * + * @name CopyToClipboard.saveToClipboard + * @private + * @param {string} text + * @function + */ + function saveToClipboard(text) { + navigator.clipboard.writeText(text); + }; + + /** + * Show alert message after text copy + * + * @name CopyToClipboard.showAlertMessage + * @private + * @param {string} message + * @function + */ + function showAlertMessage(message) { + Alert.showStatus(message); + }; + + /** + * Toogle success icon after copy + * + * @name CopyToClipboard.toggleSuccessIcon + * @private + * @function + */ + function toggleSuccessIcon() { + $(copyIcon).css('display', 'none'); + $(successIcon).css('display', 'block'); + + setTimeout(function() { + $(copyIcon).css('display', 'block'); + $(successIcon).css('display', 'none'); + }, 1000); + }; + + /** + * Show keyboard shortcut hint + * + * @name CopyToClipboard.showKeyboardShortcutHint + * @function + */ + me.showKeyboardShortcutHint = function () { + I18n._( + shortcutHint, + 'To copy document press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c' + ); + }; + + /** + * Hide keyboard shortcut hint + * + * @name CopyToClipboard.showKeyboardShortcutHint + * @function + */ + me.hideKeyboardShortcutHint = function () { + $(shortcutHint).html(''); + }; + + /** + * Set document url + * + * @name CopyToClipboard.setUrl + * @param {string} newUrl + * @function + */ + me.setUrl = function (newUrl) { + url = newUrl; + }; + + /** + * Initialize + * + * @name CopyToClipboard.init + * @function + */ + me.init = function() { + copyButton = $('#prettyMessageCopyBtn'); + copyLinkButton = $('#copyLink'); + copyIcon = $('#copyIcon'); + successIcon = $('#copySuccessIcon'); + shortcutHint = $('#copyShortcutHintText'); + + handleCopyButtonClick(); + handleCopyLinkButtonClick(); + handleKeyboardShortcut(); + }; + + return me; + })(); + /** * (controller) main PrivateBin logic * @@ -5356,10 +5696,11 @@ jQuery.PrivateBin = (function($, RawDeflate) { { PasteStatus.hideMessages(); Alert.hideMessages(); + CopyToClipboard.hideKeyboardShortcutHint(); }; /** - * creates a new paste + * creates a new document * * @name Controller.newPaste * @function @@ -5367,9 +5708,9 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.newPaste = function() { // Important: This *must not* run Alert.hideMessages() as previous - // errors from viewing a paste should be shown. + // errors from viewing a document should be shown. TopNav.hideAllButtons(); - Alert.showLoading('Preparing new paste…', 'time'); + Alert.showLoading('Preparing new document…', 'time'); PasteStatus.hideMessages(); PasteViewer.hide(); @@ -5381,7 +5722,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { TopNav.showCreateButtons(); - // newPaste could be called when user is on paste clone editing view + // newPaste could be called when user is on document clone editing view TopNav.hideCustomAttachment(); AttachmentViewer.clearDragAndDrop(); AttachmentViewer.removeAttachmentData(); @@ -5397,7 +5738,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { }; /** - * shows the loaded paste + * shows the loaded document * * @name Controller.showPaste * @function @@ -5408,12 +5749,8 @@ jQuery.PrivateBin = (function($, RawDeflate) { Model.getPasteKey(); } catch (err) { console.error(err); - - // missing decryption key (or paste ID) in URL? - if (window.location.hash.length === 0) { - Alert.showError('Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)'); - return; - } + Alert.showError('Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)'); + return; } // check if we should request loading confirmation @@ -5427,7 +5764,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { }; /** - * refreshes the loaded paste to show potential new data + * refreshes the loaded document to show potential new data * * @name Controller.refreshPaste * @function @@ -5468,7 +5805,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { } /** - * clone the current paste + * clone the current document * * @name Controller.clonePaste * @function @@ -5478,17 +5815,21 @@ jQuery.PrivateBin = (function($, RawDeflate) { TopNav.collapseBar(); TopNav.hideAllButtons(); - // hide messages from previous paste + // hide messages from previous document me.hideStatusMessages(); // erase the id and the key in url history.pushState({type: 'clone'}, document.title, Helper.baseUri()); if (AttachmentViewer.hasAttachment()) { - AttachmentViewer.moveAttachmentTo( - TopNav.getCustomAttachment(), - 'Cloned: \'%s\'' - ); + const attachments = AttachmentViewer.getAttachments(); + attachments.forEach(attachment => { + AttachmentViewer.moveAttachmentTo( + TopNav.getCustomAttachment(), + attachment, + 'Cloned: \'%s\'' + ); + }); TopNav.hideFileSelector(); AttachmentViewer.hideAttachment(); // NOTE: it also looks nice without removing the attachment @@ -5496,12 +5837,12 @@ jQuery.PrivateBin = (function($, RawDeflate) { AttachmentViewer.hideAttachmentPreview(); TopNav.showCustomAttachment(); - // show another status message to make the user aware that the - // file was cloned too! + // show another status messages to make the user aware that the + // files were cloned too! Alert.showStatus( [ - 'The cloned file \'%s\' was attached to this paste.', - AttachmentViewer.getAttachment()[1] + 'The cloned file \'%s\' was attached to this document.', + attachments.map(attachment => attachment[1]).join(', '), ], 'copy' ); @@ -5581,6 +5922,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { Prompt.init(); TopNav.init(); UiHelper.init(); + CopyToClipboard.init(); // check for legacy browsers before going any further if (!Legacy.Check.getInit()) { @@ -5594,26 +5936,29 @@ jQuery.PrivateBin = (function($, RawDeflate) { } me.initZ(); - // if delete token is passed (i.e. paste has been deleted by this - // access), there is nothing more to do + // if delete token is passed (i.e. document has been deleted by this + // access), add an event listener for the 'new' document button in the alert if (Model.hasDeleteToken()) { + $("#new-from-alert").on("click", function () { + UiHelper.reloadHome(); + }); return; } - // check whether existing paste needs to be shown + // check whether existing document needs to be shown try { Model.getPasteId(); } catch (e) { - // otherwise create a new paste + // otherwise create a new document return me.newPaste(); } - // always reload on back button to invalidate cache(protect burn after read paste) + // always reload on back button to invalidate cache (protect burn after read document) window.addEventListener('popstate', () => { window.location.reload(); }); - // display an existing paste + // display an existing document return me.showPaste(); } @@ -5637,6 +5982,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { ServerInteraction: ServerInteraction, PasteEncrypter: PasteEncrypter, PasteDecrypter: PasteDecrypter, + CopyToClipboard: CopyToClipboard, Controller: Controller }; -})(jQuery, RawDeflate); +})(jQuery); diff --git a/js/purify-3.0.8.js b/js/purify-3.0.8.js deleted file mode 100644 index 9f090115..00000000 --- a/js/purify-3.0.8.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! @license DOMPurify 3.0.8 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.0.8/LICENSE */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).DOMPurify=t()}(this,(function(){"use strict";const{entries:e,setPrototypeOf:t,isFrozen:n,getPrototypeOf:o,getOwnPropertyDescriptor:r}=Object;let{freeze:i,seal:a,create:l}=Object,{apply:c,construct:s}="undefined"!=typeof Reflect&&Reflect;i||(i=function(e){return e}),a||(a=function(e){return e}),c||(c=function(e,t,n){return e.apply(t,n)}),s||(s=function(e,t){return new e(...t)});const u=b(Array.prototype.forEach),m=b(Array.prototype.pop),f=b(Array.prototype.push),p=b(String.prototype.toLowerCase),d=b(String.prototype.toString),h=b(String.prototype.match),g=b(String.prototype.replace),T=b(String.prototype.indexOf),y=b(String.prototype.trim),E=b(RegExp.prototype.test),A=(_=TypeError,function(){for(var e=arguments.length,t=new Array(e),n=0;n1?n-1:0),r=1;r2&&void 0!==arguments[2]?arguments[2]:p;t&&t(e,null);let i=o.length;for(;i--;){let t=o[i];if("string"==typeof t){const e=r(t);e!==t&&(n(o)||(o[i]=e),t=e)}e[t]=!0}return e}function S(e){for(let t=0;t/gm),z=a(/\${[\w\W]*}/gm),B=a(/^data-[\-\w.\u00B7-\uFFFF]/),W=a(/^aria-[\-\w]+$/),G=a(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),Y=a(/^(?:\w+script|data):/i),j=a(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),q=a(/^html$/i);var X=Object.freeze({__proto__:null,MUSTACHE_EXPR:F,ERB_EXPR:H,TMPLIT_EXPR:z,DATA_ATTR:B,ARIA_ATTR:W,IS_ALLOWED_URI:G,IS_SCRIPT_OR_DATA:Y,ATTR_WHITESPACE:j,DOCTYPE_NAME:q});const K=function(){return"undefined"==typeof window?null:window},V=function(e,t){if("object"!=typeof e||"function"!=typeof e.createPolicy)return null;let n=null;const o="data-tt-policy-suffix";t&&t.hasAttribute(o)&&(n=t.getAttribute(o));const r="dompurify"+(n?"#"+n:"");try{return e.createPolicy(r,{createHTML:e=>e,createScriptURL:e=>e})}catch(e){return console.warn("TrustedTypes policy "+r+" could not be created."),null}};var $=function t(){let n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:K();const o=e=>t(e);if(o.version="3.0.8",o.removed=[],!n||!n.document||9!==n.document.nodeType)return o.isSupported=!1,o;let{document:r}=n;const a=r,c=a.currentScript,{DocumentFragment:s,HTMLTemplateElement:_,Node:b,Element:S,NodeFilter:F,NamedNodeMap:H=n.NamedNodeMap||n.MozNamedAttrMap,HTMLFormElement:z,DOMParser:B,trustedTypes:W}=n,Y=S.prototype,j=w(Y,"cloneNode"),$=w(Y,"nextSibling"),Z=w(Y,"childNodes"),J=w(Y,"parentNode");if("function"==typeof _){const e=r.createElement("template");e.content&&e.content.ownerDocument&&(r=e.content.ownerDocument)}let Q,ee="";const{implementation:te,createNodeIterator:ne,createDocumentFragment:oe,getElementsByTagName:re}=r,{importNode:ie}=a;let ae={};o.isSupported="function"==typeof e&&"function"==typeof J&&te&&void 0!==te.createHTMLDocument;const{MUSTACHE_EXPR:le,ERB_EXPR:ce,TMPLIT_EXPR:se,DATA_ATTR:ue,ARIA_ATTR:me,IS_SCRIPT_OR_DATA:fe,ATTR_WHITESPACE:pe}=X;let{IS_ALLOWED_URI:de}=X,he=null;const ge=N({},[...D,...L,...v,...k,...O]);let Te=null;const ye=N({},[...I,...M,...U,...P]);let Ee=Object.seal(l(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),Ae=null,_e=null,be=!0,Ne=!0,Se=!1,Re=!0,we=!1,De=!1,Le=!1,ve=!1,xe=!1,ke=!1,Ce=!1,Oe=!0,Ie=!1;const Me="user-content-";let Ue=!0,Pe=!1,Fe={},He=null;const ze=N({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]);let Be=null;const We=N({},["audio","video","img","source","image","track"]);let Ge=null;const Ye=N({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),je="http://www.w3.org/1998/Math/MathML",qe="http://www.w3.org/2000/svg",Xe="http://www.w3.org/1999/xhtml";let Ke=Xe,Ve=!1,$e=null;const Ze=N({},[je,qe,Xe],d);let Je=null;const Qe=["application/xhtml+xml","text/html"],et="text/html";let tt=null,nt=null;const ot=r.createElement("form"),rt=function(e){return e instanceof RegExp||e instanceof Function},it=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!nt||nt!==e){if(e&&"object"==typeof e||(e={}),e=R(e),Je=-1===Qe.indexOf(e.PARSER_MEDIA_TYPE)?et:e.PARSER_MEDIA_TYPE,tt="application/xhtml+xml"===Je?d:p,he="ALLOWED_TAGS"in e?N({},e.ALLOWED_TAGS,tt):ge,Te="ALLOWED_ATTR"in e?N({},e.ALLOWED_ATTR,tt):ye,$e="ALLOWED_NAMESPACES"in e?N({},e.ALLOWED_NAMESPACES,d):Ze,Ge="ADD_URI_SAFE_ATTR"in e?N(R(Ye),e.ADD_URI_SAFE_ATTR,tt):Ye,Be="ADD_DATA_URI_TAGS"in e?N(R(We),e.ADD_DATA_URI_TAGS,tt):We,He="FORBID_CONTENTS"in e?N({},e.FORBID_CONTENTS,tt):ze,Ae="FORBID_TAGS"in e?N({},e.FORBID_TAGS,tt):{},_e="FORBID_ATTR"in e?N({},e.FORBID_ATTR,tt):{},Fe="USE_PROFILES"in e&&e.USE_PROFILES,be=!1!==e.ALLOW_ARIA_ATTR,Ne=!1!==e.ALLOW_DATA_ATTR,Se=e.ALLOW_UNKNOWN_PROTOCOLS||!1,Re=!1!==e.ALLOW_SELF_CLOSE_IN_ATTR,we=e.SAFE_FOR_TEMPLATES||!1,De=e.WHOLE_DOCUMENT||!1,xe=e.RETURN_DOM||!1,ke=e.RETURN_DOM_FRAGMENT||!1,Ce=e.RETURN_TRUSTED_TYPE||!1,ve=e.FORCE_BODY||!1,Oe=!1!==e.SANITIZE_DOM,Ie=e.SANITIZE_NAMED_PROPS||!1,Ue=!1!==e.KEEP_CONTENT,Pe=e.IN_PLACE||!1,de=e.ALLOWED_URI_REGEXP||G,Ke=e.NAMESPACE||Xe,Ee=e.CUSTOM_ELEMENT_HANDLING||{},e.CUSTOM_ELEMENT_HANDLING&&rt(e.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(Ee.tagNameCheck=e.CUSTOM_ELEMENT_HANDLING.tagNameCheck),e.CUSTOM_ELEMENT_HANDLING&&rt(e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(Ee.attributeNameCheck=e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),e.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(Ee.allowCustomizedBuiltInElements=e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),we&&(Ne=!1),ke&&(xe=!0),Fe&&(he=N({},O),Te=[],!0===Fe.html&&(N(he,D),N(Te,I)),!0===Fe.svg&&(N(he,L),N(Te,M),N(Te,P)),!0===Fe.svgFilters&&(N(he,v),N(Te,M),N(Te,P)),!0===Fe.mathMl&&(N(he,k),N(Te,U),N(Te,P))),e.ADD_TAGS&&(he===ge&&(he=R(he)),N(he,e.ADD_TAGS,tt)),e.ADD_ATTR&&(Te===ye&&(Te=R(Te)),N(Te,e.ADD_ATTR,tt)),e.ADD_URI_SAFE_ATTR&&N(Ge,e.ADD_URI_SAFE_ATTR,tt),e.FORBID_CONTENTS&&(He===ze&&(He=R(He)),N(He,e.FORBID_CONTENTS,tt)),Ue&&(he["#text"]=!0),De&&N(he,["html","head","body"]),he.table&&(N(he,["tbody"]),delete Ae.tbody),e.TRUSTED_TYPES_POLICY){if("function"!=typeof e.TRUSTED_TYPES_POLICY.createHTML)throw A('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if("function"!=typeof e.TRUSTED_TYPES_POLICY.createScriptURL)throw A('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');Q=e.TRUSTED_TYPES_POLICY,ee=Q.createHTML("")}else void 0===Q&&(Q=V(W,c)),null!==Q&&"string"==typeof ee&&(ee=Q.createHTML(""));i&&i(e),nt=e}},at=N({},["mi","mo","mn","ms","mtext"]),lt=N({},["foreignobject","desc","title","annotation-xml"]),ct=N({},["title","style","font","a","script"]),st=N({},[...L,...v,...x]),ut=N({},[...k,...C]),mt=function(e){let t=J(e);t&&t.tagName||(t={namespaceURI:Ke,tagName:"template"});const n=p(e.tagName),o=p(t.tagName);return!!$e[e.namespaceURI]&&(e.namespaceURI===qe?t.namespaceURI===Xe?"svg"===n:t.namespaceURI===je?"svg"===n&&("annotation-xml"===o||at[o]):Boolean(st[n]):e.namespaceURI===je?t.namespaceURI===Xe?"math"===n:t.namespaceURI===qe?"math"===n&<[o]:Boolean(ut[n]):e.namespaceURI===Xe?!(t.namespaceURI===qe&&!lt[o])&&(!(t.namespaceURI===je&&!at[o])&&(!ut[n]&&(ct[n]||!st[n]))):!("application/xhtml+xml"!==Je||!$e[e.namespaceURI]))},ft=function(e){f(o.removed,{element:e});try{e.parentNode.removeChild(e)}catch(t){e.remove()}},pt=function(e,t){try{f(o.removed,{attribute:t.getAttributeNode(e),from:t})}catch(e){f(o.removed,{attribute:null,from:t})}if(t.removeAttribute(e),"is"===e&&!Te[e])if(xe||ke)try{ft(t)}catch(e){}else try{t.setAttribute(e,"")}catch(e){}},dt=function(e){let t=null,n=null;if(ve)e=""+e;else{const t=h(e,/^[\r\n\t ]+/);n=t&&t[0]}"application/xhtml+xml"===Je&&Ke===Xe&&(e=''+e+"");const o=Q?Q.createHTML(e):e;if(Ke===Xe)try{t=(new B).parseFromString(o,Je)}catch(e){}if(!t||!t.documentElement){t=te.createDocument(Ke,"template",null);try{t.documentElement.innerHTML=Ve?ee:o}catch(e){}}const i=t.body||t.documentElement;return e&&n&&i.insertBefore(r.createTextNode(n),i.childNodes[0]||null),Ke===Xe?re.call(t,De?"html":"body")[0]:De?t.documentElement:i},ht=function(e){return ne.call(e.ownerDocument||e,e,F.SHOW_ELEMENT|F.SHOW_COMMENT|F.SHOW_TEXT,null)},gt=function(e){return e instanceof z&&("string"!=typeof e.nodeName||"string"!=typeof e.textContent||"function"!=typeof e.removeChild||!(e.attributes instanceof H)||"function"!=typeof e.removeAttribute||"function"!=typeof e.setAttribute||"string"!=typeof e.namespaceURI||"function"!=typeof e.insertBefore||"function"!=typeof e.hasChildNodes)},Tt=function(e){return"function"==typeof b&&e instanceof b},yt=function(e,t,n){ae[e]&&u(ae[e],(e=>{e.call(o,t,n,nt)}))},Et=function(e){let t=null;if(yt("beforeSanitizeElements",e,null),gt(e))return ft(e),!0;const n=tt(e.nodeName);if(yt("uponSanitizeElement",e,{tagName:n,allowedTags:he}),e.hasChildNodes()&&!Tt(e.firstElementChild)&&E(/<[/\w]/g,e.innerHTML)&&E(/<[/\w]/g,e.textContent))return ft(e),!0;if(!he[n]||Ae[n]){if(!Ae[n]&&_t(n)){if(Ee.tagNameCheck instanceof RegExp&&E(Ee.tagNameCheck,n))return!1;if(Ee.tagNameCheck instanceof Function&&Ee.tagNameCheck(n))return!1}if(Ue&&!He[n]){const t=J(e)||e.parentNode,n=Z(e)||e.childNodes;if(n&&t){for(let o=n.length-1;o>=0;--o)t.insertBefore(j(n[o],!0),$(e))}}return ft(e),!0}return e instanceof S&&!mt(e)?(ft(e),!0):"noscript"!==n&&"noembed"!==n&&"noframes"!==n||!E(/<\/no(script|embed|frames)/i,e.innerHTML)?(we&&3===e.nodeType&&(t=e.textContent,u([le,ce,se],(e=>{t=g(t,e," ")})),e.textContent!==t&&(f(o.removed,{element:e.cloneNode()}),e.textContent=t)),yt("afterSanitizeElements",e,null),!1):(ft(e),!0)},At=function(e,t,n){if(Oe&&("id"===t||"name"===t)&&(n in r||n in ot))return!1;if(Ne&&!_e[t]&&E(ue,t));else if(be&&E(me,t));else if(!Te[t]||_e[t]){if(!(_t(e)&&(Ee.tagNameCheck instanceof RegExp&&E(Ee.tagNameCheck,e)||Ee.tagNameCheck instanceof Function&&Ee.tagNameCheck(e))&&(Ee.attributeNameCheck instanceof RegExp&&E(Ee.attributeNameCheck,t)||Ee.attributeNameCheck instanceof Function&&Ee.attributeNameCheck(t))||"is"===t&&Ee.allowCustomizedBuiltInElements&&(Ee.tagNameCheck instanceof RegExp&&E(Ee.tagNameCheck,n)||Ee.tagNameCheck instanceof Function&&Ee.tagNameCheck(n))))return!1}else if(Ge[t]);else if(E(de,g(n,pe,"")));else if("src"!==t&&"xlink:href"!==t&&"href"!==t||"script"===e||0!==T(n,"data:")||!Be[e]){if(Se&&!E(fe,g(n,pe,"")));else if(n)return!1}else;return!0},_t=function(e){return e.indexOf("-")>0},bt=function(e){yt("beforeSanitizeAttributes",e,null);const{attributes:t}=e;if(!t)return;const n={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:Te};let r=t.length;for(;r--;){const i=t[r],{name:a,namespaceURI:l,value:c}=i,s=tt(a);let f="value"===a?c:y(c);if(n.attrName=s,n.attrValue=f,n.keepAttr=!0,n.forceKeepAttr=void 0,yt("uponSanitizeAttribute",e,n),f=n.attrValue,n.forceKeepAttr)continue;if(pt(a,e),!n.keepAttr)continue;if(!Re&&E(/\/>/i,f)){pt(a,e);continue}we&&u([le,ce,se],(e=>{f=g(f,e," ")}));const p=tt(e.nodeName);if(At(p,s,f)){if(!Ie||"id"!==s&&"name"!==s||(pt(a,e),f=Me+f),Q&&"object"==typeof W&&"function"==typeof W.getAttributeType)if(l);else switch(W.getAttributeType(p,s)){case"TrustedHTML":f=Q.createHTML(f);break;case"TrustedScriptURL":f=Q.createScriptURL(f)}try{l?e.setAttributeNS(l,a,f):e.setAttribute(a,f),m(o.removed)}catch(e){}}}yt("afterSanitizeAttributes",e,null)},Nt=function e(t){let n=null;const o=ht(t);for(yt("beforeSanitizeShadowDOM",t,null);n=o.nextNode();)yt("uponSanitizeShadowNode",n,null),Et(n)||(n.content instanceof s&&e(n.content),bt(n));yt("afterSanitizeShadowDOM",t,null)};return o.sanitize=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=null,r=null,i=null,l=null;if(Ve=!e,Ve&&(e="\x3c!--\x3e"),"string"!=typeof e&&!Tt(e)){if("function"!=typeof e.toString)throw A("toString is not a function");if("string"!=typeof(e=e.toString()))throw A("dirty is not a string, aborting")}if(!o.isSupported)return e;if(Le||it(t),o.removed=[],"string"==typeof e&&(Pe=!1),Pe){if(e.nodeName){const t=tt(e.nodeName);if(!he[t]||Ae[t])throw A("root node is forbidden and cannot be sanitized in-place")}}else if(e instanceof b)n=dt("\x3c!----\x3e"),r=n.ownerDocument.importNode(e,!0),1===r.nodeType&&"BODY"===r.nodeName||"HTML"===r.nodeName?n=r:n.appendChild(r);else{if(!xe&&!we&&!De&&-1===e.indexOf("<"))return Q&&Ce?Q.createHTML(e):e;if(n=dt(e),!n)return xe?null:Ce?ee:""}n&&ve&&ft(n.firstChild);const c=ht(Pe?e:n);for(;i=c.nextNode();)Et(i)||(i.content instanceof s&&Nt(i.content),bt(i));if(Pe)return e;if(xe){if(ke)for(l=oe.call(n.ownerDocument);n.firstChild;)l.appendChild(n.firstChild);else l=n;return(Te.shadowroot||Te.shadowrootmode)&&(l=ie.call(a,l,!0)),l}let m=De?n.outerHTML:n.innerHTML;return De&&he["!doctype"]&&n.ownerDocument&&n.ownerDocument.doctype&&n.ownerDocument.doctype.name&&E(q,n.ownerDocument.doctype.name)&&(m="\n"+m),we&&u([le,ce,se],(e=>{m=g(m,e," ")})),Q&&Ce?Q.createHTML(m):m},o.setConfig=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};it(e),Le=!0},o.clearConfig=function(){nt=null,Le=!1},o.isValidAttribute=function(e,t,n){nt||it({});const o=tt(e),r=tt(t);return At(o,r,n)},o.addHook=function(e,t){"function"==typeof t&&(ae[e]=ae[e]||[],f(ae[e],t))},o.removeHook=function(e){if(ae[e])return m(ae[e])},o.removeHooks=function(e){ae[e]&&(ae[e]=[])},o.removeAllHooks=function(){ae={}},o}();return $})); diff --git a/js/purify-3.2.6.js b/js/purify-3.2.6.js new file mode 100644 index 00000000..a4ef769b --- /dev/null +++ b/js/purify-3.2.6.js @@ -0,0 +1,2 @@ +/*! @license DOMPurify 3.2.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.2.6/LICENSE */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).DOMPurify=t()}(this,(function(){"use strict";const{entries:e,setPrototypeOf:t,isFrozen:n,getPrototypeOf:o,getOwnPropertyDescriptor:r}=Object;let{freeze:i,seal:a,create:l}=Object,{apply:c,construct:s}="undefined"!=typeof Reflect&&Reflect;i||(i=function(e){return e}),a||(a=function(e){return e}),c||(c=function(e,t,n){return e.apply(t,n)}),s||(s=function(e,t){return new e(...t)});const u=R(Array.prototype.forEach),m=R(Array.prototype.lastIndexOf),p=R(Array.prototype.pop),f=R(Array.prototype.push),d=R(Array.prototype.splice),h=R(String.prototype.toLowerCase),g=R(String.prototype.toString),T=R(String.prototype.match),y=R(String.prototype.replace),E=R(String.prototype.indexOf),A=R(String.prototype.trim),_=R(Object.prototype.hasOwnProperty),S=R(RegExp.prototype.test),b=(N=TypeError,function(){for(var e=arguments.length,t=new Array(e),n=0;n1?n-1:0),r=1;r2&&void 0!==arguments[2]?arguments[2]:h;t&&t(e,null);let i=o.length;for(;i--;){let t=o[i];if("string"==typeof t){const e=r(t);e!==t&&(n(o)||(o[i]=e),t=e)}e[t]=!0}return e}function O(e){for(let t=0;t/gm),G=a(/\$\{[\w\W]*/gm),Y=a(/^data-[\-\w.\u00B7-\uFFFF]+$/),j=a(/^aria-[\-\w]+$/),X=a(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),q=a(/^(?:\w+script|data):/i),$=a(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),K=a(/^html$/i),V=a(/^[a-z][.\w]*(-[.\w]+)+$/i);var Z=Object.freeze({__proto__:null,ARIA_ATTR:j,ATTR_WHITESPACE:$,CUSTOM_ELEMENT:V,DATA_ATTR:Y,DOCTYPE_NAME:K,ERB_EXPR:W,IS_ALLOWED_URI:X,IS_SCRIPT_OR_DATA:q,MUSTACHE_EXPR:B,TMPLIT_EXPR:G});const J=1,Q=3,ee=7,te=8,ne=9,oe=function(){return"undefined"==typeof window?null:window};var re=function t(){let n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:oe();const o=e=>t(e);if(o.version="3.2.6",o.removed=[],!n||!n.document||n.document.nodeType!==ne||!n.Element)return o.isSupported=!1,o;let{document:r}=n;const a=r,c=a.currentScript,{DocumentFragment:s,HTMLTemplateElement:N,Node:R,Element:O,NodeFilter:B,NamedNodeMap:W=n.NamedNodeMap||n.MozNamedAttrMap,HTMLFormElement:G,DOMParser:Y,trustedTypes:j}=n,q=O.prototype,$=v(q,"cloneNode"),V=v(q,"remove"),re=v(q,"nextSibling"),ie=v(q,"childNodes"),ae=v(q,"parentNode");if("function"==typeof N){const e=r.createElement("template");e.content&&e.content.ownerDocument&&(r=e.content.ownerDocument)}let le,ce="";const{implementation:se,createNodeIterator:ue,createDocumentFragment:me,getElementsByTagName:pe}=r,{importNode:fe}=a;let de={afterSanitizeAttributes:[],afterSanitizeElements:[],afterSanitizeShadowDOM:[],beforeSanitizeAttributes:[],beforeSanitizeElements:[],beforeSanitizeShadowDOM:[],uponSanitizeAttribute:[],uponSanitizeElement:[],uponSanitizeShadowNode:[]};o.isSupported="function"==typeof e&&"function"==typeof ae&&se&&void 0!==se.createHTMLDocument;const{MUSTACHE_EXPR:he,ERB_EXPR:ge,TMPLIT_EXPR:Te,DATA_ATTR:ye,ARIA_ATTR:Ee,IS_SCRIPT_OR_DATA:Ae,ATTR_WHITESPACE:_e,CUSTOM_ELEMENT:Se}=Z;let{IS_ALLOWED_URI:be}=Z,Ne=null;const Re=w({},[...L,...C,...x,...M,...U]);let we=null;const Oe=w({},[...z,...P,...H,...F]);let De=Object.seal(l(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),ve=null,Le=null,Ce=!0,xe=!0,Ie=!1,Me=!0,ke=!1,Ue=!0,ze=!1,Pe=!1,He=!1,Fe=!1,Be=!1,We=!1,Ge=!0,Ye=!1,je=!0,Xe=!1,qe={},$e=null;const Ke=w({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]);let Ve=null;const Ze=w({},["audio","video","img","source","image","track"]);let Je=null;const Qe=w({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),et="http://www.w3.org/1998/Math/MathML",tt="http://www.w3.org/2000/svg",nt="http://www.w3.org/1999/xhtml";let ot=nt,rt=!1,it=null;const at=w({},[et,tt,nt],g);let lt=w({},["mi","mo","mn","ms","mtext"]),ct=w({},["annotation-xml"]);const st=w({},["title","style","font","a","script"]);let ut=null;const mt=["application/xhtml+xml","text/html"];let pt=null,ft=null;const dt=r.createElement("form"),ht=function(e){return e instanceof RegExp||e instanceof Function},gt=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!ft||ft!==e){if(e&&"object"==typeof e||(e={}),e=D(e),ut=-1===mt.indexOf(e.PARSER_MEDIA_TYPE)?"text/html":e.PARSER_MEDIA_TYPE,pt="application/xhtml+xml"===ut?g:h,Ne=_(e,"ALLOWED_TAGS")?w({},e.ALLOWED_TAGS,pt):Re,we=_(e,"ALLOWED_ATTR")?w({},e.ALLOWED_ATTR,pt):Oe,it=_(e,"ALLOWED_NAMESPACES")?w({},e.ALLOWED_NAMESPACES,g):at,Je=_(e,"ADD_URI_SAFE_ATTR")?w(D(Qe),e.ADD_URI_SAFE_ATTR,pt):Qe,Ve=_(e,"ADD_DATA_URI_TAGS")?w(D(Ze),e.ADD_DATA_URI_TAGS,pt):Ze,$e=_(e,"FORBID_CONTENTS")?w({},e.FORBID_CONTENTS,pt):Ke,ve=_(e,"FORBID_TAGS")?w({},e.FORBID_TAGS,pt):D({}),Le=_(e,"FORBID_ATTR")?w({},e.FORBID_ATTR,pt):D({}),qe=!!_(e,"USE_PROFILES")&&e.USE_PROFILES,Ce=!1!==e.ALLOW_ARIA_ATTR,xe=!1!==e.ALLOW_DATA_ATTR,Ie=e.ALLOW_UNKNOWN_PROTOCOLS||!1,Me=!1!==e.ALLOW_SELF_CLOSE_IN_ATTR,ke=e.SAFE_FOR_TEMPLATES||!1,Ue=!1!==e.SAFE_FOR_XML,ze=e.WHOLE_DOCUMENT||!1,Fe=e.RETURN_DOM||!1,Be=e.RETURN_DOM_FRAGMENT||!1,We=e.RETURN_TRUSTED_TYPE||!1,He=e.FORCE_BODY||!1,Ge=!1!==e.SANITIZE_DOM,Ye=e.SANITIZE_NAMED_PROPS||!1,je=!1!==e.KEEP_CONTENT,Xe=e.IN_PLACE||!1,be=e.ALLOWED_URI_REGEXP||X,ot=e.NAMESPACE||nt,lt=e.MATHML_TEXT_INTEGRATION_POINTS||lt,ct=e.HTML_INTEGRATION_POINTS||ct,De=e.CUSTOM_ELEMENT_HANDLING||{},e.CUSTOM_ELEMENT_HANDLING&&ht(e.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(De.tagNameCheck=e.CUSTOM_ELEMENT_HANDLING.tagNameCheck),e.CUSTOM_ELEMENT_HANDLING&&ht(e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(De.attributeNameCheck=e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),e.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(De.allowCustomizedBuiltInElements=e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),ke&&(xe=!1),Be&&(Fe=!0),qe&&(Ne=w({},U),we=[],!0===qe.html&&(w(Ne,L),w(we,z)),!0===qe.svg&&(w(Ne,C),w(we,P),w(we,F)),!0===qe.svgFilters&&(w(Ne,x),w(we,P),w(we,F)),!0===qe.mathMl&&(w(Ne,M),w(we,H),w(we,F))),e.ADD_TAGS&&(Ne===Re&&(Ne=D(Ne)),w(Ne,e.ADD_TAGS,pt)),e.ADD_ATTR&&(we===Oe&&(we=D(we)),w(we,e.ADD_ATTR,pt)),e.ADD_URI_SAFE_ATTR&&w(Je,e.ADD_URI_SAFE_ATTR,pt),e.FORBID_CONTENTS&&($e===Ke&&($e=D($e)),w($e,e.FORBID_CONTENTS,pt)),je&&(Ne["#text"]=!0),ze&&w(Ne,["html","head","body"]),Ne.table&&(w(Ne,["tbody"]),delete ve.tbody),e.TRUSTED_TYPES_POLICY){if("function"!=typeof e.TRUSTED_TYPES_POLICY.createHTML)throw b('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if("function"!=typeof e.TRUSTED_TYPES_POLICY.createScriptURL)throw b('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');le=e.TRUSTED_TYPES_POLICY,ce=le.createHTML("")}else void 0===le&&(le=function(e,t){if("object"!=typeof e||"function"!=typeof e.createPolicy)return null;let n=null;const o="data-tt-policy-suffix";t&&t.hasAttribute(o)&&(n=t.getAttribute(o));const r="dompurify"+(n?"#"+n:"");try{return e.createPolicy(r,{createHTML:e=>e,createScriptURL:e=>e})}catch(e){return console.warn("TrustedTypes policy "+r+" could not be created."),null}}(j,c)),null!==le&&"string"==typeof ce&&(ce=le.createHTML(""));i&&i(e),ft=e}},Tt=w({},[...C,...x,...I]),yt=w({},[...M,...k]),Et=function(e){f(o.removed,{element:e});try{ae(e).removeChild(e)}catch(t){V(e)}},At=function(e,t){try{f(o.removed,{attribute:t.getAttributeNode(e),from:t})}catch(e){f(o.removed,{attribute:null,from:t})}if(t.removeAttribute(e),"is"===e)if(Fe||Be)try{Et(t)}catch(e){}else try{t.setAttribute(e,"")}catch(e){}},_t=function(e){let t=null,n=null;if(He)e=""+e;else{const t=T(e,/^[\r\n\t ]+/);n=t&&t[0]}"application/xhtml+xml"===ut&&ot===nt&&(e=''+e+"");const o=le?le.createHTML(e):e;if(ot===nt)try{t=(new Y).parseFromString(o,ut)}catch(e){}if(!t||!t.documentElement){t=se.createDocument(ot,"template",null);try{t.documentElement.innerHTML=rt?ce:o}catch(e){}}const i=t.body||t.documentElement;return e&&n&&i.insertBefore(r.createTextNode(n),i.childNodes[0]||null),ot===nt?pe.call(t,ze?"html":"body")[0]:ze?t.documentElement:i},St=function(e){return ue.call(e.ownerDocument||e,e,B.SHOW_ELEMENT|B.SHOW_COMMENT|B.SHOW_TEXT|B.SHOW_PROCESSING_INSTRUCTION|B.SHOW_CDATA_SECTION,null)},bt=function(e){return e instanceof G&&("string"!=typeof e.nodeName||"string"!=typeof e.textContent||"function"!=typeof e.removeChild||!(e.attributes instanceof W)||"function"!=typeof e.removeAttribute||"function"!=typeof e.setAttribute||"string"!=typeof e.namespaceURI||"function"!=typeof e.insertBefore||"function"!=typeof e.hasChildNodes)},Nt=function(e){return"function"==typeof R&&e instanceof R};function Rt(e,t,n){u(e,(e=>{e.call(o,t,n,ft)}))}const wt=function(e){let t=null;if(Rt(de.beforeSanitizeElements,e,null),bt(e))return Et(e),!0;const n=pt(e.nodeName);if(Rt(de.uponSanitizeElement,e,{tagName:n,allowedTags:Ne}),Ue&&e.hasChildNodes()&&!Nt(e.firstElementChild)&&S(/<[/\w!]/g,e.innerHTML)&&S(/<[/\w!]/g,e.textContent))return Et(e),!0;if(e.nodeType===ee)return Et(e),!0;if(Ue&&e.nodeType===te&&S(/<[/\w]/g,e.data))return Et(e),!0;if(!Ne[n]||ve[n]){if(!ve[n]&&Dt(n)){if(De.tagNameCheck instanceof RegExp&&S(De.tagNameCheck,n))return!1;if(De.tagNameCheck instanceof Function&&De.tagNameCheck(n))return!1}if(je&&!$e[n]){const t=ae(e)||e.parentNode,n=ie(e)||e.childNodes;if(n&&t){for(let o=n.length-1;o>=0;--o){const r=$(n[o],!0);r.__removalCount=(e.__removalCount||0)+1,t.insertBefore(r,re(e))}}}return Et(e),!0}return e instanceof O&&!function(e){let t=ae(e);t&&t.tagName||(t={namespaceURI:ot,tagName:"template"});const n=h(e.tagName),o=h(t.tagName);return!!it[e.namespaceURI]&&(e.namespaceURI===tt?t.namespaceURI===nt?"svg"===n:t.namespaceURI===et?"svg"===n&&("annotation-xml"===o||lt[o]):Boolean(Tt[n]):e.namespaceURI===et?t.namespaceURI===nt?"math"===n:t.namespaceURI===tt?"math"===n&&ct[o]:Boolean(yt[n]):e.namespaceURI===nt?!(t.namespaceURI===tt&&!ct[o])&&!(t.namespaceURI===et&&!lt[o])&&!yt[n]&&(st[n]||!Tt[n]):!("application/xhtml+xml"!==ut||!it[e.namespaceURI]))}(e)?(Et(e),!0):"noscript"!==n&&"noembed"!==n&&"noframes"!==n||!S(/<\/no(script|embed|frames)/i,e.innerHTML)?(ke&&e.nodeType===Q&&(t=e.textContent,u([he,ge,Te],(e=>{t=y(t,e," ")})),e.textContent!==t&&(f(o.removed,{element:e.cloneNode()}),e.textContent=t)),Rt(de.afterSanitizeElements,e,null),!1):(Et(e),!0)},Ot=function(e,t,n){if(Ge&&("id"===t||"name"===t)&&(n in r||n in dt))return!1;if(xe&&!Le[t]&&S(ye,t));else if(Ce&&S(Ee,t));else if(!we[t]||Le[t]){if(!(Dt(e)&&(De.tagNameCheck instanceof RegExp&&S(De.tagNameCheck,e)||De.tagNameCheck instanceof Function&&De.tagNameCheck(e))&&(De.attributeNameCheck instanceof RegExp&&S(De.attributeNameCheck,t)||De.attributeNameCheck instanceof Function&&De.attributeNameCheck(t))||"is"===t&&De.allowCustomizedBuiltInElements&&(De.tagNameCheck instanceof RegExp&&S(De.tagNameCheck,n)||De.tagNameCheck instanceof Function&&De.tagNameCheck(n))))return!1}else if(Je[t]);else if(S(be,y(n,_e,"")));else if("src"!==t&&"xlink:href"!==t&&"href"!==t||"script"===e||0!==E(n,"data:")||!Ve[e]){if(Ie&&!S(Ae,y(n,_e,"")));else if(n)return!1}else;return!0},Dt=function(e){return"annotation-xml"!==e&&T(e,Se)},vt=function(e){Rt(de.beforeSanitizeAttributes,e,null);const{attributes:t}=e;if(!t||bt(e))return;const n={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:we,forceKeepAttr:void 0};let r=t.length;for(;r--;){const i=t[r],{name:a,namespaceURI:l,value:c}=i,s=pt(a),m=c;let f="value"===a?m:A(m);if(n.attrName=s,n.attrValue=f,n.keepAttr=!0,n.forceKeepAttr=void 0,Rt(de.uponSanitizeAttribute,e,n),f=n.attrValue,!Ye||"id"!==s&&"name"!==s||(At(a,e),f="user-content-"+f),Ue&&S(/((--!?|])>)|<\/(style|title)/i,f)){At(a,e);continue}if(n.forceKeepAttr)continue;if(!n.keepAttr){At(a,e);continue}if(!Me&&S(/\/>/i,f)){At(a,e);continue}ke&&u([he,ge,Te],(e=>{f=y(f,e," ")}));const d=pt(e.nodeName);if(Ot(d,s,f)){if(le&&"object"==typeof j&&"function"==typeof j.getAttributeType)if(l);else switch(j.getAttributeType(d,s)){case"TrustedHTML":f=le.createHTML(f);break;case"TrustedScriptURL":f=le.createScriptURL(f)}if(f!==m)try{l?e.setAttributeNS(l,a,f):e.setAttribute(a,f),bt(e)?Et(e):p(o.removed)}catch(t){At(a,e)}}else At(a,e)}Rt(de.afterSanitizeAttributes,e,null)},Lt=function e(t){let n=null;const o=St(t);for(Rt(de.beforeSanitizeShadowDOM,t,null);n=o.nextNode();)Rt(de.uponSanitizeShadowNode,n,null),wt(n),vt(n),n.content instanceof s&&e(n.content);Rt(de.afterSanitizeShadowDOM,t,null)};return o.sanitize=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=null,r=null,i=null,l=null;if(rt=!e,rt&&(e="\x3c!--\x3e"),"string"!=typeof e&&!Nt(e)){if("function"!=typeof e.toString)throw b("toString is not a function");if("string"!=typeof(e=e.toString()))throw b("dirty is not a string, aborting")}if(!o.isSupported)return e;if(Pe||gt(t),o.removed=[],"string"==typeof e&&(Xe=!1),Xe){if(e.nodeName){const t=pt(e.nodeName);if(!Ne[t]||ve[t])throw b("root node is forbidden and cannot be sanitized in-place")}}else if(e instanceof R)n=_t("\x3c!----\x3e"),r=n.ownerDocument.importNode(e,!0),r.nodeType===J&&"BODY"===r.nodeName||"HTML"===r.nodeName?n=r:n.appendChild(r);else{if(!Fe&&!ke&&!ze&&-1===e.indexOf("<"))return le&&We?le.createHTML(e):e;if(n=_t(e),!n)return Fe?null:We?ce:""}n&&He&&Et(n.firstChild);const c=St(Xe?e:n);for(;i=c.nextNode();)wt(i),vt(i),i.content instanceof s&&Lt(i.content);if(Xe)return e;if(Fe){if(Be)for(l=me.call(n.ownerDocument);n.firstChild;)l.appendChild(n.firstChild);else l=n;return(we.shadowroot||we.shadowrootmode)&&(l=fe.call(a,l,!0)),l}let m=ze?n.outerHTML:n.innerHTML;return ze&&Ne["!doctype"]&&n.ownerDocument&&n.ownerDocument.doctype&&n.ownerDocument.doctype.name&&S(K,n.ownerDocument.doctype.name)&&(m="\n"+m),ke&&u([he,ge,Te],(e=>{m=y(m,e," ")})),le&&We?le.createHTML(m):m},o.setConfig=function(){gt(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}),Pe=!0},o.clearConfig=function(){ft=null,Pe=!1},o.isValidAttribute=function(e,t,n){ft||gt({});const o=pt(e),r=pt(t);return Ot(o,r,n)},o.addHook=function(e,t){"function"==typeof t&&f(de[e],t)},o.removeHook=function(e,t){if(void 0!==t){const n=m(de[e],t);return-1===n?void 0:d(de[e],n,1)[0]}return p(de[e])},o.removeHooks=function(e){de[e]=[]},o.removeAllHooks=function(){de={afterSanitizeAttributes:[],afterSanitizeElements:[],afterSanitizeShadowDOM:[],beforeSanitizeAttributes:[],beforeSanitizeElements:[],beforeSanitizeShadowDOM:[],uponSanitizeAttribute:[],uponSanitizeElement:[],uponSanitizeShadowNode:[]}},o}();return re})); diff --git a/js/rawinflate-0.3.js b/js/rawinflate-0.3.js deleted file mode 100644 index d3ac0e01..00000000 --- a/js/rawinflate-0.3.js +++ /dev/null @@ -1,755 +0,0 @@ -/* - * $Id: rawinflate.js,v 0.3 2013/04/09 14:25:38 dankogai Exp dankogai $ - * - * GNU General Public License, version 2 (GPL-2.0) - * https://opensource.org/licenses/GPL-2.0 - * original: - * http://www.onicos.com/staff/iz/amuse/javascript/expert/inflate.txt - */ - -(function(ctx){ - -/* Copyright (C) 1999 Masanao Izumo - * Version: 1.0.0.1 - * LastModified: Dec 25 1999 - */ - -/* Interface: - * data = zip_inflate(src); - */ - -/* constant parameters */ -var zip_WSIZE = 32768; // Sliding Window size -var zip_STORED_BLOCK = 0; -var zip_STATIC_TREES = 1; -var zip_DYN_TREES = 2; - -/* for inflate */ -var zip_lbits = 9; // bits in base literal/length lookup table -var zip_dbits = 6; // bits in base distance lookup table -var zip_INBUFSIZ = 32768; // Input buffer size -var zip_INBUF_EXTRA = 64; // Extra buffer - -/* variables (inflate) */ -var zip_slide; -var zip_wp; // current position in slide -var zip_fixed_tl = null; // inflate static -var zip_fixed_td; // inflate static -var zip_fixed_bl, fixed_bd; // inflate static -var zip_bit_buf; // bit buffer -var zip_bit_len; // bits in bit buffer -var zip_method; -var zip_eof; -var zip_copy_leng; -var zip_copy_dist; -var zip_tl, zip_td; // literal/length and distance decoder tables -var zip_bl, zip_bd; // number of bits decoded by tl and td - -var zip_inflate_data; -var zip_inflate_pos; - - -/* constant tables (inflate) */ -var zip_MASK_BITS = new Array( - 0x0000, - 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, - 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff); -// Tables for deflate from PKZIP's appnote.txt. -var zip_cplens = new Array( // Copy lengths for literal codes 257..285 - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0); -/* note: see note #13 above about the 258 in this list. */ -var zip_cplext = new Array( // Extra bits for literal codes 257..285 - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99); // 99==invalid -var zip_cpdist = new Array( // Copy offsets for distance codes 0..29 - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577); -var zip_cpdext = new Array( // Extra bits for distance codes - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13); -var zip_border = new Array( // Order of the bit length code lengths - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15); -/* objects (inflate) */ - -var zip_HuftList = function() { - this.next = null; - this.list = null; -} - -var zip_HuftNode = function() { - this.e = 0; // number of extra bits or operation - this.b = 0; // number of bits in this code or subcode - - // union - this.n = 0; // literal, length base, or distance base - this.t = null; // (zip_HuftNode) pointer to next level of table -} - -var zip_HuftBuild = function(b, // code lengths in bits (all assumed <= BMAX) - n, // number of codes (assumed <= N_MAX) - s, // number of simple-valued codes (0..s-1) - d, // list of base values for non-simple codes - e, // list of extra bits for non-simple codes - mm // maximum lookup bits - ) { - this.BMAX = 16; // maximum bit length of any code - this.N_MAX = 288; // maximum number of codes in any set - this.status = 0; // 0: success, 1: incomplete table, 2: bad input - this.root = null; // (zip_HuftList) starting table - this.m = 0; // maximum lookup bits, returns actual - -/* Given a list of code lengths and a maximum table size, make a set of - tables to decode that set of codes. Return zero on success, one if - the given code set is incomplete (the tables are still built in this - case), two if the input is invalid (all zero length codes or an - oversubscribed set of lengths), and three if not enough memory. - The code with value 256 is special, and the tables are constructed - so that no bits beyond that code are fetched when that code is - decoded. */ - { - var a; // counter for codes of length k - var c = new Array(this.BMAX+1); // bit length count table - var el; // length of EOB code (value 256) - var f; // i repeats in table every f entries - var g; // maximum code length - var h; // table level - var i; // counter, current code - var j; // counter - var k; // number of bits in current code - var lx = new Array(this.BMAX+1); // stack of bits per table - var p; // pointer into c[], b[], or v[] - var pidx; // index of p - var q; // (zip_HuftNode) points to current table - var r = new zip_HuftNode(); // table entry for structure assignment - var u = new Array(this.BMAX); // zip_HuftNode[BMAX][] table stack - var v = new Array(this.N_MAX); // values in order of bit length - var w; - var x = new Array(this.BMAX+1);// bit offsets, then code stack - var xp; // pointer into x or c - var y; // number of dummy codes added - var z; // number of entries in current table - var o; - var tail; // (zip_HuftList) - - tail = this.root = null; - for(i = 0; i < c.length; i++) - c[i] = 0; - for(i = 0; i < lx.length; i++) - lx[i] = 0; - for(i = 0; i < u.length; i++) - u[i] = null; - for(i = 0; i < v.length; i++) - v[i] = 0; - for(i = 0; i < x.length; i++) - x[i] = 0; - - // Generate counts for each bit length - el = n > 256 ? b[256] : this.BMAX; // set length of EOB code, if any - p = b; pidx = 0; - i = n; - do { - c[p[pidx]]++; // assume all entries <= BMAX - pidx++; - } while(--i > 0); - if(c[0] == n) { // null input--all zero length codes - this.root = null; - this.m = 0; - this.status = 0; - return; - } - - // Find minimum and maximum length, bound *m by those - for(j = 1; j <= this.BMAX; j++) - if(c[j] != 0) - break; - k = j; // minimum code length - if(mm < j) - mm = j; - for(i = this.BMAX; i != 0; i--) - if(c[i] != 0) - break; - g = i; // maximum code length - if(mm > i) - mm = i; - - // Adjust last length count to fill out codes, if needed - for(y = 1 << j; j < i; j++, y <<= 1) - if((y -= c[j]) < 0) { - this.status = 2; // bad input: more codes than bits - this.m = mm; - return; - } - if((y -= c[i]) < 0) { - this.status = 2; - this.m = mm; - return; - } - c[i] += y; - - // Generate starting offsets into the value table for each length - x[1] = j = 0; - p = c; - pidx = 1; - xp = 2; - while(--i > 0) // note that i == g from above - x[xp++] = (j += p[pidx++]); - - // Make a table of values in order of bit lengths - p = b; pidx = 0; - i = 0; - do { - if((j = p[pidx++]) != 0) - v[x[j]++] = i; - } while(++i < n); - n = x[g]; // set n to length of v - - // Generate the Huffman codes and for each, make the table entries - x[0] = i = 0; // first Huffman code is zero - p = v; pidx = 0; // grab values in bit order - h = -1; // no tables yet--level -1 - w = lx[0] = 0; // no bits decoded yet - q = null; // ditto - z = 0; // ditto - - // go through the bit lengths (k already is bits in shortest code) - for(; k <= g; k++) { - a = c[k]; - while(a-- > 0) { - // here i is the Huffman code of length k bits for value p[pidx] - // make tables up to required level - while(k > w + lx[1 + h]) { - w += lx[1 + h]; // add bits already decoded - h++; - - // compute minimum size table less than or equal to *m bits - z = (z = g - w) > mm ? mm : z; // upper limit - if((f = 1 << (j = k - w)) > a + 1) { // try a k-w bit table - // too few codes for k-w bit table - f -= a + 1; // deduct codes from patterns left - xp = k; - while(++j < z) { // try smaller tables up to z bits - if((f <<= 1) <= c[++xp]) - break; // enough codes to use up j bits - f -= c[xp]; // else deduct codes from patterns - } - } - if(w + j > el && w < el) - j = el - w; // make EOB code end at table - z = 1 << j; // table entries for j-bit table - lx[1 + h] = j; // set table size in stack - - // allocate and link in new table - q = new Array(z); - for(o = 0; o < z; o++) { - q[o] = new zip_HuftNode(); - } - - if(tail == null) - tail = this.root = new zip_HuftList(); - else - tail = tail.next = new zip_HuftList(); - tail.next = null; - tail.list = q; - u[h] = q; // table starts after link - - /* connect to last table, if there is one */ - if(h > 0) { - x[h] = i; // save pattern for backing up - r.b = lx[h]; // bits to dump before this table - r.e = 16 + j; // bits in this table - r.t = q; // pointer to this table - j = (i & ((1 << w) - 1)) >> (w - lx[h]); - u[h-1][j].e = r.e; - u[h-1][j].b = r.b; - u[h-1][j].n = r.n; - u[h-1][j].t = r.t; - } - } - - // set up table entry in r - r.b = k - w; - if(pidx >= n) - r.e = 99; // out of values--invalid code - else if(p[pidx] < s) { - r.e = (p[pidx] < 256 ? 16 : 15); // 256 is end-of-block code - r.n = p[pidx++]; // simple code is just the value - } else { - r.e = e[p[pidx] - s]; // non-simple--look up in lists - r.n = d[p[pidx++] - s]; - } - - // fill code-like entries with r // - f = 1 << (k - w); - for(j = i >> w; j < z; j += f) { - q[j].e = r.e; - q[j].b = r.b; - q[j].n = r.n; - q[j].t = r.t; - } - - // backwards increment the k-bit code i - for(j = 1 << (k - 1); (i & j) != 0; j >>= 1) - i ^= j; - i ^= j; - - // backup over finished tables - while((i & ((1 << w) - 1)) != x[h]) { - w -= lx[h]; // don't need to update q - h--; - } - } - } - - /* return actual size of base table */ - this.m = lx[1]; - - /* Return true (1) if we were given an incomplete table */ - this.status = ((y != 0 && g != 1) ? 1 : 0); - } /* end of constructor */ -} - - -/* routines (inflate) */ - -var zip_GET_BYTE = function() { - if(zip_inflate_data.length == zip_inflate_pos) - return -1; - return zip_inflate_data.charCodeAt(zip_inflate_pos++) & 0xff; -} - -var zip_NEEDBITS = function(n) { - while(zip_bit_len < n) { - zip_bit_buf |= zip_GET_BYTE() << zip_bit_len; - zip_bit_len += 8; - } -} - -var zip_GETBITS = function(n) { - return zip_bit_buf & zip_MASK_BITS[n]; -} - -var zip_DUMPBITS = function(n) { - zip_bit_buf >>= n; - zip_bit_len -= n; -} - -var zip_inflate_codes = function(buff, off, size) { - /* inflate (decompress) the codes in a deflated (compressed) block. - Return an error code or zero if it all goes ok. */ - var e; // table entry flag/number of extra bits - var t; // (zip_HuftNode) pointer to table entry - var n; - - if(size == 0) - return 0; - - // inflate the coded data - n = 0; - for(;;) { // do until end of block - zip_NEEDBITS(zip_bl); - t = zip_tl.list[zip_GETBITS(zip_bl)]; - e = t.e; - while(e > 16) { - if(e == 99) - return -1; - zip_DUMPBITS(t.b); - e -= 16; - zip_NEEDBITS(e); - t = t.t[zip_GETBITS(e)]; - e = t.e; - } - zip_DUMPBITS(t.b); - - if(e == 16) { // then it's a literal - zip_wp &= zip_WSIZE - 1; - buff[off + n++] = zip_slide[zip_wp++] = t.n; - if(n == size) - return size; - continue; - } - - // exit if end of block - if(e == 15) - break; - - // it's an EOB or a length - - // get length of block to copy - zip_NEEDBITS(e); - zip_copy_leng = t.n + zip_GETBITS(e); - zip_DUMPBITS(e); - - // decode distance of block to copy - zip_NEEDBITS(zip_bd); - t = zip_td.list[zip_GETBITS(zip_bd)]; - e = t.e; - - while(e > 16) { - if(e == 99) - return -1; - zip_DUMPBITS(t.b); - e -= 16; - zip_NEEDBITS(e); - t = t.t[zip_GETBITS(e)]; - e = t.e; - } - zip_DUMPBITS(t.b); - zip_NEEDBITS(e); - zip_copy_dist = zip_wp - t.n - zip_GETBITS(e); - zip_DUMPBITS(e); - - // do the copy - while(zip_copy_leng > 0 && n < size) { - zip_copy_leng--; - zip_copy_dist &= zip_WSIZE - 1; - zip_wp &= zip_WSIZE - 1; - buff[off + n++] = zip_slide[zip_wp++] - = zip_slide[zip_copy_dist++]; - } - - if(n == size) - return size; - } - - zip_method = -1; // done - return n; -} - -var zip_inflate_stored = function(buff, off, size) { - /* "decompress" an inflated type 0 (stored) block. */ - var n; - - // go to byte boundary - n = zip_bit_len & 7; - zip_DUMPBITS(n); - - // get the length and its complement - zip_NEEDBITS(16); - n = zip_GETBITS(16); - zip_DUMPBITS(16); - zip_NEEDBITS(16); - if(n != ((~zip_bit_buf) & 0xffff)) - return -1; // error in compressed data - zip_DUMPBITS(16); - - // read and output the compressed data - zip_copy_leng = n; - - n = 0; - while(zip_copy_leng > 0 && n < size) { - zip_copy_leng--; - zip_wp &= zip_WSIZE - 1; - zip_NEEDBITS(8); - buff[off + n++] = zip_slide[zip_wp++] = - zip_GETBITS(8); - zip_DUMPBITS(8); - } - - if(zip_copy_leng == 0) - zip_method = -1; // done - return n; -} - -var zip_inflate_fixed = function(buff, off, size) { - /* decompress an inflated type 1 (fixed Huffman codes) block. We should - either replace this with a custom decoder, or at least precompute the - Huffman tables. */ - - // if first time, set up tables for fixed blocks - if(zip_fixed_tl == null) { - var i; // temporary variable - var l = new Array(288); // length list for huft_build - var h; // zip_HuftBuild - - // literal table - for(i = 0; i < 144; i++) - l[i] = 8; - for(; i < 256; i++) - l[i] = 9; - for(; i < 280; i++) - l[i] = 7; - for(; i < 288; i++) // make a complete, but wrong code set - l[i] = 8; - zip_fixed_bl = 7; - - h = new zip_HuftBuild(l, 288, 257, zip_cplens, zip_cplext, - zip_fixed_bl); - if(h.status != 0) { - alert("HufBuild error: "+h.status); - return -1; - } - zip_fixed_tl = h.root; - zip_fixed_bl = h.m; - - // distance table - for(i = 0; i < 30; i++) // make an incomplete code set - l[i] = 5; - zip_fixed_bd = 5; - - h = new zip_HuftBuild(l, 30, 0, zip_cpdist, zip_cpdext, zip_fixed_bd); - if(h.status > 1) { - zip_fixed_tl = null; - alert("HufBuild error: "+h.status); - return -1; - } - zip_fixed_td = h.root; - zip_fixed_bd = h.m; - } - - zip_tl = zip_fixed_tl; - zip_td = zip_fixed_td; - zip_bl = zip_fixed_bl; - zip_bd = zip_fixed_bd; - return zip_inflate_codes(buff, off, size); -} - -var zip_inflate_dynamic = function(buff, off, size) { - // decompress an inflated type 2 (dynamic Huffman codes) block. - var i; // temporary variables - var j; - var l; // last length - var n; // number of lengths to get - var t; // (zip_HuftNode) literal/length code table - var nb; // number of bit length codes - var nl; // number of literal/length codes - var nd; // number of distance codes - var ll = new Array(286+30); // literal/length and distance code lengths - var h; // (zip_HuftBuild) - - for(i = 0; i < ll.length; i++) - ll[i] = 0; - - // read in table lengths - zip_NEEDBITS(5); - nl = 257 + zip_GETBITS(5); // number of literal/length codes - zip_DUMPBITS(5); - zip_NEEDBITS(5); - nd = 1 + zip_GETBITS(5); // number of distance codes - zip_DUMPBITS(5); - zip_NEEDBITS(4); - nb = 4 + zip_GETBITS(4); // number of bit length codes - zip_DUMPBITS(4); - if(nl > 286 || nd > 30) - return -1; // bad lengths - - // read in bit-length-code lengths - for(j = 0; j < nb; j++) - { - zip_NEEDBITS(3); - ll[zip_border[j]] = zip_GETBITS(3); - zip_DUMPBITS(3); - } - for(; j < 19; j++) - ll[zip_border[j]] = 0; - - // build decoding table for trees--single level, 7 bit lookup - zip_bl = 7; - h = new zip_HuftBuild(ll, 19, 19, null, null, zip_bl); - if(h.status != 0) - return -1; // incomplete code set - - zip_tl = h.root; - zip_bl = h.m; - - // read in literal and distance code lengths - n = nl + nd; - i = l = 0; - while(i < n) { - zip_NEEDBITS(zip_bl); - t = zip_tl.list[zip_GETBITS(zip_bl)]; - j = t.b; - zip_DUMPBITS(j); - j = t.n; - if(j < 16) // length of code in bits (0..15) - ll[i++] = l = j; // save last length in l - else if(j == 16) { // repeat last length 3 to 6 times - zip_NEEDBITS(2); - j = 3 + zip_GETBITS(2); - zip_DUMPBITS(2); - if(i + j > n) - return -1; - while(j-- > 0) - ll[i++] = l; - } else if(j == 17) { // 3 to 10 zero length codes - zip_NEEDBITS(3); - j = 3 + zip_GETBITS(3); - zip_DUMPBITS(3); - if(i + j > n) - return -1; - while(j-- > 0) - ll[i++] = 0; - l = 0; - } else { // j == 18: 11 to 138 zero length codes - zip_NEEDBITS(7); - j = 11 + zip_GETBITS(7); - zip_DUMPBITS(7); - if(i + j > n) - return -1; - while(j-- > 0) - ll[i++] = 0; - l = 0; - } - } - - // build the decoding tables for literal/length and distance codes - zip_bl = zip_lbits; - h = new zip_HuftBuild(ll, nl, 257, zip_cplens, zip_cplext, zip_bl); - if(zip_bl == 0) // no literals or lengths - h.status = 1; - if(h.status != 0) { - if(h.status == 1) - ;// **incomplete literal tree** - return -1; // incomplete code set - } - zip_tl = h.root; - zip_bl = h.m; - - for(i = 0; i < nd; i++) - ll[i] = ll[i + nl]; - zip_bd = zip_dbits; - h = new zip_HuftBuild(ll, nd, 0, zip_cpdist, zip_cpdext, zip_bd); - zip_td = h.root; - zip_bd = h.m; - - if(zip_bd == 0 && nl > 257) { // lengths but no distances - // **incomplete distance tree** - return -1; - } - - if(h.status == 1) { - ;// **incomplete distance tree** - } - if(h.status != 0) - return -1; - - // decompress until an end-of-block code - return zip_inflate_codes(buff, off, size); -} - -var zip_inflate_start = function() { - var i; - - if(zip_slide == null) - zip_slide = new Array(2 * zip_WSIZE); - zip_wp = 0; - zip_bit_buf = 0; - zip_bit_len = 0; - zip_method = -1; - zip_eof = false; - zip_copy_leng = zip_copy_dist = 0; - zip_tl = null; -} - -var zip_inflate_internal = function(buff, off, size) { - // decompress an inflated entry - var n, i; - - n = 0; - while(n < size) { - if(zip_eof && zip_method == -1) - return n; - - if(zip_copy_leng > 0) { - if(zip_method != zip_STORED_BLOCK) { - // STATIC_TREES or DYN_TREES - while(zip_copy_leng > 0 && n < size) { - zip_copy_leng--; - zip_copy_dist &= zip_WSIZE - 1; - zip_wp &= zip_WSIZE - 1; - buff[off + n++] = zip_slide[zip_wp++] = - zip_slide[zip_copy_dist++]; - } - } else { - while(zip_copy_leng > 0 && n < size) { - zip_copy_leng--; - zip_wp &= zip_WSIZE - 1; - zip_NEEDBITS(8); - buff[off + n++] = zip_slide[zip_wp++] = zip_GETBITS(8); - zip_DUMPBITS(8); - } - if(zip_copy_leng == 0) - zip_method = -1; // done - } - if(n == size) - return n; - } - - if(zip_method == -1) { - if(zip_eof) - break; - - // read in last block bit - zip_NEEDBITS(1); - if(zip_GETBITS(1) != 0) - zip_eof = true; - zip_DUMPBITS(1); - - // read in block type - zip_NEEDBITS(2); - zip_method = zip_GETBITS(2); - zip_DUMPBITS(2); - zip_tl = null; - zip_copy_leng = 0; - } - - switch(zip_method) { - case 0: // zip_STORED_BLOCK - i = zip_inflate_stored(buff, off + n, size - n); - break; - - case 1: // zip_STATIC_TREES - if(zip_tl != null) - i = zip_inflate_codes(buff, off + n, size - n); - else - i = zip_inflate_fixed(buff, off + n, size - n); - break; - - case 2: // zip_DYN_TREES - if(zip_tl != null) - i = zip_inflate_codes(buff, off + n, size - n); - else - i = zip_inflate_dynamic(buff, off + n, size - n); - break; - - default: // error - i = -1; - break; - } - - if(i == -1) { - if(zip_eof) - return 0; - return -1; - } - n += i; - } - return n; -} - -var zip_inflate = function(str) { - var i, j; - - zip_inflate_start(); - zip_inflate_data = str; - zip_inflate_pos = 0; - - var buff = new Array(1024); - var aout = []; - while((i = zip_inflate_internal(buff, 0, buff.length)) > 0) { - var cbuf = new Array(i); - for(j = 0; j < i; j++){ - cbuf[j] = String.fromCharCode(buff[j]); - } - aout[aout.length] = cbuf.join(""); - } - zip_inflate_data = null; // G.C. - return aout.join(""); -} - -if (! ctx.RawDeflate) ctx.RawDeflate = {}; -ctx.RawDeflate.inflate = zip_inflate; - -})(this); diff --git a/js/test/AttachmentViewer.js b/js/test/AttachmentViewer.js index 54ddfc1a..f3016076 100644 --- a/js/test/AttachmentViewer.js +++ b/js/test/AttachmentViewer.js @@ -1,5 +1,5 @@ 'use strict'; -var common = require('../common'); +const common = require('../common'); describe('AttachmentViewer', function () { describe('setAttachment, showAttachment, removeAttachment, hideAttachment, hideAttachmentPreview, hasAttachment, getAttachment & moveAttachmentTo', function () { @@ -14,23 +14,31 @@ describe('AttachmentViewer', function () { 'string', function (mimeType, rawdata, filename, prefix, postfix) { let clean = jsdom(), - data = 'data:' + mimeType + ';base64,' + btoa(rawdata), + data = 'data:' + mimeType + ';base64,' + common.btoa(rawdata), + mimePrefix = mimeType.substring(0, 6), previewSupported = ( - mimeType.substring(0, 6) === 'image/' || - mimeType.substring(0, 6) === 'audio/' || - mimeType.substring(0, 6) === 'video/' || + mimePrefix === 'image/' || + mimePrefix === 'audio/' || + mimePrefix === 'video/' || mimeType.match(/\/pdf/i) ), results = [], result = ''; + // text node of attachment will truncate at null byte + if (filename === '\u0000') { + filename = ''; + } prefix = prefix.replace(/%(s|d)/g, '%%'); - postfix = postfix.replace(/%(s|d)/g, '%%'); + postfix = postfix.replace(/%(s|d)/g, '%%').replace(/<|>/g, ''); $('body').html( - '' + '' + + '' + + '
' + + '' + + '
' ); // mock createObjectURL for jsDOM if (typeof window.URL.createObjectURL === 'undefined') { @@ -43,29 +51,35 @@ describe('AttachmentViewer', function () { ) } $.PrivateBin.AttachmentViewer.init(); + $.PrivateBin.Model.init(); results.push( !$.PrivateBin.AttachmentViewer.hasAttachment() && $('#attachment').hasClass('hidden') && + $('#attachment').children().length === 0 && + $('#attachmenttemplate').hasClass('hidden') && $('#attachmentPreview').hasClass('hidden') ); + global.atob = common.atob; if (filename.length) { $.PrivateBin.AttachmentViewer.setAttachment(data, filename); } else { $.PrivateBin.AttachmentViewer.setAttachment(data); } - // beyond this point we will get the blob URL instead of the data + // // beyond this point we will get the blob URL instead of the data data = window.URL.createObjectURL(data); - const attachment = $.PrivateBin.AttachmentViewer.getAttachment(); + const attachment = $.PrivateBin.AttachmentViewer.getAttachments(); results.push( $.PrivateBin.AttachmentViewer.hasAttachment() && $('#attachment').hasClass('hidden') && + $('#attachment').children().length > 0 && $('#attachmentPreview').hasClass('hidden') && - attachment[0] === data && - attachment[1] === filename + attachment[0][0] === data && + attachment[0][1] === filename ); $.PrivateBin.AttachmentViewer.showAttachment(); results.push( !$('#attachment').hasClass('hidden') && + $('#attachment').children().length > 0 && (previewSupported ? !$('#attachmentPreview').hasClass('hidden') : $('#attachmentPreview').hasClass('hidden')) ); $.PrivateBin.AttachmentViewer.hideAttachment(); @@ -83,7 +97,7 @@ describe('AttachmentViewer', function () { (previewSupported ? !$('#attachmentPreview').hasClass('hidden') : $('#attachmentPreview').hasClass('hidden')) ); let element = $('
'); - $.PrivateBin.AttachmentViewer.moveAttachmentTo(element, prefix + '%s' + postfix); + $.PrivateBin.AttachmentViewer.moveAttachmentTo(element, attachment[0], prefix + '%s' + postfix); // messageIDs with links get a relaxed treatment if (prefix.indexOf('').text((prefix + filename + postfix)).text(); @@ -97,16 +111,17 @@ describe('AttachmentViewer', function () { } if (filename.length) { results.push( - element.children()[0].href === data && - element.children()[0].getAttribute('download') === filename && - element.children()[0].text === result + element.find('a')[0].href === data && + element.find('a')[0].getAttribute('download') === filename && + element.find('a')[0].text === result ); } else { - results.push(element.children()[0].href === data); + results.push(element.find('a')[0].href === data); } $.PrivateBin.AttachmentViewer.removeAttachment(); results.push( $('#attachment').hasClass('hidden') && + $('#attachment').children().length === 0 && $('#attachmentPreview').hasClass('hidden') ); clean(); @@ -115,4 +130,3 @@ describe('AttachmentViewer', function () { ); }); }); - diff --git a/js/test/Check.js b/js/test/Check.js index 474330e3..63428c93 100644 --- a/js/test/Check.js +++ b/js/test/Check.js @@ -19,10 +19,9 @@ describe('Check', function () { } ); Legacy.Check.init(); - const result1 = Legacy.Check.getInit() && !Legacy.Check.getStatus(), - result2 = (document.getElementById('errormessage').className !== 'hidden'); + const result = Legacy.Check.getInit() && !Legacy.Check.getStatus(); clean(); - return result1 && result2; + return result; } ), {tests: 10}); @@ -67,7 +66,10 @@ describe('Check', function () { 'url': (secureProtocol ? 'https' : 'http' ) + '://' + domain.join('') + '/' } ); - window.crypto = new WebCrypto(); + Object.defineProperty(window, 'crypto', { + value: new WebCrypto(), + writeable: false, + }); Legacy.Check.init(); const result1 = Legacy.Check.getInit() && Legacy.Check.getStatus(), result2 = secureProtocol === (document.getElementById('httpnotice').className === 'hidden'); diff --git a/js/test/CopyToClipboard.js b/js/test/CopyToClipboard.js new file mode 100644 index 00000000..0abfd53a --- /dev/null +++ b/js/test/CopyToClipboard.js @@ -0,0 +1,139 @@ +'use strict'; +const common = require('../common'); + +describe('CopyToClipboard', function() { + this.timeout(30000); + + describe ('Copy document to clipboard', function () { + jsc.property('Copy with button click', + common.jscFormats(), + 'nestring', + async function (format, text) { + var clean = jsdom(); + common.enableClipboard(); + + $('body').html( + '' + ); + + $.PrivateBin.PasteViewer.init(); + $.PrivateBin.PasteViewer.setFormat(format); + $.PrivateBin.PasteViewer.setText(text); + $.PrivateBin.PasteViewer.run(); + + $.PrivateBin.CopyToClipboard.init(); + + $('#prettyMessageCopyBtn').trigger('click'); + + const savedToClipboardText = await navigator.clipboard.readText(); + + clean(); + + return text === savedToClipboardText; + } + ); + + /** + * Unfortunately in JSVerify impossible to check if copy with shortcut when user selected some text on the page + * (the copy document to clipboard should not work in this case) due to lacking window.getSelection() in jsdom. + */ + jsc.property('Copy with keyboard shortcut', + common.jscFormats(), + 'nestring', + async function (format, text) { + var clean = jsdom(); + common.enableClipboard(); + + $('body').html( + '
+++ no document text ' + + '+++
' + ); + + $.PrivateBin.PasteViewer.init(); + $.PrivateBin.PasteViewer.setFormat(format); + $.PrivateBin.PasteViewer.setText(text); + $.PrivateBin.PasteViewer.run(); + + $.PrivateBin.CopyToClipboard.init(); + + $('body').trigger('copy'); + + const copiedTextWithoutSelectedText = await navigator.clipboard.readText(); + + clean(); + + return copiedTextWithoutSelectedText === text; + } + ); + }); + + + jsc.property('Copy link to clipboard', + 'nestring', + async function (text) { + var clean = jsdom(); + common.enableClipboard(); + + $('body').html(''); + + $.PrivateBin.CopyToClipboard.init(); + $.PrivateBin.CopyToClipboard.setUrl(text); + + $('#copyLink').trigger('click'); + + const copiedText = await navigator.clipboard.readText(); + + clean(); + + return text === copiedText; + } + ); + + + describe('Keyboard shortcut hint', function () { + jsc.property('Show hint', + 'nestring', + function (text) { + var clean = jsdom(); + + $('body').html(''); + + $.PrivateBin.CopyToClipboard.init(); + $.PrivateBin.CopyToClipboard.showKeyboardShortcutHint(); + + const keyboardShortcutHint = $('#copyShortcutHintText').text(); + + clean(); + + return keyboardShortcutHint.length > 0; + } + ); + + jsc.property('Hide hint', + 'nestring', + function (text) { + var clean = jsdom(); + + $('body').html('' + text + ''); + + $.PrivateBin.CopyToClipboard.init(); + $.PrivateBin.CopyToClipboard.hideKeyboardShortcutHint(); + + const keyboardShortcutHint = $('#copyShortcutHintText').text(); + + clean(); + + return keyboardShortcutHint.length === 0; + } + ); + }); +}); \ No newline at end of file diff --git a/js/test/CryptTool.js b/js/test/CryptTool.js index 627a242f..ed94320a 100644 --- a/js/test/CryptTool.js +++ b/js/test/CryptTool.js @@ -1,5 +1,5 @@ 'use strict'; -require('../common'); +const common = require('../common'); describe('CryptTool', function () { describe('cipher & decipher', function () { @@ -15,185 +15,52 @@ describe('CryptTool', function () { 'string', 'string', async function (key, password, message) { - // pause to let async functions conclude - await new Promise(resolve => setTimeout(resolve, 300)); - let clean = jsdom(); + const clean = jsdom(); // ensure zlib is getting loaded $.PrivateBin.Controller.initZ(); - window.crypto = new WebCrypto(); + Object.defineProperty(window, 'crypto', { + value: new WebCrypto(), + writeable: false, + }); + global.atob = common.atob; + global.btoa = common.btoa; message = message.trim(); - let cipherMessage = await $.PrivateBin.CryptTool.cipher( + const cipherMessage = await $.PrivateBin.CryptTool.cipher( key, password, message, [] ), plaintext = await $.PrivateBin.CryptTool.decipher( key, password, cipherMessage ); clean(); - return message === plaintext; + const result = (message === plaintext); + if (!result) console.log(plaintext, cipherMessage); + return result; } ), {tests: 3}); }); - // The below static unit tests are included to ensure deciphering of "classic" - // SJCL based pastes still works - it( - 'supports PrivateBin v1 ciphertext (SJCL & browser atob)', - function () { - delete global.Base64; - let clean = jsdom(); - window.crypto = new WebCrypto(); - - // Of course you can easily decipher the following texts, if you like. - // Bonus points for finding their sources and hidden meanings. - return $.PrivateBin.CryptTool.decipher( - '6t2qsmLyfXIokNCL+3/yl15rfTUBQvm5SOnFPvNE7Q8=', - // -- "That's amazing. I've got the same combination on my luggage." - Array.apply(0, Array(6)).map((_,b) => b + 1).join(''), - '{"iv":"4HNFIl7eYbCh6HuShctTIA==","v":1,"iter":10000,"ks"' + - ':256,"ts":128,"mode":"gcm","adata":"","cipher":"aes","sa' + - 'lt":"u0lQvePq6L0=","ct":"fGPUVrDyaVr1ZDGb+kqQ3CPEW8x4YKG' + - 'fzHDmA0Vjkh250aWNe7Cnigkps9aaFVMX9AaerrTp3yZbojJtNqVGMfL' + - 'dUTu+53xmZHqRKxCCqSfDNSNoW4Oxk5OVgAtRyuG4bXHDsWTXDNz2xce' + - 'qzVFqhkwTwlUchrV7uuFK/XUKTNjPFM744moivIcBbfM2FOeKlIFs8RY' + - 'PYuvqQhp2rMLlNGwwKh//4kykQsHMQDeSDuJl8stMQzgWR/btUBZuwNZ' + - 'EydkMH6IPpTdf5WTSrZ+wC2OK0GutCm4UaEe6txzaTMfu+WRVu4PN6q+' + - 'N+2zljWJ1XdpVcN/i0Sv4QVMym0Xa6y0eccEhj/69o47PmExmMMeEwEx' + - 'ImPalMNT9JUSiZdOZJ/GdzwrwoIuq1mdQR6vSH+XJ/8jXJQ7bjjJVJYX' + - 'TcT0Di5jixArI2Kpp1GGlGVFbLgPugwU1wczg+byqeDOAECXRRnQcoge' + - 'aJtVcRwXwfy4j3ORFcblYMilxyHqKBewcYPRVBGtBs50cVjSIkAfR84r' + - 'nc1nfvnxK/Gmm+4VBNHI6ODWNpRolVMCzXjbKYnV3Are5AgSpsTqaGl4' + - '1VJGpcco6cAwi4K0Bys1seKR+bLSdUgqRrkEqSRSdu3/VTu9HhEk8an0' + - 'rjTE4CBB5/LMn16p0TGLoOb32odKFIEtpanVvLjeyiVMvSxcgYLNnTi/' + - '5FiaAC4pJxRD+AZHedU1FICUeEXxIcac/4E5qjkHjX9SpQtLl80QLIVn' + - 'jNliZm7QLB/nKu7W8Jb0+/CiTdV3Q9LhxlH4ciprnX+W0B00BKYFHnL9' + - 'jRVzKdXhf1EHydbXMAfpCjHAXIVCkFakJinQBDIIw/SC6Yig0u0ddEID' + - '2B7LYAP1iE4RZwzTrxCB+ke2jQr8c20Jj6u6ShFOPC9DCw9XupZ4HAal' + - 'VG00kSgjus+b8zrVji3/LKEhb4EBzp1ctBJCFTeXwej8ZETLoXTylev5' + - 'dlwZSYAbuBPPcbFR/xAIPx3uDabd1E1gTqUc68ICIGhd197Mb2eRWiSv' + - 'Hr5SPsASerMxId6XA6+iQlRiI+NDR+TGVNmCnfxSlyPFMOHGTmslXOGI' + - 'qGfBR8l4ft8YVZ70lCwmwTuViGc75ULSf9mM57/LmRzQFMYQtvI8IFK9' + - 'JaQEMY5xz0HLtR4iyQUUdwR9e0ytBNdWF2a2WPDEnJuY/QJo4GzTlgv4' + - 'QUxMXI5htsn2rf0HxCFu7Po8DNYLxTS+67hYjDIYWYaEIc8LXWMLyDm9' + - 'C5fARPJ4F2BIWgzgzkNj+dVjusft2XnziamWdbS5u3kuRlVuz5LQj+R5' + - 'imnqQAincdZTkTT1nYx+DatlOLllCYIHffpI="}' - ).then(function (paste1) { - $.PrivateBin.CryptTool.decipher( - 's9pmKZKOBN7EVvHpTA8jjLFH3Xlz/0l8lB4+ONPACrM=', - '', // no password - '{"iv":"WA42mdxIVXUwBqZu7JYNiw==","v":1,"iter":10000,"ks"' + - ':256,"ts":128,"mode":"gcm","adata":"","cipher":"aes","sa' + - 'lt":"jN6CjbQMJCM=","ct":"kYYMo5DFG1+w0UHiYXT5pdV0IUuXxzO' + - 'lslkW/c3DRCbGFROCVkAskHce7HoRczee1N9c5MhHjVMJUIZE02qIS8U' + - 'yHdJ/GqcPVidTUcj9rnDNWsTXkjVv8jCwHS/cwmAjDTWpwp5ThECN+ov' + - '/wNp/NdtTj8Qj7f/T3rfZIOCWfwLH9s4Des35UNcUidfPTNQ1l0Gm0X+' + - 'r98CCUSYZjQxkZc6hRZBLPQ8EaNVooUwd5eP4GiYlmSDNA0wOSA+5isP' + - 'YxomVCt+kFf58VBlNhpfNi7BLYAUTPpXT4SfH5drR9+C7NTeZ+tTCYjb' + - 'U94PzYItOpu8vgnB1/a6BAM5h3m9w+giUb0df4hgTWeZnZxLjo5BN8WV' + - '+kdTXMj3/Vv0gw0DQrDcCuX/cBAjpy3lQGwlAN1vXoOIyZJUjMpQRrOL' + - 'dKvLB+zcmVNtGDbgnfP2IYBzk9NtodpUa27ne0T0ZpwOPlVwevsIVZO2' + - '24WLa+iQmmHOWDFFpVDlS0t0fLfOk7Hcb2xFsTxiCIiyKMho/IME1Du3' + - 'X4e6BVa3hobSSZv0rRtNgY1KcyYPrUPW2fxZ+oik3y9SgGvb7XpjVIta' + - '8DWlDWRfZ9kzoweWEYqz9IA8Xd373RefpyuWI25zlHoX3nwljzsZU6dC' + - '//h/Dt2DNr+IAvKO3+u23cWoB9kgcZJ2FJuqjLvVfCF+OWcig7zs2pTY' + - 'JW6Rg6lqbBCxiUUlae6xJrjfv0pzD2VYCLY7v1bVTagppwKzNI3WaluC' + - 'OrdDYUCxUSe56yd1oAoLPRVbYvomRboUO6cjQhEknERyvt45og2kORJO' + - 'EJayHW+jZgR0Y0jM3Nk17ubpij2gHxNx9kiLDOiCGSV5mn9mV7qd3HHc' + - 'OMSykiBgbyzjobi96LT2dIGLeDXTIdPOog8wyobO4jWq0GGs0vBB8oSY' + - 'XhHvixZLcSjX2KQuHmEoWzmJcr3DavdoXZmAurGWLKjzEdJc5dSD/eNr' + - '99gjHX7wphJ6umKMM+fn6PcbYJkhDh2GlJL5COXjXfm/5aj/vuyaRRWZ' + - 'MZtmnYpGAtAPg7AUG"}' - ).then(function (paste2) { - clean(); - assert.ok( - paste1.includes('securely packed in iron') && - paste2.includes('Sol is right') - ); - }); - }); - } - ); - - it( - 'supports ZeroBin ciphertext (SJCL & Base64 1.7)', - function () { - global.Base64 = require('../base64-1.7').Base64; - var clean = jsdom(); - window.crypto = new WebCrypto(); - - // Of course you can easily decipher the following texts, if you like. - // Bonus points for finding their sources and hidden meanings. - return $.PrivateBin.CryptTool.decipher( - '6t2qsmLyfXIokNCL+3/yl15rfTUBQvm5SOnFPvNE7Q8=', - // -- "That's amazing. I've got the same combination on my luggage." - Array.apply(0, Array(6)).map((_,b) => b + 1).join(''), - '{"iv":"aTnR2qBL1CAmLX8FdWe3VA==","v":1,"iter":10000,"ks"' + - ':256,"ts":128,"mode":"gcm","adata":"","cipher":"aes","sa' + - 'lt":"u0lQvePq6L0=","ct":"A3nBTvICZtYy6xqbIJE0c8Veored5lM' + - 'JUGgGUm4581wjrPFlU0Q0tUZSf+RUUoZj2jqDa4kiyyZ5YNMe30hNMV0' + - 'oVSalNhRgD9svVMnPuF162IbyhVCwr7ULjT981CHxVlGNqGqmIU6L/Xi' + - 'xgdArxAA8x1GCrfAkBWWGeq8Qw5vJPG/RCHpwR4Wy3azrluqeyERBzma' + - 'OQjO/kM35TiI6IrLYFyYyL7upYlxAaxS0XBMZvN8QU8Lnerwvh5JVC6O' + - 'kkKrhogajTJIKozCF79yI78c50LUh7tTuI3Yoh7+fXxhoODvQdYFmoiU' + - 'lrutN7Y5ZMRdITvVu8fTYtX9c7Fiufmcq5icEimiHp2g1bvfpOaGOsFT' + - '+XNFgC9215jcp5mpBdN852xs7bUtw+nDrf+LsDEX6iRpRZ+PYgLDN5xQ' + - 'T1ByEtYbeP+tO38pnx72oZdIB3cj8UkOxnxdNiZM5YB5egn4jUj1fHot' + - '1I69WoTiUJipZ5PIATv7ScymRB+AYzjxjurQ9lVfX9QtAbEH2dhdmoUo' + - '3IDRSXpWNCe9RC1aUIyWfZO7oI7FEohNscHNTLEcT+wFnFUPByLlXmjN' + - 'Z7FKeNpvUm3jTY4t4sbZH8o2dUl624PAw1INcJ6FKqWGWwoFT2j1MYC+' + - 'YV/LkLTdjuWfayvwLMh27G/FfKCRbW36vqinegqpPDylsx9+3oFkEw3y' + - '5Z8+44oN91rE/4Md7JhPJeRVlFC9TNCj4dA+EVhbbQqscvSnIH2uHkMw' + - '7mNNo7xba/YT9KoPDaniqnYqb+q2pX1WNWE7dLS2wfroMAS3kh8P22DA' + - 'V37AeiNoD2PcI6ZcHbRdPa+XRrRcJhSPPW7UQ0z4OvBfjdu/w390QxAx' + - 'SxvZewoh49fKKB6hTsRnZb4tpHkjlww=="}' - ).then(function (paste1) { - $.PrivateBin.CryptTool.decipher( - 's9pmKZKOBN7EVvHpTA8jjLFH3Xlz/0l8lB4+ONPACrM=', - '', // no password - '{"iv":"Z7lAZQbkrqGMvruxoSm6Pw==","v":1,"iter":10000,"ks"' + - ':256,"ts":128,"mode":"gcm","adata":"","cipher":"aes","sa' + - 'lt":"jN6CjbQMJCM=","ct":"PuOPWB3i2FPcreSrLYeQf84LdE8RHjs' + - 'c+MGtiOr4b7doNyWKYtkNorbRadxaPnEee2/Utrp1MIIfY5juJSy8RGw' + - 'EPX5ciWcYe6EzsXWznsnvhmpKNj9B7eIIrfSbxfy8E2e/g7xav1nive+' + - 'ljToka3WT1DZ8ILQd/NbnJeHWaoSEOfvz8+d8QJPb1tNZvs7zEY95Dum' + - 'QwbyOsIMKAvcZHJ9OJNpujXzdMyt6DpcFcqlldWBZ/8q5rAUTw0HNx/r' + - 'CgbhAxRYfNoTLIcMM4L0cXbPSgCjwf5FuO3EdE13mgEDhcClW79m0Qvc' + - 'nIh8xgzYoxLbp0+AwvC/MbZM8savN/0ieWr2EKkZ04ggiOIEyvfCUuNp' + - 'rQBYO+y8kKduNEN6by0Yf4LRCPfmwN+GezDLuzTnZIMhPbGqUAdgV6Ex' + - 'qK2ULEEIrQEMoOuQIxfoMhqLlzG79vXGt2O+BY+4IiYfvmuRLks4UXfy' + - 'HqxPXTJg48IYbGs0j4TtJPUgp3523EyYLwEGyVTAuWhYAmVIwd/hoV7d' + - '7tmfcF73w9dufDFI3LNca2KxzBnWNPYvIZKBwWbq8ncxkb191dP6mjEi' + - '7NnhqVk5A6vIBbu4AC5PZf76l6yep4xsoy/QtdDxCMocCXeAML9MQ9uP' + - 'QbuspOKrBvMfN5igA1kBqasnxI472KBNXsdZnaDddSVUuvhTcETM="}' - ).then(function (paste2) { - clean(); - delete global.Base64; - assert.ok( - paste1.includes('securely packed in iron') && - paste2.includes('Sol is right') - ); - }); - }); - } - ); - it('does not truncate messages', async function () { - let message = fs.readFileSync('test/compression-sample.txt', 'utf8'), + const message = fs.readFileSync('test/compression-sample.txt', 'ascii').trim(), clean = jsdom(); - window.crypto = new WebCrypto(); + Object.defineProperty(window, 'crypto', { + value: new WebCrypto(), + writeable: false, + }); // ensure zlib is getting loaded $.PrivateBin.Controller.initZ(); - let cipherMessage = await $.PrivateBin.CryptTool.cipher( + global.atob = common.atob; + global.btoa = common.btoa; + const cipherMessage = await $.PrivateBin.CryptTool.cipher( 'foo', 'bar', message, [] ), plaintext = await $.PrivateBin.CryptTool.decipher( - 'foo', 'bar', cipherMessage + 'foo', 'bar', cipherMessage ); clean(); - assert.strictEqual( - message, - plaintext - ); + const result = (message === plaintext); + if (!result) console.log(plaintext, cipherMessage); + assert.ok(result); }); it('can en- and decrypt a particular message (#260)', function () { @@ -201,8 +68,6 @@ describe('CryptTool', function () { 'string', 'string', async function (key, password) { - // pause to let async functions conclude - await new Promise(resolve => setTimeout(resolve, 300)); const message = ` 1 subgoal @@ -225,18 +90,23 @@ isWhile : interp (while expr sBody) (MemElem mem) = ======================== ( 1 / 1 ) conseq_or_bottom inv (interp (nth_iterate sBody n) (MemElem mem)) `; - let clean = jsdom(); + const clean = jsdom(); // ensure zlib is getting loaded $.PrivateBin.Controller.initZ(); - window.crypto = new WebCrypto(); - let cipherMessage = await $.PrivateBin.CryptTool.cipher( + Object.defineProperty(window, 'crypto', { + value: new WebCrypto(), + writeable: false, + }); + const cipherMessage = await $.PrivateBin.CryptTool.cipher( key, password, message, [] ), plaintext = await $.PrivateBin.CryptTool.decipher( key, password, cipherMessage ); clean(); - return message === plaintext; + const result = (message === plaintext); + if (!result) console.log(plaintext, cipherMessage); + return result; } ), {tests: 3}); @@ -244,23 +114,27 @@ conseq_or_bottom inv (interp (nth_iterate sBody n) (MemElem mem)) }); describe('getSymmetricKey', function () { - this.timeout(30000); - var keys = []; + this.timeout(10000); + let keys = []; // the parameter is used to ensure the test is run more then one time - jsc.property( - 'returns random, non-empty keys', - 'integer', - function(counter) { - var clean = jsdom(); - window.crypto = new WebCrypto(); - var key = $.PrivateBin.CryptTool.getSymmetricKey(), - result = (key !== '' && keys.indexOf(key) === -1); - keys.push(key); - clean(); - return result; - } - ); + it('returns random, non-empty keys', function () { + jsc.assert(jsc.forall( + 'integer', + function(counter) { + const clean = jsdom(); + Object.defineProperty(window, 'crypto', { + value: new WebCrypto(), + writeable: false, + }); + const key = $.PrivateBin.CryptTool.getSymmetricKey(), + result = (key !== '' && keys.indexOf(key) === -1); + keys.push(key); + clean(); + return result; + } + ), + {tests: 10}); + }); }); }); - diff --git a/js/test/Editor.js b/js/test/Editor.js index 4115aa46..209f8028 100644 --- a/js/test/Editor.js +++ b/js/test/Editor.js @@ -16,7 +16,7 @@ describe('Editor', function () { 'role="presentation" class="active">Editor
  • Preview
  • ' + + 'id="placeholder" class="hidden">+++ no document text +++
    ' + '

    +

    +

    + +

    @@ -598,7 +645,7 @@ endif;

    -

    - diff --git a/tpl/bootstrap5.php b/tpl/bootstrap5.php new file mode 100644 index 00000000..b3644ddd --- /dev/null +++ b/tpl/bootstrap5.php @@ -0,0 +1,551 @@ + + class="h-100"> + + + + + + + + <?php echo I18n::_($NAME); ?> + + + + + + + + + _scriptTag('js/jquery-3.7.1.js', 'defer'); ?> + + _scriptTag('js/kjua-0.10.0.js', 'defer'); ?> + + _scriptTag('js/zlib-1.3.1-1.js', 'defer'); ?> + _scriptTag('js/base-x-5.0.1.js', 'defer'); ?> + _scriptTag('js/bootstrap-5.3.7.js', 'defer'); ?> + _scriptTag('js/dark-mode-switch.js', 'defer'); ?> + + _scriptTag('js/prettify.js', 'defer'); ?> + + _scriptTag('js/showdown-2.1.0.js', 'defer'); ?> + + _scriptTag('js/purify-3.2.6.js', 'defer'); ?> + _scriptTag('js/legacy.js', 'defer'); ?> + _scriptTag('js/privatebin.js', 'defer'); ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + + +

    +

    + + +

    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    +
    -
    +

    +

    + ', ''), ' ', $INFO, PHP_EOL; + ?> +

    +
    +
    + + + + + + diff --git a/tpl/page.php b/tpl/page.php deleted file mode 100644 index 71028de7..00000000 --- a/tpl/page.php +++ /dev/null @@ -1,302 +0,0 @@ - -> - - - - - - <?php echo I18n::_($NAME); ?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - ', ''), ' ', $INFO; - ?> -
    - - -
    -


    -


    -

    - - - - - - -
    -
    -
    - -
    - -
    - - - - - - - - - - - - - - - - - - - - - - -
    - -
    - -
    - -
    - - - - - - - - - - -
    -
    -
    - -
    - - - - - - -
    - -
    - - diff --git a/tpl/yourlsproxy.php b/tpl/shortenerproxy.php similarity index 56% rename from tpl/yourlsproxy.php rename to tpl/shortenerproxy.php index fc56ba82..548418f8 100644 --- a/tpl/yourlsproxy.php +++ b/tpl/shortenerproxy.php @@ -1,10 +1,9 @@ - > - <?php echo I18n::_($NAME); ?> @@ -13,12 +12,12 @@ use PrivateBin\I18n; -

    %s (Hit [Ctrl]+[c] to copy)', $SHORTURL, $SHORTURL); ?>

    +

    %s (Hit Ctrl+c to copy)', $SHORTURL, $SHORTURL); ?>

    -

    +

    _config = $config; - $this->_connection = new ConnectionInterfaceStub(); - } + /** + * example paste version 2 + * + * @var array + */ + private static $pasteV2 = array( + 'adata' => array( + array( + 'gMSNoLOk4z0RnmsYwXZ8mw==', + 'TZO+JWuIuxs=', + 100000, + 256, + 128, + 'aes', + 'gcm', + 'zlib', + ), + 'plaintext', + 1, + 0, + ), + 'meta' => array( + 'expire' => '5min', + ), + 'v' => 2, + 'ct' => 'ME5JF/YBEijp2uYMzLZozbKtWc5wfy6R59NBb7SmRig=', + ); - public function bucket($name, $userProject = false) + /** + * example ID of a comment + * + * @var string + */ + private static $commentid = '5a52eebf11c4c94b'; + + /** + * example comment meta data + * + * @var array + */ + private static $commentV2 = array( + 'icon' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGUlEQVQokWOsl5/94983CNKQMjnxaOePf98MeKwPfNjkLZ3AgARab6b9+PeNEVnDj3/ff/z7ZiHnzsDA8Pv7H2TVPJw8EAYLAwb48OaVgIgYKycLsrYv378wMDB8//qdCVMDRA9EKSsnCwRBxNsepaLboMFlyMDAICAi9uHNK24GITQ/MDAwoNhgIGMLtwGrzegaLjw5jMz9+vUdnN17uwDCQDhJgk0O07yvX9+teDX1x79v6DYIsIjgcgMaYGFgYOBg4kJx2JejkAiBxAw+PzAwMNz4dp6wDXDw4MdNNOl0rWYsNkD89OLXI/xmo9sgzatJjAYmBgYGDiauD3/ePP18nVgb4MF89+M5ZX6js293wUMpnr8KTQMAxsCJnJ30apMAAAAASUVORK5CYII=', + 'created' => 1344803528, + ); + + /** + * JS files and their SRI hashes + * + * @var array + */ + private static $hashes = array(); + + /** + * get example paste ID + * + * @return string + */ + public static function getPasteId(): string { - if (!key_exists($name, self::$_buckets)) { - $b = new BucketStub($this->_connection, $name, array(), $this); - self::$_buckets[$name] = $b; - } - return self::$_buckets[$name]; + return self::$pasteid; } /** - * @throws \Google\Cloud\Core\Exception\NotFoundException + * get example paste, as stored on server + * + * @param array $meta + * @return array */ - public function deleteBucket($name) + public static function getPaste(array $meta = array()): array { - if (key_exists($name, self::$_buckets)) { - unset(self::$_buckets[$name]); + $example = self::$pasteV2; + $example['meta']['salt'] = ServerSalt::generate(); + $example['meta'] = array_merge($example['meta'], $meta); + return $example; + } + + /** + * get example paste, as decoded from POST by the request object + * + * @param array $meta + * @return array + */ + public static function getPastePost(array $meta = array()): array + { + $example = self::getPaste($meta); + $example['meta'] = array('expire' => $example['meta']['expire']); + return $example; + } + + /** + * get example paste, as received via POST by the user + * + * @param array $meta + * @return string + */ + public static function getPasteJson(array $meta = array()): string + { + return json_encode(self::getPastePost($meta)); + } + + /** + * get example paste ID + * + * @return string + */ + public static function getCommentId(): string + { + return self::$commentid; + } + + /** + * get example comment, as stored on server + * + * @param array $meta + * @return array + */ + public static function getComment(array $meta = array()): array + { + $example = self::$pasteV2; + $example['adata'] = $example['adata'][0]; + $example['pasteid'] = $example['parentid'] = self::getPasteId(); + unset($example['meta']['expire']); + $example['meta'] = array_merge($example['meta'], self::$commentV2); + $example['meta'] = array_merge($example['meta'], $meta); + return $example; + } + + /** + * get example comment, as decoded from POST by the request object + * + * @return array + */ + public static function getCommentPost(): array + { + $example = self::getComment(); + unset($example['meta']); + return $example; + } + + /** + * get example comment, as received via POST by user + * + * @return string + */ + public static function getCommentJson(): string + { + return json_encode(self::getCommentPost()); + } + + /** + * Returns 16 random hexadecimal characters. + * + * @return string + */ + public static function getRandomId(): string + { + // 8 binary bytes are 16 characters long in hex + return bin2hex(random_bytes(8)); + } + + /** + * delete directory and all its contents recursively + * + * @param string $path + * @throws Exception + * @return void + */ + public static function rmDir($path): void + { + if (is_dir($path)) { + $path .= DIRECTORY_SEPARATOR; + $dir = dir($path); + while (false !== ($file = $dir->read())) { + if ($file != '.' && $file != '..') { + if (is_dir($path . $file)) { + self::rmDir($path . $file); + } elseif (is_file($path . $file)) { + if (!unlink($path . $file)) { + throw new Exception('Error deleting file "' . $path . $file . '".'); + } + } + } + } + $dir->close(); + if (!rmdir($path)) { + throw new Exception('Error deleting directory "' . $path . '".'); + } + } + } + + /** + * create a backup of the config file + * + * @return void + */ + public static function confBackup(): void + { + if (!is_file(CONF . '.bak') && is_file(CONF)) { + rename(CONF, CONF . '.bak'); + } + if (!is_file(CONF_SAMPLE . '.bak') && is_file(CONF_SAMPLE)) { + copy(CONF_SAMPLE, CONF_SAMPLE . '.bak'); + } + } + + /** + * restor backup of the config file + * + * @return void + */ + public static function confRestore(): void + { + if (is_file(CONF . '.bak')) { + rename(CONF . '.bak', CONF); + } + if (is_file(CONF_SAMPLE . '.bak')) { + rename(CONF_SAMPLE . '.bak', CONF_SAMPLE); + } + } + + /** + * create ini file + * + * @param string $pathToFile + * @param array $values + */ + public static function createIniFile($pathToFile, array $values): void + { + if (count($values)) { + @unlink($pathToFile); + $ini = fopen($pathToFile, 'a'); + foreach ($values as $section => $options) { + fwrite($ini, "[$section]" . PHP_EOL); + foreach ($options as $option => $setting) { + if (is_null($setting)) { + continue; + } elseif (is_string($setting)) { + $setting = '"' . $setting . '"'; + } elseif (is_array($setting)) { + foreach ($setting as $key => $value) { + if (is_null($value)) { + $value = 'null'; + } elseif (is_string($value)) { + $value = '"' . $value . '"'; + } else { + $value = var_export($value, true); + } + fwrite($ini, $option . "[$key] = $value" . PHP_EOL); + } + continue; + } else { + $setting = var_export($setting, true); + } + fwrite($ini, "$option = $setting" . PHP_EOL); + } + fwrite($ini, PHP_EOL); + } + fclose($ini); + } + } + + /** + * a var_export that returns arrays without line breaks + * by linus@flowingcreativity.net via php.net + * + * @param mixed $var + * @param bool $return + * @return void|string + */ + public static function varExportMin($var, $return = false): string + { + if (is_array($var)) { + $toImplode = array(); + foreach ($var as $key => $value) { + $toImplode[] = var_export($key, true) . ' => ' . self::varExportMin($value, true); + } + $code = 'array(' . implode(', ', $toImplode) . ')'; + if ($return) { + return $code; + } else { + echo $code; + } } else { - throw new NotFoundException(); + return var_export($var, $return); } } - public function buckets(array $options = array()) + /** + * update all templates with the latest SRI hashes for all JS files + * + * @return void + */ + public static function updateSubresourceIntegrity(): void { - throw new BadMethodCallException('not supported by this stub'); - } - - public function registerStreamWrapper($protocol = null) - { - throw new BadMethodCallException('not supported by this stub'); - } - - public function unregisterStreamWrapper($protocol = null) - { - throw new BadMethodCallException('not supported by this stub'); - } - - public function signedUrlUploader($uri, $data, array $options = array()) - { - throw new BadMethodCallException('not supported by this stub'); - } - - public function timestamp(\DateTimeInterface $timestamp, $nanoSeconds = null) - { - throw new BadMethodCallException('not supported by this stub'); - } - - public function getServiceAccount(array $options = array()) - { - throw new BadMethodCallException('not supported by this stub'); - } - - public function hmacKeys(array $options = array()) - { - throw new BadMethodCallException('not supported by this stub'); - } - - public function hmacKey($accessId, $projectId = null, array $metadata = array()) - { - throw new BadMethodCallException('not supported by this stub'); - } - - public function createHmacKey($serviceAccountEmail, array $options = array()) - { - throw new BadMethodCallException('not supported by this stub'); - } - - public function createBucket($name, array $options = array()) - { - if (key_exists($name, self::$_buckets)) { - throw new BadRequestException('already exists'); + foreach (new GlobIterator(PATH . 'js' . DIRECTORY_SEPARATOR . '*.js') as $file) { + if ($file->getBasename() == 'common.js') { + continue; // ignore JS unit test bootstrap + } + self::$hashes[$file->getBasename()] = base64_encode( + hash('sha512', file_get_contents($file->getPathname()), true) + ); + } + + $counter = 0; + $file = PATH . 'lib' . DIRECTORY_SEPARATOR . 'Configuration.php'; + $content = preg_replace_callback( + '#\'js/([a-z0-9.-]+.js)(\' +)=\> \'[^\']*\',#', + function ($matches) use (&$counter) { + if (array_key_exists($matches[1], Helper::$hashes)) { + ++$counter; + return '\'js/' . $matches[1] . $matches[2] . + '=> \'sha512-' . Helper::$hashes[$matches[1]] . '\','; + } else { + throw new Exception('SRI hash for file js/' . $matches[1] . ' not found, please add the missing file or remove it from lib/Configuration.php.'); + } + }, + file_get_contents($file) + ); + file_put_contents($file, $content); + if ($counter != count(self::$hashes)) { + throw new Exception('Mismatch between ' . count(self::$hashes) . ' found js files and ' . $counter . ' SRI hashes in lib/Configuration.php, please update lib/Configuration.php to match the list of js files.'); } - $b = new BucketStub($this->_connection, $name, array(), $this); - self::$_buckets[$name] = $b; - return $b; } } @@ -468,6 +713,11 @@ class ConnectionInterfaceStub implements ConnectionInterface throw new BadMethodCallException('not supported by this stub'); } + public function restoreBucket(array $args = array()) + { + throw new BadMethodCallException('not supported by this stub'); + } + public function getBucket(array $args = array()) { throw new BadMethodCallException('not supported by this stub'); @@ -508,6 +758,11 @@ class ConnectionInterfaceStub implements ConnectionInterface throw new BadMethodCallException('not supported by this stub'); } + public function restoreObject(array $args = array()) + { + throw new BadMethodCallException('not supported by this stub'); + } + public function copyObject(array $args = array()) { throw new BadMethodCallException('not supported by this stub'); @@ -518,6 +773,11 @@ class ConnectionInterfaceStub implements ConnectionInterface throw new BadMethodCallException('not supported by this stub'); } + public function moveObject(array $args = array()) + { + throw new BadMethodCallException('not supported by this stub'); + } + public function composeObject(array $args = array()) { throw new BadMethodCallException('not supported by this stub'); @@ -605,386 +865,92 @@ class ConnectionInterfaceStub implements ConnectionInterface } /** - * Class Helper provides unit tests pastes and comments of various formats + * Class StorageClientStub provides a limited stub for performing the unit test */ -class Helper +class StorageClientStub extends StorageClient { - /** - * example ID of a paste - * - * @var string - */ - private static $pasteid = '5b65a01b43987bc2'; + private $_config = null; + private $_connection = null; + private static $_buckets = array(); - /** - * example paste version 1 - * - * @var array - */ - private static $pasteV1 = array( - 'data' => '{"iv":"EN39/wd5Nk8HAiSG2K5AsQ","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"QKN1DBXe5PI","ct":"8hA83xDdXjD7K2qfmw5NdA"}', - 'attachment' => '{"iv":"Pd4pOKWkmDTT9uPwVwd5Ag","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"6nOCU3peNDclDDpFtJEBKA"}', - 'attachmentname' => '{"iv":"76MkAtOGC4oFogX/aSMxRA","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"b6Ae/U1xJdsX/+lATud4sQ"}', - 'meta' => array( - 'formatter' => 'plaintext', - 'postdate' => 1344803344, - 'opendiscussion' => true, - ), - ); - - /** - * example paste version 2 - * - * @var array - */ - private static $pasteV2 = array( - 'adata' => array( - array( - 'gMSNoLOk4z0RnmsYwXZ8mw==', - 'TZO+JWuIuxs=', - 100000, - 256, - 128, - 'aes', - 'gcm', - 'zlib', - ), - 'plaintext', - 1, - 0, - ), - 'meta' => array( - 'expire' => '5min', - 'created' => 1344803344, - ), - 'v' => 2, - 'ct' => 'ME5JF/YBEijp2uYMzLZozbKtWc5wfy6R59NBb7SmRig=', - ); - - /** - * example ID of a comment - * - * @var string - */ - private static $commentid = '5a52eebf11c4c94b'; - - /** - * example comment - * - * @var array - */ - private static $commentV1 = array( - 'data' => '{"iv":"Pd4pOKWkmDTT9uPwVwd5Ag","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"6nOCU3peNDclDDpFtJEBKA"}', - 'meta' => array( - 'nickname' => '{"iv":"76MkAtOGC4oFogX/aSMxRA","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"b6Ae/U1xJdsX/+lATud4sQ"}', - 'vizhash' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGUlEQVQokWOsl5/94983CNKQMjnxaOePf98MeKwPfNjkLZ3AgARab6b9+PeNEVnDj3/ff/z7ZiHnzsDA8Pv7H2TVPJw8EAYLAwb48OaVgIgYKycLsrYv378wMDB8//qdCVMDRA9EKSsnCwRBxNsepaLboMFlyMDAICAi9uHNK24GITQ/MDAwoNhgIGMLtwGrzegaLjw5jMz9+vUdnN17uwDCQDhJgk0O07yvX9+teDX1x79v6DYIsIjgcgMaYGFgYOBg4kJx2JejkAiBxAw+PzAwMNz4dp6wDXDw4MdNNOl0rWYsNkD89OLXI/xmo9sgzatJjAYmBgYGDiauD3/ePP18nVgb4MF89+M5ZX6js293wUMpnr8KTQMAxsCJnJ30apMAAAAASUVORK5CYII=', - 'postdate' => 1344803528, - ), - ); - - /** - * JS files and their SRI hashes - * - * @var array - */ - private static $hashes = array(); - - /** - * get example paste ID - * - * @return string - */ - public static function getPasteId() + public function __construct(array $config = array()) { - return version_compare(PHP_VERSION, '5.6', '<') ? hash('fnv164', self::$pasteV2['ct']) : self::$pasteid; + $this->_config = $config; + $this->_connection = new ConnectionInterfaceStub(); } - /** - * get example paste, as stored on server - * - * @param int $version - * @param array $meta - * @return array - */ - public static function getPaste($version = 2, array $meta = array()) + public function bucket($name, $userProject = false, array $config = array()) { - $example = self::getPasteWithAttachment($version, $meta); - // v1 has the attachment stored in a separate property - if ($version === 1) { - unset($example['attachment'], $example['attachmentname']); + if (!key_exists($name, self::$_buckets)) { + self::$_buckets[$name] = new BucketStub($this->_connection, $name, array(), $this); } - return $example; + return self::$_buckets[$name]; } /** - * get example paste with attachment, as stored on server - * - * @param int $version - * @param array $meta - * @return array + * @throws \Google\Cloud\Core\Exception\NotFoundException */ - public static function getPasteWithAttachment($version = 2, array $meta = array()) + public function deleteBucket($name) { - $example = $version === 1 ? self::$pasteV1 : self::$pasteV2; - $example['meta']['salt'] = ServerSalt::generate(); - $example['meta'] = array_merge($example['meta'], $meta); - return $example; - } - - /** - * get example paste, as decoded from POST by the request object - * - * @param int $version - * @param array $meta - * @return array - */ - public static function getPastePost($version = 2, array $meta = array()) - { - $example = self::getPaste($version, $meta); - if ($version == 2) { - $example['meta'] = array('expire' => $example['meta']['expire']); + if (key_exists($name, self::$_buckets)) { + unset(self::$_buckets[$name]); } else { - unset($example['meta']['postdate']); - } - return $example; - } - - /** - * get example paste, as received via POST by the user - * - * @param int $version - * @param array $meta - * @return array - */ - public static function getPasteJson($version = 2, array $meta = array()) - { - return json_encode(self::getPastePost($version, $meta)); - } - - /** - * get example paste ID - * - * @return string - */ - public static function getCommentId() - { - return self::$commentid; - } - - /** - * get example comment, as stored on server - * - * @param int $version - * @param array $meta - * @return array - */ - public static function getComment($version = 2, array $meta = array()) - { - $example = $version === 1 ? self::$commentV1 : self::$pasteV2; - if ($version === 2) { - $example['adata'] = $example['adata'][0]; - $example['pasteid'] = $example['parentid'] = self::getPasteId(); - $example['meta']['created'] = self::$commentV1['meta']['postdate']; - $example['meta']['icon'] = self::$commentV1['meta']['vizhash']; - unset($example['meta']['expire']); - } - $example['meta'] = array_merge($example['meta'], $meta); - return $example; - } - - /** - * get example comment, as decoded from POST by the request object - * - * @param int $version - * @return array - */ - public static function getCommentPost() - { - $example = self::getComment(); - unset($example['meta']); - return $example; - } - - /** - * get example comment, as received via POST by user - * - * @param int $version - * @return array - */ - public static function getCommentJson() - { - return json_encode(self::getCommentPost()); - } - - /** - * delete directory and all its contents recursively - * - * @param string $path - * @throws Exception - */ - public static function rmDir($path) - { - if (is_dir($path)) { - $path .= DIRECTORY_SEPARATOR; - $dir = dir($path); - while (false !== ($file = $dir->read())) { - if ($file != '.' && $file != '..') { - if (is_dir($path . $file)) { - self::rmDir($path . $file); - } elseif (is_file($path . $file)) { - if (!unlink($path . $file)) { - throw new Exception('Error deleting file "' . $path . $file . '".'); - } - } - } - } - $dir->close(); - if (!rmdir($path)) { - throw new Exception('Error deleting directory "' . $path . '".'); - } + throw new NotFoundException(); } } - /** - * create a backup of the config file - * - * @return void - */ - public static function confBackup() + public function buckets(array $options = array()) { - if (!is_file(CONF . '.bak') && is_file(CONF)) { - rename(CONF, CONF . '.bak'); - } - if (!is_file(CONF_SAMPLE . '.bak') && is_file(CONF_SAMPLE)) { - copy(CONF_SAMPLE, CONF_SAMPLE . '.bak'); - } + throw new BadMethodCallException('not supported by this stub'); } - /** - * restor backup of the config file - * - * @return void - */ - public static function confRestore() + public function registerStreamWrapper($protocol = null) { - if (is_file(CONF . '.bak')) { - rename(CONF . '.bak', CONF); - } - if (is_file(CONF_SAMPLE . '.bak')) { - rename(CONF_SAMPLE . '.bak', CONF_SAMPLE); - } + throw new BadMethodCallException('not supported by this stub'); } - /** - * create ini file - * - * @param string $pathToFile - * @param array $values - */ - public static function createIniFile($pathToFile, array $values) + public function unregisterStreamWrapper($protocol = null) { - if (count($values)) { - @unlink($pathToFile); - $ini = fopen($pathToFile, 'a'); - foreach ($values as $section => $options) { - fwrite($ini, "[$section]" . PHP_EOL); - foreach ($options as $option => $setting) { - if (is_null($setting)) { - continue; - } elseif (is_string($setting)) { - $setting = '"' . $setting . '"'; - } elseif (is_array($setting)) { - foreach ($setting as $key => $value) { - if (is_null($value)) { - $value = 'null'; - } elseif (is_string($value)) { - $value = '"' . $value . '"'; - } else { - $value = var_export($value, true); - } - fwrite($ini, $option . "[$key] = $value" . PHP_EOL); - } - continue; - } else { - $setting = var_export($setting, true); - } - fwrite($ini, "$option = $setting" . PHP_EOL); - } - fwrite($ini, PHP_EOL); - } - fclose($ini); - } + throw new BadMethodCallException('not supported by this stub'); } - /** - * a var_export that returns arrays without line breaks - * by linus@flowingcreativity.net via php.net - * - * @param mixed $var - * @param bool $return - * @return void|string - */ - public static function varExportMin($var, $return = false) + public function signedUrlUploader($uri, $data, array $options = array()) { - if (is_array($var)) { - $toImplode = array(); - foreach ($var as $key => $value) { - $toImplode[] = var_export($key, true) . ' => ' . self::varExportMin($value, true); - } - $code = 'array(' . implode(', ', $toImplode) . ')'; - if ($return) { - return $code; - } else { - echo $code; - } - } else { - return var_export($var, $return); - } + throw new BadMethodCallException('not supported by this stub'); } - /** - * update all templates with the latest SRI hashes for all JS files - * - * @return void - */ - public static function updateSubresourceIntegrity() + public function timestamp(\DateTimeInterface $timestamp, $nanoSeconds = null) { - $dir = dir(PATH . 'js'); - while (false !== ($file = $dir->read())) { - if (substr($file, -3) === '.js') { - self::$hashes[$file] = base64_encode( - hash('sha512', file_get_contents( - PATH . 'js' . DIRECTORY_SEPARATOR . $file - ), true) - ); - } - } + throw new BadMethodCallException('not supported by this stub'); + } - $dir = dir(PATH . 'tpl'); - while (false !== ($file = $dir->read())) { - if (substr($file, -4) === '.php') { - $content = file_get_contents( - PATH . 'tpl' . DIRECTORY_SEPARATOR . $file - ); - $content = preg_replace_callback( - '##', - function ($matches) { - if (array_key_exists($matches[2], Helper::$hashes)) { - return ''; - } else { - return $matches[0]; - } - }, - $content - ); - file_put_contents( - PATH . 'tpl' . DIRECTORY_SEPARATOR . $file, - $content - ); - } + public function getServiceAccount(array $options = array()) + { + throw new BadMethodCallException('not supported by this stub'); + } + + public function hmacKeys(array $options = array()) + { + throw new BadMethodCallException('not supported by this stub'); + } + + public function hmacKey($accessId, $projectId = null, array $metadata = array()) + { + throw new BadMethodCallException('not supported by this stub'); + } + + public function createHmacKey($serviceAccountEmail, array $options = array()) + { + throw new BadMethodCallException('not supported by this stub'); + } + + public function createBucket($name, array $options = array()) + { + if (key_exists($name, self::$_buckets)) { + throw new BadRequestException('already exists'); } + $b = new BucketStub($this->_connection, $name, array(), $this); + self::$_buckets[$name] = $b; + return $b; } } diff --git a/tst/ConfigurationTest.php b/tst/ConfigurationTest.php index 687fc46a..5a7a11f2 100644 --- a/tst/ConfigurationTest.php +++ b/tst/ConfigurationTest.php @@ -1,4 +1,4 @@ -assertEquals($options, $conf->get(), 'not overriding "missing" subkeys'); } - public function testHandlePreRenameConfig() - { - $options = $this->_options; - $options['model']['class'] = 'zerobin_data'; - Helper::createIniFile(CONF, $options); - $conf = new Configuration; - $this->assertEquals('Filesystem', $conf->getKey('class', 'model'), 'old data class gets renamed'); - - $options['model']['class'] = 'zerobin_db'; - Helper::createIniFile(CONF, $options); - $conf = new Configuration; - $this->assertEquals('Database', $conf->getKey('class', 'model'), 'old db class gets renamed'); - } - public function testConfigPath() { // setup diff --git a/tst/ControllerTest.php b/tst/ControllerTest.php index 8aee7829..41aad6e9 100644 --- a/tst/ControllerTest.php +++ b/tst/ControllerTest.php @@ -1,6 +1,7 @@ -getProperty('_conf'); + $configValue->setAccessible(true); + ob_start(); + $controller = new Controller($newConfig); + ob_end_clean(); + $this->assertSame($newConfig, $configValue->getValue($controller)); + } + /** * @runInSeparateProcess */ @@ -170,6 +185,7 @@ class ControllerTest extends TestCase $this->assertEquals(0, $response['status'], 'outputs status'); $this->assertTrue($this->_data->exists($response['id']), 'paste exists after posting data'); $paste = $this->_data->read($response['id']); + $this->assertFalse(array_key_exists('created', $paste['meta']), 'does not output created'); $this->assertEquals( hash_hmac('sha256', $response['id'], $paste['meta']['salt']), $response['deletetoken'], @@ -185,7 +201,7 @@ class ControllerTest extends TestCase $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; Helper::createIniFile(CONF, $options); - $paste = Helper::getPasteJson(2, array('expire' => 25)); + $paste = Helper::getPasteJson(array('expire' => 25)); $file = tempnam(sys_get_temp_dir(), 'FOO'); file_put_contents($file, $paste); Request::setInputStream($file); @@ -272,7 +288,8 @@ class ControllerTest extends TestCase $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; Helper::createIniFile(CONF, $options); - $this->_data->create(Helper::getPasteId(), Helper::getPaste()); + $paste = Helper::getPaste(); + $this->_data->create(Helper::getPasteId(), $paste); $paste = Helper::getPasteJson(); $file = tempnam(sys_get_temp_dir(), 'FOO'); file_put_contents($file, $paste); @@ -362,7 +379,7 @@ class ControllerTest extends TestCase $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; Helper::createIniFile(CONF, $options); - $paste = Helper::getPasteJson(2, array('expire' => 'foo')); + $paste = Helper::getPasteJson(array('expire' => 'foo')); $file = tempnam(sys_get_temp_dir(), 'FOO'); file_put_contents($file, $paste); Request::setInputStream($file); @@ -493,7 +510,7 @@ class ControllerTest extends TestCase $options['traffic']['limit'] = 0; Helper::createIniFile(CONF, $options); $file = tempnam(sys_get_temp_dir(), 'FOO'); - file_put_contents($file, Helper::getPasteJson(1)); + file_put_contents($file, '{"data":"","meta":{}}'); Request::setInputStream($file); $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest'; $_SERVER['REQUEST_METHOD'] = 'POST'; @@ -522,7 +539,8 @@ class ControllerTest extends TestCase $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest'; $_SERVER['REQUEST_METHOD'] = 'POST'; $_SERVER['REMOTE_ADDR'] = '::1'; - $this->_data->create(Helper::getPasteId(), Helper::getPaste()); + $paste = Helper::getPaste(); + $this->_data->create(Helper::getPasteId(), $paste); ob_start(); new Controller; $content = ob_get_contents(); @@ -548,7 +566,8 @@ class ControllerTest extends TestCase $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest'; $_SERVER['REQUEST_METHOD'] = 'POST'; $_SERVER['REMOTE_ADDR'] = '::1'; - $this->_data->create(Helper::getPasteId(), Helper::getPaste()); + $paste = Helper::getPaste(); + $this->_data->create(Helper::getPasteId(), $paste); ob_start(); new Controller; $content = ob_get_contents(); @@ -617,8 +636,10 @@ class ControllerTest extends TestCase $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; Helper::createIniFile(CONF, $options); - $this->_data->create(Helper::getPasteId(), Helper::getPaste()); - $this->_data->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId(), Helper::getComment()); + $paste = Helper::getPaste(); + $this->_data->create(Helper::getPasteId(), $paste); + $comment = Helper::getComment(); + $this->_data->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId(), $comment); $this->assertTrue($this->_data->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId()), 'comment exists before posting data'); $comment = Helper::getCommentJson(); $file = tempnam(sys_get_temp_dir(), 'FOO'); @@ -650,7 +671,7 @@ class ControllerTest extends TestCase ob_end_clean(); $response = json_decode($content, true); $this->assertEquals(1, $response['status'], 'outputs error status'); - $this->assertEquals('Invalid paste ID.', $response['message'], 'outputs error message'); + $this->assertEquals('Invalid document ID.', $response['message'], 'outputs error message'); } /** @@ -667,7 +688,7 @@ class ControllerTest extends TestCase ob_end_clean(); $response = json_decode($content, true); $this->assertEquals(1, $response['status'], 'outputs error status'); - $this->assertEquals('Paste does not exist, has expired or has been deleted.', $response['message'], 'outputs error message'); + $this->assertEquals('Document does not exist, has expired or has been deleted.', $response['message'], 'outputs error message'); } /** @@ -675,7 +696,7 @@ class ControllerTest extends TestCase */ public function testReadExpired() { - $expiredPaste = Helper::getPaste(2, array('expire_date' => 1344803344)); + $expiredPaste = Helper::getPaste(array('expire_date' => 1344803344)); $this->_data->create(Helper::getPasteId(), $expiredPaste); $_SERVER['QUERY_STRING'] = Helper::getPasteId(); $_GET[Helper::getPasteId()] = ''; @@ -686,7 +707,7 @@ class ControllerTest extends TestCase ob_end_clean(); $response = json_decode($content, true); $this->assertEquals(1, $response['status'], 'outputs error status'); - $this->assertEquals('Paste does not exist, has expired or has been deleted.', $response['message'], 'outputs error message'); + $this->assertEquals('Document does not exist, has expired or has been deleted.', $response['message'], 'outputs error message'); } /** @@ -712,7 +733,7 @@ class ControllerTest extends TestCase $this->assertEquals($paste['adata'][1], $response['adata'][1], 'outputs formatter correctly'); $this->assertEquals($paste['adata'][2], $response['adata'][2], 'outputs opendiscussion correctly'); $this->assertEquals($paste['adata'][3], $response['adata'][3], 'outputs burnafterreading correctly'); - $this->assertEquals($paste['meta']['created'], $response['meta']['created'], 'outputs created correctly'); + $this->assertFalse(array_key_exists('created', $response['meta']), 'does not output created'); $this->assertEquals(0, $response['comment_count'], 'outputs comment_count correctly'); $this->assertEquals(0, $response['comment_offset'], 'outputs comment_offset correctly'); // by default it will be deleted instantly after it is read @@ -741,38 +762,7 @@ class ControllerTest extends TestCase $this->assertEquals($paste['adata'][1], $response['adata'][1], 'outputs formatter correctly'); $this->assertEquals($paste['adata'][2], $response['adata'][2], 'outputs opendiscussion correctly'); $this->assertEquals($paste['adata'][3], $response['adata'][3], 'outputs burnafterreading correctly'); - $this->assertEquals($paste['meta']['created'], $response['meta']['created'], 'outputs created correctly'); - $this->assertEquals(0, $response['comment_count'], 'outputs comment_count correctly'); - $this->assertEquals(0, $response['comment_offset'], 'outputs comment_offset correctly'); - } - - /** - * @runInSeparateProcess - */ - public function testReadOldSyntax() - { - $paste = Helper::getPaste(1); - $paste['meta'] = array( - 'syntaxcoloring' => true, - 'postdate' => $paste['meta']['postdate'], - 'opendiscussion' => $paste['meta']['opendiscussion'], - ); - $this->_data->create(Helper::getPasteId(), $paste); - $_SERVER['QUERY_STRING'] = Helper::getPasteId(); - $_GET[Helper::getPasteId()] = ''; - $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest'; - ob_start(); - new Controller; - $content = ob_get_contents(); - ob_end_clean(); - $response = json_decode($content, true); - $this->assertEquals(0, $response['status'], 'outputs success status'); - $this->assertEquals(Helper::getPasteId(), $response['id'], 'outputs data correctly'); - $this->assertStringEndsWith('?' . $response['id'], $response['url'], 'returned URL points to new paste'); - $this->assertEquals($paste['data'], $response['data'], 'outputs data correctly'); - $this->assertEquals('syntaxhighlighting', $response['meta']['formatter'], 'outputs format correctly'); - $this->assertEquals($paste['meta']['postdate'], $response['meta']['postdate'], 'outputs postdate correctly'); - $this->assertEquals($paste['meta']['opendiscussion'], $response['meta']['opendiscussion'], 'outputs opendiscussion correctly'); + $this->assertFalse(array_key_exists('created', $response['meta']), 'does not output created'); $this->assertEquals(0, $response['comment_count'], 'outputs comment_count correctly'); $this->assertEquals(0, $response['comment_offset'], 'outputs comment_offset correctly'); } @@ -803,7 +793,8 @@ class ControllerTest extends TestCase */ public function testDelete() { - $this->_data->create(Helper::getPasteId(), Helper::getPaste()); + $paste = Helper::getPaste(); + $this->_data->create(Helper::getPasteId(), $paste); $this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists before deleting data'); $paste = $this->_data->read(Helper::getPasteId()); $_GET['pasteid'] = Helper::getPasteId(); @@ -813,7 +804,7 @@ class ControllerTest extends TestCase $content = ob_get_contents(); ob_end_clean(); $this->assertMatchesRegularExpression( - '#]*id="status"[^>]*>.*Paste was properly deleted\.#s', + '#]*id="status"[^>]*>.*Document was properly deleted\.#s', $content, 'outputs deleted status correctly' ); @@ -825,7 +816,8 @@ class ControllerTest extends TestCase */ public function testDeleteInvalidId() { - $this->_data->create(Helper::getPasteId(), Helper::getPaste()); + $paste = Helper::getPaste(); + $this->_data->create(Helper::getPasteId(), $paste); $_GET['pasteid'] = 'foo'; $_GET['deletetoken'] = 'bar'; ob_start(); @@ -833,7 +825,7 @@ class ControllerTest extends TestCase $content = ob_get_contents(); ob_end_clean(); $this->assertMatchesRegularExpression( - '#]*id="errormessage"[^>]*>.*Invalid paste ID\.#s', + '#]*id="errormessage"[^>]*>.*Invalid document ID\.#s', $content, 'outputs delete error correctly' ); @@ -852,7 +844,7 @@ class ControllerTest extends TestCase $content = ob_get_contents(); ob_end_clean(); $this->assertMatchesRegularExpression( - '#]*id="errormessage"[^>]*>.*Paste does not exist, has expired or has been deleted\.#s', + '#]*id="errormessage"[^>]*>.*Document does not exist, has expired or has been deleted\.#s', $content, 'outputs delete error correctly' ); @@ -863,7 +855,8 @@ class ControllerTest extends TestCase */ public function testDeleteInvalidToken() { - $this->_data->create(Helper::getPasteId(), Helper::getPaste()); + $paste = Helper::getPaste(); + $this->_data->create(Helper::getPasteId(), $paste); $_GET['pasteid'] = Helper::getPasteId(); $_GET['deletetoken'] = 'bar'; ob_start(); @@ -871,7 +864,7 @@ class ControllerTest extends TestCase $content = ob_get_contents(); ob_end_clean(); $this->assertMatchesRegularExpression( - '#]*id="errormessage"[^>]*>.*Wrong deletion token\. Paste was not deleted\.#s', + '#]*id="errormessage"[^>]*>.*Wrong deletion token\. Document was not deleted\.#s', $content, 'outputs delete error correctly' ); @@ -883,7 +876,8 @@ class ControllerTest extends TestCase */ public function testDeleteInvalidBurnAfterReading() { - $this->_data->create(Helper::getPasteId(), Helper::getPaste()); + $paste = Helper::getPaste(); + $this->_data->create(Helper::getPasteId(), $paste); $this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists before deleting data'); $file = tempnam(sys_get_temp_dir(), 'FOO'); file_put_contents($file, json_encode(array( @@ -908,7 +902,7 @@ class ControllerTest extends TestCase */ public function testDeleteExpired() { - $expiredPaste = Helper::getPaste(2, array('expire_date' => 1000)); + $expiredPaste = Helper::getPaste(array('expire_date' => 1000)); $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste does not exist before being created'); $this->_data->create(Helper::getPasteId(), $expiredPaste); $this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists before deleting data'); @@ -919,33 +913,10 @@ class ControllerTest extends TestCase $content = ob_get_contents(); ob_end_clean(); $this->assertMatchesRegularExpression( - '#]*id="errormessage"[^>]*>.*Paste does not exist, has expired or has been deleted\.#s', + '#]*id="errormessage"[^>]*>.*Document does not exist, has expired or has been deleted\.#s', $content, 'outputs error correctly' ); $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste successfully deleted'); } - - /** - * @runInSeparateProcess - */ - public function testDeleteMissingPerPasteSalt() - { - $paste = Helper::getPaste(); - unset($paste['meta']['salt']); - $this->_data->create(Helper::getPasteId(), $paste); - $this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists before deleting data'); - $_GET['pasteid'] = Helper::getPasteId(); - $_GET['deletetoken'] = hash_hmac('sha256', Helper::getPasteId(), ServerSalt::get()); - ob_start(); - new Controller; - $content = ob_get_contents(); - ob_end_clean(); - $this->assertMatchesRegularExpression( - '#]*id="status"[^>]*>.*Paste was properly deleted\.#s', - $content, - 'outputs deleted status correctly' - ); - $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste successfully deleted'); - } } diff --git a/tst/ControllerWithDbTest.php b/tst/ControllerWithDbTest.php index d8ec1114..43ae641d 100644 --- a/tst/ControllerWithDbTest.php +++ b/tst/ControllerWithDbTest.php @@ -1,4 +1,4 @@ -_model->delete(Helper::getPasteId()); // storing pastes @@ -56,25 +57,31 @@ class DatabaseTest extends TestCase $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist'); $this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste'); $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it'); + ini_set('error_log', '/dev/null'); $this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store the same paste twice'); + ini_set('error_log', $error_log_setting); $this->assertEquals($paste, $this->_model->read(Helper::getPasteId())); // storing comments - $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'v1 comment does not yet exist'); - $this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), Helper::getComment(1)) !== false, 'store v1 comment'); - $this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'v1 comment exists after storing it'); - $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId()), 'v2 comment does not yet exist'); - $this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId(), Helper::getComment(2)) !== false, 'store v2 comment'); - $this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId()), 'v2 comment exists after storing it'); - $comment1 = Helper::getComment(1); + $comment1 = Helper::getComment(); + $comment2 = Helper::getComment(); + $meta1 = $comment1['meta']; + $meta2 = $comment2['meta']; + $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment 1 does not yet exist'); + $this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), $comment1) !== false, 'store comment 1'); + $this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment 2 exists after storing it'); + $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId()), 'comment 2 does not yet exist'); + $this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId(), $comment2) !== false, 'store comment 2'); + $this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId()), 'comment 2 exists after storing it'); $comment1['id'] = Helper::getCommentId(); $comment1['parentid'] = Helper::getPasteId(); - $comment2 = Helper::getComment(2); + $comment1['meta'] = $meta1; $comment2['id'] = Helper::getPasteId(); $comment2['parentid'] = Helper::getPasteId(); + $comment2['meta'] = $meta2; $this->assertEquals( array( - $comment1['meta']['postdate'] => $comment1, + $comment1['meta']['created'] => $comment1, $comment2['meta']['created'] . '.1' => $comment2, ), $this->_model->readComments(Helper::getPasteId()) @@ -89,17 +96,16 @@ class DatabaseTest extends TestCase public function testDatabaseBasedAttachmentStoreWorks() { - // this assumes a version 1 formatted paste + $error_log_setting = ini_get('error_log'); $this->_model->delete(Helper::getPasteId()); - $original = $paste = Helper::getPasteWithAttachment(1, array('expire_date' => 1344803344)); + $original = $paste = Helper::getPaste(array('expire_date' => 1344803344)); $paste['meta']['burnafterreading'] = $original['meta']['burnafterreading'] = true; - $paste['meta']['attachment'] = $paste['attachment']; - $paste['meta']['attachmentname'] = $paste['attachmentname']; - unset($paste['attachment'], $paste['attachmentname']); $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist'); $this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste'); $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it'); + ini_set('error_log', '/dev/null'); $this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store the same paste twice'); + ini_set('error_log', $error_log_setting); $this->assertEquals($original, $this->_model->read(Helper::getPasteId())); } @@ -109,8 +115,8 @@ class DatabaseTest extends TestCase public function testPurge() { $this->_model->delete(Helper::getPasteId()); - $expired = Helper::getPaste(2, array('expire_date' => 1344803344)); - $paste = Helper::getPaste(2, array('expire_date' => time() + 3600)); + $expired = Helper::getPaste(array('expire_date' => 1344803344)); + $paste = Helper::getPaste(array('expire_date' => time() + 3600)); $keys = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z'); $ids = array(); foreach ($keys as $key) { @@ -120,7 +126,8 @@ class DatabaseTest extends TestCase if (in_array($key, array('y', 'z'))) { $this->assertTrue($this->_model->create($ids[$key], $paste), "store $key paste"); } elseif ($key === 'x') { - $this->assertTrue($this->_model->create($ids[$key], Helper::getPaste()), "store $key paste"); + $data = Helper::getPaste(); + $this->assertTrue($this->_model->create($ids[$key], $data), "store $key paste"); } else { $this->assertTrue($this->_model->create($ids[$key], $expired), "store $key paste"); } @@ -137,6 +144,34 @@ class DatabaseTest extends TestCase } } + public function testErrorDetection() + { + $error_log_setting = ini_get('error_log'); + $this->_model->delete(Helper::getPasteId()); + $paste = Helper::getPaste(array('expire' => "Invalid UTF-8 sequence: \xB1\x31")); + $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist'); + ini_set('error_log', '/dev/null'); + $this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store broken paste'); + ini_set('error_log', $error_log_setting); + $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does still not exist'); + } + + public function testCommentErrorDetection() + { + $error_log_setting = ini_get('error_log'); + $this->_model->delete(Helper::getPasteId()); + $data = Helper::getPaste(); + $comment = Helper::getComment(array('icon' => "Invalid UTF-8 sequence: \xB1\x31")); + $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist'); + $this->assertTrue($this->_model->create(Helper::getPasteId(), $data), 'store new paste'); + $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it'); + $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does not yet exist'); + ini_set('error_log', '/dev/null'); + $this->assertFalse($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), $comment), 'unable to store broken comment'); + ini_set('error_log', $error_log_setting); + $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does still not exist'); + } + public function testGetIbmInstance() { $this->expectException(PDOException::class); @@ -236,93 +271,6 @@ class DatabaseTest extends TestCase new Database($options); } - public function testOldAttachments() - { - mkdir($this->_path); - $path = $this->_path . DIRECTORY_SEPARATOR . 'attachement-test.sq3'; - if (is_file($path)) { - unlink($path); - } - $this->_options['dsn'] = 'sqlite:' . $path; - $this->_options['tbl'] = 'bar_'; - $model = new Database($this->_options); - - $original = $paste = Helper::getPasteWithAttachment(1, array('expire_date' => 1344803344)); - $meta = $paste['meta']; - $meta['attachment'] = $paste['attachment']; - $meta['attachmentname'] = $paste['attachmentname']; - unset($paste['attachment'], $paste['attachmentname']); - - $db = new PDO( - $this->_options['dsn'], - $this->_options['usr'], - $this->_options['pwd'], - $this->_options['opt'] - ); - $statement = $db->prepare('INSERT INTO bar_paste VALUES(?,?,?,?,?,?,?,?,?)'); - $statement->execute( - array( - Helper::getPasteId(), - $paste['data'], - $paste['meta']['postdate'], - $paste['meta']['expire_date'], - 0, - 0, - json_encode($meta), - null, - null, - ) - ); - $statement->closeCursor(); - - $this->assertTrue($model->exists(Helper::getPasteId()), 'paste exists after storing it'); - $this->assertEquals($original, $model->read(Helper::getPasteId())); - - Helper::rmDir($this->_path); - } - - public function testCorruptMeta() - { - mkdir($this->_path); - $path = $this->_path . DIRECTORY_SEPARATOR . 'meta-test.sq3'; - if (is_file($path)) { - unlink($path); - } - $this->_options['dsn'] = 'sqlite:' . $path; - $this->_options['tbl'] = 'baz_'; - $model = new Database($this->_options); - $paste = Helper::getPaste(1, array('expire_date' => 1344803344)); - unset($paste['meta']['formatter'], $paste['meta']['opendiscussion'], $paste['meta']['salt']); - $model->delete(Helper::getPasteId()); - - $db = new PDO( - $this->_options['dsn'], - $this->_options['usr'], - $this->_options['pwd'], - $this->_options['opt'] - ); - $statement = $db->prepare('INSERT INTO baz_paste VALUES(?,?,?,?,?,?,?,?,?)'); - $statement->execute( - array( - Helper::getPasteId(), - $paste['data'], - $paste['meta']['postdate'], - $paste['meta']['expire_date'], - 0, - 0, - '{', - null, - null, - ) - ); - $statement->closeCursor(); - - $this->assertTrue($model->exists(Helper::getPasteId()), 'paste exists after storing it'); - $this->assertEquals($paste, $model->read(Helper::getPasteId())); - - Helper::rmDir($this->_path); - } - public function testTableUpgrade() { mkdir($this->_path); diff --git a/tst/Data/FilesystemTest.php b/tst/Data/FilesystemTest.php index 67366be2..9906f6a7 100644 --- a/tst/Data/FilesystemTest.php +++ b/tst/Data/FilesystemTest.php @@ -1,4 +1,4 @@ -_model->delete(Helper::getPasteId()); // storing pastes - $paste = Helper::getPaste(2, array('expire_date' => 1344803344)); + $paste = Helper::getPaste(array('expire_date' => 1344803344)); $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist'); $this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste'); $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it'); @@ -45,11 +45,11 @@ class FilesystemTest extends TestCase $this->assertEquals($paste, $this->_model->read(Helper::getPasteId())); // storing comments - $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does not yet exist'); - $this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), Helper::getComment()), 'store comment'); - $this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment exists after storing it'); - $this->assertFalse($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), Helper::getComment()), 'unable to store the same comment twice'); $comment = Helper::getComment(); + $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does not yet exist'); + $this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), $comment), 'store comment'); + $this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment exists after storing it'); + $this->assertFalse($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), $comment), 'unable to store the same comment twice'); $comment['id'] = Helper::getCommentId(); $comment['parentid'] = Helper::getPasteId(); $this->assertEquals( @@ -67,10 +67,7 @@ class FilesystemTest extends TestCase public function testFileBasedAttachmentStoreWorks() { $this->_model->delete(Helper::getPasteId()); - $original = $paste = Helper::getPasteWithAttachment(1, array('expire_date' => 1344803344)); - $paste['meta']['attachment'] = $paste['attachment']; - $paste['meta']['attachmentname'] = $paste['attachmentname']; - unset($paste['attachment'], $paste['attachmentname']); + $original = $paste = Helper::getPaste(array('expire_date' => 1344803344)); $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist'); $this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste'); $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it'); @@ -84,8 +81,8 @@ class FilesystemTest extends TestCase public function testPurge() { mkdir($this->_path . DIRECTORY_SEPARATOR . '00', 0777, true); - $expired = Helper::getPaste(2, array('expire_date' => 1344803344)); - $paste = Helper::getPaste(2, array('expire_date' => time() + 3600)); + $expired = Helper::getPaste(array('expire_date' => 1344803344)); + $paste = Helper::getPaste(array('expire_date' => time() + 3600)); $keys = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z'); $ids = array(); foreach ($keys as $key) { @@ -94,7 +91,8 @@ class FilesystemTest extends TestCase if (in_array($key, array('x', 'y', 'z'))) { $this->assertTrue($this->_model->create($ids[$key], $paste), "store $key paste"); } elseif ($key === 'x') { - $this->assertTrue($this->_model->create($ids[$key], Helper::getPaste()), "store $key paste"); + $data = Helper::getPaste(); + $this->assertTrue($this->_model->create($ids[$key], $data), "store $key paste"); } else { $this->assertTrue($this->_model->create($ids[$key], $expired), "store $key paste"); } @@ -113,23 +111,30 @@ class FilesystemTest extends TestCase public function testErrorDetection() { + $error_log_setting = ini_get('error_log'); $this->_model->delete(Helper::getPasteId()); - $paste = Helper::getPaste(2, array('expire' => "Invalid UTF-8 sequence: \xB1\x31")); + $paste = Helper::getPaste(array('expire' => "Invalid UTF-8 sequence: \xB1\x31")); $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist'); + ini_set('error_log', '/dev/null'); $this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store broken paste'); + ini_set('error_log', $error_log_setting); $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does still not exist'); $this->assertFalse($this->_model->setValue('foo', 'non existing namespace'), 'rejects setting value in non existing namespace'); } public function testCommentErrorDetection() { + $error_log_setting = ini_get('error_log'); $this->_model->delete(Helper::getPasteId()); - $comment = Helper::getComment(1, array('nickname' => "Invalid UTF-8 sequence: \xB1\x31")); + $data = Helper::getPaste(); + $comment = Helper::getComment(array('icon' => "Invalid UTF-8 sequence: \xB1\x31")); $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist'); - $this->assertTrue($this->_model->create(Helper::getPasteId(), Helper::getPaste()), 'store new paste'); + $this->assertTrue($this->_model->create(Helper::getPasteId(), $data), 'store new paste'); $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it'); $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does not yet exist'); + ini_set('error_log', '/dev/null'); $this->assertFalse($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), $comment), 'unable to store broken comment'); + ini_set('error_log', $error_log_setting); $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does still not exist'); } @@ -141,9 +146,7 @@ class FilesystemTest extends TestCase $commentid = Helper::getCommentId(); $ids = array(); for ($i = 0, $max = 10; $i < $max; ++$i) { - // PHPs mt_rand only supports 32 bit or up 0x7fffffff on 64 bit systems to be precise :-/ - $dataid = str_pad(dechex(mt_rand(0, mt_getrandmax())), 8, '0', STR_PAD_LEFT) . - str_pad(dechex(mt_rand(0, mt_getrandmax())), 8, '0', STR_PAD_LEFT); + $dataid = Helper::getRandomId(); $storagedir = $this->_path . DIRECTORY_SEPARATOR . substr($dataid, 0, 2) . DIRECTORY_SEPARATOR . substr($dataid, 2, 2) . DIRECTORY_SEPARATOR; $ids[$dataid] = $storagedir; @@ -162,6 +165,7 @@ class FilesystemTest extends TestCase // check that all 10 pastes were converted after the purge $this->_model->purge(10); foreach ($ids as $dataid => $storagedir) { + $dataid = (string) $dataid; // undue potential key cast, see https://www.php.net/manual/en/language.types.array.php $this->assertFileExists($storagedir . $dataid . '.php', "paste $dataid exists in new format"); $this->assertFileDoesNotExist($storagedir . $dataid, "old format paste $dataid got removed"); $this->assertTrue($this->_model->exists($dataid), "paste $dataid exists"); @@ -177,4 +181,18 @@ class FilesystemTest extends TestCase $this->assertEquals($this->_model->readComments($dataid), array($comment['meta']['created'] => $comment), "comment of $dataid wasn't modified in the conversion"); } } + + public function testValueFileErrorHandling() + { + define('VALID', 'valid content'); + foreach (array('purge_limiter', 'salt', 'traffic_limiter') as $namespace) { + file_put_contents($this->_invalidPath . DIRECTORY_SEPARATOR . $namespace . '.php', 'invalid content'); + $model = new Filesystem(array('dir' => $this->_invalidPath)); + ob_start(); // hide "invalid content", when file gets included + $this->assertEquals($model->getValue($namespace), '', 'empty default value returned, invalid content ignored'); + ob_end_clean(); + $this->assertTrue($model->setValue(VALID, $namespace), 'setting valid value'); + $this->assertEquals($model->getValue($namespace), VALID, 'valid value returned'); + } + } } diff --git a/tst/Data/GoogleCloudStorageTest.php b/tst/Data/GoogleCloudStorageTest.php index b7cfe349..f5736f78 100644 --- a/tst/Data/GoogleCloudStorageTest.php +++ b/tst/Data/GoogleCloudStorageTest.php @@ -1,4 +1,4 @@ -_model->delete(Helper::getPasteId()); // storing pastes - $paste = Helper::getPaste(2, array('expire_date' => 1344803344)); + $paste = Helper::getPaste(array('expire_date' => 1344803344)); $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist'); $this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste'); $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it'); @@ -58,11 +59,11 @@ class GoogleCloudStorageTest extends TestCase $this->assertEquals($paste, $this->_model->read(Helper::getPasteId())); // storing comments - $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does not yet exist'); - $this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), Helper::getComment()), 'store comment'); - $this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment exists after storing it'); - $this->assertFalse($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), Helper::getComment()), 'unable to store the same comment twice'); $comment = Helper::getComment(); + $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does not yet exist'); + $this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), $comment), 'store comment'); + $this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment exists after storing it'); + $this->assertFalse($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), $comment), 'unable to store the same comment twice'); $comment['id'] = Helper::getCommentId(); $comment['parentid'] = Helper::getPasteId(); $this->assertEquals( @@ -82,8 +83,8 @@ class GoogleCloudStorageTest extends TestCase */ public function testPurge() { - $expired = Helper::getPaste(2, array('expire_date' => 1344803344)); - $paste = Helper::getPaste(2, array('expire_date' => time() + 3600)); + $expired = Helper::getPaste(array('expire_date' => 1344803344)); + $paste = Helper::getPaste(array('expire_date' => time() + 3600)); $keys = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z'); $ids = array(); foreach ($keys as $key) { @@ -92,7 +93,8 @@ class GoogleCloudStorageTest extends TestCase if (in_array($key, array('x', 'y', 'z'))) { $this->assertTrue($this->_model->create($ids[$key], $paste), "store $key paste"); } elseif ($key === 'x') { - $this->assertTrue($this->_model->create($ids[$key], Helper::getPaste()), "store $key paste"); + $data = Helper::getPaste(); + $this->assertTrue($this->_model->create($ids[$key], $data), "store $key paste"); } else { $this->assertTrue($this->_model->create($ids[$key], $expired), "store $key paste"); } @@ -112,7 +114,7 @@ class GoogleCloudStorageTest extends TestCase public function testErrorDetection() { $this->_model->delete(Helper::getPasteId()); - $paste = Helper::getPaste(2, array('expire' => "Invalid UTF-8 sequence: \xB1\x31")); + $paste = Helper::getPaste(array('expire' => "Invalid UTF-8 sequence: \xB1\x31")); $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist'); $this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store broken paste'); $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does still not exist'); @@ -121,9 +123,10 @@ class GoogleCloudStorageTest extends TestCase public function testCommentErrorDetection() { $this->_model->delete(Helper::getPasteId()); - $comment = Helper::getComment(1, array('nickname' => "Invalid UTF-8 sequence: \xB1\x31")); + $data = Helper::getPaste(); + $comment = Helper::getComment(array('icon' => "Invalid UTF-8 sequence: \xB1\x31")); $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist'); - $this->assertTrue($this->_model->create(Helper::getPasteId(), Helper::getPaste()), 'store new paste'); + $this->assertTrue($this->_model->create(Helper::getPasteId(), $data), 'store new paste'); $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it'); $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does not yet exist'); $this->assertFalse($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), $comment), 'unable to store broken comment'); diff --git a/tst/FilterTest.php b/tst/FilterTest.php index 39c4f5df..cd1d1018 100644 --- a/tst/FilterTest.php +++ b/tst/FilterTest.php @@ -1,4 +1,4 @@ -assertEquals('1 B', Filter::formatHumanReadableSize(1)); - $this->assertEquals('1 000 B', Filter::formatHumanReadableSize(1000)); - $this->assertEquals('1.00 KiB', Filter::formatHumanReadableSize(1024)); - $this->assertEquals('1.21 KiB', Filter::formatHumanReadableSize(1234)); - $exponent = 1024; - $this->assertEquals('1 000.00 KiB', Filter::formatHumanReadableSize(1000 * $exponent)); - $this->assertEquals('1.00 MiB', Filter::formatHumanReadableSize(1024 * $exponent)); - $this->assertEquals('1.21 MiB', Filter::formatHumanReadableSize(1234 * $exponent)); - $exponent *= 1024; - $this->assertEquals('1 000.00 MiB', Filter::formatHumanReadableSize(1000 * $exponent)); - $this->assertEquals('1.00 GiB', Filter::formatHumanReadableSize(1024 * $exponent)); - $this->assertEquals('1.21 GiB', Filter::formatHumanReadableSize(1234 * $exponent)); - $exponent *= 1024; - $this->assertEquals('1 000.00 GiB', Filter::formatHumanReadableSize(1000 * $exponent)); - $this->assertEquals('1.00 TiB', Filter::formatHumanReadableSize(1024 * $exponent)); - $this->assertEquals('1.21 TiB', Filter::formatHumanReadableSize(1234 * $exponent)); - $exponent *= 1024; - $this->assertEquals('1 000.00 TiB', Filter::formatHumanReadableSize(1000 * $exponent)); - $this->assertEquals('1.00 PiB', Filter::formatHumanReadableSize(1024 * $exponent)); - $this->assertEquals('1.21 PiB', Filter::formatHumanReadableSize(1234 * $exponent)); - $exponent *= 1024; - $this->assertEquals('1 000.00 PiB', Filter::formatHumanReadableSize(1000 * $exponent)); - $this->assertEquals('1.00 EiB', Filter::formatHumanReadableSize(1024 * $exponent)); - $this->assertEquals('1.21 EiB', Filter::formatHumanReadableSize(1234 * $exponent)); - $exponent *= 1024; - $this->assertEquals('1 000.00 EiB', Filter::formatHumanReadableSize(1000 * $exponent)); - $this->assertEquals('1.00 ZiB', Filter::formatHumanReadableSize(1024 * $exponent)); - $this->assertEquals('1.21 ZiB', Filter::formatHumanReadableSize(1234 * $exponent)); - $exponent *= 1024; - $this->assertEquals('1 000.00 ZiB', Filter::formatHumanReadableSize(1000 * $exponent)); - $this->assertEquals('1.00 YiB', Filter::formatHumanReadableSize(1024 * $exponent)); - $this->assertEquals('1.21 YiB', Filter::formatHumanReadableSize(1234 * $exponent)); + $this->assertEquals('1.00 kB', Filter::formatHumanReadableSize(1000)); + $this->assertEquals('1.02 kB', Filter::formatHumanReadableSize(1024)); + $this->assertEquals('1.23 kB', Filter::formatHumanReadableSize(1234)); + $exponent = 1000; + $this->assertEquals('1.00 MB', Filter::formatHumanReadableSize(1000 * $exponent)); + $this->assertEquals('1.02 MB', Filter::formatHumanReadableSize(1024 * $exponent)); + $this->assertEquals('1.23 MB', Filter::formatHumanReadableSize(1234 * $exponent)); + $exponent *= 1000; + $this->assertEquals('1.00 GB', Filter::formatHumanReadableSize(1000 * $exponent)); + $this->assertEquals('1.02 GB', Filter::formatHumanReadableSize(1024 * $exponent)); + $this->assertEquals('1.23 GB', Filter::formatHumanReadableSize(1234 * $exponent)); + $exponent *= 1000; + $this->assertEquals('1.00 TB', Filter::formatHumanReadableSize(1000 * $exponent)); + $this->assertEquals('1.02 TB', Filter::formatHumanReadableSize(1024 * $exponent)); + $this->assertEquals('1.23 TB', Filter::formatHumanReadableSize(1234 * $exponent)); + $exponent *= 1000; + $this->assertEquals('1.00 PB', Filter::formatHumanReadableSize(1000 * $exponent)); + $this->assertEquals('1.02 PB', Filter::formatHumanReadableSize(1024 * $exponent)); + $this->assertEquals('1.23 PB', Filter::formatHumanReadableSize(1234 * $exponent)); + $exponent *= 1000; + $this->assertEquals('1.00 EB', Filter::formatHumanReadableSize(1000 * $exponent)); + $this->assertEquals('1.02 EB', Filter::formatHumanReadableSize(1024 * $exponent)); + $this->assertEquals('1.23 EB', Filter::formatHumanReadableSize(1234 * $exponent)); + $exponent *= 1000; + $this->assertEquals('1.00 ZB', Filter::formatHumanReadableSize(1000 * $exponent)); + $this->assertEquals('1.02 ZB', Filter::formatHumanReadableSize(1024 * $exponent)); + $this->assertEquals('1.23 ZB', Filter::formatHumanReadableSize(1234 * $exponent)); + $exponent *= 1000; + $this->assertEquals('1.00 YB', Filter::formatHumanReadableSize(1000 * $exponent)); + $this->assertEquals('1.02 YB', Filter::formatHumanReadableSize(1024 * $exponent)); + $this->assertEquals('1.23 YB', Filter::formatHumanReadableSize(1234 * $exponent)); } } diff --git a/tst/FormatV2Test.php b/tst/FormatV2Test.php index 8b8b6b82..2e13d8f5 100644 --- a/tst/FormatV2Test.php +++ b/tst/FormatV2Test.php @@ -1,4 +1,4 @@ -assertTrue(FormatV2::isValid(Helper::getPastePost()), 'valid format'); - $this->assertTrue(FormatV2::isValid(Helper::getCommentPost(), true), 'valid format'); + $paste = Helper::getPastePost(); + $comment = Helper::getCommentPost(); + $this->assertTrue(FormatV2::isValid($paste), 'valid format'); + $this->assertTrue(FormatV2::isValid($comment, true), 'valid format'); - $paste = Helper::getPastePost(); $paste['adata'][0][0] = '$'; $this->assertFalse(FormatV2::isValid($paste), 'invalid base64 encoding of iv'); @@ -68,6 +69,7 @@ class FormatV2Test extends TestCase $paste['adata'][0][7] = '!#@'; $this->assertFalse(FormatV2::isValid($paste), 'invalid compression'); - $this->assertFalse(FormatV2::isValid(Helper::getPaste()), 'invalid meta key'); + $paste = Helper::getPaste(); + $this->assertFalse(FormatV2::isValid($paste), 'invalid meta key'); } } diff --git a/tst/I18nTest.php b/tst/I18nTest.php index e606a8b3..af0acfb0 100644 --- a/tst/I18nTest.php +++ b/tst/I18nTest.php @@ -1,4 +1,4 @@ -assertEquals('cs', I18n::getLanguage(), 'browser language cs'); - $this->assertEquals('1 hodina', I18n::_('%d hours', 1), '1 hour in Czech'); - $this->assertEquals('2 hodiny', I18n::_('%d hours', 2), '2 hours in Czech'); - $this->assertEquals('5 minut', I18n::_('%d minutes', 5), '5 minutes in Czech'); - $this->assertEquals('14 minut', I18n::_('%d minutes', 14), '14 minutes in Czech'); + $this->assertEquals('1 hodina', I18n::_('%d hours', 1), '1 hour in Czech'); + $this->assertEquals('2 hodiny', I18n::_('%d hours', 2), '2 hours in Czech'); + $this->assertEquals('5 minut', I18n::_('%d minutes', 5), '5 minutes in Czech'); + $this->assertEquals('14 minut', I18n::_('%d minutes', 14), '14 minutes in Czech'); } public function testBrowserLanguageAnyDetection() @@ -198,7 +198,7 @@ class I18nTest extends TestCase $languageCount = 0; foreach ($languageIterator as $file) { ++$languageCount; - $this->assertTrue(copy($file, $path . DIRECTORY_SEPARATOR . $file->getBasename())); + $this->assertTrue(copy($file->getPathname(), $path . DIRECTORY_SEPARATOR . $file->getBasename())); } I18nMock::resetPath($path); diff --git a/tst/JsonApiTest.php b/tst/JsonApiTest.php index 45784d24..90545c93 100644 --- a/tst/JsonApiTest.php +++ b/tst/JsonApiTest.php @@ -1,4 +1,4 @@ -_model->create(Helper::getPasteId(), Helper::getPaste()); + $data = Helper::getPaste(); + $this->_model->create(Helper::getPasteId(), $data); $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data'); $paste = $this->_model->read(Helper::getPasteId()); $file = tempnam(sys_get_temp_dir(), 'FOO'); @@ -141,7 +142,8 @@ class JsonApiTest extends TestCase */ public function testDeleteWithPost() { - $this->_model->create(Helper::getPasteId(), Helper::getPaste()); + $data = Helper::getPaste(); + $this->_model->create(Helper::getPasteId(), $data); $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data'); $paste = $this->_model->read(Helper::getPasteId()); $file = tempnam(sys_get_temp_dir(), 'FOO'); @@ -166,7 +168,7 @@ class JsonApiTest extends TestCase */ public function testRead() { - $paste = Helper::getPaste(); + $paste = Helper::getPaste(); $this->_model->create(Helper::getPasteId(), $paste); $_SERVER['QUERY_STRING'] = Helper::getPasteId(); $_GET[Helper::getPasteId()] = ''; @@ -180,7 +182,7 @@ class JsonApiTest extends TestCase $this->assertEquals(Helper::getPasteId(), $response['id'], 'outputs data correctly'); $this->assertStringEndsWith('?' . $response['id'], $response['url'], 'returned URL points to new paste'); $this->assertEquals($paste['ct'], $response['ct'], 'outputs data correctly'); - $this->assertEquals($paste['meta']['created'], $response['meta']['created'], 'outputs postdate correctly'); + $this->assertFalse(array_key_exists('created', $paste['meta']), 'does not output created'); $this->assertEquals(0, $response['comment_count'], 'outputs comment_count correctly'); $this->assertEquals(0, $response['comment_offset'], 'outputs comment_offset correctly'); } @@ -285,26 +287,130 @@ class JsonApiTest extends TestCase /** * @runInSeparateProcess + * @dataProvider baseUriProvider */ - public function testShortenViaYourls() + public function testShortenViaYourls($baseUri) { $mock_yourls_service = $this->_path . DIRECTORY_SEPARATOR . 'yourls.json'; $options = parse_ini_file(CONF, true); $options['main']['basepath'] = 'https://example.com/path'; // missing slash gets added by Configuration constructor - $options['main']['urlshortener'] = 'https://example.com/path/shortenviayourls?link='; + $options['main']['urlshortener'] = 'https://example.com' . $baseUri . 'link='; $options['yourls']['apiurl'] = $mock_yourls_service; Helper::createIniFile(CONF, $options); // the real service answer is more complex, but we only look for the shorturl & statusCode file_put_contents($mock_yourls_service, '{"shorturl":"https:\/\/example.com\/1","statusCode":200}'); - $_SERVER['REQUEST_URI'] = '/path/shortenviayourls?link=https%3A%2F%2Fexample.com%2Fpath%2F%3Ffoo%23bar'; + $_SERVER['REQUEST_URI'] = $baseUri . 'link=https%3A%2F%2Fexample.com%2Fpath%2F%3Ffoo%23bar'; $_GET['link'] = 'https://example.com/path/?foo#bar'; + if (str_contains($baseUri, '?shortenviayourls')) { + $_GET['shortenviayourls'] = null; + } ob_start(); new Controller; $content = ob_get_contents(); ob_end_clean(); - $this->assertStringContainsString('id="pasteurl" href="https://example.com/1"', $content, 'outputs shortened URL correctly'); + $this->assertStringContainsString('id="pasteurl" href="https://example.com/1"', $content, "'{$baseUri}' outputs shortened URL correctly"); + } + + /** + * @runInSeparateProcess + * @dataProvider baseShlinkUriProvider + */ + public function testShortenViaShlink($baseUri) + { + $mock_shlink_service = $this->_path . DIRECTORY_SEPARATOR . 'shlink.json'; + $options = parse_ini_file(CONF, true); + $options['main']['basepath'] = 'https://example.com/path'; // missing slash gets added by Configuration constructor + $options['main']['urlshortener'] = 'https://example.com' . $baseUri . 'link='; + $options['shlink']['apiurl'] = $mock_shlink_service; + Helper::createIniFile(CONF, $options); + + // the real service answer is more complex, but we only look for the shorturl & statusCode + file_put_contents($mock_shlink_service, '{"shortUrl":"https:\/\/example.com\/1"}'); + + $_SERVER['REQUEST_URI'] = $baseUri . 'link=https%3A%2F%2Fexample.com%2Fpath%2F%3Ffoo%23bar'; + $_GET['link'] = 'https://example.com/path/?foo#bar'; + if (str_contains($baseUri, '?shortenviashlink')) { + $_GET['shortenviashlink'] = null; + } + ob_start(); + new Controller; + $content = ob_get_contents(); + ob_end_clean(); + $this->assertStringContainsString('id="pasteurl" href="https://example.com/1"', $content, "'{$baseUri}' outputs shortened URL correctly"); + } + + /** + * @runInSeparateProcess + * @dataProvider baseShlinkUriProvider + */ + public function testShortenViaShlinkFailureHttp($baseUri) + { + $mock_shlink_service = 'https://httpbin.org/status/403'; + $options = parse_ini_file(CONF, true); + $options['main']['basepath'] = 'https://example.com/path'; // missing slash gets added by Configuration constructor + $options['main']['urlshortener'] = 'https://example.com' . $baseUri . 'link='; + $options['shlink']['apiurl'] = $mock_shlink_service; + Helper::createIniFile(CONF, $options); + + $_SERVER['REQUEST_URI'] = $baseUri . 'link=https%3A%2F%2Fexample.com%2Fpath%2F%3Ffoo%23bar'; + $_GET['link'] = 'https://example.com/path/?foo#bar'; + if (str_contains($baseUri, '?shortenviashlink')) { + $_GET['shortenviashlink'] = null; + } + ob_start(); + // Use @ to ignore the http warning for the 403. It will be handled appropriately by AbstractProxy + @new Controller; + $content = ob_get_contents(); + ob_end_clean(); + $this->assertStringContainsString('Proxy error: Bad response.', $content, 'outputs error correctly'); + } + + /** + * @runInSeparateProcess + * @dataProvider baseShlinkUriProvider + */ + public function testShortenViaShlinkSuccessButMissingShortUrl($baseUri) + { + $mock_shlink_service = $this->_path . DIRECTORY_SEPARATOR . 'shlink.json'; + $options = parse_ini_file(CONF, true); + $options['main']['basepath'] = 'https://example.com/path'; // missing slash gets added by Configuration constructor + $options['main']['urlshortener'] = 'https://example.com' . $baseUri . 'link='; + $options['shlink']['apiurl'] = $mock_shlink_service; + Helper::createIniFile(CONF, $options); + + // Ideally, this should never happen, just in case "shortUrl" is somehow missing in the 200 response + file_put_contents($mock_shlink_service, '{}'); + + $_SERVER['REQUEST_URI'] = $baseUri . 'link=https%3A%2F%2Fexample.com%2Fpath%2F%3Ffoo%23bar'; + $_GET['link'] = 'https://example.com/path/?foo#bar'; + if (str_contains($baseUri, '?shortenviashlink')) { + $_GET['shortenviashlink'] = null; + } + ob_start(); + new Controller; + $content = ob_get_contents(); + ob_end_clean(); + $this->assertStringContainsString('Proxy error: Error parsing proxy response.', $content, 'outputs error correctly'); + } + + public function baseUriProvider() + { + return array( + array('/path/shortenviayourls?'), + array('/path/index.php/shortenviayourls?'), + array('/path?shortenviayourls&'), + ); + } + + public function baseShlinkUriProvider() + { + return array( + array('/path/shortenviashlink?'), + array('/path/index.php/shortenviashlink?'), + array('/path?shortenviashlink&'), + ); } /** @@ -312,12 +418,32 @@ class JsonApiTest extends TestCase */ public function testShortenViaYourlsFailure() { + $options = parse_ini_file(CONF, true); + $options['main']['basepath'] = 'https://example.com/path'; // missing slash gets added by Configuration constructor + Helper::createIniFile(CONF, $options); $_SERVER['REQUEST_URI'] = '/path/shortenviayourls?link=https%3A%2F%2Fexample.com%2Fpath%2F%3Ffoo%23bar'; $_GET['link'] = 'https://example.com/path/?foo#bar'; ob_start(); new Controller; $content = ob_get_contents(); ob_end_clean(); - $this->assertStringContainsString('Error calling YOURLS.', $content, 'outputs error correctly'); + $this->assertStringContainsString('Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.', $content, 'outputs error correctly'); + } + + /** + * @runInSeparateProcess + */ + public function testShortenViaShlinkFailure() + { + $options = parse_ini_file(CONF, true); + $options['main']['basepath'] = 'https://example.com/path'; // missing slash gets added by Configuration constructor + Helper::createIniFile(CONF, $options); + $_SERVER['REQUEST_URI'] = '/path/shortenviashlink?link=https%3A%2F%2Fexample.com%2Fpath%2F%3Ffoo%23bar'; + $_GET['link'] = 'https://example.com/path/?foo#bar'; + ob_start(); + new Controller; + $content = ob_get_contents(); + ob_end_clean(); + $this->assertStringContainsString('Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.', $content, 'outputs error correctly'); } } diff --git a/tst/MigrateTest.php b/tst/MigrateTest.php index 81828b62..fd6cc9af 100644 --- a/tst/MigrateTest.php +++ b/tst/MigrateTest.php @@ -1,4 +1,4 @@ -_model_2->delete(Helper::getPasteId()); // storing paste & comment - $this->_model_1->create(Helper::getPasteId(), Helper::getPaste()); - $this->_model_1->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), Helper::getComment()); + $data = Helper::getPaste(); + $this->_model_1->create(Helper::getPasteId(), $data); + $data = Helper::getComment(); + $this->_model_1->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), $data); // migrate files to database $output = null; diff --git a/tst/ModelTest.php b/tst/ModelTest.php index 03855405..39c5173c 100644 --- a/tst/ModelTest.php +++ b/tst/ModelTest.php @@ -1,6 +1,6 @@ -assertEquals(array(), $paste->getComments(), 'comment was deleted with paste'); } - public function testPasteV1() - { - $pasteData = Helper::getPaste(1); - unset($pasteData['meta']['formatter']); - - $path = $this->_path . DIRECTORY_SEPARATOR . 'v1-test.sq3'; - if (is_file($path)) { - unlink($path); - } - $options = parse_ini_file(CONF_SAMPLE, true); - $options['purge']['limit'] = 0; - $options['model'] = array( - 'class' => 'Database', - ); - $options['model_options'] = array( - 'dsn' => 'sqlite:' . $path, - 'usr' => null, - 'pwd' => null, - 'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION), - ); - Helper::createIniFile(CONF, $options); - $model = new Model(new Configuration); - $model->getPaste('0000000000000000')->exists(); // triggers database table creation - $model->getPaste(Helper::getPasteId())->delete(); // deletes the cache - - $db = new PDO( - $options['model_options']['dsn'], - $options['model_options']['usr'], - $options['model_options']['pwd'], - $options['model_options']['opt'] - ); - $statement = $db->prepare('INSERT INTO paste VALUES(?,?,?,?,?,?,?,?,?)'); - $statement->execute( - array( - Helper::getPasteId(), - $pasteData['data'], - $pasteData['meta']['postdate'], - 0, - 0, - 0, - json_encode($pasteData['meta']), - null, - null, - ) - ); - $statement->closeCursor(); - - $paste = $model->getPaste(Helper::getPasteId()); - $this->assertNotEmpty($paste->getDeleteToken(), 'excercise the condition to load the data from storage'); - $this->assertEquals('plaintext', $paste->get()['meta']['formatter'], 'paste got created with default formatter'); - } - public function testCommentDefaults() { $class = 'PrivateBin\\Data\\' . $this->_conf->getKey('class', 'model'); @@ -164,7 +112,8 @@ class ModelTest extends TestCase $this->_conf->getSection('model_options') ) ); - $comment->setPaste($this->_model->getPaste(Helper::getPasteId())); + $paste = $this->_model->getPaste(Helper::getPasteId()); + $comment->setPaste($paste); $this->assertEquals(Helper::getPasteId(), $comment->getParentId(), 'comment parent ID gets initialized to paste ID'); } @@ -308,16 +257,27 @@ class ModelTest extends TestCase $comment->get(); $comment->store(); - $identicon = new Identicon(); - $pngdata = $identicon->getImageDataUri(TrafficLimiter::getHash(), 16); - $comment = current($this->_model->getPaste(Helper::getPasteId())->get()['comments']); + $identicon = new Identicon(array( + 'hash' => TrafficLimiter::getHash(), + 'size' => 16, + 'style' => array( + 'backgroundColor' => '#fff0', // fully transparent, for dark mode + 'padding' => 0, + ), + )); + $pngdata = $identicon->getImageDataUri('png'); + $comment = current($this->_model->getPaste(Helper::getPasteId())->get()['comments']); $this->assertEquals($pngdata, $comment['meta']['icon'], 'icon gets set'); } public function testPasteIdValidation() { $this->assertTrue(Paste::isValidId('a242ab7bdfb2581a'), 'valid paste id'); - $this->assertFalse(Paste::isValidId('foo'), 'invalid hex values'); + $this->assertFalse(Paste::isValidId('foo'), 'invalid hex values & length'); + $this->assertFalse(Paste::isValidId('f00'), 'invalid length'); + $this->assertFalse(Paste::isValidId('foo bar baz quux'), 'invalid hex values'); + $this->assertFalse(Paste::isValidId("\n01234567feedcafe"), 'invalid line breaks'); + $this->assertFalse(Paste::isValidId("deadbeef01234567\n"), 'invalid line breaks'); $this->assertFalse(Paste::isValidId('../bar/baz'), 'path attack'); } @@ -406,26 +366,13 @@ class ModelTest extends TestCase $this->assertEquals((float) 300, (float) $paste['meta']['time_to_live'], 'remaining time is set correctly', 1.0); } - public function testCommentDeletion() - { - $pasteData = Helper::getPastePost(); - $this->_model->getPaste(Helper::getPasteId())->delete(); - - $paste = $this->_model->getPaste(); - $paste->setData($pasteData); - $paste->store(); - $this->expectException(Exception::class); - $this->expectExceptionCode(64); - $paste->getComment(Helper::getPasteId())->delete(); - } - public function testPurge() { $conf = new Configuration; $store = new Database($conf->getSection('model_options')); $store->delete(Helper::getPasteId()); - $expired = Helper::getPaste(2, array('expire_date' => 1344803344)); - $paste = Helper::getPaste(2, array('expire_date' => time() + 3600)); + $expired = Helper::getPaste(array('expire_date' => 1344803344)); + $paste = Helper::getPaste(array('expire_date' => time() + 3600)); $keys = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'x', 'y', 'z'); $ids = array(); foreach ($keys as $key) { @@ -452,12 +399,13 @@ class ModelTest extends TestCase public function testCommentWithDisabledVizhash() { - $options = parse_ini_file(CONF, true); - $options['main']['icon'] = 'none'; - $options['model'] = array( + $options = parse_ini_file(CONF, true); + $options['main']['discussiondatedisplay'] = 'false'; + $options['main']['icon'] = 'none'; + $options['model'] = array( 'class' => 'Database', ); - $options['model_options'] = array( + $options['model_options'] = array( 'dsn' => 'sqlite::memory:', 'usr' => null, 'pwd' => null, @@ -494,6 +442,10 @@ class ModelTest extends TestCase $comment = current($this->_model->getPaste(Helper::getPasteId())->get()['comments']); $this->assertFalse(array_key_exists('icon', $comment['meta']), 'icon was not generated'); + $this->assertTrue(array_key_exists('created', $comment['meta']), 'creation is set, when using default configuration'); + + $comment = current($paste->get()['comments']); + $this->assertFalse(array_key_exists('created', $comment['meta']), 'creation is not set, if using disabled configuration'); } public function testCommentVizhash() @@ -527,6 +479,6 @@ class ModelTest extends TestCase $vz = new Vizhash16x16(); $pngdata = 'data:image/png;base64,' . base64_encode($vz->generate(TrafficLimiter::getHash())); $comment = current($this->_model->getPaste(Helper::getPasteId())->get()['comments']); - $this->assertEquals($pngdata, $comment['meta']['icon'], 'nickname triggers vizhash to be set'); + $this->assertEquals($pngdata, $comment['meta']['icon'], 'vizhash was generated'); } } diff --git a/tst/Persistence/PurgeLimiterTest.php b/tst/Persistence/PurgeLimiterTest.php index 656818ed..d4c8bd5b 100644 --- a/tst/Persistence/PurgeLimiterTest.php +++ b/tst/Persistence/PurgeLimiterTest.php @@ -1,4 +1,4 @@ -assertFalse(TrafficLimiter::canPass(), 'expected an exception'); } catch (Exception $e) { - $this->assertEquals($e->getMessage(), 'Your IP is not authorized to create pastes.', 'not a creator'); + $this->assertEquals($e->getMessage(), 'Your IP is not authorized to create documents.', 'not a creator'); } $_SERVER['REMOTE_ADDR'] = '10.10.10.10'; $this->assertTrue(TrafficLimiter::canPass(), 'IPv4 in creator range'); @@ -103,7 +103,7 @@ class TrafficLimiterTest extends TestCase try { $this->assertFalse(TrafficLimiter::canPass(), 'expected an exception'); } catch (Exception $e) { - $this->assertEquals($e->getMessage(), 'Your IP is not authorized to create pastes.', 'request is to fast, not a creator'); + $this->assertEquals($e->getMessage(), 'Your IP is not authorized to create documents.', 'request is to fast, not a creator'); } $_SERVER['REMOTE_ADDR'] = 'foobar'; $this->assertTrue(TrafficLimiter::canPass(), 'non-IP address'); diff --git a/tst/RequestTest.php b/tst/RequestTest.php index 6734ba3b..eb22655f 100644 --- a/tst/RequestTest.php +++ b/tst/RequestTest.php @@ -1,4 +1,4 @@ -reset(); - $id = $this->getRandomId(); + $id = Helper::getRandomId(); + $_SERVER['REQUEST_METHOD'] = 'GET'; + $_SERVER['QUERY_STRING'] = $id; + $_GET[$id] = ''; + $request = new Request; + $this->assertFalse($request->isJsonApiCall(), 'is HTML call'); + $this->assertEquals($id, $request->getParam('pasteid')); + $this->assertEquals('read', $request->getOperation()); + } + + /** + * paste IDs are 8 bytes hex encoded strings, if unlucky, this turns into + * a numeric string that PHP will cast to an int, for example in array keys + * @see https://www.php.net/manual/en/language.types.array.php + */ + public function testReadNumeric() + { + $this->reset(); + $id = '1234567812345678'; $_SERVER['REQUEST_METHOD'] = 'GET'; $_SERVER['QUERY_STRING'] = $id; $_GET[$id] = ''; @@ -67,7 +73,7 @@ class RequestTest extends TestCase public function testDelete() { $this->reset(); - $id = $this->getRandomId(); + $id = Helper::getRandomId(); $_SERVER['REQUEST_METHOD'] = 'GET'; $_GET['pasteid'] = $id; $_GET['deletetoken'] = 'bar'; @@ -110,7 +116,7 @@ class RequestTest extends TestCase public function testApiRead() { $this->reset(); - $id = $this->getRandomId(); + $id = Helper::getRandomId(); $_SERVER['REQUEST_METHOD'] = 'GET'; $_SERVER['HTTP_ACCEPT'] = 'application/json, text/javascript, */*; q=0.01'; $_SERVER['QUERY_STRING'] = $id; @@ -124,7 +130,7 @@ class RequestTest extends TestCase public function testApiDelete() { $this->reset(); - $id = $this->getRandomId(); + $id = Helper::getRandomId(); $_SERVER['REQUEST_METHOD'] = 'POST'; $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest'; $_SERVER['QUERY_STRING'] = $id; @@ -155,7 +161,7 @@ class RequestTest extends TestCase public function testReadWithNegotiation() { $this->reset(); - $id = $this->getRandomId(); + $id = Helper::getRandomId(); $_SERVER['REQUEST_METHOD'] = 'GET'; $_SERVER['HTTP_ACCEPT'] = 'text/html,text/html; charset=UTF-8,application/xhtml+xml, application/xml;q=0.9,*/*;q=0.8, text/csv,application/json'; $_SERVER['QUERY_STRING'] = $id; @@ -169,7 +175,7 @@ class RequestTest extends TestCase public function testReadWithXhtmlNegotiation() { $this->reset(); - $id = $this->getRandomId(); + $id = Helper::getRandomId(); $_SERVER['REQUEST_METHOD'] = 'GET'; $_SERVER['HTTP_ACCEPT'] = 'application/xhtml+xml,text/html,text/html; charset=UTF-8, application/xml;q=0.9,*/*;q=0.8, text/csv,application/json'; $_SERVER['QUERY_STRING'] = $id; @@ -183,7 +189,7 @@ class RequestTest extends TestCase public function testApiReadWithNegotiation() { $this->reset(); - $id = $this->getRandomId(); + $id = Helper::getRandomId(); $_SERVER['REQUEST_METHOD'] = 'GET'; $_SERVER['HTTP_ACCEPT'] = 'text/plain,text/csv, application/xml;q=0.9, application/json, text/html,text/html; charset=UTF-8,application/xhtml+xml, */*;q=0.8'; $_SERVER['QUERY_STRING'] = $id; @@ -197,7 +203,7 @@ class RequestTest extends TestCase public function testReadWithFailedNegotiation() { $this->reset(); - $id = $this->getRandomId(); + $id = Helper::getRandomId(); $_SERVER['REQUEST_METHOD'] = 'GET'; $_SERVER['HTTP_ACCEPT'] = 'text/plain,text/csv, application/xml;q=0.9, */*;q=0.8'; $_SERVER['QUERY_STRING'] = $id; @@ -211,7 +217,7 @@ class RequestTest extends TestCase public function testPasteIdExtraction() { $this->reset(); - $id = $this->getRandomId(); + $id = Helper::getRandomId(); $queryParams = array($id); $queryParamCount = random_int(1, 5); for ($i = 0; $i < $queryParamCount; ++$i) { diff --git a/tst/TemplateSwitcherTest.php b/tst/TemplateSwitcherTest.php new file mode 100644 index 00000000..16aec6b0 --- /dev/null +++ b/tst/TemplateSwitcherTest.php @@ -0,0 +1,71 @@ +getKey('availabletemplates')); + + TemplateSwitcher::setTemplateFallback($wrongBootstrapTemplateFallback); + $this->assertEquals($defaultTemplateFallback, TemplateSwitcher::getTemplate(), 'Wrong bootstrap template fallback'); + + TemplateSwitcher::setTemplateFallback($wrongTemplateFallback); + $this->assertEquals($defaultTemplateFallback, TemplateSwitcher::getTemplate(), 'Wrong template fallback'); + + TemplateSwitcher::setTemplateFallback($existingTemplateFallback); + $this->assertEquals($existingTemplateFallback, TemplateSwitcher::getTemplate(), 'Correct template fallback'); + } + + public function testSetAvailableTemplates() + { + $conf = new Configuration; + $availableTemplates = $conf->getKey('availabletemplates'); + + TemplateSwitcher::setAvailableTemplates($availableTemplates); + $this->assertEquals($availableTemplates, TemplateSwitcher::getAvailableTemplates(), 'Set available templates'); + } + + public function testGetTemplate() + { + $defaultTemplateFallback = 'bootstrap5'; + $customTemplate = 'bootstrap-dark'; + $customWrongTemplate = 'bootstrap-wrong'; + + TemplateSwitcher::setTemplateFallback($defaultTemplateFallback); + + $_COOKIE['template'] = $customWrongTemplate; + $this->assertEquals($defaultTemplateFallback, TemplateSwitcher::getTemplate(), 'Custom wrong template'); + + $_COOKIE['template'] = $customTemplate; + $this->assertEquals($customTemplate, TemplateSwitcher::getTemplate(), 'Custom template'); + } + + public function testGetAvailableTemplates() + { + $this->assertNotEmpty(TemplateSwitcher::getAvailableTemplates(), 'Get available templates'); + } + + public function testIsTemplateAvailable() + { + $conf = new Configuration; + + $existingTemplate = 'bootstrap'; + $nonExistentTemplate = 'bootstrap-wrong'; + + TemplateSwitcher::setAvailableTemplates($conf->getKey('availabletemplates')); + + $this->assertTrue(TemplateSwitcher::isTemplateAvailable($existingTemplate), 'Existing template'); + $this->assertFalse(TemplateSwitcher::isTemplateAvailable($nonExistentTemplate), 'Non-existent template'); + } +} diff --git a/tst/ViewTest.php b/tst/ViewTest.php index 8043534a..fcb0bdac 100644 --- a/tst/ViewTest.php +++ b/tst/ViewTest.php @@ -1,4 +1,4 @@ - 'Plain Text', 'syntaxhighlighting' => 'Source Code', @@ -38,6 +40,7 @@ class ViewTest extends TestCase $page->assign('BASEPATH', ''); $page->assign('ERROR', self::$error); $page->assign('STATUS', self::$status); + $page->assign('ISDELETED', self::$is_deleted); $page->assign('VERSION', self::$version); $page->assign('DISCUSSION', true); $page->assign('OPENDISCUSSION', true); @@ -49,7 +52,6 @@ class ViewTest extends TestCase $page->assign('BURNAFTERREADINGSELECTED', false); $page->assign('PASSWORD', true); $page->assign('FILEUPLOAD', false); - $page->assign('ZEROBINCOMPATIBILITY', false); $page->assign('INFO', 'example'); $page->assign('NOTICE', 'example'); $page->assign('LANGUAGESELECTION', ''); @@ -63,6 +65,7 @@ class ViewTest extends TestCase $page->assign('HTTPSLINK', 'https://example.com/'); $page->assign('COMPRESSION', 'zlib'); $page->assign('CSPHEADER', 'default-src \'none\''); + $page->assign('SRI', array()); $dir = dir(PATH . 'tpl'); while (false !== ($file = $dir->read())) { @@ -103,8 +106,8 @@ class ViewTest extends TestCase $content, $template . ': outputs error correctly' ); - if ($template === 'yourlsproxy') { - // yourlsproxy template only displays error message + if ($template === 'shortenerproxy') { + // shortenerproxy template only displays error message continue; } $this->assertMatchesRegularExpression( @@ -138,4 +141,20 @@ class ViewTest extends TestCase $this->expectExceptionCode(80); $test->draw('123456789 does not exist!'); } + + public function testTemplateFilePath() + { + $template = 'bootstrap'; + $templatePath = PATH . 'tpl' . DIRECTORY_SEPARATOR . $template . '.php'; + $path = View::getTemplateFilePath($template); + $this->assertEquals($templatePath, $path, 'Template file path'); + } + + public function testIsBootstrapTemplate() + { + $bootstrapTemplate = 'bootstrap-dark'; + $nonBootstrapTemplate = 'bootstrap5'; + $this->assertTrue(View::isBootstrapTemplate($bootstrapTemplate), 'Is bootstrap template'); + $this->assertFalse(View::isBootstrapTemplate($nonBootstrapTemplate), 'Is not bootstrap template'); + } } diff --git a/tst/Vizhash16x16Test.php b/tst/Vizhash16x16Test.php index 63782e51..4ead75fd 100644 --- a/tst/Vizhash16x16Test.php +++ b/tst/Vizhash16x16Test.php @@ -1,4 +1,4 @@ -_conf, 'https://example.com/?foo#bar'); $this->assertFalse($yourls->isError()); $this->assertEquals($yourls->getUrl(), 'https://example.com/1'); + + $yourls = new YourlsProxy($this->_conf, 'https://example.com/?@foreign.malicious.example?foo#bar'); + $this->assertFalse($yourls->isError()); + $this->assertEquals($yourls->getUrl(), 'https://example.com/1'); } - public function testForeignUrl() + /** + * @dataProvider providerInvalidUrl + */ + public function testImvalidUrl($url): void { - $yourls = new YourlsProxy($this->_conf, 'https://other.example.com/?foo#bar'); + $yourls = new YourlsProxy($this->_conf, $url); + $this->assertTrue($yourls->isError()); + $this->assertEquals($yourls->getError(), 'Invalid URL given.'); + } + + public function providerInvalidUrl(): array + { + return array( + array(''), + array(' '), + array('foo'), + array('https://'), + array('https://example.com'), // missing path and query parameter, + array('https://example.com/'), // missing query parameter + array('https://example.com?paste=something'), // missing path parameter + array('https://example.com@foreign.malicious.example?foo#bar'), // missing path parameter + ); + } + + /** + * This tests for a trick using username of an URI, see: + * {@see https://cloud.google.com/blog/topics/threat-intelligence/url-obfuscation-schema-abuse/?hl=en} + * + * @dataProvider providerForeignUrlUsernameTrick + */ + public function testForeignUrlUsingUsernameTrick($url): void + { + $yourls = new YourlsProxy($this->_conf, $url); $this->assertTrue($yourls->isError()); $this->assertEquals($yourls->getError(), 'Trying to shorten a URL that isn\'t pointing at our instance.'); } + public function providerForeignUrlUsernameTrick(): array + { + return array( + array('https://example.com@foreign.malicious.example/?foo#bar'), + array('https://example.com/@foreign.malicious.example?foo#bar'), + ); + } + + /** + * @dataProvider providerForeignUrl + */ + public function testForeignUrl($url): void + { + $yourls = new YourlsProxy($this->_conf, $url); + $this->assertTrue($yourls->isError()); + $this->assertEquals($yourls->getError(), 'Trying to shorten a URL that isn\'t pointing at our instance.'); + } + + public function providerForeignUrl(): array + { + return array( + array('ftp://example.com/?n=np'), // wrong protocol + array('https://other.example.com/?foo#bar'), // wrong domain + array('https://other.example.com/?q=https://example.com/?foo#bar'), // domain included inside string + ); + } + public function testYourlsError() { // when statusCode is not 200, shorturl may not have been set @@ -61,7 +122,7 @@ class YourlsProxyTest extends TestCase $yourls = new YourlsProxy($this->_conf, 'https://example.com/?foo#bar'); $this->assertTrue($yourls->isError()); - $this->assertEquals($yourls->getError(), 'Error parsing YOURLS response.'); + $this->assertEquals($yourls->getError(), 'Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.'); } public function testServerError() @@ -71,6 +132,6 @@ class YourlsProxyTest extends TestCase $yourls = new YourlsProxy($this->_conf, 'https://example.com/?foo#bar'); $this->assertTrue($yourls->isError()); - $this->assertEquals($yourls->getError(), 'Error calling YOURLS. Probably a configuration issue, like wrong or missing "apiurl" or "signature".'); + $this->assertEquals($yourls->getError(), 'Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.'); } } diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index bad3bf3e..113f8533 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -6,6 +6,7 @@ $vendorDir = dirname(__DIR__); $baseDir = dirname($vendorDir); return array( + 'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', 'IPLib\\Address\\AddressInterface' => $vendorDir . '/mlocati/ip-lib/src/Address/AddressInterface.php', 'IPLib\\Address\\AssignedRange' => $vendorDir . '/mlocati/ip-lib/src/Address/AssignedRange.php', @@ -64,7 +65,7 @@ return array( 'Jdenticon\\Shapes\\Shape' => $vendorDir . '/jdenticon/jdenticon/src/Shapes/Shape.php', 'Jdenticon\\Shapes\\ShapeCategory' => $vendorDir . '/jdenticon/jdenticon/src/Shapes/ShapeCategory.php', 'Jdenticon\\Shapes\\ShapeDefinitions' => $vendorDir . '/jdenticon/jdenticon/src/Shapes/ShapeDefinitions.php', - 'Jdenticon\\Shapes\\ShapePosition' => $vendorDir . '/jdenticon/jdenticon/src/Shapes/ShapePosition.php', + 'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php', 'PrivateBin\\Configuration' => $baseDir . '/lib/Configuration.php', 'PrivateBin\\Controller' => $baseDir . '/lib/Controller.php', 'PrivateBin\\Data\\AbstractData' => $baseDir . '/lib/Data/AbstractData.php', @@ -84,8 +85,16 @@ return array( 'PrivateBin\\Persistence\\PurgeLimiter' => $baseDir . '/lib/Persistence/PurgeLimiter.php', 'PrivateBin\\Persistence\\ServerSalt' => $baseDir . '/lib/Persistence/ServerSalt.php', 'PrivateBin\\Persistence\\TrafficLimiter' => $baseDir . '/lib/Persistence/TrafficLimiter.php', + 'PrivateBin\\Proxy\\AbstractProxy' => $baseDir . '/lib/Proxy/AbstractProxy.php', + 'PrivateBin\\Proxy\\ShlinkProxy' => $baseDir . '/lib/Proxy/ShlinkProxy.php', + 'PrivateBin\\Proxy\\YourlsProxy' => $baseDir . '/lib/Proxy/YourlsProxy.php', 'PrivateBin\\Request' => $baseDir . '/lib/Request.php', + 'PrivateBin\\TemplateSwitcher' => $baseDir . '/lib/TemplateSwitcher.php', 'PrivateBin\\View' => $baseDir . '/lib/View.php', 'PrivateBin\\Vizhash16x16' => $baseDir . '/lib/Vizhash16x16.php', - 'PrivateBin\\YourlsProxy' => $baseDir . '/lib/YourlsProxy.php', + 'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', + 'Symfony\\Polyfill\\Php80\\Php80' => $vendorDir . '/symfony/polyfill-php80/Php80.php', + 'Symfony\\Polyfill\\Php80\\PhpToken' => $vendorDir . '/symfony/polyfill-php80/PhpToken.php', + 'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', + 'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', ); diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php new file mode 100644 index 00000000..5b61514d --- /dev/null +++ b/vendor/composer/autoload_files.php @@ -0,0 +1,10 @@ + $vendorDir . '/symfony/polyfill-php80/bootstrap.php', +); diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index 7681c025..9d995374 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -6,6 +6,7 @@ $vendorDir = dirname(__DIR__); $baseDir = dirname($vendorDir); return array( + 'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'), 'PrivateBin\\' => array($baseDir . '/lib'), 'Jdenticon\\' => array($vendorDir . '/jdenticon/jdenticon/src'), 'Identicon\\' => array($vendorDir . '/yzalis/identicon/src/Identicon'), diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index 4b546606..d653992a 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -33,6 +33,18 @@ class ComposerAutoloaderInitDontChange $loader->register(true); + $filesToLoad = \Composer\Autoload\ComposerStaticInitDontChange::$files; + $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + + require $file; + } + }, null, null); + foreach ($filesToLoad as $fileIdentifier => $file) { + $requireFile($fileIdentifier, $file); + } + return $loader; } } diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 7f69e1df..ef0e05a6 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -6,7 +6,15 @@ namespace Composer\Autoload; class ComposerStaticInitDontChange { + public static $files = array ( + 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', + ); + public static $prefixLengthsPsr4 = array ( + 'S' => + array ( + 'Symfony\\Polyfill\\Php80\\' => 23, + ), 'P' => array ( 'PrivateBin\\' => 11, @@ -23,6 +31,10 @@ class ComposerStaticInitDontChange ); public static $prefixDirsPsr4 = array ( + 'Symfony\\Polyfill\\Php80\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php80', + ), 'PrivateBin\\' => array ( 0 => __DIR__ . '/../..' . '/lib', @@ -42,6 +54,7 @@ class ComposerStaticInitDontChange ); public static $classMap = array ( + 'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 'IPLib\\Address\\AddressInterface' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Address/AddressInterface.php', 'IPLib\\Address\\AssignedRange' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Address/AssignedRange.php', @@ -100,7 +113,7 @@ class ComposerStaticInitDontChange 'Jdenticon\\Shapes\\Shape' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Shapes/Shape.php', 'Jdenticon\\Shapes\\ShapeCategory' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Shapes/ShapeCategory.php', 'Jdenticon\\Shapes\\ShapeDefinitions' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Shapes/ShapeDefinitions.php', - 'Jdenticon\\Shapes\\ShapePosition' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Shapes/ShapePosition.php', + 'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php', 'PrivateBin\\Configuration' => __DIR__ . '/../..' . '/lib/Configuration.php', 'PrivateBin\\Controller' => __DIR__ . '/../..' . '/lib/Controller.php', 'PrivateBin\\Data\\AbstractData' => __DIR__ . '/../..' . '/lib/Data/AbstractData.php', @@ -120,10 +133,18 @@ class ComposerStaticInitDontChange 'PrivateBin\\Persistence\\PurgeLimiter' => __DIR__ . '/../..' . '/lib/Persistence/PurgeLimiter.php', 'PrivateBin\\Persistence\\ServerSalt' => __DIR__ . '/../..' . '/lib/Persistence/ServerSalt.php', 'PrivateBin\\Persistence\\TrafficLimiter' => __DIR__ . '/../..' . '/lib/Persistence/TrafficLimiter.php', + 'PrivateBin\\Proxy\\AbstractProxy' => __DIR__ . '/../..' . '/lib/Proxy/AbstractProxy.php', + 'PrivateBin\\Proxy\\ShlinkProxy' => __DIR__ . '/../..' . '/lib/Proxy/ShlinkProxy.php', + 'PrivateBin\\Proxy\\YourlsProxy' => __DIR__ . '/../..' . '/lib/Proxy/YourlsProxy.php', 'PrivateBin\\Request' => __DIR__ . '/../..' . '/lib/Request.php', + 'PrivateBin\\TemplateSwitcher' => __DIR__ . '/../..' . '/lib/TemplateSwitcher.php', 'PrivateBin\\View' => __DIR__ . '/../..' . '/lib/View.php', 'PrivateBin\\Vizhash16x16' => __DIR__ . '/../..' . '/lib/Vizhash16x16.php', - 'PrivateBin\\YourlsProxy' => __DIR__ . '/../..' . '/lib/YourlsProxy.php', + 'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', + 'Symfony\\Polyfill\\Php80\\Php80' => __DIR__ . '/..' . '/symfony/polyfill-php80/Php80.php', + 'Symfony\\Polyfill\\Php80\\PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/PhpToken.php', + 'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', + 'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', ); public static function getInitializer(ClassLoader $loader) diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index 7b5b519f..8519f72e 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -3,7 +3,7 @@ 'name' => 'privatebin/privatebin', 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => 'c1b3bffe8c5214f69f663b6fb59736a6f5fafa86', + 'reference' => '3ba29ea29e04d8a16d64e0f49994ba416c1b008f', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -11,18 +11,18 @@ ), 'versions' => array( 'jdenticon/jdenticon' => array( - 'pretty_version' => '1.0.2', - 'version' => '1.0.2.0', - 'reference' => 'cabb7a44c413c318392a341c5d3ca30fcdd57a6f', + 'pretty_version' => '2.0.0', + 'version' => '2.0.0.0', + 'reference' => 'fb39a98a0a54982a130b7e7b06305d4fd8c9717e', 'type' => 'library', 'install_path' => __DIR__ . '/../jdenticon/jdenticon', 'aliases' => array(), 'dev_requirement' => false, ), 'mlocati/ip-lib' => array( - 'pretty_version' => '1.18.0', - 'version' => '1.18.0.0', - 'reference' => 'c77bd0b1f3e3956c7e9661e75cb1f54ed67d95d2', + 'pretty_version' => '1.20.0', + 'version' => '1.20.0.0', + 'reference' => 'fd45fc3bf08ed6c7e665e2e70562082ac954afd4', 'type' => 'library', 'install_path' => __DIR__ . '/../mlocati/ip-lib', 'aliases' => array(), @@ -31,12 +31,21 @@ 'privatebin/privatebin' => array( 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => 'c1b3bffe8c5214f69f663b6fb59736a6f5fafa86', + 'reference' => '3ba29ea29e04d8a16d64e0f49994ba416c1b008f', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev_requirement' => false, ), + 'symfony/polyfill-php80' => array( + 'pretty_version' => 'v1.31.0', + 'version' => '1.31.0.0', + 'reference' => '60328e362d4c2c802a54fcbf04f9d3fb892b4cf8', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-php80', + 'aliases' => array(), + 'dev_requirement' => false, + ), 'yzalis/identicon' => array( 'pretty_version' => '2.0.0', 'version' => '2.0.0.0', diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php index 92370c5a..580fa960 100644 --- a/vendor/composer/platform_check.php +++ b/vendor/composer/platform_check.php @@ -4,8 +4,8 @@ $issues = array(); -if (!(PHP_VERSION_ID >= 70300)) { - $issues[] = 'Your Composer dependencies require a PHP version ">= 7.3.0". You are running ' . PHP_VERSION . '.'; +if (!(PHP_VERSION_ID >= 70400)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 7.4.0". You are running ' . PHP_VERSION . '.'; } if ($issues) { diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Canvas.php b/vendor/jdenticon/jdenticon/src/Canvas/Canvas.php index 6c5222f2..c00dfdfb 100644 --- a/vendor/jdenticon/jdenticon/src/Canvas/Canvas.php +++ b/vendor/jdenticon/jdenticon/src/Canvas/Canvas.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -11,7 +11,6 @@ namespace Jdenticon\Canvas; -use Jdenticon\Canvas\Rasterization\Edge; use Jdenticon\Canvas\Rasterization\EdgeTable; use Jdenticon\Canvas\Rasterization\Rasterizer; use Jdenticon\Canvas\Png\PngPalette; @@ -21,15 +20,15 @@ use Jdenticon\Canvas\ColorUtils; class Canvas { - private $edges; + private EdgeTable $edges; /** * Creates a new canvas with the specified dimensions given in pixels. * - * @param integer $width Canvas width in pixels. - * @param integer $height Canvas height in pixels. + * @param int $width Canvas width in pixels. + * @param int $height Canvas height in pixels. */ - public function __construct($width, $height) + public function __construct(int $width, int $height) { $this->width = $width; $this->height = $height; @@ -38,17 +37,13 @@ class Canvas /** * The width of the canvas in pixels. - * - * @var integer */ - public $width = 0; + public int $width = 0; /** * The height of the canvas in pixels. - * - * @var integer */ - public $height = 0; + public int $height = 0; /** * Specifies the background color. Allowed values are: @@ -57,16 +52,16 @@ class Canvas * - strings on the format #RRGGBB * - strings on the format #RRGGBBAA * - * @var integer|string + * @var int|string */ public $backColor = 0x00000000; /** * Gets a context used to draw polygons on this canvas. * - * @returns \Jdenticon\Canvas\CanvasContext + * @return \Jdenticon\Canvas\CanvasContext */ - public function getContext() + public function getContext(): CanvasContext { return new CanvasContext($this, $this->edges); } @@ -74,13 +69,13 @@ class Canvas /** * Renders the canvas as a PNG data stream. * - * @param array $keywords Keywords to be written to the PNG stream. + * @param array $keywords Keywords to be written to the PNG stream. * See https://www.w3.org/TR/PNG/#11keywords. - * @returns string + * @return string */ - public function toPng($keywords = array()) + public function toPng(array $keywords = []): string { - $colorRanges = array(); + $colorRanges = []; Rasterizer::rasterize( $colorRanges, $this->edges, diff --git a/vendor/jdenticon/jdenticon/src/Canvas/CanvasContext.php b/vendor/jdenticon/jdenticon/src/Canvas/CanvasContext.php index 9acfe5b1..b930d630 100644 --- a/vendor/jdenticon/jdenticon/src/Canvas/CanvasContext.php +++ b/vendor/jdenticon/jdenticon/src/Canvas/CanvasContext.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -12,26 +12,27 @@ namespace Jdenticon\Canvas; use Jdenticon\Canvas\ColorUtils; -use Jdenticon\Canvas\CanvasState; use Jdenticon\Canvas\Rasterization\EdgeTable; use Jdenticon\Canvas\Rasterization\Edge; use Jdenticon\Canvas\Matrix; class CanvasContext { - private $savedStates = array(); - private $edges; - private $transform; - private $paths; - private $canvas; + /** @var array */ + private array $savedStates = []; + private EdgeTable $edges; + private Matrix $transform; + /** @var array */ + private array $paths; + private Canvas $canvas; /** * Creates a new canvas with the specified dimensions given in pixels. * * @param \Jdenticon\Canvas\Canvas $canvas The owner canvas. - * @param array $edges The owner canvas' edge buffer. + * @param \Jdenticon\Canvas\Rasterization\EdgeTable $edges The owner canvas' edge buffer. */ - public function __construct($canvas, &$edges) + public function __construct(Canvas $canvas, EdgeTable &$edges) { $this->edges = $edges; $this->canvas = $canvas; @@ -46,25 +47,25 @@ class CanvasContext * - strings on the format #RRGGBB * - strings on the format #RRGGBBAA * - * @var integer|string + * @var int|string */ public $fillStyle = 0x000000ff; /** * Saves the current state to the state stack. */ - public function save() + public function save(): void { - array_push($this->savedStates, array( + array_push($this->savedStates, [ 'transform' => $this->transform, 'fillStyle' => $this->fillStyle - )); + ]); } /** * Restores the last saved state of the CanvasContext. */ - public function restore() + public function restore(): void { $state = array_pop($this->savedStates); if ($state != NULL) { @@ -76,7 +77,7 @@ class CanvasContext /** * Resets the internal path buffer and begins a new path. */ - public function resetTransform() + public function resetTransform(): void { $this->transform = new Matrix(1, 0, 0, 1, 0, 0); } @@ -84,36 +85,16 @@ class CanvasContext /** * Multiplies the current transformation matrix with the specified values. */ - public function transform($a, $b, $c, $d, $e, $f) + public function transform(float $a, float $b, float $c, float $d, float $e, float $f): void { - if (gettype($a) != 'integer' || - gettype($b) != 'integer' || - gettype($c) != 'integer' || - gettype($d) != 'integer' || - gettype($e) != 'integer' || - gettype($f) != 'integer' - ) { - return; - } - $this->transform = $this->transform->multiply($a, $b, $c, $d, $e, $f); } /** * Sets the transformation matrix to the specified matrix. */ - public function setTransform($a, $b, $c, $d, $e, $f) + public function setTransform(float $a, float $b, float $c, float $d, float $e, float $f): void { - if (gettype($a) != 'integer' || - gettype($b) != 'integer' || - gettype($c) != 'integer' || - gettype($d) != 'integer' || - gettype($e) != 'integer' || - gettype($f) != 'integer' - ) { - return; - } - $this->transform = new Matrix($a, $b, $c, $d, $e, $f); } @@ -123,7 +104,7 @@ class CanvasContext * @param float $x Distance to move in the horizontal direction in pixels. * @param float $y Distance to move in the vertical direction in pixels. */ - public function translate($x, $y) + public function translate(float $x, float $y): void { $this->transform = $this->transform->translate($x, $y); } @@ -134,7 +115,7 @@ class CanvasContext * @param float $x Scale in the horizontal direction. 1 means no scale. * @param float $y Scale in the vertical direction. 1 means no scale. */ - public function scale($x, $y) + public function scale(float $x, float $y): void { $this->transform = $this->transform->scale($x, $y); } @@ -142,10 +123,9 @@ class CanvasContext /** * Applies a rotation transformation to the canvas around its current origo. * - * @param float $angle Angle in radians measured clockwise from the - * positive x axis. + * @param float $angle Angle in radians measured clockwise from the positive x axis. */ - public function rotate($angle) + public function rotate(float $angle): void { $this->transform = $this->transform->rotate($angle); } @@ -153,16 +133,16 @@ class CanvasContext /** * Removes all existing subpaths and begins a new path. */ - public function beginPath() + public function beginPath(): void { - $this->paths = array(); + $this->paths = []; } /** * Starts a new subpath that begins in the same point as the start and end * point of the previous one. */ - public function closePath() + public function closePath(): void { $pathsCount = count($this->paths); if ($pathsCount > 0) { @@ -179,7 +159,7 @@ class CanvasContext } // Begin a new path - $this->paths[] = array($path[0], $path[1]); + $this->paths[] = [$path[0], $path[1]]; } } } @@ -187,27 +167,26 @@ class CanvasContext /** * Begins a new subpath by moving the cursor to the specified position. * - * @param float $x X coordinate. - * @param float $y Y coordinate. + * @param float $x X coordinate. + * @param float $y Y coordinate. */ - public function moveTo($x, $y) + public function moveTo(float $x, float $y): void { $p = $this->transform->multiplyPoint($x, $y); - $this->paths[] = array($p->x, $p->y); + $this->paths[] = [$p->x, $p->y]; } /** * Inserts an edge between the last and specified position. * - * @param float $x Target X coordinate. - * @param float $y Target Y coordinate. - * @public + * @param float $x Target X coordinate. + * @param float $y Target Y coordinate. */ - public function lineTo($x, $y) + public function lineTo(float $x, float $y): void { $pathsCount = count($this->paths); if ($pathsCount == 0) { - $this->paths[] = array(); + $this->paths[] = []; $pathsCount++; } @@ -227,10 +206,10 @@ class CanvasContext * measured clockwise from the positive x axis. * @param float $endAngle The angle in radians at which the arc end, * measured clockwise from the positive x axis. - * @param boolean $anticlockwise Specifies whether the arc will be drawn + * @param bool $anticlockwise Specifies whether the arc will be drawn * counter clockwise. Default is clockwise. */ - public function arc($x, $y, $radius, $startAngle, $endAngle, $anticlockwise) + public function arc(float $x, float $y, float $radius, float $startAngle, float $endAngle, bool $anticlockwise): void { $TARGET_CHORD_LENGTH_PIXELS = 3; @@ -269,8 +248,6 @@ class CanvasContext } } - $dx; - $dy; $sectors = ($endAngle - $startAngle) / $sectorAngle; $angle = $startAngle; @@ -296,7 +273,7 @@ class CanvasContext * @param float $width Width of the rectangle. * @param float $height Height of the rectangle. */ - public function clearRect($x, $y, $width, $height) + public function clearRect(float $x, float $y, float $width, float $height): void { $fullCanvas = false; @@ -330,23 +307,23 @@ class CanvasContext * @param float $width Width of the rectangle. * @param float $height Height of the rectangle. */ - public function fillRect($x, $y, $width, $height) + public function fillRect(float $x, float $y, float $width, float $height): void { $fillColor = ColorUtils::parse($this->fillStyle); $this->_fillRect($fillColor, $x, $y, $width, $height); } - private function _fillRect($fillColor, $x, $y, $width, $height) + private function _fillRect(int $fillColor, float $x, float $y, float $width, float $height): void { $polygonId = $this->edges->getNextPolygonId(); - $points = array( + $points = [ $this->transform->multiplyPoint($x, $y), $this->transform->multiplyPoint($x + $width, $y), $this->transform->multiplyPoint($x + $width, $y + $height), $this->transform->multiplyPoint($x, $y + $height), $this->transform->multiplyPoint($x, $y) - ); + ]; $pointsCount = count($points); for ($i = 1; $i < $pointsCount; $i++) { @@ -363,11 +340,11 @@ class CanvasContext /** * Fills the defined paths. * - * @param string $windingRule The winding rule to be used for determining + * @param string $windingRule The winding rule to be used for determining * which areas are covered by the current path. Valid values are * "evenodd" and "nonzero". Default is "nonzero". */ - public function fill($windingRule = "nonzero") + public function fill(string $windingRule = "nonzero"): void { $polygonId = $this->edges->getNextPolygonId(); $fillColor = ColorUtils::parse($this->fillStyle); diff --git a/vendor/jdenticon/jdenticon/src/Canvas/ColorUtils.php b/vendor/jdenticon/jdenticon/src/Canvas/ColorUtils.php index 7709027d..5b17cccf 100644 --- a/vendor/jdenticon/jdenticon/src/Canvas/ColorUtils.php +++ b/vendor/jdenticon/jdenticon/src/Canvas/ColorUtils.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -15,9 +15,9 @@ class ColorUtils { /** * Transparent color. - * @var integer + * @var int */ - const TRANSPARENT = 0; + public const TRANSPARENT = 0; /** * Specifies a transparent color that will not blend with layers below the @@ -25,15 +25,15 @@ class ColorUtils * * @var float */ - const FORCE_TRANSPARENT = INF; + public const FORCE_TRANSPARENT = INF; /** * Creates a color on the format 0xRRGGBBAA from the specified * color components. * - * @return integer + * @return int */ - public static function from($a, $r, $g, $b) + public static function from(int $a, int $r, int $g, int $b): int { return ($r << 24) | ($g << 16) | ($b << 8) | $a; } @@ -41,10 +41,10 @@ class ColorUtils /** * Gets the alpha component of a color. * - * @param integer $color 32-bit color value on the format 0xRRGGBBAA. - * @return integer Alpha in the range [0, 255]. + * @param int $color 32-bit color value on the format 0xRRGGBBAA. + * @return int Alpha in the range [0, 255]. */ - public static function alpha($color) + public static function alpha(int $color): int { return $color & 0xff; } @@ -52,10 +52,10 @@ class ColorUtils /** * Gets the red component of a color. * - * @param integer $color 32-bit color value on the format 0xRRGGBBAA. - * @return integer Red component in the range [0, 255]. + * @param int $color 32-bit color value on the format 0xRRGGBBAA. + * @return int Red component in the range [0, 255]. */ - public static function red($color) + public static function red(int $color): int { return ($color >> 24) & 0xff; } @@ -63,10 +63,10 @@ class ColorUtils /** * Gets the green component of a color. * - * @param integer $color 32-bit color value on the format 0xRRGGBBAA. - * @return integer Green component in the range [0, 255]. + * @param int $color 32-bit color value on the format 0xRRGGBBAA. + * @return int Green component in the range [0, 255]. */ - public static function green($color) + public static function green(int $color): int { return ($color >> 16) & 0xff; } @@ -74,10 +74,10 @@ class ColorUtils /** * Gets the blue component of a color. * - * @param integer $color 32-bit color value on the format 0xRRGGBBAA. - * @return integer Blue component in the range [0, 255]. + * @param int $color 32-bit color value on the format 0xRRGGBBAA. + * @return int Blue component in the range [0, 255]. */ - public static function blue($color) + public static function blue(int $color): int { return ($color >> 8) & 0xff; } @@ -85,10 +85,10 @@ class ColorUtils /** * Formats a color as a string. * - * @param integer $color Color to format. + * @param int $color Color to format. * @return string */ - public static function format($color) + public static function format(int $color): string { return bin2hex(pack('N', $color)); } @@ -97,13 +97,13 @@ class ColorUtils * Computes a mix of the two specified colors, with the proportion given * by the specified weight. * - * @param integer $color1 First color to mix. - * @param integer $color2 Second color to mix. + * @param int $color1 First color to mix. + * @param int $color2 Second color to mix. * @param float $weight Weight in the range [0,1]. * 0 gives $color1, 1 gives $color2. - * @return integer Mixed color. + * @return int Mixed color. */ - public static function mix($color1, $color2, $weight) + public static function mix(int $color1, int $color2, float $weight): int { if ($weight < 0) { $weight = 0; @@ -142,10 +142,10 @@ class ColorUtils /** * Parses a value to a 32-bit color on the format 0xRRGGBBAA. * - * @param integer|string $color The value to parse. - * @return integer + * @param int|string $color The value to parse. + * @return int */ - public static function parse($color) + public static function parse($color): int { if (gettype($color) == "integer") { return $color & 0xffffffff; @@ -187,11 +187,11 @@ class ColorUtils /** * Blends this color with another color using the over blending operation. * - * @param integer $fore The foreground color. - * @param integer $back The background color. - * @return integer + * @param int $fore The foreground color. + * @param int $back The background color. + * @return int */ - public static function over($fore, $back) + public static function over(int $fore, int $back): int { $foreA = ($fore & 0xff); $backA = ($back & 0xff); diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Matrix.php b/vendor/jdenticon/jdenticon/src/Canvas/Matrix.php index 9ce00dcb..aa329b2f 100644 --- a/vendor/jdenticon/jdenticon/src/Canvas/Matrix.php +++ b/vendor/jdenticon/jdenticon/src/Canvas/Matrix.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -15,17 +15,17 @@ use Jdenticon\Canvas\Point; class Matrix { - private $a; - private $b; - private $c; - private $d; - private $e; - private $f; + private float $a; + private float $b; + private float $c; + private float $d; + private float $e; + private float $f; /** * Creates a new transformation matrix. */ - public function __construct($a, $b, $c, $d, $e, $f) + public function __construct(float $a, float $b, float $c, float $d, float $e, float $f) { $this->a = $a; $this->b = $b; @@ -40,7 +40,7 @@ class Matrix * * @return boolean */ - public function hasSkewing() + public function hasSkewing(): bool { return $this->b || $this->c; } @@ -50,7 +50,7 @@ class Matrix * * @return boolean */ - public function hasTranslation() + public function hasTranslation(): bool { return $this->e || $this->f; } @@ -60,7 +60,7 @@ class Matrix * * @return boolean */ - public function hasScaling() + public function hasScaling(): bool { return $this->a != 1 || $this->d != 1; } @@ -71,7 +71,7 @@ class Matrix * * @return \Jdenticon\Canvas\Matrix */ - public function multiply($a, $b, $c, $d, $e, $f) + public function multiply(float $a, float $b, float $c, float $d, float $e, float $f): Matrix { return new Matrix( $this->a * $a + $this->c * $b, @@ -91,7 +91,7 @@ class Matrix * @param float $y Y coordinate. * @return \Jdenticon\Canvas\Point */ - public function multiplyPoint($x, $y) + public function multiplyPoint(float $x, float $y): Point { return new Point( $this->a * $x + $this->c * $y + $this->e, @@ -106,7 +106,7 @@ class Matrix * @param float $angle Rotation angle in radians. * @return \Jdenticon\Canvas\Matrix */ - public function rotate($angle) + public function rotate(float $angle): Matrix { $sin = sin($angle); $cos = cos($angle); @@ -121,7 +121,7 @@ class Matrix * @param float $y Vertical move distance. * @return \Jdenticon\Canvas\Matrix */ - public function translate($x, $y) + public function translate(float $x, float $y): Matrix { return $this->multiply(1, 0, 0, 1, $x, $y); } @@ -134,7 +134,7 @@ class Matrix * @param float $y Vertical scale. * @return \Jdenticon\Canvas\Matrix */ - public function scale($x, $y) + public function scale(float $x, float $y): Matrix { return $this->multiply($x, 0, 0, $y, 0, 0); } diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Png/PngBuffer.php b/vendor/jdenticon/jdenticon/src/Canvas/Png/PngBuffer.php index 78a90ba5..4a5e9e66 100644 --- a/vendor/jdenticon/jdenticon/src/Canvas/Png/PngBuffer.php +++ b/vendor/jdenticon/jdenticon/src/Canvas/Png/PngBuffer.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -13,15 +13,15 @@ namespace Jdenticon\Canvas\Png; class PngBuffer { - private $buffer = ''; - private $chunkPreviousBuffer = ''; + private string $buffer = ''; + private string $chunkPreviousBuffer = ''; /** * Writes a string to the buffer. * * @param string $str String to write. */ - public function writeString($str) + public function writeString(string $str): void { $this->buffer .= $str; } @@ -31,7 +31,7 @@ class PngBuffer * * @param integer $value Value to write. */ - public function writeUInt32BE($value) + public function writeUInt32BE(int $value): void { $this->buffer .= pack('N', $value); } @@ -41,7 +41,7 @@ class PngBuffer * * @param integer $value Value to write. */ - public function writeUInt8($value) + public function writeUInt8(int $value): void { $this->buffer .= pack('C', $value); } @@ -52,7 +52,7 @@ class PngBuffer * @param string $type Name of the chunk. Must contain exactly 4 * ASCII characters. */ - public function startChunk($type) + public function startChunk(string $type): void { $this->chunkPreviousBuffer = $this->buffer; $this->buffer = $type; @@ -61,7 +61,7 @@ class PngBuffer /** * Closes the current PNG chunk. */ - public function endChunk() + public function endChunk(): void { // Compute Crc32 for type + data $data = $this->buffer; @@ -85,7 +85,7 @@ class PngBuffer * * @return string */ - public function getBuffer() + public function getBuffer(): string { return $this->buffer; } diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Png/PngEncoder.php b/vendor/jdenticon/jdenticon/src/Canvas/Png/PngEncoder.php index 5927e704..033b24b7 100644 --- a/vendor/jdenticon/jdenticon/src/Canvas/Png/PngEncoder.php +++ b/vendor/jdenticon/jdenticon/src/Canvas/Png/PngEncoder.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -13,7 +13,6 @@ namespace Jdenticon\Canvas\Png; use Jdenticon\Canvas\Png\PngPalette; use Jdenticon\Canvas\Png\PngBuffer; -use Jdenticon\Canvas\ColorUtils; class PngEncoder { @@ -23,7 +22,7 @@ class PngEncoder const GRAYSCALE_WITH_ALPHA = 4; const TRUE_COLOR_WITH_ALPHA = 6; - private $buffer; + private PngBuffer $buffer; public function __construct() { @@ -36,10 +35,10 @@ class PngEncoder * * @param int $width Image width in pixels. * @param int $height Image height in pixels. - * @param int $colorType Color depth, speocfy one of the constants in + * @param int $colorType Color depth, specify one of the constants in * PngEncoder. */ - public function writeImageHeader($width, $height, $colorType) + public function writeImageHeader(int $width, int $height, int $colorType): void { $this->buffer->startChunk("IHDR"); $this->buffer->writeUInt32BE($width); @@ -57,7 +56,7 @@ class PngEncoder * * @param int $gamma Gamma value. */ - public function writeImageGamma($gamma = 45455) + public function writeImageGamma(int $gamma = 45455): void { $this->buffer->startChunk("gAMA"); $this->buffer->writeUInt32BE($gamma); @@ -68,12 +67,11 @@ class PngEncoder * Writes an IDAT chunk of truecolor encoded image data. * * @param array $colorRanges Image data on the format - * array(count0, color0, count1, color1, ...) + * [count0, color0, count1, color1, ...] * @param int $width Image width in pixels. * @param int $height Image height in pixels. */ - public function writeTrueColorWithAlpha( - array & $colorRanges, $width, $height) + public function writeTrueColorWithAlpha(array &$colorRanges, int $width, int $height): void { $this->buffer->startChunk("IDAT"); @@ -111,16 +109,13 @@ class PngEncoder * Writes an IDAT chunk of indexed image data. * * @param array $colorRanges Image data on the format - * array(count0, color0, count1, color1, ...) + * [count0, color0, count1, color1, ...] * @param \Jdenticon\Canvas\Png\PngPalette $palette Palette containing the * indexed colors. * @param int $width Image width in pixels. * @param int $height Image height in pixels. */ - public function writeIndexed( - array & $colorRanges, - PngPalette $palette, - $width, $height) + public function writeIndexed(array &$colorRanges, PngPalette $palette, int $width, int $height): void { $this->buffer->startChunk("IDAT"); @@ -162,7 +157,7 @@ class PngEncoder * @param \Jdenticon\Canvas\Png\PngPalette $palette Palette containing the * indexed colors. */ - public function writePalette(PngPalette $palette) + public function writePalette(PngPalette $palette): void { if ($palette && $palette->isValid) { $this->buffer->startChunk("PLTE"); @@ -184,7 +179,7 @@ class PngEncoder * @param \Jdenticon\Canvas\Png\PngPalette $palette Palette containing the * indexed colors. */ - public function writeTransparency(PngPalette $palette) + public function writeTransparency(PngPalette $palette): void { if ($palette && $palette->isValid && $palette->hasAlphaChannel) { $this->buffer->startChunk("tRNS"); @@ -208,7 +203,7 @@ class PngEncoder * {@link https://www.w3.org/TR/2003/REC-PNG-20031110/#11keywords} * @param string $value Value. */ - public function writeTextualData($key, $value) + public function writeTextualData(string $key, string $value): void { $this->buffer->startChunk("tEXt"); $this->buffer->writeString($key); @@ -220,7 +215,7 @@ class PngEncoder /** * Writes an IEND chunk to the png data stream. */ - public function writeImageEnd() + public function writeImageEnd(): void { $this->buffer->startChunk("IEND"); $this->buffer->endChunk(); @@ -231,7 +226,7 @@ class PngEncoder * * @return string */ - public function getBuffer() + public function getBuffer(): string { return $this->buffer->getBuffer(); } diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Png/PngPalette.php b/vendor/jdenticon/jdenticon/src/Canvas/Png/PngPalette.php index 37887b65..609b2046 100644 --- a/vendor/jdenticon/jdenticon/src/Canvas/Png/PngPalette.php +++ b/vendor/jdenticon/jdenticon/src/Canvas/Png/PngPalette.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -11,8 +11,6 @@ namespace Jdenticon\Canvas\Png; -use Jdenticon\Canvas\ColorUtils; - /** * Contains the colors of a PNG color palette. */ @@ -21,13 +19,13 @@ class PngPalette /** * Creates a PNG color palette for the specified bitmap data. * - * @param array(integer) $colorRanges Array of interleaved values on the - * format array(count0, color0, count1, color1, ...). + * @param array $colorRanges Array of interleaved values on the + * format [count0, color0, count1, color1, ...] */ - function __construct(& $colorRanges) + function __construct(array &$colorRanges) { - $lookup = array(); - $colors = array(); + $lookup = []; + $colors = []; $hasAlphaChannel = false; $colorsCount = 0; @@ -63,30 +61,22 @@ class PngPalette /** * Specifies if the palette is valid to be used for encoding a PNG image. - * - * @var boolean */ - public $isValid; + public bool $isValid; /** * Specifies if the palette has any partial or fully transparent * colors. - * - * @var boolean */ - public $hasAlphaChannel; + public bool $hasAlphaChannel; /** * Array of colors in the palette. - * - * @var array */ - public $colors; + public array $colors; /** * Lookup table from 32-bit color value to color index. - * - * @var array */ - public $lookup; + public array $lookup; } diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Point.php b/vendor/jdenticon/jdenticon/src/Canvas/Point.php index 0c73133f..edda9f36 100644 --- a/vendor/jdenticon/jdenticon/src/Canvas/Point.php +++ b/vendor/jdenticon/jdenticon/src/Canvas/Point.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -15,17 +15,13 @@ class Point { /** * X coordinate. - * - * @var float */ - public $x; + public float $x; /** * Y coordinate. - * - * @var float */ - public $y; + public float $y; /** * Creates a new 2D point. @@ -33,7 +29,7 @@ class Point * @param float $x X coordinate. * @param float $y Y coordinate. */ - public function __construct($x, $y) + public function __construct(float $x, float $y) { $this->x = $x; $this->y = $y; diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Edge.php b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Edge.php index d554b91d..f7cef4f2 100644 --- a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Edge.php +++ b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Edge.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -13,16 +13,22 @@ namespace Jdenticon\Canvas\Rasterization; class Edge { - public $polygonId; - public $x0; - public $x1; - public $y0; - public $y1; - public $color; - public $windingRule; + public int $polygonId; + public float $x0; + public float $x1; + public float $y0; + public float $y1; + public int $color; + public string $windingRule; public function __construct( - $polygonId, $x0, $y0, $x1, $y1, $color, $windingRule = null) + int $polygonId, + float $x0, + float $y0, + float $x1, + float $y1, + int $color, + string $windingRule = "nonzero") { $this->polygonId = $polygonId; $this->x0 = $x0; @@ -33,7 +39,7 @@ class Edge $this->windingRule = $windingRule; } - public function intersection($y) + public function intersection(float $y): float { $dx = ($this->x1 - $this->x0) * ($this->y0 - $y) / diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeIntersection.php b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeIntersection.php index 59f0ef37..3186bf12 100644 --- a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeIntersection.php +++ b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeIntersection.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -13,11 +13,11 @@ namespace Jdenticon\Canvas\Rasterization; class EdgeIntersection { - public $fromX; - public $width; - public $edge; + public int $fromX; + public int $width; + public Edge $edge; - public function __construct($fromX, $width, $edge) + public function __construct(int $fromX, int $width, Edge $edge) { $this->fromX = $fromX; $this->width = $width; diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeSuperSampleIntersection.php b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeSuperSampleIntersection.php index b88a2711..8fa8374b 100644 --- a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeSuperSampleIntersection.php +++ b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeSuperSampleIntersection.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -13,10 +13,10 @@ namespace Jdenticon\Canvas\Rasterization; class EdgeSuperSampleIntersection { - public $x; - public $edge; + public float $x; + public Edge $edge; - public function __construct($x, $edge) + public function __construct(float $x, Edge $edge) { $this->x = $x; $this->edge = $edge; diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeTable.php b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeTable.php index 6a67f505..95327184 100644 --- a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeTable.php +++ b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeTable.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -11,20 +11,25 @@ namespace Jdenticon\Canvas\Rasterization; +use Jdenticon\Canvas\Rasterization\Edge; + class EdgeTable { - private $scanlines; - private $nextPolygonId; - private $width; - private $height; + /** + * @var array> + */ + private array $scanlines; + private int $nextPolygonId; + private int $width; + private int $height; /** * Keeps a list of edges per scanline. * - * @param integer $width Clipping width. - * @param integer $height Clipping height. + * @param int $width Clipping width. + * @param int $height Clipping height. */ - public function __construct($width, $height) + public function __construct(int $width, int $height) { $this->width = $width; $this->height = $height; @@ -34,9 +39,9 @@ class EdgeTable /** * Sorts the edges of each scanline in ascending x coordinates. */ - public function clear() + public function clear(): void { - $this->scanlines = array(); + $this->scanlines = []; $this->nextPolygonId = 1; } @@ -45,18 +50,19 @@ class EdgeTable * * @return int */ - public function getNextPolygonId() + public function getNextPolygonId(): int { return $this->nextPolygonId++; } /** - * Gets the scaline for the specified Y coordinate, or NULL if there are + * Gets the scanline for the specified Y coordinate, or NULL if there are * no edges for the specified Y coordinate. * - * @return array|null. + * @param int $y + * @return array|null */ - public function getScanline($y) + public function getScanline(int $y): ?array { return isset($this->scanlines[$y]) ? $this->scanlines[$y] : null; } @@ -66,7 +72,7 @@ class EdgeTable * * @param \Jdenticon\Canvas\Rasterization\Edge $edge */ - public function add(\Jdenticon\Canvas\Rasterization\Edge $edge) + public function add(Edge $edge): void { $minY = 0; $maxY = 0; @@ -121,7 +127,7 @@ class EdgeTable if ($fromX < $this->width) { if (!isset($this->scanlines[$y])) { - $this->scanlines[$y] = array(); + $this->scanlines[$y] = []; } $this->scanlines[$y][] = new EdgeIntersection( @@ -134,7 +140,7 @@ class EdgeTable } } - private static function edge_cmp($x, $y) + private static function edge_cmp(EdgeIntersection $x, EdgeIntersection $y): int { if ($x->fromX < $y->fromX) { return -1; @@ -148,11 +154,10 @@ class EdgeTable /** * Sorts the edges of each scanline in ascending x coordinates. */ - public function sort() + public function sort(): void { foreach ($this->scanlines as $i => &$scanline) { - usort($scanline, array( - 'Jdenticon\\Canvas\\Rasterization\\EdgeTable', 'edge_cmp')); + usort($scanline, [self::class, 'edge_cmp']); } } } \ No newline at end of file diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Layer.php b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Layer.php index f3d83bf0..9243939b 100644 --- a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Layer.php +++ b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Layer.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -13,14 +13,21 @@ namespace Jdenticon\Canvas\Rasterization; class Layer { - public $polygonId; - public $color; - public $winding; - public $windingRule; + public int $polygonId; + public int $color; + public int $winding; + public string $windingRule; + public ?Layer $nextLayer = null; - public $nextLayer; - - public function __construct($polygonId, $color, $winding, $windingRule) + /** + * Creates a new layer. + * + * @param int $polygonId Unique id for this layer. + * @param int $color Color on the format 0xRRGGBBAA. + * @param int $winding Differential winding value, either 1 or -1. + * @param string $windingRule Winding rule for the polygon, either "evenodd" or "nonzero". + */ + public function __construct(int $polygonId, int $color, int $winding, string $windingRule) { $this->polygonId = $polygonId; $this->color = $color; diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/LayerManager.php b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/LayerManager.php index 98592729..1c4b0d93 100644 --- a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/LayerManager.php +++ b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/LayerManager.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -21,13 +21,12 @@ use Jdenticon\Canvas\Rasterization\Edge; */ class LayerManager { - public $topLayer; + public ?Layer $topLayer = null; /** * The current visible color. - * @var integer */ - public $color; + public int $color; public function __construct() { @@ -40,7 +39,7 @@ class LayerManager * @param \Jdenticon\Canvas\Rasterization\LayerManager $other The * LayerManager to copy all layers to. */ - public function copyTo(LayerManager $other) + public function copyTo(LayerManager $other): void { $other->color = $this->color; @@ -72,7 +71,7 @@ class LayerManager * * @param \Jdenticon\Canvas\Rasterization\Edge edge */ - public function add(Edge $edge) + public function add(Edge $edge): void { $dwinding = $edge->y0 < $edge->y1 ? 1 : -1; diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Rasterizer.php b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Rasterizer.php index 0a5269af..c6a4daa4 100644 --- a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Rasterizer.php +++ b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Rasterizer.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -37,15 +37,18 @@ class Rasterizer /** * Rasterizes the edges in the edge table to a list of color ranges. No * range will span multiple scanlines. + * + * @param array $colorData + * @return array */ - public static function rasterize(& $colorData, $edgeTable, $width, $height) + public static function rasterize(array &$colorData, EdgeTable $edgeTable, int $width, int $height): array { $edgeTable->sort(); $superSampleBuffer = new SuperSampleBuffer( $width, self::SAMPLES_PER_PIXEL_X); - $layers = array(); + $layers = []; $color = 0; // Keeps track of how many of the subpixellayers that are used for @@ -278,7 +281,7 @@ class Rasterizer return $colorData; } - private static function intersection_cmp($a, $b) + private static function intersection_cmp(EdgeSuperSampleIntersection $a, EdgeSuperSampleIntersection $b): int { if ($a->x < $b->x) { return -1; @@ -296,14 +299,14 @@ class Rasterizer * y coordinate. For each intersecting edge the intersecting x coordinate is * returned. * - * @param array $edges Array of edges in the current scanline. - * @param int $y Y coordinate of the current scanline. - * @return array Array containing EdgeSuperSampleIntersection. Objects - * are sorted ascending by x coordinate. + * @param array $edges Array of edges in the current scanline. + * @param float $y Y coordinate of the current scanline. + * @return array Intersections sorted ascending by x coordinate. */ - private static function getIntersections($edges, $y) + private static function getIntersections(array $edges, float $y): array { - $intersections = array(); + /** @var array */ + $intersections = []; foreach ($edges as $edge) { if ($edge->y0 < $y && $edge->y1 >= $y || @@ -317,9 +320,7 @@ class Rasterizer } } - usort($intersections, array( - 'Jdenticon\\Canvas\\Rasterization\\Rasterizer', - 'intersection_cmp')); + usort($intersections, [self::class, 'intersection_cmp']); return $intersections; } @@ -327,12 +328,13 @@ class Rasterizer /** * Determines what ranges of a scanline that needs to be supersampled. * - * @param array $scanline Array of edges in the current scanline. - * @return array Array of SuperSampleRange. + * @param array $scanline Array of edges in the current scanline. + * @param int $width + * @return array */ - private static function getSuperSampleRanges(&$scanline, $width) + private static function getSuperSampleRanges(array &$scanline, int $width): array { - $superSampleRanges = array(); + $superSampleRanges = []; $rangeIndex = 0; $scanlineCount = count($scanline); diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleBuffer.php b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleBuffer.php index 45a611de..14d81453 100644 --- a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleBuffer.php +++ b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleBuffer.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -21,25 +21,25 @@ class SuperSampleBuffer const IDX_G = 3; const IDX_B = 4; - private $samples; - private $samplesPerPixel; + private array $samples; + private int $samplesPerPixel; - private $pixelOffset; - private $subPixelOffset; + private int $pixelOffset; + private int $subPixelOffset; - private $width; - private $used; + private int $width; + private int $used; /** * Creates a color buffer keeping an average color out of several * color samples per pixel. * - * @param integer $width Width of the buffer in pixels. - * @param integer $samplesPerPixel Number of samples to keep per pixel. + * @param int $width Width of the buffer in pixels. + * @param int $samplesPerPixel Number of samples to keep per pixel. */ - public function __construct($width, $samplesPerPixel) + public function __construct(int $width, int $samplesPerPixel) { - $this->samples = array(); + $this->samples = []; $this->samplesPerPixel = $samplesPerPixel; $this->pixelOffset = 0; @@ -52,7 +52,7 @@ class SuperSampleBuffer /** * Rewinds the cursor to the beginning of the buffer. */ - public function rewind() + public function rewind(): void { $this->pixelOffset = 0; $this->subPixelOffset = 0; @@ -61,7 +61,7 @@ class SuperSampleBuffer /** * Clears the samples in this buffer. */ - public function clear() + public function clear(): void { $this->pixelOffset = 0; $this->subPixelOffset = 0; @@ -71,11 +71,11 @@ class SuperSampleBuffer /** * Writes the average color of each pixel to a specified color array. * - * @param array $colorData The average colors will be written to this + * @param array $colorData The average colors will be written to this * color array. - * @param integer $count Number of pixels to write. + * @param int $count Number of pixels to write. */ - public function emptyTo(& $colorData, $count) + public function emptyTo(array &$colorData, int $count): void { for ($i = 0; $i < $count; $i++) { $sampleCount = $this->samples[$i * 5 + self::IDX_COUNT]; @@ -100,10 +100,10 @@ class SuperSampleBuffer /** * Gets the average color of the pixel at a specified index. * - * @param integer $index The index of the pixel. - * @return integer + * @param int $index The index of the pixel. + * @return int */ - public function colorAt($index) + public function colorAt(int $index): int { $sampleCount = $this->samples[$index * 5 + self::IDX_COUNT]; $alphaSum = $this->samples[$index * 5 + self::IDX_A]; @@ -119,10 +119,14 @@ class SuperSampleBuffer /** * Adds a color to the current pixel in the buffer. * - * @param integer $count Number of samples of the color to be added to + * @param int $count Number of samples of the color to be added to * the buffer. + * @param int $a Alpha value. + * @param int $r Red value. + * @param int $g Green value. + * @param int $b Blue value. */ - private function _add($count, $a, $r, $g, $b) + private function _add(int $count, int $a, int $r, int $g, int $b): void { if ($this->used < $this->pixelOffset) { $this->used = $this->pixelOffset; @@ -147,11 +151,11 @@ class SuperSampleBuffer /** * Adds a color to the buffer up until the specified x index. * - * @param integer $color Color to write. - * @param float $untilX Samples of the color will be added the buffer until + * @param int $color Color to write. + * @param float $untilX Samples of the color will be added to the buffer until * the cursor reaches this coordinate. */ - public function add($color, $untilX) + public function add(int $color, float $untilX): void { $samplesLeft = (int)($untilX * $this->samplesPerPixel) - diff --git a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleRange.php b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleRange.php index d65b1768..04306efa 100644 --- a/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleRange.php +++ b/vendor/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleRange.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -13,15 +13,16 @@ namespace Jdenticon\Canvas\Rasterization; class SuperSampleRange { - public $fromX; - public $toXExcl; - public $edges; - public $width; + public int $fromX; + public int $toXExcl; + /** @var array */ + public array $edges; + public int $width; - public function __construct($fromX, $toXExcl) + public function __construct(int $fromX, int $toXExcl) { $this->fromX = $fromX; $this->toXExcl = $toXExcl; - $this->edges = array(); + $this->edges = []; } } \ No newline at end of file diff --git a/vendor/jdenticon/jdenticon/src/Color.php b/vendor/jdenticon/jdenticon/src/Color.php index c07c9054..b657a348 100644 --- a/vendor/jdenticon/jdenticon/src/Color.php +++ b/vendor/jdenticon/jdenticon/src/Color.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -16,32 +16,28 @@ namespace Jdenticon; */ class Color { - private static $lightnessCompensations = array( - 0.55, 0.5, 0.5, 0.46, 0.6, 0.55, 0.55); + /** @var array */ + private static array $lightnessCompensations = [0.55, 0.5, 0.5, 0.46, 0.6, 0.55, 0.55]; /** * The red component of the color in the range [0, 255]. - * @var int */ - public $r; + public int $r; /** * The green component of the color in the range [0, 255]. - * @var int */ - public $g; + public int $g; /** * The blue component of the color in the range [0, 255]. - * @var int */ - public $b; + public int $b; /** * The alpha component of the color in the range [0, 255]. - * @var int */ - public $a; + public int $a; // Users of the struct should use the static factory methods // to create Color value. @@ -52,12 +48,13 @@ class Color /** * Creates a Color from an RGB value. * - * @param int $alpha Alpha channel value in the range [0, 255]. * @param int $red Red component in the range [0, 255]. - * @param int $green GReen component in the range [0, 255]. + * @param int $green Green component in the range [0, 255]. * @param int $blue Blue component in the range [0, 255]. + * @param int $alpha Alpha channel value in the range [0, 255]. + * @return \Jdenticon\Color */ - public static function fromRgb($red, $green, $blue, $alpha = 255) + public static function fromRgb(int $red, int $green, int $blue, int $alpha = 255): Color { $color = new Color(); $color->r = $red; @@ -70,12 +67,13 @@ class Color /** * Creates a Color instance from HSL color parameters. * - * @param float $hue Hue in the range [0, 1] - * @param float $saturation Saturation in the range [0, 1] - * @param float $lightness Lightness in the range [0, 1] + * @param float $hue Hue in the range [0, 1]. + * @param float $saturation Saturation in the range [0, 1]. + * @param float $lightness Lightness in the range [0, 1]. * @param float $alpha Alpha channel value in the range [0, 1]. + * @return \Jdenticon\Color */ - public static function fromHsl($hue, $saturation, $lightness, $alpha = 1.0) + public static function fromHsl(float $hue, float $saturation, float $lightness, float $alpha = 1.0): Color { if ($hue < 0) $hue = 0; if ($hue > 1) $hue = 1; @@ -111,15 +109,16 @@ class Color } /** - * Creates a Color> instance from HSL color parameters and will compensate + * Creates a Color instance from HSL color parameters and compensates * the lightness for hues that appear to be darker than others. * * @param float $hue Hue in the range [0, 1]. * @param float $saturation Saturation in the range [0, 1]. * @param float $lightness Lightness in the range [0, 1]. * @param float $alpha Alpha channel value in the range [0, 1]. + * @return \Jdenticon\Color */ - public static function fromHslCompensated($hue, $saturation, $lightness, $alpha = 1.0) + public static function fromHslCompensated(float $hue, float $saturation, float $lightness, float $alpha = 1.0): Color { if ($hue < 0) $hue = 0; if ($hue > 1) $hue = 1; @@ -135,7 +134,7 @@ class Color } // Helper method for FromHsl - private static function hueToRgb($m1, $m2, $h) + private static function hueToRgb(float $m1, float $m2, float $h): int { if ($h < 0) { $h = $h + 6; @@ -161,7 +160,7 @@ class Color * * @return int */ - public function toRgba() + public function toRgba(): int { return ($this->r << 24) | @@ -175,7 +174,7 @@ class Color * * @return string */ - public function __toString() + public function __toString(): string { return '#' . bin2hex(pack('N', $this->toRgba())); } @@ -183,9 +182,10 @@ class Color /** * Gets a hexadecimal representation of this color on the format #rrggbbaa. * + * @param int $length Length of the hex string (6 or 8). * @return string */ - public function toHexString($length = 8) + public function toHexString(int $length = 8): string { if ($length === 8) { return $this->__toString(); @@ -197,10 +197,11 @@ class Color * Tries to parse a value as a Color. * * @param mixed $value Value to parse. - * @throws InvalidArgumentException + * @throws \InvalidArgumentException * @return \Jdenticon\Color */ - public static function parse($value) { + public static function parse($value): Color + { if ($value instanceof Color) { return $value; } @@ -252,7 +253,7 @@ class Color * * @return boolean */ - private static function parsePercent($input, &$result) + private static function parsePercent(string $input, ?float &$result): bool { // Detect and remove percent sign if (preg_match('/^\\s*(\\d*(?:\\.\\d*)?)%\\s*$/', $input, $matches)) { @@ -274,7 +275,7 @@ class Color * * @return boolean */ - private static function parseAlpha($input, &$result) + private static function parseAlpha(?string $input, ?float &$result): bool { if ($input === null || $input === '' @@ -303,21 +304,21 @@ class Color /** * Parses an RGB component. * - * @param string $input Input string. - * @param float $result Hue in range [0, 255]. + * @param string $input Input string. + * @param int $result RGB component in range [0, 255]. * * @return boolean */ - private static function parseRgbComponent($input, &$result) + private static function parseRgbComponent(string $input, ?int &$result): bool { if (preg_match('/^\\s*(\\d*(?:\\.\\d*)?)(%?)\\s*$/', $input, $matches)) { - $result = floatval($matches[1]); + $float = floatval($matches[1]); if ($matches[2] === '%') { - $result = 255 * $result / 100; + $float = 255 * $float / 100; } - $result = (int)$result; + $result = (int)$float; if ($result < 0) $result = 0; if ($result > 255) $result = 255; @@ -327,7 +328,7 @@ class Color return false; } - /** + /** * Parses a hue component. * * @param string $input Input string. @@ -335,7 +336,7 @@ class Color * * @return boolean */ - private static function parseHue($input, &$result) + private static function parseHue(string $input, ?float &$result): bool { if (preg_match( '/^\s*(\d*(?:\.\d*)?)(deg|grad|rad|turn|)\s*$/', @@ -355,7 +356,7 @@ class Color break; case "turn": // Turns: range 0 - 1 - $result = $result; + // No change break; default: // Degree: range 0 - 360 @@ -373,16 +374,16 @@ class Color } return false; } - + /** * Parses a hex color string. * * @param string $input Input string. - * @param float $result Hue in range [0, 1]. + * @param \Jdenticon\Color $result Parsed color. * * @return boolean */ - private static function parseHexColor($input, &$result) + private static function parseHexColor(string $input, ?Color &$result): bool { if ($input[0] === '#') { $input = substr($input, 1); @@ -444,9 +445,9 @@ class Color * * @param string $input Input string. * - * @return \Jdenticon\Color + * @return \Jdenticon\Color|null */ - private static function parseNamedColor($input) + private static function parseNamedColor(string $input): ?Color { // Source: https://www.w3.org/TR/css-color-4/#named-colors switch ($input) { diff --git a/vendor/jdenticon/jdenticon/src/Identicon.php b/vendor/jdenticon/jdenticon/src/Identicon.php index 48183b86..9e9a24d1 100644 --- a/vendor/jdenticon/jdenticon/src/Identicon.php +++ b/vendor/jdenticon/jdenticon/src/Identicon.php @@ -2,10 +2,11 @@ /** * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ - * - * Copyright (c) 2018 Daniel Mester Pirttijärvi - * - * For full license information, please see the LICENSE file that was + * + * Copyright (c) 2025 Daniel Mester Pirttijärvi + * Copyright (c) 2024 Peter Putzer + * + * For full license information, please see the LICENSE file that was * distributed with this source code. */ @@ -28,51 +29,31 @@ class Identicon * @var mixed */ private $value; - - /** - * @var boolean - */ - private $valueSet = false; - - /** - * Defaults to hash of an empty string. - * - * @var string - */ - private $hash = 'da39a3ee5e6b4b0d3255bfef95601890afd80709'; - - /** - * @var integer - */ - private $size = 100; - - /** - * @var Jdenticon\Rendering\IconGenerator - */ - private $iconGenerator; - - /** - * @var Jdenticon\IdenticonStyle - */ - private $style; + + private bool $valueSet = false; /** - * @var bool + * Defaults to hash of an empty string. */ - private $enableImageMagick; + private string $hash = 'da39a3ee5e6b4b0d3255bfef95601890afd80709'; + + private int $size = 100; + private IconGenerator $iconGenerator; + private ?IdenticonStyle $style = null; + private ?bool $enableImageMagick = null; /** * Creates an Identicon instance with the specified hash. * - * @param string $hash A binary string containing the hash that will be used + * @param string $hash A binary string containing the hash that will be used * as base for this icon. The hash must contain at least 6 bytes. - * @param int|float|double $size The size of the icon in pixels (the icon + * @param int|float|double $size The size of the icon in pixels (the icon * is quadratic). */ - public function __construct($options = null) + public function __construct(?array $options = null) { $this->iconGenerator = IconGenerator::getDefaultGenerator(); - + if ($options !== null) { $this->setOptions($options); } @@ -81,79 +62,79 @@ class Identicon $this->style = new IdenticonStyle(); } } - + /** * Creates an Identicon instance from a specified hash. * - * @param string $hash A binary string containing the hash that will be used + * @param string $hash A binary string containing the hash that will be used * as base for this icon. The hash must contain at least 6 bytes. * @param int $size The size of the icon in pixels (the icon is quadratic). * @return \Jdenticon\Identicon */ - public static function fromHash($hash, $size) + public static function fromHash(string $hash, int $size): self { - return new Identicon(array('hash' => $hash, 'size' => $size)); + return new Identicon(['hash' => $hash, 'size' => $size]); } /** * Creates an Identicon instance from a specified value. * - * @param mixed $value The value that will be used as base for this icon. - * The value will be converted to a UTF8 encoded string and then hashed + * @param mixed $value The value that will be used as base for this icon. + * The value will be converted to a UTF8 encoded string and then hashed * using SHA1. * @param int $size The size of the icon in pixels (the icon is quadratic). * @return \Jdenticon\Identicon */ - public static function fromValue($value, $size) + public static function fromValue($value, int $size): self { - return new Identicon(array('value' => $value, 'size' => $size)); + return new Identicon(['value' => $value, 'size' => $size]); } - + /** * Gets an associative array of all options of this identicon. * - * @return array + * @return array */ - public function getOptions() + public function getOptions(): array { - $options = array(); - + $options = []; + if ($this->valueSet) { $options['value'] = $this->getValue(); } elseif ($this->hash !== null) { $options['hash'] = $this->getHash(); } - + $options['size'] = $this->getSize(); $options['style'] = $this->getStyle()->getOptions(); if ($this->enableImageMagick !== null) { $options['enableImageMagick'] = $this->getEnableImageMagick(); } - + if ($this->iconGenerator !== IconGenerator::getDefaultGenerator()) { $options['iconGenerator'] = $this->getIconGenerator(); } - + return $options; } - + /** - * Sets options in this identicon by specifying an associative array of + * Sets options in this identicon by specifying an associative array of * option values. * - * @param array $options Options to set. + * @param array $options Options to set. * @return self */ - public function setOptions(array $options) + public function setOptions(array $options): self { foreach ($options as $key => $value) { $this->__set($key, $value); } return $this; } - - public function __get($name) + + public function __get(string $name) { switch (strtolower($name)) { case 'size': @@ -173,8 +154,8 @@ class Identicon "Unknown Identicon option '$name'."); } } - - public function __set($name, $value) + + public function __set(string $name, $value) { switch (strtolower($name)) { case 'size': @@ -200,86 +181,80 @@ class Identicon "Unknown Identicon option '$name'."); } } - - /** + + /** * Gets the size of the icon in pixels. */ - public function getSize() + public function getSize(): int { return $this->size; } - + /** * Sets the size of this icon in pixels. * * @param int|float|double $size The width and height of the icon. */ - public function setSize($size) + public function setSize($size): void { if (!is_numeric($size) || $size < 1) { throw new \InvalidArgumentException( "An invalid identicon size was specified. ". "A numeric value >= 1 was expected. Specified value: $size."); } - + $this->size = (int)$size; } - /** + /** * Gets the size of the icon in pixels. */ - public function getEnableImageMagick() + public function getEnableImageMagick(): bool { - // Enable ImageMagick on PHP < 7. On PHP 7 the performance increase - // is not as obvious as on PHP 5. Since the ImageMagick renderer has a - // lot of quirks, we don't want to use it unless really needed. + // Performance of using Imagick on PHP 7 and later is generally worse than using + // the internal renderer. Because of this, default to false. if ($this->enableImageMagick === null) { - return PHP_MAJOR_VERSION < 7 && extension_loaded('imagick'); + return false; } - + return $this->enableImageMagick; } - + /** * Sets whether ImageMagick should be used to generate PNG icons. * * @param bool $enable true to enable ImageMagick. */ - public function setEnableImageMagick($enable) + public function setEnableImageMagick(bool $enable): void { - if (!is_bool($enable)) { - throw new \InvalidArgumentException( - "enableImageMagick can only assume boolean values. Specified value: $enable."); - } - // Verify that the Imagick extension is installed if ($enable && !extension_loaded('imagick')) { throw new \Exception( 'Failed to enable ImageMagick. '. 'The Imagick PHP extension was not found on this system.'); } - + $this->enableImageMagick = $enable; } - + /** * Gets the {@see IconGenerator} used to generate icons. * * @return \Jdenticon\Rendering\IconGenerator */ - public function getIconGenerator() + public function getIconGenerator(): IconGenerator { return $this->iconGenerator; } - + /** * Sets the {@see IconGenerator} used to generate icons. * - * @param \Jdenticon\Rendering\IconGenerator $iconGenerator Icon generator + * @param \Jdenticon\Rendering\IconGenerator $iconGenerator Icon generator * that will render the shapes of the identicon. * @return \Jdenticon\Identicon */ - public function setIconGenerator(IconGenerator $iconGenerator) + public function setIconGenerator(IconGenerator $iconGenerator): self { if ($iconGenerator === null) { $iconGenerator = IconGenerator::getDefaultGenerator(); @@ -287,25 +262,25 @@ class Identicon $this->iconGenerator = $iconGenerator; return $this; } - + /** * Gets or sets the style of the icon. * * @return \Jdenticon\IdenticonStyle */ - public function getStyle() + public function getStyle(): IdenticonStyle { return $this->style; } - + /** * Gets or sets the style of the icon. * - * @param array|\Jdenticon\IdenticonStyle $style The new style of the icon. + * @param array|\Jdenticon\IdenticonStyle $style The new style of the icon. * NULL will revert the identicon to use the default style. * @return self */ - public function setStyle($style) + public function setStyle($style): self { if ($style == null) { $this->style = new IdenticonStyle(); @@ -319,84 +294,79 @@ class Identicon "Allowed values are IdenticonStyle instances and associative ". "arrays containing IdenticonStyle options."); } - + return $this; } /** - * Gets a binary string containing the hash that is used as base for this + * Gets a binary string containing the hash that is used as base for this * icon. */ - public function getHash() + public function getHash(): string { return $this->hash; } - + /** - * Sets a binary string containing the hash that is used as base for this + * Sets a binary string containing the hash that is used as base for this * icon. The string should contain at least 6 bytes. * * @param string $hash Binary string containing the hash. */ - public function setHash($hash) + public function setHash(string $hash): self { - if (!is_string($hash)) { - throw new \InvalidArgumentException( - 'An invalid $hash was passed to Identicon. ' . - 'A binary string was expected.'); - } if (strlen($hash) < 6) { throw new \InvalidArgumentException( - 'An invalid $hash was passed to Identicon. ' . + 'An invalid $hash was passed to Identicon. ' . 'The hash was expected to contain at least 6 bytes.'); } - + $this->hash = $hash; $this->value = null; $this->valueSet = false; return $this; } - + /** - * Gets a binary string containing the hash that is used as base for this + * Gets a binary string containing the hash that is used as base for this * icon. */ public function getValue() { return $this->value; } - + /** * Sets a value that will be used as base for this icon. The value will * be converted to a string and then hashed using SHA1. * * @param mixed $value Value that will be hashed. */ - public function setValue($value) + public function setValue($value): self { $this->hash = sha1("$value"); $this->value = $value; $this->valueSet = true; return $this; } - + /** * Gets the bounds of the icon excluding its padding. * * @return \Jdenticon\Rendering\Rectangle */ - public function getIconBounds() + public function getIconBounds(): Rectangle { // Round padding to nearest integer $padding = (int)($this->style->getPadding() * $this->size + 0.5); - + return new Rectangle( $padding, $padding, $this->size - $padding * 2, $this->size - $padding * 2); } - - private function getRenderer($imageFormat) + + private function getRenderer(string $imageFormat): RendererInterface { switch (strtolower($imageFormat)) { case 'svg': @@ -408,26 +378,23 @@ class Identicon new InternalPngRenderer($this->size, $this->size); } } - + /** * Draws this icon using a specified renderer. * - * This method is only intended for usage with custom renderers. A custom - * renderer could as an example render an Identicon in a file format not - * natively supported by Jdenticon. To implement a new file format, + * This method is only intended for usage with custom renderers. A custom + * renderer could as an example render an Identicon in a file format not + * natively supported by Jdenticon. To implement a new file format, * implement {@see \Jdenticon\Rendering\RendererInterface}. * - * @param \Jdenticon\Rendering\RendererInterface $renderer The renderer used + * @param \Jdenticon\Rendering\RendererInterface $renderer The renderer used * to render this icon. - * @param \Jdenticon\Rendering\Rectangle $rect The bounds of the rendered + * @param \Jdenticon\Rendering\Rectangle $rect The bounds of the rendered * icon. No padding will be applied to the rectangle. If the parameter * is omitted, the rectangle is calculated from the current icon * size and padding. */ - public function draw( - \Jdenticon\Rendering\RendererInterface $renderer, - \Jdenticon\Rendering\Rectangle $rect = null) - { + public function draw(RendererInterface $renderer, ?Rectangle $rect = null): void { if ($rect === null) { $rect = $this->getIconBounds(); } @@ -438,14 +405,14 @@ class Identicon /** * Renders the icon directly to the page output. * - * The method will set the 'Content-Type' HTTP header. You are recommended - * to set an appropriate 'Cache-Control' header before calling this method + * The method will set the 'Content-Type' HTTP header. You are recommended + * to set an appropriate 'Cache-Control' header before calling this method * to ensure the icon is cached client side. * - * @param string $imageFormat The image format of the output. + * @param string $imageFormat The image format of the output. * Supported values are 'png' and 'svg'. */ - public function displayImage($imageFormat = 'png') + public function displayImage(string $imageFormat = 'png'): void { $renderer = $this->getRenderer($imageFormat); $this->draw($renderer, $this->getIconBounds()); @@ -454,32 +421,32 @@ class Identicon header("Content-Type: $mimeType"); echo $data; } - + /** * Renders the icon to a binary string. * - * @param string $imageFormat The image format of the output string. + * @param string $imageFormat The image format of the output string. * Supported values are 'png' and 'svg'. * @return string */ - public function getImageData($imageFormat = 'png') + public function getImageData(string $imageFormat = 'png'): string { $renderer = $this->getRenderer($imageFormat); $this->draw($renderer, $this->getIconBounds()); return $renderer->getData(); } - + /** - * Renders the icon as a data URI. It is recommended to avoid using this - * method unless really necessary, since it will effectively disable client - * caching of generated icons, and will also cause the same icon to be + * Renders the icon as a data URI. It is recommended to avoid using this + * method unless really necessary, since it will effectively disable client + * caching of generated icons, and will also cause the same icon to be * rendered multiple times, when used multiple times on a single page. * - * @param string $imageFormat The image format of the data URI. + * @param string $imageFormat The image format of the data URI. * Supported values are 'png' and 'svg'. * @return string */ - public function getImageDataUri($imageFormat = 'png') + public function getImageDataUri(string $imageFormat = 'png'): string { $renderer = $this->getRenderer($imageFormat); $this->draw($renderer, $this->getIconBounds()); @@ -488,5 +455,3 @@ class Identicon return "data:$mimeType;base64,$base64"; } } - - diff --git a/vendor/jdenticon/jdenticon/src/IdenticonStyle.php b/vendor/jdenticon/jdenticon/src/IdenticonStyle.php index ad388c5e..8def2ce1 100644 --- a/vendor/jdenticon/jdenticon/src/IdenticonStyle.php +++ b/vendor/jdenticon/jdenticon/src/IdenticonStyle.php @@ -2,10 +2,11 @@ /** * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ - * - * Copyright (c) 2018 Daniel Mester Pirttijärvi - * - * For full license information, please see the LICENSE file that was + * + * Copyright (c) 2025 Daniel Mester Pirttijärvi + * Copyright (c) 2024 Peter Putzer + * + * For full license information, please see the LICENSE file that was * distributed with this source code. */ @@ -18,42 +19,15 @@ use Jdenticon\Color; */ class IdenticonStyle { - /** - * @var \Jdenticon\Color - */ - private $backgroundColor; - - /** - * @var float - */ - private $padding; - - /** - * @var float - */ - private $colorSaturation; - - /** - * @var float - */ - private $grayscaleSaturation; - - /** - * @var array(float) - */ - private $colorLightness; - - /** - * @var array(float) - */ - private $grayscaleLightness; + private Color $backgroundColor; + private float $padding; + private float $colorSaturation; + private float $grayscaleSaturation; + private array $colorLightness; + private array $grayscaleLightness; + private ?array $hues = null; - /** - * @var array(integer) - */ - private $hues; - - public function __construct(array $options = null) + public function __construct(?array $options = null) { $this->backgroundColor = self::getDefaultBackgroundColor(); $this->padding = self::getDefaultPadding(); @@ -61,20 +35,20 @@ class IdenticonStyle $this->grayscaleSaturation = self::getDefaultGrayscaleSaturation(); $this->colorLightness = self::getDefaultColorLightness(); $this->grayscaleLightness = self::getDefaultGrayscaleLightness(); - + if ($options !== null) { $this->setOptions($options); } } - + /** * Gets an associative array of all options of this style. * * @return array */ - public function getOptions() + public function getOptions(): array { - $options = array(); + $options = []; $options['backgroundColor'] = $this->getBackgroundColor()->__toString(); $options['padding'] = $this->getPadding(); @@ -89,7 +63,7 @@ class IdenticonStyle return $options; } - + /** * Sets options in this style by specifying an associative array of option * values. @@ -97,15 +71,15 @@ class IdenticonStyle * @param array $options Options to set. * @return self */ - public function setOptions(array $options) + public function setOptions(array $options): self { foreach ($options as $key => $value) { $this->__set($key, $value); } return $this; } - - public function __get($name) + + public function __get(string $name) { switch (strtolower($name)) { case 'backgroundcolor': @@ -127,8 +101,8 @@ class IdenticonStyle "Unknown IdenticonStyle option '$name'."); } } - - public function __set($name, $value) + + public function __set(string $name, $value): void { switch (strtolower($name)) { case 'backgroundcolor': @@ -157,34 +131,34 @@ class IdenticonStyle "Unknown IdenticonStyle option '$name'."); } } - + /** * Normalizes a hue to the first turn [0, 360). - * - * @param mixed $hue + * + * @param int|float $hue * @return integer */ - private static function normalizeHue($hue) + private static function normalizeHue($hue): int { if (!is_numeric($hue)) { throw new \InvalidArgumentException( "'$hue' is not a valid hue."); } - $hue = $hue % 360; + $hue = (int)$hue % 360; if ($hue < 0) { $hue += 360; } return $hue; } - + /** * Gets an array of allowed hues, or null if there are no restrictions. * - * @return array(int)|null + * @return array|null */ - public function getHues() + public function getHues(): ?array { return $this->hues; } @@ -192,14 +166,14 @@ class IdenticonStyle /** * Sets the allowed hues of generated icons. * - * @param array(integer)|integer|null $value A hue specified in degrees, + * @param array|integer|null $value A hue specified in degrees, * or an array of hues specified in degrees. If set to null, the hue * list is cleared. * @return self */ - public function setHues($value) + public function setHues($value): self { - $hues = array(); + $hues = []; if ($value !== null) { if (is_array($value)) { @@ -214,26 +188,26 @@ class IdenticonStyle $this->hues = empty($hues) ? null : $hues; return $this; } - + /** * Gets the padding of an icon in percents in the range [0.0, 0.4]. * * @return float */ - public function getPadding() + public function getPadding(): float { return $this->padding; } - + /** * Sets the padding of an icon in percents. * * @param float $value New padding in the range [0.0, 0.4]. * @return self */ - public function setPadding($value) + public function setPadding(float $value): self { - if (!is_numeric($value) || $value < 0 || $value > 0.4) { + if ($value < 0 || $value > 0.4) { throw new \InvalidArgumentException( "Padding '$value' out of range. ". "Values in the range [0.0, 0.4] are allowed."); @@ -241,55 +215,53 @@ class IdenticonStyle $this->padding = (float)$value; return $this; } - + /** * Gets the color of the identicon background. * * @return \Jdenticon\Color */ - public function getBackgroundColor() + public function getBackgroundColor(): Color { return $this->backgroundColor; } - + /** * Sets the color of the identicon background. * * @param \Jdenticon\Color|string $value New background color. * @return \Jdenticon\IdenticonStyle */ - public function setBackgroundColor($value) + public function setBackgroundColor($value): self { if ($value instanceof Color) { $this->backgroundColor = $value; } else { $this->backgroundColor = Color::parse($value); } - + return $this; } - + /** * Gets the saturation of the originally grayscale identicon shapes. * * @return float Saturation in the range [0.0, 1.0]. */ - public function getGrayscaleSaturation() + public function getGrayscaleSaturation(): float { return $this->grayscaleSaturation; } - + /** * Sets the saturation of the originally grayscale identicon shapes. * * @param $value float Saturation in the range [0.0, 1.0]. * @return self */ - public function setGrayscaleSaturation($value) + public function setGrayscaleSaturation(float $value): self { - if (!is_numeric($value) || - $value < 0 || $value > 1 - ) { + if ($value < 0 || $value > 1) { throw new \InvalidArgumentException( "The grayscale saturation was invalid. ". "Only values in the range [0.0, 1.0] are allowed."); @@ -297,28 +269,26 @@ class IdenticonStyle $this->grayscaleSaturation = (float)$value; return $this; } - + /** * Gets the saturation of the colored identicon shapes. * * @return float Saturation in the range [0.0, 1.0]. */ - public function getColorSaturation() + public function getColorSaturation(): float { return $this->colorSaturation; } - + /** * Sets the saturation of the colored identicon shapes. * * @param $value float Saturation in the range [0.0, 1.0]. * @return self */ - public function setColorSaturation($value) + public function setColorSaturation(float $value): self { - if (!is_numeric($value) || - $value < 0 || $value > 1 - ) { + if ($value < 0 || $value > 1) { throw new \InvalidArgumentException( "The color saturation was invalid. ". "Only values in the range [0.0, 1.0] are allowed."); @@ -326,27 +296,26 @@ class IdenticonStyle $this->colorSaturation = (float)$value; return $this; } - + /** * Gets the value of the ColorLightness property. * - * @return array(float, float) + * @return array */ - public function getColorLightness() + public function getColorLightness(): array { return $this->colorLightness; } - + /** * Sets the value of the ColorLightness property. * - * @param $value array(float, float) Lightness range. + * @param array $value Lightness range. * @return self */ - public function setColorLightness($value) + public function setColorLightness(array $value): self { - if (!is_array($value) || - !array_key_exists(0, $value) || + if (!array_key_exists(0, $value) || !array_key_exists(1, $value) || !is_numeric($value[0]) || !is_numeric($value[1]) || @@ -357,31 +326,30 @@ class IdenticonStyle "The value passed to setColorLightness was invalid. ". "Please check the documentation."); } - - $this->colorLightness = array((float)$value[0], (float)$value[1]); + + $this->colorLightness = [(float)$value[0], (float)$value[1]]; return $this; } - + /** * Gets the value of the GrayscaleLightness property. * - * @return array(float, float) + * @return array */ - public function getGrayscaleLightness() + public function getGrayscaleLightness(): array { return $this->grayscaleLightness; } - + /** * Sets the value of the GrayscaleLightness property. * - * @param $value array(float, float) Lightness range. + * @param array $value Lightness range. * @return self */ - public function setGrayscaleLightness($value) + public function setGrayscaleLightness(array $value): self { - if (!is_array($value) || - !array_key_exists(0, $value) || + if (!array_key_exists(0, $value) || !array_key_exists(1, $value) || !is_numeric($value[0]) || !is_numeric($value[1]) || @@ -392,69 +360,69 @@ class IdenticonStyle "The value passed to setGrayscaleLightness was invalid. ". "Please check the documentation."); } - $this->grayscaleLightness = array((float)$value[0], (float)$value[1]); + $this->grayscaleLightness = [(float)$value[0], (float)$value[1]]; return $this; } - - - + + + /** * Gets the default value of the BackgroundColor property. Resolves to transparent. * * @return \Jdenticon\Color */ - public static function getDefaultBackgroundColor() + public static function getDefaultBackgroundColor(): Color { return Color::fromRgb(255, 255, 255, 255); } - + /** * Gets the default value of the Padding property. Resolves to 0.08. * * @return float */ - public static function getDefaultPadding() + public static function getDefaultPadding(): float { return 0.08; } - + /** * Gets the default value of the ColorSaturation property. Resolves to 0.5. * * @return float */ - public static function getDefaultColorSaturation() + public static function getDefaultColorSaturation(): float { return 0.5; } - + /** * Gets the default value of the GrayscaleSaturation property. Resolves to 0. * * @return float */ - public static function getDefaultGrayscaleSaturation() + public static function getDefaultGrayscaleSaturation(): float { return 0; } - + /** * Gets the default value of the ColorLightness property. Resolves to [0.4, 0.8]. * - * @return array + * @return array */ - public static function getDefaultColorLightness() + public static function getDefaultColorLightness(): array { - return array(0.4, 0.8); + return [0.4, 0.8]; } - + /** * Gets the default value of the GrayscaleLightness property. Resolves to [0.3, 0.9]. * - * @return array + * @return array */ - public static function getDefaultGrayscaleLightness() + public static function getDefaultGrayscaleLightness(): array { - return array(0.3, 0.9); + return [0.3, 0.9]; } } diff --git a/vendor/jdenticon/jdenticon/src/Rendering/AbstractRenderer.php b/vendor/jdenticon/jdenticon/src/Rendering/AbstractRenderer.php index 0aeac805..a8cde27b 100644 --- a/vendor/jdenticon/jdenticon/src/Rendering/AbstractRenderer.php +++ b/vendor/jdenticon/jdenticon/src/Rendering/AbstractRenderer.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -11,6 +11,9 @@ namespace Jdenticon\Rendering; +use Jdenticon\Color; +use Jdenticon\Rendering\Transform; + /** * Base class for rendering shapes in an identicon. Implement this class to e.g. * support a new file format that is not natively supported by Jdenticon. To @@ -19,9 +22,9 @@ namespace Jdenticon\Rendering; */ abstract class AbstractRenderer implements RendererInterface { - private $transform; - protected $backgroundColor; - + private Transform $transform; + protected ?Color $backgroundColor = null; + public function __construct() { $this->transform = Transform::getEmpty(); @@ -31,10 +34,10 @@ abstract class AbstractRenderer implements RendererInterface * Sets the current transform that will be applied on all coordinates before * being rendered to the target image. * - * @param \Jdenticon\Rendering\Transform $transform The transform to set. + * @param \Jdenticon\Rendering\Transform|null $transform The transform to set. * If NULL is specified any existing transform is removed. */ - public function setTransform(\Jdenticon\Rendering\Transform $transform) + public function setTransform(?Transform $transform): void { $this->transform = $transform === null ? Transform::getEmpty() : $transform; @@ -46,7 +49,7 @@ abstract class AbstractRenderer implements RendererInterface * * @return \Jdenticon\Rendering\Transform */ - public function getTransform() + public function getTransform(): Transform { return $this->transform; } @@ -54,29 +57,26 @@ abstract class AbstractRenderer implements RendererInterface /** * Adds a polygon without translating its coordinates. * - * @param array $points An array of the points that the polygon consists of. + * @param array<\Jdenticon\Rendering\Point> $points An array of the points that the polygon consists of. */ - abstract protected function addPolygonNoTransform($points); + abstract protected function addPolygonNoTransform(array $points): void; /** * Adds a circle without translating its coordinates. * - * @param float $x The x-coordinate of the bounding rectangle - * upper-left corner. - * @param float $y The y-coordinate of the bounding rectangle - * upper-left corner. + * @param float $x The x-coordinate of the bounding rectangle upper-left corner. + * @param float $y The y-coordinate of the bounding rectangle upper-left corner. * @param float $size The size of the bounding rectangle. - * @param bool $counterClockwise If true the circle will be drawn - * counter clockwise. + * @param bool $counterClockwise If true the circle will be drawn counter clockwise. */ - abstract protected function addCircleNoTransform($x, $y, $size, $counterClockwise); + abstract protected function addCircleNoTransform(float $x, float $y, float $size, bool $counterClockwise): void; /** * Sets the background color of the image. * - * @param \Jdenticon\Color $color The image background color. + * @param \Jdenticon\Color $color The image background color. */ - public function setBackgroundColor(\Jdenticon\Color $color) + public function setBackgroundColor(Color $color): void { $this->backgroundColor = $color; } @@ -86,14 +86,20 @@ abstract class AbstractRenderer implements RendererInterface * * @return \Jdenticon\Color */ - public function getBackgroundColor() + public function getBackgroundColor(): Color { + if ($this->backgroundColor === null) { + $this->backgroundColor = Color::fromRgb(0, 0, 0, 0); + } return $this->backgroundColor; } - private function addPolygonCore(array $points, $invert) + /** + * @param array $points + */ + private function addPolygonCore(array $points, bool $invert): void { - $transformedPoints = array(); + $transformedPoints = []; foreach ($points as $point) { $transformedPoints[] = $this->transform->transformPoint($point->x, $point->y); @@ -102,9 +108,7 @@ abstract class AbstractRenderer implements RendererInterface if ($invert) { $transformedPoints = array_reverse($transformedPoints); } - - //var_dump($transformedPoints); - + $this->addPolygonNoTransform($transformedPoints); } @@ -118,28 +122,25 @@ abstract class AbstractRenderer implements RendererInterface * @param bool $invert If true the area of the rectangle will be removed * from the filled area. */ - public function addRectangle($x, $y, $width, $height, $invert = false) + public function addRectangle(float $x, float $y, float $width, float $height, bool $invert = false): void { - $this->addPolygonCore(array( + $this->addPolygonCore([ new Point($x, $y), new Point($x + $width, $y), new Point($x + $width, $y + $height), new Point($x, $y + $height), - ), $invert); + ], $invert); } /** * Adds a circle to the image. * - * @param float $x The x-coordinate of the bounding rectangle - * upper-left corner. - * @param float $y The y-coordinate of the bounding rectangle - * upper-left corner. + * @param float $x The x-coordinate of the bounding rectangle upper-left corner. + * @param float $y The y-coordinate of the bounding rectangle upper-left corner. * @param float $size The size of the bounding rectangle. - * @param bool $invert If true the area of the circle will be removed - * from the filled area. + * @param bool $invert If true the area of the circle will be removed from the filled area. */ - public function addCircle($x, $y, $size, $invert = false) + public function addCircle(float $x, float $y, float $size, bool $invert = false): void { $northWest = $this->transform->transformPoint($x, $y, $size, $size); $this->addCircleNoTransform($northWest->x, $northWest->y, $size, $invert); @@ -148,11 +149,10 @@ abstract class AbstractRenderer implements RendererInterface /** * Adds a polygon to the image. * - * @param array $points Array of points that the polygon consists of. - * @param bool $invert If true the area of the polygon will be removed - * from the filled area. + * @param array $points Array of points that the polygon consists of. + * @param bool $invert If true the area of the polygon will be removed from the filled area. */ - public function addPolygon($points, $invert = false) + public function addPolygon(array $points, bool $invert = false): void { $this->addPolygonCore($points, $invert); } @@ -160,25 +160,22 @@ abstract class AbstractRenderer implements RendererInterface /** * Adds a triangle to the image. * - * @param float $x The x-coordinate of the bounding rectangle - * upper-left corner. - * @param float $y The y-coordinate of the bounding rectangle - * upper-left corner. + * @param float $x The x-coordinate of the bounding rectangle upper-left corner. + * @param float $y The y-coordinate of the bounding rectangle upper-left corner. * @param float $width The width of the bounding rectangle. * @param float $height The height of the bounding rectangle. - * @param float $direction The direction of the 90 degree corner of the - * triangle. - * @param bool $invert If true the area of the triangle will be removed - * from the filled area. + * @param int $direction The direction of the 90-degree corner of the triangle. + * Value of {@link \Jdenticon\Rendering\TriageDirection} + * @param bool $invert If true the area of the triangle will be removed from the filled area. */ - public function addTriangle($x, $y, $width, $height, $direction, $invert = false) + public function addTriangle(float $x, float $y, float $width, float $height, int $direction, bool $invert = false): void { - $points = array( + $points = [ new Point($x + $width, $y), new Point($x + $width, $y + $height), new Point($x, $y + $height), new Point($x, $y) - ); + ]; array_splice($points, $direction, 1); @@ -188,22 +185,19 @@ abstract class AbstractRenderer implements RendererInterface /** * Adds a rhombus to the image. * - * @param float $x The x-coordinate of the bounding rectangle - * upper-left corner. - * @param float $y The y-coordinate of the bounding rectangle - * upper-left corner. + * @param float $x The x-coordinate of the bounding rectangle upper-left corner. + * @param float $y The y-coordinate of the bounding rectangle upper-left corner. * @param float $width The width of the bounding rectangle. * @param float $height The height of the bounding rectangle. - * @param bool $invert If true the area of the rhombus will be removed - * from the filled area. + * @param bool $invert If true the area of the rhombus will be removed from the filled area. */ - public function addRhombus($x, $y, $width, $height, $invert = false) + public function addRhombus(float $x, float $y, float $width, float $height, bool $invert = false): void { - $this->addPolygonCore(array( + $this->addPolygonCore([ new Point($x + $width / 2, $y), new Point($x + $width, $y + $height / 2), new Point($x + $width / 2, $y + $height), new Point($x, $y + $height / 2), - ), $invert); + ], $invert); } } diff --git a/vendor/jdenticon/jdenticon/src/Rendering/ColorTheme.php b/vendor/jdenticon/jdenticon/src/Rendering/ColorTheme.php index 24af0f97..00dde3ee 100644 --- a/vendor/jdenticon/jdenticon/src/Rendering/ColorTheme.php +++ b/vendor/jdenticon/jdenticon/src/Rendering/ColorTheme.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -12,17 +12,18 @@ namespace Jdenticon\Rendering; use Jdenticon\Color; +use Jdenticon\IdenticonStyle; /** * Specifies the colors to be used in an identicon. */ class ColorTheme { - private $darkGray; - private $midColor; - private $lightGray; - private $lightColor; - private $darkColor; + private Color $darkGray; + private Color $midColor; + private Color $lightGray; + private Color $lightColor; + private Color $darkColor; /** * Creates a new ColorTheme. @@ -31,7 +32,7 @@ class ColorTheme * @param \Jdenticon\IdenticonStyle $style The style that specifies the * lightness and saturation of the icon. */ - public function __construct($hue, \Jdenticon\IdenticonStyle $style) + public function __construct(float $hue, IdenticonStyle $style) { $grayscaleLightness = $style->getGrayscaleLightness(); $colorLightness = $style->getColorLightness(); @@ -60,9 +61,9 @@ class ColorTheme * Gets a color from this color theme by index. * * @param int $index Color index in the range [0, getCount()). - * @return Jdenticon\Color + * @return \Jdenticon\Color|null */ - public function getByIndex($index) + public function getByIndex(int $index): ?Color { if ($index === 0) return $this->darkGray; if ($index === 1) return $this->midColor; @@ -77,7 +78,7 @@ class ColorTheme * * @return int */ - public function getCount() + public function getCount(): int { return 5; } diff --git a/vendor/jdenticon/jdenticon/src/Rendering/IconGenerator.php b/vendor/jdenticon/jdenticon/src/Rendering/IconGenerator.php index d31fdf3b..6a83389e 100644 --- a/vendor/jdenticon/jdenticon/src/Rendering/IconGenerator.php +++ b/vendor/jdenticon/jdenticon/src/Rendering/IconGenerator.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -11,6 +11,7 @@ namespace Jdenticon\Rendering; +use Jdenticon\IdenticonStyle; use Jdenticon\Shapes\Shape; use Jdenticon\Shapes\ShapeCategory; use Jdenticon\Shapes\ShapeDefinitions; @@ -24,19 +25,20 @@ use Jdenticon\Shapes\ShapeDefinitions; */ class IconGenerator { - private $defaultShapes; - private static $instance; - + /** @var array */ + private array $defaultShapes; + private static ?IconGenerator $instance = null; + protected function __construct() { - $this->defaultShapes = array( + $this->defaultShapes = [ // Sides new ShapeCategory( /*$colorIndex=*/ 8, /*$shapes=*/ ShapeDefinitions::getOuterShapes(), /*$shapeIndex=*/ 2, /*$rotationIndex=*/ 3, - /*$positions=*/ array(1,0, 2,0, 2,3, 1,3, 0,1, 3,1, 3,2, 0,2) + /*$positions=*/ [1,0, 2,0, 2,3, 1,3, 0,1, 3,1, 3,2, 0,2] ), // Corners @@ -45,7 +47,7 @@ class IconGenerator /*$shapes=*/ ShapeDefinitions::getOuterShapes(), /*$shapeIndex=*/ 4, /*$rotationIndex=*/ 5, - /*$positions=*/ array(0,0, 3,0, 3,3, 0,3) + /*$positions=*/ [0,0, 3,0, 3,3, 0,3] ), // Center @@ -54,12 +56,12 @@ class IconGenerator /*$shapes=*/ ShapeDefinitions::getCenterShapes(), /*$shapeIndex=*/ 1, /*$rotationIndex=*/ null, - /*$positions=*/ array(1,1, 2,1, 2,2, 1,2) + /*$positions=*/ [1,1, 2,1, 2,2, 1,2] ) - ); + ]; } - public static function getDefaultGenerator() + public static function getDefaultGenerator(): IconGenerator { if (self::$instance === null) { self::$instance = new IconGenerator(); @@ -73,7 +75,7 @@ class IconGenerator * * @return int */ - public function getCellCount() + public function getCellCount(): int { return 4; } @@ -83,7 +85,7 @@ class IconGenerator * * @return float Hue in the range [0, 1]. */ - protected static function getHue($hash) + protected static function getHue(string $hash): float { $value = hexdec(substr($hash, -7)); return $value / 0xfffffff; @@ -97,7 +99,7 @@ class IconGenerator */ private static function isDuplicate( array $source, $newValue, - array $duplicateValues) + array $duplicateValues): bool { if (in_array($newValue, $duplicateValues, true)) { foreach ($duplicateValues as $value) { @@ -116,7 +118,7 @@ class IconGenerator * @param int $index The zero-based index of the octet to be returned. * @return int */ - protected static function getOctet($hash, $index) + protected static function getOctet(string $hash, int $index): int { return hexdec($hash[$index]); } @@ -125,9 +127,9 @@ class IconGenerator * Gets an array of the shape categories to be rendered in icons generated * by this IconGenerator. * - * @return array + * @return array */ - protected function getCategories() + protected function getCategories(): array { return $this->defaultShapes; } @@ -139,13 +141,13 @@ class IconGenerator * @param \Jdenticon\Rendering\ColorTheme $colorTheme A color theme * specifying the colors to be used in the icon. * @param string $hash The hash for which the shapes will be returned. - * @return array(Jdenticon\Shapes\Shape) + * @return array<\Jdenticon\Shapes\Shape> */ - protected function getShapes($colorTheme, $hash) + protected function getShapes(ColorTheme $colorTheme, string $hash): array { - $usedColorThemeIndexes = array(); + $usedColorThemeIndexes = []; $categories = self::getCategories(); - $shapes = array(); + $shapes = []; $colorCount = $colorTheme->getCount(); foreach ($categories as $category) { @@ -154,10 +156,10 @@ class IconGenerator if (self::isDuplicate( // Disallow dark gray and dark color combo - $usedColorThemeIndexes, $colorThemeIndex, array(0, 4)) || + $usedColorThemeIndexes, $colorThemeIndex, [0, 4]) || self::isDuplicate( // Disallow light gray and light color combo - $usedColorThemeIndexes, $colorThemeIndex, array(2, 3)) + $usedColorThemeIndexes, $colorThemeIndex, [2, 3]) ) { $colorThemeIndex = 1; } @@ -190,7 +192,7 @@ class IconGenerator * @param \Jdenticon\Rendering\Rectangle $rect The rectangle to be * normalized. */ - protected function normalizeRectangle(\Jdenticon\Rendering\Rectangle $rect) + protected function normalizeRectangle(Rectangle $rect): Rectangle { $size = (int)min($rect->width, $rect->height); @@ -216,12 +218,12 @@ class IconGenerator * @param string $hash The hash to be used as basis for the generated icon. */ protected function renderBackground( - \Jdenticon\Rendering\RendererInterface $renderer, - \Jdenticon\Rendering\Rectangle $rect, - \Jdenticon\IdenticonStyle $style, - \Jdenticon\Rendering\ColorTheme $colorTheme, - $hash) - { + RendererInterface $renderer, + Rectangle $rect, + IdenticonStyle $style, + ColorTheme $colorTheme, + string $hash + ): void { $renderer->setBackgroundColor($style->getBackgroundColor()); } @@ -237,12 +239,12 @@ class IconGenerator * @param string $hash The hash to be used as basis for the generated icon. */ protected function renderForeground( - \Jdenticon\Rendering\RendererInterface $renderer, - \Jdenticon\Rendering\Rectangle $rect, - \Jdenticon\IdenticonStyle $style, - \Jdenticon\Rendering\ColorTheme $colorTheme, - $hash) - { + RendererInterface $renderer, + Rectangle $rect, + IdenticonStyle $style, + ColorTheme $colorTheme, + string $hash + ): void { // Ensure rect is quadratic and a multiple of the cell count $normalizedRect = $this->normalizeRectangle($rect); $cellSize = $normalizedRect->width / $this->getCellCount(); @@ -259,7 +261,7 @@ class IconGenerator $normalizedRect->y + $shape->positions[$i + 1] * $cellSize, $cellSize, $rotation++ % 4)); - $shape->definition->__invoke($renderer, $cellSize, $i / 2); + call_user_func($shape->definition, $renderer, $cellSize, $i / 2); } $renderer->endShape(); @@ -276,11 +278,11 @@ class IconGenerator * @param string $hash The hash to be used as basis for the generated icon. */ public function generate( - \Jdenticon\Rendering\RendererInterface $renderer, - \Jdenticon\Rendering\Rectangle $rect, - \Jdenticon\IdenticonStyle $style, - $hash) - { + RendererInterface $renderer, + Rectangle $rect, + IdenticonStyle $style, + string $hash + ): void { $hue = self::getHue($hash); $colorTheme = new ColorTheme($hue, $style); diff --git a/vendor/jdenticon/jdenticon/src/Rendering/ImagickRenderer.php b/vendor/jdenticon/jdenticon/src/Rendering/ImagickRenderer.php index dbd6cf36..bc825d9e 100644 --- a/vendor/jdenticon/jdenticon/src/Rendering/ImagickRenderer.php +++ b/vendor/jdenticon/jdenticon/src/Rendering/ImagickRenderer.php @@ -1,6 +1,8 @@ ry; @@ -44,12 +47,12 @@ class ImagickRendererLine /** * Computes the point at which two lines intersect. * + * @param ImagickRendererLine $l1 + * @param ImagickRendererLine $l2 * @return Point|null */ - public static function intersection( - ImagickRendererLine $l1, - ImagickRendererLine $l2 - ) { + public static function intersection(ImagickRendererLine $l1, ImagickRendererLine $l2): ?Point + { $rs = $l1->rx * $l2->ry - $l1->ry * $l2->rx; if ($rs == 0) { @@ -66,25 +69,21 @@ class ImagickRendererLine /** * X coordiate of a point on the line. - * @var float */ - public $Px; + public float $Px; /** * Y coordiate of a point on the line. - * @var float */ - public $Py; + public float $Py; /** * X component of the direction vector. - * @var float */ - public $rx; + public float $rx; /** * Y component of the direction vector. - * @var float */ - public $ry; + public float $ry; } /** @@ -108,17 +107,17 @@ class ImagickRendererLine */ class ImagickRenderer extends AbstractRenderer { - private $draw; - private $polygon; - private $width; - private $height; + private \ImagickDraw $draw; + private array $polygon; + private int $width; + private int $height; /** * This constant is added to all coordinates to avoid white pixels * that sometimes appear near edge intersections when a polygon including * its 1/2 invisible border is perfectly aligned to the pixel grid. */ - const PREVENT_WHITE_PIXELS_OFFSET = -0.00013; + private const PREVENT_WHITE_PIXELS_OFFSET = -0.00013; /** * Creates an instance of the class ImagickRenderer. @@ -126,7 +125,7 @@ class ImagickRenderer extends AbstractRenderer * @param int $width The width of the icon in pixels. * @param int $height The height of the icon in pixels. */ - public function __construct($width, $height) + public function __construct(int $width, int $height) { parent::__construct(); $this->draw = new \ImagickDraw(); @@ -141,7 +140,7 @@ class ImagickRenderer extends AbstractRenderer * * @return string */ - public function getMimeType() + public function getMimeType(): string { return 'image/png'; } @@ -149,15 +148,12 @@ class ImagickRenderer extends AbstractRenderer /** * Adds a circle without translating its coordinates. * - * @param float $x The x-coordinate of the bounding rectangle - * upper-left corner. - * @param float $y The y-coordinate of the bounding rectangle - * upper-left corner. - * @param float $size The size of the bounding rectangle. - * @param bool $counterClockwise If true the circle will be drawn - * counter clockwise. + * @param float $x The x-coordinate of the bounding rectangle upper-left corner. + * @param float $y The y-coordinate of the bounding rectangle upper-left corner. + * @param float $size The size of the bounding rectangle. + * @param bool $counterClockwise If true the circle will be drawn counter clockwise. */ - protected function addCircleNoTransform($x, $y, $size, $counterClockwise) + protected function addCircleNoTransform(float $x, float $y, float $size, bool $counterClockwise): void { if ($counterClockwise) { $x -= $size + 0.5; @@ -179,9 +175,9 @@ class ImagickRenderer extends AbstractRenderer /** * Adds a polygon without translating its coordinates. * - * @param array $points An array of the points that the polygon consists of. + * @param array $points An array of the points that the polygon consists of. */ - protected function addPolygonNoTransform($points) + protected function addPolygonNoTransform(array $points): void { $firstPoint = $points[0]; $lastPoint = end($points); @@ -209,7 +205,7 @@ class ImagickRenderer extends AbstractRenderer // ImageMagick draws all polygons 1 pixel too large. To prevent this, // shrink polygons by 1 pixel. - $lines = array(); + $lines = []; $previousPoint = null; // Transform all edges to lines. @@ -259,7 +255,7 @@ class ImagickRenderer extends AbstractRenderer * * @param \Jdenticon\Color $color The color of the shape. */ - public function beginShape(\Jdenticon\Color $color) + public function beginShape(Color $color): void { $this->draw->setFillColor($color->__toString()); $this->draw->pathStart(); @@ -268,7 +264,7 @@ class ImagickRenderer extends AbstractRenderer /** * Ends the currently drawn shape. */ - public function endShape() + public function endShape(): void { $this->draw->pathFinish(); } @@ -278,7 +274,7 @@ class ImagickRenderer extends AbstractRenderer * * @return string */ - public function getData() + public function getData(): string { $imagick = new \Imagick(); $imagick->newImage($this->width, $this->height, $this->backgroundColor->__toString()); diff --git a/vendor/jdenticon/jdenticon/src/Rendering/InternalPngRenderer.php b/vendor/jdenticon/jdenticon/src/Rendering/InternalPngRenderer.php index 10c816be..2858b93a 100644 --- a/vendor/jdenticon/jdenticon/src/Rendering/InternalPngRenderer.php +++ b/vendor/jdenticon/jdenticon/src/Rendering/InternalPngRenderer.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -12,14 +12,16 @@ namespace Jdenticon\Rendering; use Jdenticon\Canvas\Canvas; +use Jdenticon\Canvas\CanvasContext; +use Jdenticon\Color; /** * Renders icons as PNG using the internal vector rasterizer. */ class InternalPngRenderer extends AbstractRenderer { - private $canvas; - private $ctx; + private Canvas $canvas; + private CanvasContext $ctx; /** * Creates an instance of the class ImagickRenderer. @@ -27,7 +29,7 @@ class InternalPngRenderer extends AbstractRenderer * @param int $width The width of the icon in pixels. * @param int $height The height of the icon in pixels. */ - public function __construct($width, $height) + public function __construct(int $width, int $height) { parent::__construct(); $this->canvas = new Canvas($width, $height); @@ -39,7 +41,7 @@ class InternalPngRenderer extends AbstractRenderer * * @return string */ - public function getMimeType() + public function getMimeType(): string { return 'image/png'; } @@ -55,7 +57,7 @@ class InternalPngRenderer extends AbstractRenderer * @param bool $counterClockwise If true the circle will be drawn * counter clockwise. */ - protected function addCircleNoTransform($x, $y, $size, $counterClockwise) + protected function addCircleNoTransform(float $x, float $y, float $size, bool $counterClockwise): void { $radius = $size / 2; $this->ctx->moveTo($x + $size, $y + $radius); @@ -69,9 +71,9 @@ class InternalPngRenderer extends AbstractRenderer /** * Adds a polygon without translating its coordinates. * - * @param array $points An array of the points that the polygon consists of. + * @param array $points An array of the points that the polygon consists of. */ - protected function addPolygonNoTransform($points) + protected function addPolygonNoTransform(array $points): void { $pointCount = count($points); $this->ctx->moveTo($points[0]->x, $points[0]->y); @@ -86,7 +88,7 @@ class InternalPngRenderer extends AbstractRenderer * * @param \Jdenticon\Color $color The background color. */ - public function setBackgroundColor(\Jdenticon\Color $color) + public function setBackgroundColor(Color $color): void { parent::setBackgroundColor($color); $this->canvas->backColor = $this->backgroundColor->toRgba(); @@ -97,7 +99,7 @@ class InternalPngRenderer extends AbstractRenderer * * @param \Jdenticon\Color $color The color of the shape. */ - public function beginShape(\Jdenticon\Color $color) + public function beginShape(Color $color): void { $this->ctx->fillStyle = $color->toRgba(); $this->ctx->beginPath(); @@ -106,7 +108,7 @@ class InternalPngRenderer extends AbstractRenderer /** * Ends the currently drawn shape. */ - public function endShape() + public function endShape(): void { $this->ctx->fill(); } @@ -116,8 +118,8 @@ class InternalPngRenderer extends AbstractRenderer * * @return string */ - public function getData() + public function getData(): string { - return $this->canvas->toPng(array('Software' => 'Jdenticon')); + return $this->canvas->toPng(['Software' => 'Jdenticon']); } } diff --git a/vendor/jdenticon/jdenticon/src/Rendering/Point.php b/vendor/jdenticon/jdenticon/src/Rendering/Point.php index 020845e6..7c25363c 100644 --- a/vendor/jdenticon/jdenticon/src/Rendering/Point.php +++ b/vendor/jdenticon/jdenticon/src/Rendering/Point.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -22,7 +22,7 @@ class Point * @param float $x X coordinate. * @param float $y Y coordinate. */ - public function __construct($x, $y) + public function __construct(float $x, float $y) { $this->x = $x; $this->y = $y; @@ -30,25 +30,19 @@ class Point /** * The X coordinate of this point. - * - * @var float */ - public $x; + public float $x; /** * The Y coordinate of this point. - * - * @var float */ - public $y; + public float $y; /** * Gets a string representation of the point. - * - * @return string */ - public function __toString() + public function __toString(): string { - return $this->x + ", " + $this->y; + return $this->x . ", " . $this->y; } } diff --git a/vendor/jdenticon/jdenticon/src/Rendering/Rectangle.php b/vendor/jdenticon/jdenticon/src/Rendering/Rectangle.php index 27056c65..7fc919e5 100644 --- a/vendor/jdenticon/jdenticon/src/Rendering/Rectangle.php +++ b/vendor/jdenticon/jdenticon/src/Rendering/Rectangle.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -18,29 +18,23 @@ class Rectangle { /** * The X coordinate of the left side of the rectangle. - * - * @var float */ - public $x; + public float $x; /** * The Y coordinate of the top side of the rectangle. - * - * @var float */ - public $y; + public float $y; /** * The width of the rectangle. - * @var float */ - public $width; + public float $width; /** * The height of the rectangle. - * @var float */ - public $height; + public float $height; /** * Creates a new Rectangle. @@ -50,7 +44,7 @@ class Rectangle * @param float $width The width of the rectangle. * @param float $height The height of the rectangle. */ - public function __construct($x, $y, $width, $height) + public function __construct(float $x, float $y, float $width, float $height) { $this->x = $x; $this->y = $y; diff --git a/vendor/jdenticon/jdenticon/src/Rendering/RendererInterface.php b/vendor/jdenticon/jdenticon/src/Rendering/RendererInterface.php index 2e579e0c..ed3ce527 100644 --- a/vendor/jdenticon/jdenticon/src/Rendering/RendererInterface.php +++ b/vendor/jdenticon/jdenticon/src/Rendering/RendererInterface.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -25,7 +25,7 @@ interface RendererInterface * @param \Jdenticon\Rendering\Transform $transform The transform to set. * If NULL is specified any existing transform is removed. */ - public function setTransform(\Jdenticon\Rendering\Transform $transform); + public function setTransform(Transform $transform): void; /** * Gets the current transform that will be applied on all coordinates before @@ -33,40 +33,40 @@ interface RendererInterface * * @return \Jdenticon\Rendering\Transform */ - public function getTransform(); + public function getTransform(): Transform; /** * Sets the background color of the image. * * @param \Jdenticon\Color $color The image background color. */ - public function setBackgroundColor(Color $color); + public function setBackgroundColor(Color $color): void; /** * Gets the background color of the image. * * @return \Jdenticon\Color */ - public function getBackgroundColor(); + public function getBackgroundColor(): Color; /** * Gets the MIME type of the renderer output. * * @return string */ - public function getMimeType(); + public function getMimeType(): string; /** * Begins a new shape. The shape should be ended with a call to endShape. * * @param \Jdenticon\Color $color The color of the shape. */ - public function beginShape(Color $color); + public function beginShape(Color $color): void; /** * Ends the currently drawn shape. */ - public function endShape(); + public function endShape(): void; /** * Adds a rectangle to the image. @@ -78,7 +78,7 @@ interface RendererInterface * @param bool $invert If true the area of the rectangle will be removed * from the filled area. */ - public function addRectangle($x, $y, $width, $height, $invert = false); + public function addRectangle(float $x, float $y, float $width, float $height, bool $invert = false): void; /** * Adds a circle to the image. @@ -91,16 +91,16 @@ interface RendererInterface * @param bool $invert If true the area of the circle will be removed from * the filled area. */ - public function addCircle($x, $y, $size, $invert = false); + public function addCircle(float $x, float $y, float $size, bool $invert = false): void; /** * Adds a polygon to the image. * - * @param array $points Array of points that the polygon consists of. + * @param array $points Array of points that the polygon consists of. * @param bool $invert If true the area of the polygon will be removed from * the filled area. */ - public function addPolygon($points, $invert = false); + public function addPolygon(array $points, bool $invert = false): void; /** * Adds a triangle to the image. @@ -111,12 +111,12 @@ interface RendererInterface * upper-left corner. * @param float $width The width of the bounding rectangle. * @param float $height The height of the bounding rectangle. - * @param float $direction The direction of the 90 degree corner of - * the triangle. + * @param int $direction The direction of the 90 degree corner of + * the triangle. Value of {@link \Jdenticon\Rendering\TriageDirection} * @param bool $invert If true the area of the triangle will be removed * from the filled area. */ - public function addTriangle($x, $y, $width, $height, $direction, $invert = false); + public function addTriangle(float $x, float $y, float $width, float $height, int $direction, bool $invert = false): void; /** * Adds a rhombus to the image. @@ -130,12 +130,12 @@ interface RendererInterface * @param bool $invert If true the area of the rhombus will be removed * from the filled area. */ - public function addRhombus($x, $y, $width, $height, $invert = false); + public function addRhombus(float $x, float $y, float $width, float $height, bool $invert = false): void; /** * Gets the output from the renderer. * * @return string */ - public function getData(); + public function getData(): string; } diff --git a/vendor/jdenticon/jdenticon/src/Rendering/SvgPath.php b/vendor/jdenticon/jdenticon/src/Rendering/SvgPath.php index d3b5b44d..b8a8be81 100644 --- a/vendor/jdenticon/jdenticon/src/Rendering/SvgPath.php +++ b/vendor/jdenticon/jdenticon/src/Rendering/SvgPath.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -16,8 +16,8 @@ namespace Jdenticon\Rendering; */ class SvgPath { - private $dataString; - + private string $dataString; + public function __construct() { $this->dataString = ''; @@ -33,7 +33,7 @@ class SvgPath * clockwise. This affects the rendering since the evenodd filling rule * is used by Jdenticon. */ - public function addCircle($x, $y, $size, $counterClockwise) + public function addCircle(float $x, float $y, float $size, bool $counterClockwise): void { $sweepFlag = $counterClockwise ? '0' : '1'; $radiusAsString = number_format($size / 2, 2, '.', ''); @@ -50,10 +50,10 @@ class SvgPath /** * Adds a polygon to the SVG. * - * @param array(\Jdenticon\Rendering\Point) $points The corners of the + * @param array<\Jdenticon\Rendering\Point> $points The corners of the * polygon. */ - public function addPolygon($points) + public function addPolygon(array $points): void { $pointCount = count($points); @@ -75,7 +75,7 @@ class SvgPath * * @return string */ - public function __toString() + public function __toString(): string { return $this->dataString; } diff --git a/vendor/jdenticon/jdenticon/src/Rendering/SvgRenderer.php b/vendor/jdenticon/jdenticon/src/Rendering/SvgRenderer.php index 3a1df854..6df5c487 100644 --- a/vendor/jdenticon/jdenticon/src/Rendering/SvgRenderer.php +++ b/vendor/jdenticon/jdenticon/src/Rendering/SvgRenderer.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -11,15 +11,18 @@ namespace Jdenticon\Rendering; +use Jdenticon\Color; + /** * Renders icons as SVG paths. */ class SvgRenderer extends AbstractRenderer { - private $pathsByColor = array(); - private $path; - private $width; - private $height; + /** @var array */ + private array $pathsByColor = []; + private ?SvgPath $path = null; + private int $width; + private int $height; /** * Creates a new SvgRenderer. @@ -27,7 +30,7 @@ class SvgRenderer extends AbstractRenderer * @param int $width The width of the icon in pixels. * @param int $height The height of the icon in pixels. */ - public function __construct($width, $height) + public function __construct(int $width, int $height) { $this->width = $width; $this->height = $height; @@ -38,7 +41,7 @@ class SvgRenderer extends AbstractRenderer * * @return string */ - public function getMimeType() + public function getMimeType(): string { return 'image/svg+xml'; } @@ -54,7 +57,7 @@ class SvgRenderer extends AbstractRenderer * @param bool $counterClockwise If true the circle will be drawn * counter clockwise. */ - protected function addCircleNoTransform($x, $y, $size, $counterClockwise) + protected function addCircleNoTransform(float $x, float $y, float $size, bool $counterClockwise): void { $this->path->addCircle($x, $y, $size, $counterClockwise); } @@ -62,9 +65,9 @@ class SvgRenderer extends AbstractRenderer /** * Adds a polygon without translating its coordinates. * - * @param array $points An array of the points that the polygon consists of. + * @param array $points An array of the points that the polygon consists of. */ - protected function addPolygonNoTransform($points) + protected function addPolygonNoTransform(array $points): void { $this->path->addPolygon($points); } @@ -74,7 +77,7 @@ class SvgRenderer extends AbstractRenderer * * @param \Jdenticon\Color $color The color of the shape. */ - public function beginShape(\Jdenticon\Color $color) + public function beginShape(Color $color): void { $colorString = $color->toHexString(6); @@ -89,7 +92,7 @@ class SvgRenderer extends AbstractRenderer /** * Ends the currently drawn shape. */ - public function endShape() + public function endShape(): void { } @@ -98,8 +101,9 @@ class SvgRenderer extends AbstractRenderer * * @param bool $fragment If true an SVG string without the root svg element * will be rendered. + * @return string */ - public function getData($fragment = false) + public function getData(bool $fragment = false): string { $svg = ''; $widthAsString = number_format($this->width, 0, '.', ''); diff --git a/vendor/jdenticon/jdenticon/src/Rendering/Transform.php b/vendor/jdenticon/jdenticon/src/Rendering/Transform.php index f93de626..142cd2da 100644 --- a/vendor/jdenticon/jdenticon/src/Rendering/Transform.php +++ b/vendor/jdenticon/jdenticon/src/Rendering/Transform.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -16,10 +16,10 @@ namespace Jdenticon\Rendering; */ class Transform { - private $x; - private $y; - private $size; - private $rotation; + private float $x; + private float $y; + private float $size; + private int $rotation; /** * Creates a new Transform. @@ -29,10 +29,10 @@ class Transform * @param float $y The y-coordinate of the upper left corner of the * transformed rectangle. * @param float $size The size of the transformed rectangle. - * @param integer $rotation Rotation specified as + * @param int $rotation Rotation specified as * 0 = 0 rad, 1 = 0.5π rad, 2 = π rad, 3 = 1.5π rad. */ - public function __construct($x, $y, $size, $rotation) + public function __construct(float $x, float $y, float $size, int $rotation) { $this->x = $x; $this->y = $y; @@ -45,7 +45,7 @@ class Transform * * @return \Jdenticon\Rendering\Transform */ - public static function getEmpty() + public static function getEmpty(): Transform { return new Transform(0, 0, 0, 0); } @@ -64,7 +64,7 @@ class Transform * corner of the transformed rectangle. * @return \Jdenticon\Rendering\Point */ - public function transformPoint($x, $y, $width = 0, $height = 0) + public function transformPoint(float $x, float $y, float $width = 0, float $height = 0): Point { $right = $this->x + $this->size; $bottom = $this->y + $this->size; diff --git a/vendor/jdenticon/jdenticon/src/Rendering/TriangleDirection.php b/vendor/jdenticon/jdenticon/src/Rendering/TriangleDirection.php index fb1fff91..7f8fc2a1 100644 --- a/vendor/jdenticon/jdenticon/src/Rendering/TriangleDirection.php +++ b/vendor/jdenticon/jdenticon/src/Rendering/TriangleDirection.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -19,17 +19,17 @@ class TriangleDirection /** * The 90 degree angle is pointing to South West. */ - const SOUTH_WEST = 0; + public const SOUTH_WEST = 0; /** * The 90 degree angle is pointing to North West. */ - const NORTH_WEST = 1; + public const NORTH_WEST = 1; /** * The 90 degree angle is pointing to North East. */ - const NORTH_EAST = 2; + public const NORTH_EAST = 2; /** * The 90 degree angle is pointing to South East. */ - const SOUTH_EAST = 3; + public const SOUTH_EAST = 3; } diff --git a/vendor/jdenticon/jdenticon/src/Shapes/Shape.php b/vendor/jdenticon/jdenticon/src/Shapes/Shape.php index 33b0e160..664ef1ec 100644 --- a/vendor/jdenticon/jdenticon/src/Shapes/Shape.php +++ b/vendor/jdenticon/jdenticon/src/Shapes/Shape.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -11,6 +11,8 @@ namespace Jdenticon\Shapes; +use Jdenticon\Color; + /** * Represents a shape to be rendered in an icon. These instances are * hash specific. @@ -20,39 +22,35 @@ class Shape /** * The shape definition to be used to render the shape. * - * @var function( + * @var callable( * \Jdenticon\Rendering\RendererInterface $renderer, - * \Jdenticon\Shapes\ShapePosition $cell, - * int $index) + * int $cell, + * int $index): void */ public $definition; /** * The fill color of the shape. - * - * @var Jdenticon\Color */ - public $color; + public Color $color; /** - * The positions in which the shape will be rendered. - * - * @var array(\Jdenticon\Shapes\ShapePosition) + * The positions in which the shape will be rendered. Interleaved x and y cell coordinates. + * + * @var array */ - public $positions; + public array $positions; /** * The rotation index of the icon in the first position. - * - * @var int */ - public $startRotationIndex; + public int $startRotationIndex; public function __construct( - $definition, - \Jdenticon\Color $color, + callable $definition, + Color $color, array $positions, - $startRotationIndex) + int $startRotationIndex) { $this->definition = $definition; $this->color = $color; diff --git a/vendor/jdenticon/jdenticon/src/Shapes/ShapeCategory.php b/vendor/jdenticon/jdenticon/src/Shapes/ShapeCategory.php index 202de814..ad29f994 100644 --- a/vendor/jdenticon/jdenticon/src/Shapes/ShapeCategory.php +++ b/vendor/jdenticon/jdenticon/src/Shapes/ShapeCategory.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -20,46 +20,44 @@ class ShapeCategory /** * The index of the hash octet determining the color of shapes in this * category. - * - * @var int */ - public $colorIndex; + public int $colorIndex; /** * A list of possible shape definitions in this category. * - * @var array(function( + * @var array */ - public $shapes; + public array $shapes; /** * The index of the hash octet determining which of the shape definitions * that will be used for a particular hash. - * - * @var int */ - public $shapeIndex; + public int $shapeIndex; /** * The index of the hash octet determining the rotation index of the shape * in the first position. - * - * @var int */ - public $rotationIndex; + public ?int $rotationIndex; /** * The positions in which the shapes of this category will be rendered. * - * @var array(int) + * @var array */ - public $positions; + public array $positions; public function __construct( - $colorIndex, array $shapes, $shapeIndex, $rotationIndex, array $positions) + int $colorIndex, + array $shapes, + int $shapeIndex, + ?int $rotationIndex, + array $positions) { $this->colorIndex = $colorIndex; $this->shapes = $shapes; diff --git a/vendor/jdenticon/jdenticon/src/Shapes/ShapeDefinitions.php b/vendor/jdenticon/jdenticon/src/Shapes/ShapeDefinitions.php index 8278be0f..a4ef050d 100644 --- a/vendor/jdenticon/jdenticon/src/Shapes/ShapeDefinitions.php +++ b/vendor/jdenticon/jdenticon/src/Shapes/ShapeDefinitions.php @@ -3,7 +3,7 @@ * This file is part of Jdenticon for PHP. * https://github.com/dmester/jdenticon-php/ * - * Copyright (c) 2018 Daniel Mester Pirttijärvi + * Copyright (c) 2025 Daniel Mester Pirttijärvi * * For full license information, please see the LICENSE file that was * distributed with this source code. @@ -12,6 +12,7 @@ namespace Jdenticon\Shapes; use Jdenticon\Rendering\Point; +use Jdenticon\Rendering\RendererInterface; use Jdenticon\Rendering\TriangleDirection; /** @@ -19,16 +20,16 @@ use Jdenticon\Rendering\TriangleDirection; */ class ShapeDefinitions { - private static $outerShapes; - private static $centerShapes; - + private static ?array $outerShapes = null; + private static ?array $centerShapes = null; + /** * Gets an array of all possible outer shapes. Do not modify the returned * array. * - * @return array(\Jdenticon\Rendering\Shape) + * @return array */ - public static function getOuterShapes() + public static function getOuterShapes(): array { if (self::$outerShapes === null) { self::$outerShapes = self::createOuterShapes(); @@ -40,9 +41,9 @@ class ShapeDefinitions * Gets an array of all possible center shapes. Do not modify the returned * array. * - * @return array(\Jdenticon\Rendering\Shape) + * @return array */ - public static function getCenterShapes() + public static function getCenterShapes(): array { if (self::$centerShapes === null) { self::$centerShapes = self::createCenterShapes(); @@ -50,58 +51,60 @@ class ShapeDefinitions return self::$centerShapes; } - private static function createOuterShapes() + /** + * Creates an array of outer shape definitions. + * + * @return array + */ + private static function createOuterShapes(): array { - return array( - function ($renderer, $cell, $index) - { + return [ + function (RendererInterface $renderer, int $cell, int $index): void { $renderer->addTriangle(0, 0, $cell, $cell, 0); }, - function ($renderer, $cell, $index) - { + function (RendererInterface $renderer, int $cell, int $index): void { $renderer->addTriangle(0, $cell / 2, $cell, $cell / 2, 0); }, - function ($renderer, $cell, $index) - { + function (RendererInterface $renderer, int $cell, int $index): void { $renderer->addRhombus(0, 0, $cell, $cell); }, - function ($renderer, $cell, $index) - { + function (RendererInterface $renderer, int $cell, int $index): void { $m = $cell / 6; $renderer->addCircle($m, $m, $cell - 2 * $m); } - ); + ]; } - private static function createCenterShapes() + /** + * Creates an array of center shape definitions. + * + * @return array + */ + private static function createCenterShapes(): array { - return array( - function ($renderer, $cell, $index) - { + return [ + function (RendererInterface $renderer, int $cell, int $index): void { $k = $cell * 0.42; - $renderer->addPolygon(array( + $renderer->addPolygon([ new Point(0, 0), new Point($cell, 0), new Point($cell, $cell - $k * 2), new Point($cell - $k, $cell), new Point(0, $cell) - )); + ]); }, - function ($renderer, $cell, $index) - { + function (RendererInterface $renderer, int $cell, int $index): void { $w = (int)($cell * 0.5); $h = (int)($cell * 0.8); $renderer->addTriangle( $cell - $w, 0, $w, $h, TriangleDirection::NORTH_EAST); }, - function ($renderer, $cell, $index) - { + function (RendererInterface $renderer, int $cell, int $index): void { $s = (int)($cell / 3); $renderer->addRectangle($s, $s, $cell - $s, $cell - $s); }, - function ($renderer, $cell, $index) - { + function (RendererInterface $renderer, int $cell, int $index): void { $tmp = $cell * 0.1; if ($tmp > 1) { @@ -129,14 +132,12 @@ class ShapeDefinitions $outer, $outer, $cell - $inner - $outer, $cell - $inner - $outer); }, - function ($renderer, $cell, $index) - { + function (RendererInterface $renderer, int $cell, int $index): void { $m = (int)($cell * 0.15); $s = (int)($cell * 0.5); $renderer->addCircle($cell - $s - $m, $cell - $s - $m, $s); }, - function ($renderer, $cell, $index) - { + function (RendererInterface $renderer, int $cell, int $index): void { $inner = $cell * 0.1; $outer = $inner * 4; @@ -146,42 +147,38 @@ class ShapeDefinitions } $renderer->addRectangle(0, 0, $cell, $cell); - $renderer->addPolygon(array( + $renderer->addPolygon([ new Point($outer, $outer), new Point($cell - $inner, $outer), new Point($outer + ($cell - $outer - $inner) / 2, $cell - $inner) - ), true); + ], true); }, - function ($renderer, $cell, $index) - { - $renderer->addPolygon(array( + function (RendererInterface $renderer, int $cell, int $index): void { + $renderer->addPolygon([ new Point(0, 0), new Point($cell, 0), new Point($cell, $cell * 0.7), new Point($cell * 0.4, $cell * 0.4), new Point($cell * 0.7, $cell), new Point(0, $cell) - )); + ]); }, - function ($renderer, $cell, $index) - { + function (RendererInterface $renderer, int $cell, int $index): void { $renderer->addTriangle( $cell / 2, $cell / 2, $cell / 2, $cell / 2, TriangleDirection::SOUTH_EAST); }, - function ($renderer, $cell, $index) - { - $renderer->addPolygon(array( + function (RendererInterface $renderer, int $cell, int $index): void { + $renderer->addPolygon([ new Point(0, 0), new Point($cell, 0), new Point($cell, $cell / 2), new Point($cell / 2, $cell), new Point(0, $cell) - )); + ]); }, - function ($renderer, $cell, $index) - { + function (RendererInterface $renderer, int $cell, int $index): void { $tmp = $cell * 0.14; if ($cell < 8) { @@ -207,8 +204,7 @@ class ShapeDefinitions $outer, $outer, $cell - $outer - $inner, $cell - $outer - $inner, true); }, - function ($renderer, $cell, $index) - { + function (RendererInterface $renderer, int $cell, int $index): void { $inner = $cell * 0.12; $outer = $inner * 3; @@ -216,21 +212,18 @@ class ShapeDefinitions $renderer->addCircle($outer, $outer, $cell - $inner - $outer, true); }, - function ($renderer, $cell, $index) - { + function (RendererInterface $renderer, int $cell, int $index): void { $renderer->addTriangle( $cell / 2, $cell / 2, $cell / 2, $cell / 2, TriangleDirection::SOUTH_EAST); }, - function ($renderer, $cell, $index) - { + function (RendererInterface $renderer, int $cell, int $index): void { $m = $cell * 0.25; $renderer->addRectangle(0, 0, $cell, $cell); $renderer->addRhombus($m, $m, $cell - $m, $cell - $m, true); }, - function ($renderer, $cell, $index) - { + function (RendererInterface $renderer, int $cell, int $index): void { $m = $cell * 0.4; $s = $cell * 1.2; @@ -238,6 +231,6 @@ class ShapeDefinitions $renderer->addCircle($m, $m, $s); } } - ); + ]; } } diff --git a/vendor/jdenticon/jdenticon/src/Shapes/ShapePosition.php b/vendor/jdenticon/jdenticon/src/Shapes/ShapePosition.php deleted file mode 100644 index 9c780fce..00000000 --- a/vendor/jdenticon/jdenticon/src/Shapes/ShapePosition.php +++ /dev/null @@ -1,45 +0,0 @@ -x = $x; - $this->y = $y; - } -} - diff --git a/vendor/mlocati/ip-lib/src/Address/AddressInterface.php b/vendor/mlocati/ip-lib/src/Address/AddressInterface.php index f484c621..c367a4d5 100644 --- a/vendor/mlocati/ip-lib/src/Address/AddressInterface.php +++ b/vendor/mlocati/ip-lib/src/Address/AddressInterface.php @@ -153,4 +153,30 @@ interface AddressInterface * @example for IPv6 it returns something like x.x.x.x..x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.ip6.arpa */ public function getReverseDNSLookupName(); + + /** + * Shift the bits of the address, padding with zeroes. + * + * @param int $bits If negative the bits will be shifted left, if positive the bits will be shifted right + * + * @return self + * + * @since 1.20.0 + * + * @example shifting by 1 127.0.0.1 you'll have 63.128.0.0 + * @example shifting by -1 127.0.0.1 you'll have 254.0.0.2 + */ + public function shift($bits); + + /** + * Create a new IP address by adding to this address another address. + * + * @return self|null returns NULL if $other is not compatible with this address, or if it generates an invalid address + * + * @since 1.20.0 + * + * @example adding 0.0.0.10 to 127.0.0.1 generates the IP 127.0.0.11 + * @example adding 255.0.0.10 to 127.0.0.1 generates NULL + */ + public function add(AddressInterface $other); } diff --git a/vendor/mlocati/ip-lib/src/Address/IPv4.php b/vendor/mlocati/ip-lib/src/Address/IPv4.php index cd2c416f..1fa109de 100644 --- a/vendor/mlocati/ip-lib/src/Address/IPv4.php +++ b/vendor/mlocati/ip-lib/src/Address/IPv4.php @@ -512,4 +512,62 @@ class IPv4 implements AddressInterface array_reverse($this->getBytes()) ) . '.in-addr.arpa'; } + + /** + * {@inheritdoc} + * + * @see \IPLib\Address\AddressInterface::shift() + */ + public function shift($bits) + { + $bits = (int) $bits; + if ($bits === 0) { + return $this; + } + $absBits = abs($bits); + if ($absBits >= 32) { + return new self('0.0.0.0'); + } + $pad = str_repeat('0', $absBits); + $paddedBits = $this->getBits(); + if ($bits > 0) { + $paddedBits = $pad . substr($paddedBits, 0, -$bits); + } else { + $paddedBits = substr($paddedBits, $absBits) . $pad; + } + $bytes = array_map('bindec', str_split($paddedBits, 8)); + + return new static(implode('.', $bytes)); + } + + /** + * {@inheritdoc} + * + * @see \IPLib\Address\AddressInterface::add() + */ + public function add(AddressInterface $other) + { + if (!$other instanceof self) { + return null; + } + $myBytes = $this->getBytes(); + $otherBytes = $other->getBytes(); + $sum = array_fill(0, 4, 0); + $carry = 0; + for ($index = 3; $index >= 0; $index--) { + $byte = $myBytes[$index] + $otherBytes[$index] + $carry; + if ($byte > 0xFF) { + $carry = $byte >> 8; + $byte &= 0xFF; + } else { + $carry = 0; + } + $sum[$index] = $byte; + } + if ($carry !== 0) { + return null; + } + + return new static(implode('.', $sum)); + } } diff --git a/vendor/mlocati/ip-lib/src/Address/IPv6.php b/vendor/mlocati/ip-lib/src/Address/IPv6.php index e094881b..ad7e2a7f 100644 --- a/vendor/mlocati/ip-lib/src/Address/IPv6.php +++ b/vendor/mlocati/ip-lib/src/Address/IPv6.php @@ -605,4 +605,62 @@ class IPv6 implements AddressInterface array_reverse(str_split(str_replace(':', '', $this->toString(true)), 1)) ) . '.ip6.arpa'; } + + /** + * {@inheritdoc} + * + * @see \IPLib\Address\AddressInterface::shift() + */ + public function shift($bits) + { + $bits = (int) $bits; + if ($bits === 0) { + return $this; + } + $absBits = abs($bits); + if ($absBits >= 128) { + return new self('0000:0000:0000:0000:0000:0000:0000:0000'); + } + $pad = str_repeat('0', $absBits); + $paddedBits = $this->getBits(); + if ($bits > 0) { + $paddedBits = $pad . substr($paddedBits, 0, -$bits); + } else { + $paddedBits = substr($paddedBits, $absBits) . $pad; + } + $bytes = array_map('bindec', str_split($paddedBits, 16)); + + return static::fromWords($bytes); + } + + /** + * {@inheritdoc} + * + * @see \IPLib\Address\AddressInterface::add() + */ + public function add(AddressInterface $other) + { + if (!$other instanceof self) { + return null; + } + $myWords = $this->getWords(); + $otherWords = $other->getWords(); + $sum = array_fill(0, 7, 0); + $carry = 0; + for ($index = 7; $index >= 0; $index--) { + $word = $myWords[$index] + $otherWords[$index] + $carry; + if ($word > 0xFFFF) { + $carry = $word >> 16; + $word &= 0xFFFF; + } else { + $carry = 0; + } + $sum[$index] = $word; + } + if ($carry !== 0) { + return null; + } + + return static::fromWords($sum); + } } diff --git a/vendor/mlocati/ip-lib/src/Factory.php b/vendor/mlocati/ip-lib/src/Factory.php index 31b21d41..9338a2d6 100644 --- a/vendor/mlocati/ip-lib/src/Factory.php +++ b/vendor/mlocati/ip-lib/src/Factory.php @@ -84,17 +84,17 @@ class Factory * For upgrading: * - if $supportNonDecimalIPv4 is true, use the ParseStringFlag::IPV4_MAYBE_NON_DECIMAL flag * - * @param string|mixed $address + * @param string|mixed $range * @param bool $supportNonDecimalIPv4 * - * @return \IPLib\Address\AddressInterface|null + * @return \IPLib\Range\RangeInterface|null * * @see \IPLib\Factory::parseRangeString() * @since 1.10.0 added the $supportNonDecimalIPv4 argument */ - public static function rangeFromString($address, $supportNonDecimalIPv4 = false) + public static function rangeFromString($range, $supportNonDecimalIPv4 = false) { - return static::parseRangeString($address, $supportNonDecimalIPv4 ? ParseStringFlag::IPV4_MAYBE_NON_DECIMAL : 0); + return static::parseRangeString($range, $supportNonDecimalIPv4 ? ParseStringFlag::IPV4_MAYBE_NON_DECIMAL : 0); } /** @@ -215,20 +215,20 @@ class Factory } /** - * @param \IPLib\Address\AddressInterface $from - * @param \IPLib\Address\AddressInterface $to + * @param \IPLib\Address\AddressInterface|null $from + * @param \IPLib\Address\AddressInterface|null $to * * @return \IPLib\Range\RangeInterface|null * * @since 1.2.0 */ - protected static function rangeFromBoundaryAddresses(AddressInterface $from = null, AddressInterface $to = null) + protected static function rangeFromBoundaryAddresses($from = null, $to = null) { - if ($from === null && $to === null) { + if (!$from instanceof AddressInterface && !$to instanceof AddressInterface) { $result = null; - } elseif ($to === null) { + } elseif (!$to instanceof AddressInterface) { $result = Range\Single::fromAddress($from); - } elseif ($from === null) { + } elseif (!$from instanceof AddressInterface) { $result = Range\Single::fromAddress($to); } else { $result = null; diff --git a/vendor/mlocati/ip-lib/src/Range/AbstractRange.php b/vendor/mlocati/ip-lib/src/Range/AbstractRange.php index 12204350..24783ca5 100644 --- a/vendor/mlocati/ip-lib/src/Range/AbstractRange.php +++ b/vendor/mlocati/ip-lib/src/Range/AbstractRange.php @@ -7,6 +7,7 @@ use IPLib\Address\IPv4; use IPLib\Address\IPv6; use IPLib\Address\Type as AddressType; use IPLib\Factory; +use OutOfBoundsException; /** * Base class for range classes. @@ -122,4 +123,48 @@ abstract class AbstractRange implements RangeInterface return $result; } + + /** + * {@inheritdoc} + * + * @see \IPLib\Range\RangeInterface::split() + */ + public function split($networkPrefix, $forceSubnet = false) + { + $networkPrefix = (int) $networkPrefix; + $myNetworkPrefix = $this->getNetworkPrefix(); + if ($networkPrefix === $myNetworkPrefix) { + return array( + $forceSubnet ? $this->asSubnet() : $this, + ); + } + if ($networkPrefix < $myNetworkPrefix) { + throw new OutOfBoundsException("The value of the \$networkPrefix parameter can't be smaller than the network prefix of the range ({$myNetworkPrefix})"); + } + $startIp = $this->getStartAddress(); + $maxPrefix = $startIp::getNumberOfBits(); + if ($networkPrefix > $maxPrefix) { + throw new OutOfBoundsException("The value of the \$networkPrefix parameter can't be larger than the maximum network prefix of the range ({$maxPrefix})"); + } + if ($startIp instanceof IPv4) { + $one = IPv4::fromBytes(array(0, 0, 0, 1)); + } elseif ($startIp instanceof IPv6) { + $one = IPv6::fromBytes(array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1)); + } + $delta = $one->shift($networkPrefix - $maxPrefix); + $result = array(); + while (true) { + $range = Subnet::parseString("{$startIp}/{$networkPrefix}"); + if (!$forceSubnet && $this instanceof Pattern) { + $range = $range->asPattern() ?: $range; + } + $result[] = $range; + $startIp = $startIp->add($delta); + if ($startIp === null || !$this->contains($startIp)) { + break; + } + } + + return $result; + } } diff --git a/vendor/mlocati/ip-lib/src/Range/Pattern.php b/vendor/mlocati/ip-lib/src/Range/Pattern.php index 1e180ead..f7afeebb 100644 --- a/vendor/mlocati/ip-lib/src/Range/Pattern.php +++ b/vendor/mlocati/ip-lib/src/Range/Pattern.php @@ -308,9 +308,11 @@ class Pattern extends AbstractRange } /** - * @return float|int + * {@inheritdoc} + * + * @see \IPLib\Range\RangeInterface::getNetworkPrefix() */ - private function getNetworkPrefix() + public function getNetworkPrefix() { switch ($this->getAddressType()) { case AddressType::T_IPv4: diff --git a/vendor/mlocati/ip-lib/src/Range/RangeInterface.php b/vendor/mlocati/ip-lib/src/Range/RangeInterface.php index 4d4d8347..4c7c02d6 100644 --- a/vendor/mlocati/ip-lib/src/Range/RangeInterface.php +++ b/vendor/mlocati/ip-lib/src/Range/RangeInterface.php @@ -157,4 +157,30 @@ interface RangeInterface * @since 1.16.0 */ public function getSize(); + + /** + * Get the "network prefix", that is how many bits of the address are dedicated to the network portion. + * + * @return int + * + * @since 1.19.0 + * + * @example for 10.0.0.0/24 it's 24 + * @example for 10.0.0.* it's 24 + */ + public function getNetworkPrefix(); + + /** + * Split the range into smaller ranges. + * + * @param int $networkPrefix + * @param bool $forceSubnet set to true to always have ranges in "subnet format" (ie 1.2.3.4/5), to false to try to keep the original format if possible (that is, pattern to pattern, single to single) + * + * @throws \OutOfBoundsException if $networkPrefix is not valid + * + * @return \IPLib\Range\RangeInterface[] + * + * @since 1.19.0 + */ + public function split($networkPrefix, $forceSubnet = false); } diff --git a/vendor/mlocati/ip-lib/src/Range/Single.php b/vendor/mlocati/ip-lib/src/Range/Single.php index ec3531f6..09af4d8d 100644 --- a/vendor/mlocati/ip-lib/src/Range/Single.php +++ b/vendor/mlocati/ip-lib/src/Range/Single.php @@ -190,12 +190,7 @@ class Single extends AbstractRange */ public function asSubnet() { - $networkPrefixes = array( - AddressType::T_IPv4 => 32, - AddressType::T_IPv6 => 128, - ); - - return new Subnet($this->address, $this->address, $networkPrefixes[$this->address->getAddressType()]); + return new Subnet($this->address, $this->address, $this->getNetworkPrefix()); } /** @@ -241,4 +236,19 @@ class Single extends AbstractRange { return 1; } + + /** + * {@inheritdoc} + * + * @see \IPLib\Range\RangeInterface::getNetworkPrefix() + */ + public function getNetworkPrefix() + { + switch ($this->getAddressType()) { + case AddressType::T_IPv4: + return 32; + case AddressType::T_IPv6: + return 128; + } + } } diff --git a/vendor/mlocati/ip-lib/src/Range/Subnet.php b/vendor/mlocati/ip-lib/src/Range/Subnet.php index ea397622..9c00a101 100644 --- a/vendor/mlocati/ip-lib/src/Range/Subnet.php +++ b/vendor/mlocati/ip-lib/src/Range/Subnet.php @@ -261,10 +261,9 @@ class Subnet extends AbstractRange } /** - * Get subnet prefix. - * - * @return int + * {@inheritdoc} * + * @see \IPLib\Range\RangeInterface::getNetworkPrefix() * @since 1.7.0 */ public function getNetworkPrefix() diff --git a/vendor/symfony/polyfill-php80/Php80.php b/vendor/symfony/polyfill-php80/Php80.php new file mode 100644 index 00000000..362dd1a9 --- /dev/null +++ b/vendor/symfony/polyfill-php80/Php80.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Php80; + +/** + * @author Ion Bazan + * @author Nico Oelgart + * @author Nicolas Grekas + * + * @internal + */ +final class Php80 +{ + public static function fdiv(float $dividend, float $divisor): float + { + return @($dividend / $divisor); + } + + public static function get_debug_type($value): string + { + switch (true) { + case null === $value: return 'null'; + case \is_bool($value): return 'bool'; + case \is_string($value): return 'string'; + case \is_array($value): return 'array'; + case \is_int($value): return 'int'; + case \is_float($value): return 'float'; + case \is_object($value): break; + case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class'; + default: + if (null === $type = @get_resource_type($value)) { + return 'unknown'; + } + + if ('Unknown' === $type) { + $type = 'closed'; + } + + return "resource ($type)"; + } + + $class = \get_class($value); + + if (false === strpos($class, '@')) { + return $class; + } + + return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous'; + } + + public static function get_resource_id($res): int + { + if (!\is_resource($res) && null === @get_resource_type($res)) { + throw new \TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res))); + } + + return (int) $res; + } + + public static function preg_last_error_msg(): string + { + switch (preg_last_error()) { + case \PREG_INTERNAL_ERROR: + return 'Internal error'; + case \PREG_BAD_UTF8_ERROR: + return 'Malformed UTF-8 characters, possibly incorrectly encoded'; + case \PREG_BAD_UTF8_OFFSET_ERROR: + return 'The offset did not correspond to the beginning of a valid UTF-8 code point'; + case \PREG_BACKTRACK_LIMIT_ERROR: + return 'Backtrack limit exhausted'; + case \PREG_RECURSION_LIMIT_ERROR: + return 'Recursion limit exhausted'; + case \PREG_JIT_STACKLIMIT_ERROR: + return 'JIT stack limit exhausted'; + case \PREG_NO_ERROR: + return 'No error'; + default: + return 'Unknown error'; + } + } + + public static function str_contains(string $haystack, string $needle): bool + { + return '' === $needle || false !== strpos($haystack, $needle); + } + + public static function str_starts_with(string $haystack, string $needle): bool + { + return 0 === strncmp($haystack, $needle, \strlen($needle)); + } + + public static function str_ends_with(string $haystack, string $needle): bool + { + if ('' === $needle || $needle === $haystack) { + return true; + } + + if ('' === $haystack) { + return false; + } + + $needleLength = \strlen($needle); + + return $needleLength <= \strlen($haystack) && 0 === substr_compare($haystack, $needle, -$needleLength); + } +} diff --git a/vendor/symfony/polyfill-php80/PhpToken.php b/vendor/symfony/polyfill-php80/PhpToken.php new file mode 100644 index 00000000..fe6e6910 --- /dev/null +++ b/vendor/symfony/polyfill-php80/PhpToken.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Php80; + +/** + * @author Fedonyuk Anton + * + * @internal + */ +class PhpToken implements \Stringable +{ + /** + * @var int + */ + public $id; + + /** + * @var string + */ + public $text; + + /** + * @var int + */ + public $line; + + /** + * @var int + */ + public $pos; + + public function __construct(int $id, string $text, int $line = -1, int $position = -1) + { + $this->id = $id; + $this->text = $text; + $this->line = $line; + $this->pos = $position; + } + + public function getTokenName(): ?string + { + if ('UNKNOWN' === $name = token_name($this->id)) { + $name = \strlen($this->text) > 1 || \ord($this->text) < 32 ? null : $this->text; + } + + return $name; + } + + /** + * @param int|string|array $kind + */ + public function is($kind): bool + { + foreach ((array) $kind as $value) { + if (\in_array($value, [$this->id, $this->text], true)) { + return true; + } + } + + return false; + } + + public function isIgnorable(): bool + { + return \in_array($this->id, [\T_WHITESPACE, \T_COMMENT, \T_DOC_COMMENT, \T_OPEN_TAG], true); + } + + public function __toString(): string + { + return (string) $this->text; + } + + /** + * @return static[] + */ + public static function tokenize(string $code, int $flags = 0): array + { + $line = 1; + $position = 0; + $tokens = token_get_all($code, $flags); + foreach ($tokens as $index => $token) { + if (\is_string($token)) { + $id = \ord($token); + $text = $token; + } else { + [$id, $text, $line] = $token; + } + $tokens[$index] = new static($id, $text, $line, $position); + $position += \strlen($text); + } + + return $tokens; + } +} diff --git a/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php b/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php new file mode 100644 index 00000000..2b955423 --- /dev/null +++ b/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#[Attribute(Attribute::TARGET_CLASS)] +final class Attribute +{ + public const TARGET_CLASS = 1; + public const TARGET_FUNCTION = 2; + public const TARGET_METHOD = 4; + public const TARGET_PROPERTY = 8; + public const TARGET_CLASS_CONSTANT = 16; + public const TARGET_PARAMETER = 32; + public const TARGET_ALL = 63; + public const IS_REPEATABLE = 64; + + /** @var int */ + public $flags; + + public function __construct(int $flags = self::TARGET_ALL) + { + $this->flags = $flags; + } +} diff --git a/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php b/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php new file mode 100644 index 00000000..bd1212f6 --- /dev/null +++ b/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (\PHP_VERSION_ID < 80000 && extension_loaded('tokenizer')) { + class PhpToken extends Symfony\Polyfill\Php80\PhpToken + { + } +} diff --git a/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php b/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php new file mode 100644 index 00000000..7c62d750 --- /dev/null +++ b/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (\PHP_VERSION_ID < 80000) { + interface Stringable + { + /** + * @return string + */ + public function __toString(); + } +} diff --git a/vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php b/vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php new file mode 100644 index 00000000..01c6c6c8 --- /dev/null +++ b/vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (\PHP_VERSION_ID < 80000) { + class UnhandledMatchError extends Error + { + } +} diff --git a/vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php b/vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php new file mode 100644 index 00000000..783dbc28 --- /dev/null +++ b/vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (\PHP_VERSION_ID < 80000) { + class ValueError extends Error + { + } +} diff --git a/vendor/symfony/polyfill-php80/bootstrap.php b/vendor/symfony/polyfill-php80/bootstrap.php new file mode 100644 index 00000000..e5f7dbc1 --- /dev/null +++ b/vendor/symfony/polyfill-php80/bootstrap.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Php80 as p; + +if (\PHP_VERSION_ID >= 80000) { + return; +} + +if (!defined('FILTER_VALIDATE_BOOL') && defined('FILTER_VALIDATE_BOOLEAN')) { + define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN); +} + +if (!function_exists('fdiv')) { + function fdiv(float $num1, float $num2): float { return p\Php80::fdiv($num1, $num2); } +} +if (!function_exists('preg_last_error_msg')) { + function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); } +} +if (!function_exists('str_contains')) { + function str_contains(?string $haystack, ?string $needle): bool { return p\Php80::str_contains($haystack ?? '', $needle ?? ''); } +} +if (!function_exists('str_starts_with')) { + function str_starts_with(?string $haystack, ?string $needle): bool { return p\Php80::str_starts_with($haystack ?? '', $needle ?? ''); } +} +if (!function_exists('str_ends_with')) { + function str_ends_with(?string $haystack, ?string $needle): bool { return p\Php80::str_ends_with($haystack ?? '', $needle ?? ''); } +} +if (!function_exists('get_debug_type')) { + function get_debug_type($value): string { return p\Php80::get_debug_type($value); } +} +if (!function_exists('get_resource_id')) { + function get_resource_id($resource): int { return p\Php80::get_resource_id($resource); } +}