diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 000000000..862d102d5 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,5 @@ +# End of line reformating +3daf6593d89c608a6660a6c0b872eeb2607548ba +# Convert all tabs to spaces +a4cb0561f627c918cf304663fd32fd2b192f1565 + diff --git a/.gitattributes b/.gitattributes index 992f86d17..3e71d1166 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,8 +4,11 @@ # Generate pretty patches for PHP *.php diff=php +# Do not generate diff for vendored files +includes/vendor/** -diff +includes/vendor/** linguist-generated + # Exclude certain files or directories when generating an archive -assets/less/ export-ignore /.git* export-ignore /*.md export-ignore tests/ export-ignore diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index 5dbbbc9e4..78388b571 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -11,24 +11,4 @@ permissions: jobs: dependabot: name: Dependabot - runs-on: ubuntu-latest - if: ${{ github.actor == 'dependabot[bot]' }} - steps: - - name: Dependabot metadata - id: dependabot-metadata - uses: dependabot/fetch-metadata@v1.1.1 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Approve a PR - if: steps.dependabot-metadata.outputs.update-type != 'version-update:semver-major' - run: gh pr review --approve "$PR_URL" - env: - PR_URL: ${{ github.event.pull_request.html_url }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Enable auto-merge for Dependabot PRs - run: gh pr merge --auto --rebase "$PR_URL" - env: - PR_URL: ${{ github.event.pull_request.html_url }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + uses: YOURLS/.github/.github/workflows/auto-merge.yml@main diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 678d5bfea..aea15a584 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,30 +2,30 @@ name: CI on: push: - pull_request: branches: [ master ] + pull_request: + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: test: - name: PHP + name: PHP ${{ matrix.php }} runs-on: ubuntu-latest strategy: fail-fast: false matrix: - php: ['8.0'] - phpunit: ['latest'] + php: ['8.1', '8.2', '8.3', '8.4', '8.5', '8.6'] include: - - php: '7.2' - phpunit: '8.5.13' - - php: '7.3' - phpunit: '8.5.13' - - php: '7.4' - phpunit: '8.5.13' - coverage: xdebug - flags: '--coverage-clover clover.xml' -# - php: '8.1' -# experimental: true + - php: '8.1' + coverage: xdebug + flags: '--coverage-clover clover.xml' + + continue-on-error: ${{ matrix.php == '8.6' }} services: mysql: @@ -36,17 +36,19 @@ jobs: MYSQL_ALLOW_EMPTY_PASSWORD: false MYSQL_ROOT_PASSWORD: secret MYSQL_DATABASE: yourls_tests - options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + MARIADB_MYSQL_LOCALHOST_USER: 1 + MARIADB_MYSQL_LOCALHOST_GRANTS: USAGE + options: --health-cmd="healthcheck.sh --su-mysql --connect --innodb_initialized" --health-interval=10s --health-timeout=5s --health-retries=3 steps: - - uses: actions/checkout@v2.4.0 + - uses: actions/checkout@v6 - name: Use PHP ${{ matrix.php }} - uses: shivammathur/setup-php@2.16.0 + uses: shivammathur/setup-php@2.36.0 with: php-version: ${{ matrix.php }} extensions: mbstring, curl, zip, dom, simplexml, intl, pdo_mysql - tools: phpunit:${{ matrix.phpunit }} + tools: phpunit coverage: ${{ matrix.coverage }} # - name: Validate composer.json and composer.lock @@ -77,11 +79,6 @@ jobs: cp tests/data/config/yourls-tests-config-ci.php user/config.php - name: Test - run: phpunit --configuration phpunit.xml.dist ${{ matrix.flags }} + run: phpunit --configuration phpunit.xml.dist --display-skipped --display-incomplete --display-deprecations --display-notices --display-warnings --display-errors ${{ matrix.flags }} env: DB_PORT: ${{ job.services.mysql.ports['3306'] }} - - - name: Upload Scrutinizer coverage - uses: sudo-bot/action-scrutinizer@latest - with: - cli-args: "--format=php-clover clover.xml" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 0c50be464..000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: Release - -on: - push: - tags: - - '*' - -jobs: - docker: - name: Docker image - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2.4.0 - with: - repository: YOURLS/docker - ref: main - - - name: Get the version - id: get_version - run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//} - - - name: Set published version - run: echo "${{ steps.get_version.outputs.VERSION }}" > yourls_version - - - name: Create Pull Request - uses: peter-evans/create-pull-request@v3.12.1 - with: - token: ${{ secrets.PAT }} - commit-message: Bump YOURLS to ${{ steps.get_version.outputs.VERSION }} - title: Bump YOURLS to ${{ steps.get_version.outputs.VERSION }} - delete-branch: true - - charts: - name: Helm charts - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2.4.0 - with: - repository: YOURLS/charts - ref: main - - - name: Get the version - id: get_version - run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//} - - - name: Set published version - run: | - sed -i "s/appVersion:.*/appVersion: \"${{ steps.get_version.outputs.VERSION }}\"/" charts/yourls/Chart.yaml - - - name: Create Pull Request - uses: peter-evans/create-pull-request@v3.12.1 - with: - token: ${{ secrets.PAT }} - commit-message: Bump YOURLS to ${{ steps.get_version.outputs.VERSION }} - title: Bump YOURLS to ${{ steps.get_version.outputs.VERSION }} - delete-branch: true - draft: true diff --git a/.github/workflows/update-certificates.yml b/.github/workflows/update-certificates.yml new file mode 100644 index 000000000..c583fbd1a --- /dev/null +++ b/.github/workflows/update-certificates.yml @@ -0,0 +1,91 @@ +name: Update certificates + +on: + # Run every Monday at 13:37 + schedule: + - cron: '37 13 * * 1' + # And manually + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: write + pull-requests: write + +jobs: + certificate-check: + name: "Check for updated certificate bundle" + # Don't run the cron job on forks. + if: ${{ github.event_name != 'schedule' || github.repository == 'YOURLS/YOURLS' }} + + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Generate token + uses: actions/create-github-app-token@v2 + id: app-token + with: + app-id: ${{ vars.BOT_APP_ID }} + private-key: ${{ secrets.BOT_PRIVATE_KEY }} + + - name: Get GitHub App User ID + id: get-user-id + run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT" + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + + - name: Get current certificate bundle + working-directory: ./includes/vendor/rmccue/requests/certificates + run: | + curl --remote-name https://curl.se/ca/cacert.pem + curl --remote-name https://curl.se/ca/cacert.pem.sha256 + + - name: Verify the checksum of the downloaded bundle + working-directory: ./includes/vendor/rmccue/requests/certificates + run: sha256sum --check cacert.pem.sha256 + + - name: "Debug info: Show git status" + run: git status -vv --untracked=all + + - name: "Get date" + id: get-date + run: echo "DATE=$(/bin/date -u "+%F")" >> $GITHUB_OUTPUT + + - name: Create pull request + uses: peter-evans/create-pull-request@v8 + id: pull-request + with: + token: ${{ steps.app-token.outputs.token }} + author: "${{ steps.app-token.outputs.app-slug }}[bot] <${{ steps.get-user-id.outputs.user-id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com>" + base: master + branch: auto-update-cacert + delete-branch: true + commit-message: "Update certificates" + title: "Update certificates" + body: | + Updated certificates, last verified on ${{ steps.get-date.outputs.DATE }}. + + Source: https://curl.se/docs/caextract.html + labels: | + dependencies + + - name: Approve a PR + if: ${{ steps.pull-request.outputs.pull-request-url && steps.pull-request.outputs.pull-request-operation != 'none' }} + run: gh pr review --approve "$PR_URL" + env: + PR_URL: ${{ steps.pull-request.outputs.pull-request-url }} + GITHUB_TOKEN: ${{ github.token }} + + - name: Enable Pull Request Automerge + if: ${{ steps.pull-request.outputs.pull-request-url && steps.pull-request.outputs.pull-request-operation != 'none' }} + run: gh pr merge --auto --rebase "$PR_URL" + env: + PR_URL: ${{ steps.pull-request.outputs.pull-request-url }} + GITHUB_TOKEN: ${{ github.token }} diff --git a/.github/workflows/update-geoip.yml b/.github/workflows/update-geoip.yml new file mode 100644 index 000000000..a92f21419 --- /dev/null +++ b/.github/workflows/update-geoip.yml @@ -0,0 +1,92 @@ +name: Update GeoIP DB + +on: + # Run every Monday at 13:37 + schedule: + - cron: '37 13 * * 1' + # Run manually + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: write + pull-requests: write + +jobs: + update-geoip: + name: "Check for updated GeoIP DB" + + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Generate token + uses: actions/create-github-app-token@v2 + id: app-token + with: + app-id: ${{ vars.BOT_APP_ID }} + private-key: ${{ secrets.BOT_PRIVATE_KEY }} + + - name: Get GitHub App User ID + id: get-user-id + run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT" + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + + - name: Check if newer GeoIP DB + env: + MAXMIND_API_KEY: ${{ secrets.MAXMIND_API_KEY }} + run: | + URL="https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=${MAXMIND_API_KEY}&suffix=tar.gz" + REMOTE_MODIFIED=$(curl --silent --head "$URL" | grep "last-modified" | sed 's/last-modified: //') + REMOTE_CTIME=$(date -d "$REMOTE_MODIFIED" +%s) + LOCAL_MODIFIED=$(curl -fsSL https://api.github.com/repos/YOURLS/YOURLS/commits?path=includes/geo/GeoLite2-Country.mmdb | \ + jq -r '.[0]["commit"]["author"]["date"]') + LOCAL_CTIME=$(date -d "$LOCAL_MODIFIED" +%s) + echo "Remote: $REMOTE_CTIME ($(date -d @$REMOTE_CTIME))" + echo "Local: $LOCAL_CTIME ($(date -d @$LOCAL_CTIME))" + if [ $LOCAL_CTIME -lt $REMOTE_CTIME ] ; then curl -fsSL "$URL" | tar -zvx -C includes/geo/ --strip-components 1 -- ; fi + + - name: "Debug info: Show git status" + run: git status -vv --untracked=all + + - name: "Get date" + id: get-date + run: echo "DATE=$(/bin/date -u "+%F")" >> $GITHUB_OUTPUT + + - name: Create pull request + uses: peter-evans/create-pull-request@v8 + id: pull-request + with: + token: ${{ steps.app-token.outputs.token }} + author: "${{ steps.app-token.outputs.app-slug }}[bot] <${{ steps.get-user-id.outputs.user-id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com>" + base: master + branch: auto-update-geoip + commit-message: "Update GeoIP DB" + title: "Update GeoIP DB" + body: | + Updated GeoIP database, last verified on ${{ steps.get-date.outputs.DATE }}. + + Source: https://www.maxmind.com/en/account/login + labels: | + dependencies + + - name: Approve a PR + if: ${{ steps.pull-request.outputs.pull-request-url && steps.pull-request.outputs.pull-request-operation != 'none' }} + run: gh pr review --approve "$PR_URL" + env: + PR_URL: ${{ steps.pull-request.outputs.pull-request-url }} + GITHUB_TOKEN: ${{ github.token }} + + - name: Enable Pull Request Automerge + if: ${{ steps.pull-request.outputs.pull-request-url && steps.pull-request.outputs.pull-request-operation != 'none' }} + run: gh pr merge --auto --rebase "$PR_URL" + env: + PR_URL: ${{ steps.pull-request.outputs.pull-request-url }} + GITHUB_TOKEN: ${{ github.token }} diff --git a/.github/workflows/update-translations.yml b/.github/workflows/update-translations.yml new file mode 100644 index 000000000..a084e77bb --- /dev/null +++ b/.github/workflows/update-translations.yml @@ -0,0 +1,115 @@ +name: Update translations + +on: + push: + tags: + - '*' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + translations-check: + name: Check for updated translations + if: ${{ github.event_name != 'schedule' || github.repository == 'YOURLS/YOURLS' }} + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install GNU gettext + run: sudo apt-get install gettext + + - name: Get version + id: get-version + run: echo "yourls-version=$(php -r 'require "includes/version.php"; echo YOURLS_VERSION;')" >> $GITHUB_OUTPUT + + - name: Extract translations + env: + YOURLS_VERSION: ${{ steps.get-version.outputs.yourls-version }} + run: | + find . -name "*.php" ! -path "./user/*" ! -path "./tests/*" ! -path "./includes/vendor/*" \ + | xargs xgettext \ + --output=YOURLS.pot --package-name=YOURLS --package-version=$YOURLS_VERSION --foreign-user \ + --add-location --language=PHP --from-code=UTF-8 --sort-by-file \ + --keyword=yourls__ \ + --keyword=yourls_e \ + --keyword=yourls_s \ + --keyword=yourls_se \ + --keyword=yourls_esc_attr__ \ + --keyword=yourls_esc_html__ \ + --keyword=yourls_x \ + --keyword=yourls_ex \ + --keyword=yourls_esc_attr_x \ + --keyword=yourls_esc_html_x \ + --keyword=yourls_n:1,2 \ + --keyword=yourls_nx:1,2 \ + --keyword=yourls_n_noop:1,2 \ + --keyword=yourls_nx_noop:1,2 + + - uses: actions/upload-artifact@v6 + with: + name: YOURLS-pot + path: YOURLS.pot + + translations-submit: + name: Submit updated translations + if: ${{ github.event_name == 'workflow_dispatch' && github.repository == 'YOURLS/YOURLS' }} + runs-on: ubuntu-latest + needs: + - translations-check + steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + repository: YOURLS/YOURLS.pot + + - uses: actions/download-artifact@v7 + with: + name: YOURLS-pot + + - name: Generate token + uses: actions/create-github-app-token@v2 + id: app-token + with: + app-id: ${{ vars.BOT_APP_ID }} + private-key: ${{ secrets.BOT_PRIVATE_KEY }} + owner: ${{ github.repository_owner }} + + - name: Get GitHub App User ID + id: get-user-id + run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT" + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + + - name: Show git status + run: git status -vv --untracked=all + + - name: Get date + id: get-date + run: echo "DATE=$(/bin/date -u "+%F")" >> $GITHUB_OUTPUT + + - name: Create pull request + uses: peter-evans/create-pull-request@v8 + id: pull-request + with: + token: ${{ steps.app-token.outputs.token }} + author: "${{ steps.app-token.outputs.app-slug }}[bot] <${{ steps.get-user-id.outputs.user-id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com>" + base: main + branch: auto-update-translations + delete-branch: true + commit-message: "Update translations" + title: "Update translations" + body: | + Updated translations, last verified on ${{ steps.get-date.outputs.DATE }}. + labels: | + dependencies + + - name: Enable Pull Request Automerge + if: ${{ steps.pull-request.outputs.pull-request-url && steps.pull-request.outputs.pull-request-operation != 'none' }} + run: gh pr merge --auto --rebase "$PR_URL" + env: + PR_URL: ${{ steps.pull-request.outputs.pull-request-url }} + GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} diff --git a/.gitignore b/.gitignore index 4f03131e2..c05b5b456 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,8 @@ includes/**/tests/ build/ coverage/ phpunit.xml +.phpunit.result.cache +.phpunit.cache tests/yourls-tests-config.php tests/vendor/ tests/data/auth/config-test-auth-hashed.php @@ -45,6 +47,8 @@ Thumbs.db Desktop.ini # Mac crap .DS_Store -# NetBeans files +# IDE files /nbproject/ .idea +.vs +.vscode diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bcda616f..1b2f7d1d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,87 @@ YOURLS Changelog _This file lists the main changes through all versions of YOURLS. For a much more detailed list, simply refer to [commit messages](https://github.com/YOURLS/YOURLS/commits/master)._ +1.10.3 +--- +- added: testing on PHP 8.5 & 8.6 (#4036) +- added: function to get reserved URLs from global variable (#3999) +- added: database index on long URLs, for faster searches (#4013) +- added: `$context` parameter of `yourls_get_db()` (#4020) +- changed: hide referrers on public statistics page by default (#4005) +- changed: set the infos cache of the keyword after a url is added/updated/deleted (#4008) +- changed: fix hover-actions in tables for screen reader users (#4025) +- changed: confirm link deletion with a modal dialog (#3932) +- fixed: upgrade spatie/array-to-xml to address deprecation warnings in newer PHP version (#4037) +- fixed: filtering for links with more than 0 clicks (#3977) +- fixed: case-sensitivity in admin search (#3997) +- fixed: missing or invalid reserved URL configuration causing crash (#3999) +- fixed: handling of invalid charsets on remote sites (#4007) +- fixed: preserve backslashes in URLs (#4000) +- fixed: validate JSONP callback names (#4030) +- fixed: enhance configuration template formatting (#3994) +- fixed: minor cleanup (#3979, #3984, #3988) + +1.10.2 +--- +- fixed: `admin/tools.php` now uses `yourls_get_nonce_life()` (#3906) +- fixed: "Display 1 to 0 of 0 URLs" on admin list page (#3910) +- fixed: replace deprecated `get_all_options` filter with an action (#3683) +- fixed: defer loading text domain after plugins (#3679) +- removed: Gandi references (#3929) + +1.10.1 +--- +- fixed: sandbox exceptions when disabling plugins (#3893) +- fixed: stats date calculation are now correct (#3895) +- fixed: unexpected warning raised on login page +- removed: unsupported installation cases with Composer + +1.10.0 +--- +- added: Support PHP 8.3 & 8.4 +- removed: Support for PHP prior to 8.1 which is now minimal requirement +- changed: Ensure all `statusCode`/`errorCode` API values are strings (#3756) +- fixed: Results with 0 clicks on search (#3589) +- fixed: Upgrade Aura.SQL to fix PHP 8.4 compatibility (#3852) +- fixed: login page accessibility (#3660) +- fixed: MySQL 8+ compatibility (#3828) +- changed: Upgrade dependencies +- changed: Update GeoIP DB +- changed: Update certificates + +1.9.2 +--- +- added: Support PHP 8.2 (#3474) +- improved: Googlebot indexing now filterable for plugins, for your SEO needs (#3517) +- improved: Use safe sandbox for all included files (#3478) +- fixed: bookmarklets with URL containing special chars (#3527) +- fixed: unwanted cookies could interfere with YOURLS (#3516) +- fixed: cosmetic bugs in the admin interface (#3485, #3431, #3518) +- fixed: support usernames containing brackets (#3365) +- updated: third party libs and binaries + +1.9.1 +--- +- fixed: error `Undefined constant "intval"` when upgrading (#3332) +- fixed: warnings on PHP 8.1 (#3317) +- fixed: incorrect HTTP status header with the API when shortening a duplicate (#3355) +- fixed: no hyphen in random keywords (#3353) +- added: required/suggested PHP extensions in composer.json (#3339) +- updated: third party libs and binaries + +1.9 +--- +- removed : support for PHP prior to 7.4 +- improved: the API plugin with more plugin functions (#3281), a sandbox and a plugin uninstall procedure (#3282) +- improved: inline documentation, [online documentation](https://docs.yourls.org/) and unit tests +- improved: concurrency during mass shortening (#3233) +- improved: minor security fixes - sanitize step name during upgrade (#3055), + nonce on the logout link (#3264), salt cookie with newer hash (#3278) +- improved: Remove ozh/phpass library and use native PHP password_* functions (#3232) +- added: more hooks in the admin view & search (#3265) +- fixed: incorrect notice when "prefix and shorten" while not logged in (#3189) +- fixed: UI sometimes not responsive after editing a URL (#3244) + 1.8.2 --- - fixed: display SVG logo for IE 11 (#2864) @@ -35,8 +116,8 @@ For a much more detailed list, simply refer to [commit messages](https://github. 1.7.9 --- - improved: compatibility of YOURLS with proxies and reversed proxies -- improved: accept timestamped signature in API requests with [arbitrary hash](https://github.com/YOURLS/YOURLS/wiki/PasswordlessAPI#use-other-hash-algorithms-than-md5) -- improved: YOURLS pages are now located in `user/` and [documented](https://github.com/YOURLS/YOURLS/wiki/Pages) +- improved: accept timestamped signature in API requests with [arbitrary hash](https://docs.yourls.org/guide/advanced/passwordless-api.html#use-other-hash-algorithms-than-md5) +- improved: YOURLS pages are now located in `user/` and [documented](https://docs.yourls.org/guide/extend/pages.html) - improved: accessibility, with labels and aria tags in the main admin screen - fixed: various little things here and also there @@ -76,7 +157,7 @@ For a much more detailed list, simply refer to [commit messages](https://github. 1.7.1 --- - added: compatibility with PHP 7 -- added: allow hooks with closures (see [Advanced Hook Syntax](https://github.com/YOURLS/YOURLS/wiki/Advanced-Hook-Syntax)) +- added: allow hooks with closures (see [Advanced Hook Syntax](https://docs.yourls.org/development/hooks.html)) - improved: you can now search across all fields at once in the admin interface - improved: bookmarklets are now human readable in the PHP source, and minified on the fly - improved, still not perfect: support for URLs and page titles with encoded chars diff --git a/README.md b/README.md index f7546e5e6..1a57344bf 100644 --- a/README.md +++ b/README.md @@ -6,20 +6,15 @@ > Your Own URL Shortener -![CI](https://github.com/YOURLS/YOURLS/workflows/CI/badge.svg) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/YOURLS/YOURLS/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/YOURLS/YOURLS/?branch=master) ![PHP Version Support](https://img.shields.io/packagist/php-v/yourls/yourls) [![Packagist](https://img.shields.io/packagist/v/yourls/yourls.svg)](https://packagist.org/packages/yourls/yourls) [![OpenCollective](https://opencollective.com/yourls/backers/badge.svg)](https://opencollective.com/yourls#contributors) +[![CI](https://github.com/YOURLS/YOURLS/actions/workflows/ci.yml/badge.svg)](https://github.com/YOURLS/YOURLS/actions/workflows/ci.yml) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/YOURLS/YOURLS/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/YOURLS/YOURLS/?branch=master) ![PHP Version Support](https://img.shields.io/packagist/php-v/yourls/yourls) [![Packagist](https://img.shields.io/packagist/v/yourls/yourls.svg)](https://packagist.org/packages/yourls/yourls) [![OpenCollective](https://opencollective.com/yourls/backers/badge.svg)](https://opencollective.com/yourls#contributors) [![OpenCollective](https://opencollective.com/yourls/sponsors/badge.svg)](#sponsors) **YOURLS** is a set of PHP scripts that will allow you to run Your Own URL Shortener, on **your** server. You'll have full control over your data, detailed stats, analytics, plugins, and more. It's free and open-source. -## Quick Start +## Getting Started -Get YOURLS : -* Download the latest [release](https://github.com/YOURLS/YOURLS/releases) -* Using Composer? You can simply `composer create-project yourls/yourls .` in an empty directory. - -Install YOURLS: -* Read [yourls.org](https://yourls.org) for starters -* There are important additional information on the [Wiki documentation](https://github.com/YOURLS/YOURLS/wiki/). +Check out the complete documentation on [docs.yourls.org](https://docs.yourls.org). +It contains everything from beginners to experts. ## Community news, tips and tricks @@ -34,7 +29,6 @@ Feature suggestion? Bug to report? __Before opening any issue, please search for existing [issues](https://github.com/YOURLS/YOURLS/issues) (open and closed) and read the [Contributing Guidelines](https://github.com/YOURLS/.github/blob/master/CONTRIBUTING.md).__ - ## Backers Do you use and enjoy YOURLS? [Become a backer](https://opencollective.com/yourls#backer) and show your support to our open source project. diff --git a/admin/admin-ajax.php b/admin/admin-ajax.php index 77f68ac2b..edfa16a49 100644 --- a/admin/admin-ajax.php +++ b/admin/admin-ajax.php @@ -10,43 +10,38 @@ yourls_no_frame_header(); if( !isset( $_REQUEST['action'] ) ) - die(); + die(); // Pick action $action = $_REQUEST['action']; switch( $action ) { - case 'add': - yourls_verify_nonce( 'add_url', $_REQUEST['nonce'], false, 'omg error' ); - $return = yourls_add_new_link( $_REQUEST['url'], $_REQUEST['keyword'] ); - echo json_encode($return); - break; - - case 'edit_display': - yourls_verify_nonce( 'edit-link_'.$_REQUEST['id'], $_REQUEST['nonce'], false, 'omg error' ); - $row = yourls_table_edit_row ( $_REQUEST['keyword'] ); - echo json_encode( array('html' => $row) ); - break; - - case 'edit_save': - yourls_verify_nonce( 'edit-save_'.$_REQUEST['id'], $_REQUEST['nonce'], false, 'omg error' ); - $return = yourls_edit_link( $_REQUEST['url'], $_REQUEST['keyword'], $_REQUEST['newkeyword'], $_REQUEST['title'] ); - echo json_encode($return); - break; - - case 'delete': - yourls_verify_nonce( 'delete-link_'.$_REQUEST['id'], $_REQUEST['nonce'], false, 'omg error' ); - $query = yourls_delete_link_by_keyword( $_REQUEST['keyword'] ); - echo json_encode(array('success'=>$query)); - break; - - case 'logout': - // unused for the moment - yourls_logout(); - break; - - default: - yourls_do_action( 'yourls_ajax_'.$action ); + case 'add': + yourls_verify_nonce( 'add_url', $_REQUEST['nonce'], false, 'omg error' ); + $return = yourls_add_new_link( $_REQUEST['url'], $_REQUEST['keyword'], '', $_REQUEST['rowid'] ); + echo json_encode($return); + break; + + case 'edit_display': + yourls_verify_nonce( 'edit-link_'.$_REQUEST['id'], $_REQUEST['nonce'], false, 'omg error' ); + $row = yourls_table_edit_row ( $_REQUEST['keyword'], $_REQUEST['id'] ); + echo json_encode( array('html' => $row) ); + break; + + case 'edit_save': + yourls_verify_nonce( 'edit-save_'.$_REQUEST['id'], $_REQUEST['nonce'], false, 'omg error' ); + $return = yourls_edit_link( $_REQUEST['url'], $_REQUEST['keyword'], $_REQUEST['newkeyword'], $_REQUEST['title'] ); + echo json_encode($return); + break; + + case 'delete': + yourls_verify_nonce( 'delete-link_'.$_REQUEST['id'], $_REQUEST['nonce'], false, 'omg error' ); + $query = yourls_delete_link_by_keyword( $_REQUEST['keyword'] ); + echo json_encode(array('success'=>$query)); + break; + + default: + yourls_do_action( 'yourls_ajax_'.$action ); } diff --git a/admin/index.php b/admin/index.php index 9a6d688d5..1e60a56c3 100644 --- a/admin/index.php +++ b/admin/index.php @@ -30,17 +30,20 @@ $search_in = $view_params->get_search_in(); $search_in_text = $view_params->get_param_long_name($search_in); if( $search && $search_in && $search_in_text ) { - $search_sentence = yourls_s( 'Searching for %1$s in %2$s.', yourls_esc_html( $search ), yourls_esc_html( $search_in_text ) ); - $search_text = $search; - $search = str_replace( '*', '%', '*' . $search . '*' ); + $search_sentence = yourls_s( 'Searching for %1$s in %2$s.', yourls_esc_html( $search ), yourls_esc_html( $search_in_text ) ); + $search_text = $search; + $search = str_replace( '*', '%', '*' . $search . '*' ); if( $search_in == 'all' ) { - $where['sql'] .= " AND CONCAT_WS('',`keyword`,`url`,`title`,`ip`) LIKE (:search)"; - // Search across all fields. The resulting SQL will be something like: - // SELECT * FROM `yourls_url` WHERE CONCAT_WS('',`keyword`,`url`,`title`,`ip`) LIKE ("%ozh%") - // CONCAT_WS because CONCAT('foo', 'bar', NULL) = NULL. NULL wins. Not sure if values can be NULL now or in the future, so better safe. - // TODO: pay attention to this bit when the DB schema changes + $where['sql'] .= " AND `keyword` LIKE (:search) + OR `url` LIKE (:search) + OR `title` COLLATE utf8mb4_unicode_ci LIKE (:search) COLLATE utf8mb4_unicode_ci + OR `ip` LIKE (:search) "; } else { - $where['sql'] .= " AND `$search_in` LIKE (:search)"; + $collate = ''; + if( $search_in == 'title' ) { + $collate = ' COLLATE utf8mb4_unicode_ci'; + } + $where['sql'] .= " AND `$search_in` $collate LIKE (:search) $collate"; } $where['binds']['search'] = $search; } @@ -96,139 +99,139 @@ // Get URLs Count for current filter, total links in DB & total clicks list( $total_urls, $total_clicks ) = array_values( yourls_get_db_stats() ); if ( !empty($where['sql']) ) { - list( $total_items, $total_items_clicks ) = array_values( yourls_get_db_stats( $where ) ); + list( $total_items, $total_items_clicks ) = array_values( yourls_get_db_stats( $where ) ); } else { - $total_items = $total_urls; - $total_items_clicks = false; + $total_items = $total_urls; + $total_items_clicks = false; } // This is a bookmarklet if ( isset( $_GET['u'] ) or isset( $_GET['up'] ) ) { - $is_bookmark = true; - yourls_do_action( 'bookmarklet' ); - - // No sanitization needed here: everything happens in yourls_add_new_link() - if( isset( $_GET['u'] ) ) { - // Old school bookmarklet: ?u= - $url = urldecode( $_GET['u'] ); - } else { - // New style bookmarklet: ?up=&us=&ur= - $url = urldecode( $_GET['up'] . $_GET['us'] . $_GET['ur'] ); - } - $keyword = ( isset( $_GET['k'] ) ? ( $_GET['k'] ) : '' ); - $title = ( isset( $_GET['t'] ) ? ( $_GET['t'] ) : '' ); - $return = yourls_add_new_link( $url, $keyword, $title ); - - // If fails because keyword already exist, retry with no keyword - if ( isset( $return['status'] ) && $return['status'] == 'fail' && isset( $return['code'] ) && $return['code'] == 'error:keyword' ) { - $msg = $return['message']; - $return = yourls_add_new_link( $url, '' ); - $return['message'] .= ' ('.$msg.')'; - } - - // Stop here if bookmarklet with a JSON callback function - if( isset( $_GET['jsonp'] ) && $_GET['jsonp'] == 'yourls' ) { - $short = $return['shorturl'] ? $return['shorturl'] : ''; - $message = $return['message']; - yourls_content_type_header( 'application/javascript' ); - echo yourls_apply_filter( 'bookmarklet_jsonp', "yourls_callback({'short_url':'$short','message':'$message'});" ); - - die(); - } - - // Now use the URL that has been sanitized and returned by yourls_add_new_link() - $url = $return['url']['url']; - $where['sql'] .= ' AND `url` LIKE :url '; + $is_bookmark = true; + yourls_do_action( 'bookmarklet' ); + + // No sanitization needed here: everything happens in yourls_add_new_link() + if( isset( $_GET['u'] ) ) { + // Old school bookmarklet: ?u= + $url = $_GET['u']; + } else { + // New style bookmarklet: ?up=&us=&ur= + $url = $_GET['up'] . $_GET['us'] . $_GET['ur']; + } + $keyword = ( isset( $_GET['k'] ) ? ( $_GET['k'] ) : '' ); + $title = ( isset( $_GET['t'] ) ? ( $_GET['t'] ) : '' ); + $return = yourls_add_new_link( $url, $keyword, $title ); + + // If fails because keyword already exist, retry with no keyword + if ( isset( $return['status'] ) && $return['status'] == 'fail' && isset( $return['code'] ) && $return['code'] == 'error:keyword' ) { + $msg = $return['message']; + $return = yourls_add_new_link( $url, '' ); + $return['message'] .= ' ('.$msg.')'; + } + + // Stop here if bookmarklet with a JSON callback function + if( isset( $_GET['jsonp'] ) && $_GET['jsonp'] == 'yourls' ) { + $short = $return['shorturl'] ? $return['shorturl'] : ''; + $message = $return['message']; + yourls_content_type_header( 'application/javascript' ); + echo yourls_apply_filter( 'bookmarklet_jsonp', "yourls_callback({'short_url':'$short','message':'$message'});" ); + + die(); + } + + // Now use the URL that has been sanitized and returned by yourls_add_new_link() + $url = $return['url']['url']; + $where['sql'] .= ' AND `url` LIKE :url '; $where['binds']['url'] = $url; - $page = $total_pages = $perpage = 1; - $offset = 0; - - $text = ( isset( $_GET['s'] ) ? stripslashes( $_GET['s'] ) : '' ); - - // Sharing with social bookmarklets - if( !empty($_GET['share']) ) { - yourls_do_action( 'pre_share_redirect' ); - switch ( $_GET['share'] ) { - case 'twitter': - // share with Twitter - $destination = sprintf( "https://twitter.com/intent/tweet?url=%s&text=%s", urlencode( $return['shorturl'] ), urlencode( $title ) ); - yourls_redirect( $destination, 303 ); - - // Deal with the case when redirection failed: - $return['status'] = 'error'; - $return['errorCode'] = 400; - $return['message'] = yourls_s( 'Short URL created, but could not redirect to %s !', 'Twitter' ); - break; - - case 'facebook': - // share with Facebook - $destination = sprintf( "https://www.facebook.com/sharer/sharer.php?u=%s&t=%s", urlencode( $return['shorturl'] ), urlencode( $title ) ); - yourls_redirect( $destination, 303 ); - - // Deal with the case when redirection failed: - $return['status'] = 'error'; - $return['errorCode'] = 400; - $return['message'] = yourls_s( 'Short URL created, but could not redirect to %s !', 'Facebook' ); - break; - - case 'tumblr': - // share with Tumblr - $destination = sprintf( "https://www.tumblr.com/share?v=3&u=%s&t=%s&s=%s", urlencode( $return['shorturl'] ), urlencode( $title ), urlencode( $text ) ); - yourls_redirect( $destination, 303 ); - - // Deal with the case when redirection failed: - $return['status'] = 'error'; - $return['errorCode'] = 400; - $return['message'] = yourls_s( 'Short URL created, but could not redirect to %s !', 'Tumblr' ); - break; - - default: - // Is there a custom registered social bookmark? - yourls_do_action( 'share_redirect_' . $_GET['share'], $return ); - - // Still here? That was an unknown 'share' method, then. - $return['status'] = 'error'; - $return['errorCode'] = 400; - $return['message'] = yourls__( 'Unknown "Share" bookmarklet' ); - break; - } - } + $page = $total_pages = $perpage = 1; + $offset = 0; + + $text = ( isset( $_GET['s'] ) ? stripslashes( $_GET['s'] ) : '' ); + + // Sharing with social bookmarklets + if( !empty($_GET['share']) ) { + yourls_do_action( 'pre_share_redirect' ); + switch ( $_GET['share'] ) { + case 'twitter': + // share with Twitter + $destination = sprintf( "https://twitter.com/intent/tweet?url=%s&text=%s", urlencode( $return['shorturl'] ), urlencode( $title ) ); + yourls_redirect( $destination, 303 ); + + // Deal with the case when redirection failed: + $return['status'] = 'error'; + $return['errorCode'] = '400'; + $return['message'] = yourls_s( 'Short URL created, but could not redirect to %s !', 'Twitter' ); + break; + + case 'facebook': + // share with Facebook + $destination = sprintf( "https://www.facebook.com/sharer/sharer.php?u=%s&t=%s", urlencode( $return['shorturl'] ), urlencode( $title ) ); + yourls_redirect( $destination, 303 ); + + // Deal with the case when redirection failed: + $return['status'] = 'error'; + $return['errorCode'] = '400'; + $return['message'] = yourls_s( 'Short URL created, but could not redirect to %s !', 'Facebook' ); + break; + + case 'tumblr': + // share with Tumblr + $destination = sprintf( "https://www.tumblr.com/share?v=3&u=%s&t=%s&s=%s", urlencode( $return['shorturl'] ), urlencode( $title ), urlencode( $text ) ); + yourls_redirect( $destination, 303 ); + + // Deal with the case when redirection failed: + $return['status'] = 'error'; + $return['errorCode'] = '400'; + $return['message'] = yourls_s( 'Short URL created, but could not redirect to %s !', 'Tumblr' ); + break; + + default: + // Is there a custom registered social bookmark? + yourls_do_action( 'share_redirect_' . $_GET['share'], $return ); + + // Still here? That was an unknown 'share' method, then. + $return['status'] = 'error'; + $return['errorCode'] = '400'; + $return['message'] = yourls__( 'Unknown "Share" bookmarklet' ); + break; + } + } // This is not a bookmarklet } else { - $is_bookmark = false; - - // Checking $page, $offset, $perpage - if( empty($page) || $page == 0 ) { - $page = 1; - } - if( empty($offset) ) { - $offset = 0; - } - if( empty($perpage) || $perpage == 0) { - $perpage = 50; - } - - // Determine $offset - $offset = ( $page-1 ) * $perpage; - - // Determine Max Number Of Items To Display On Page - if( ( $offset + $perpage ) > $total_items ) { - $max_on_page = $total_items; - } else { - $max_on_page = ( $offset + $perpage ); - } - - // Determine Number Of Items To Display On Page - if ( ( $offset + 1 ) > $total_items ) { - $display_on_page = $total_items; - } else { - $display_on_page = ( $offset + 1 ); - } - - // Determing Total Amount Of Pages - $total_pages = ceil( $total_items / $perpage ); + $is_bookmark = false; + + // Checking $page, $offset, $perpage + if( empty($page) || $page == 0 ) { + $page = 1; + } + if( empty($offset) ) { + $offset = 0; + } + if( empty($perpage) || $perpage == 0) { + $perpage = 50; + } + + // Determine $offset + $offset = ( $page-1 ) * $perpage; + + // Determine Max Number Of Items To Display On Page + if( ( $offset + $perpage ) > $total_items ) { + $max_on_page = $total_items; + } else { + $max_on_page = ( $offset + $perpage ); + } + + // Determine Number Of Items To Display On Page + if ( ( $offset + 1 ) > $total_items ) { + $display_on_page = $total_items; + } else { + $display_on_page = ( $offset + 1 ); + } + + // Determine Total Amount Of Pages + $total_pages = ceil( $total_items / $perpage ); } @@ -241,12 +244,18 @@ yourls_do_action( 'admin_page_before_content' ); if ( !$is_bookmark ) { ?> -

-

%1$s to %2$s of %3$s URLs' ), $display_on_page, $max_on_page, $total_items ); - if( $total_items_clicks !== false ) - echo ", " . sprintf( yourls_n( 'counting 1 click', 'counting %s clicks', $total_items_clicks ), yourls_number_format_i18n( $total_items_clicks ) ); - ?>.

+

+

%1$s to %2$s of %3$s URLs' ), $display_on_page, $max_on_page, $total_items ); + if( $total_items_clicks !== false ) + echo ", " . sprintf( yourls_n( 'counting 1 click', 'counting %s clicks', $total_items_clicks ), yourls_number_format_i18n( $total_items_clicks ) ); + } + ?>.

%1$s links, %2$s clicks, and counting!' ), yourls_number_format_i18n( $total_urls ), yourls_number_format_i18n( $total_clicks ) ); ?>

$(document).ready(function(){ - feedback( "' . $return['message'] . '", "'. $return['status'] .'"); - init_clipboard(); - });'; + echo ''; } yourls_do_action( 'admin_page_before_table' ); @@ -270,42 +279,42 @@ yourls_table_head(); if ( !$is_bookmark ) { - $params = array( - 'search' => $search, - 'search_text' => $search_text, - 'search_in' => $search_in, - 'sort_by' => $sort_by, - 'sort_order' => $sort_order, - 'page' => $page, - 'perpage' => $perpage, - 'click_filter' => $click_filter, - 'click_limit' => $click_limit, - 'total_pages' => $total_pages, - 'date_filter' => $date_filter, - 'date_first' => $date_first, - 'date_second' => $date_second, - ); - yourls_html_tfooter( $params ); + $params = array( + 'search' => $search, + 'search_text' => $search_text, + 'search_in' => $search_in, + 'sort_by' => $sort_by, + 'sort_order' => $sort_order, + 'page' => $page, + 'perpage' => $perpage, + 'click_filter' => $click_filter, + 'click_limit' => $click_limit, + 'total_pages' => $total_pages, + 'date_filter' => $date_filter, + 'date_first' => $date_first, + 'date_second' => $date_second, + ); + yourls_html_tfooter( $params ); } yourls_table_tbody_start(); // Main Query $where = yourls_apply_filter( 'admin_list_where', $where ); -$url_results = yourls_get_db()->fetchObjects( "SELECT * FROM `$table_url` WHERE 1=1 ${where['sql']} ORDER BY `$sort_by` $sort_order LIMIT $offset, $perpage;", $where['binds'] ); +$url_results = yourls_get_db('read-admin_index')->fetchObjects( "SELECT * FROM `$table_url` WHERE 1=1 {$where['sql']} ORDER BY `$sort_by` $sort_order LIMIT $offset, $perpage;", $where['binds'] ); $found_rows = false; if( $url_results ) { - $found_rows = true; - foreach( $url_results as $url_result ) { - $keyword = yourls_sanitize_keyword($url_result->keyword); - $timestamp = strtotime( $url_result->timestamp ); - $url = stripslashes( $url_result->url ); - $ip = $url_result->ip; - $title = $url_result->title ? $url_result->title : ''; - $clicks = $url_result->clicks; - - echo yourls_table_add_row( $keyword, $url, $title, $ip, $clicks, $timestamp ); - } + $found_rows = true; + foreach( $url_results as $url_result ) { + $keyword = yourls_sanitize_keyword($url_result->keyword); + $timestamp = strtotime( $url_result->timestamp ); + $url = stripslashes( $url_result->url ); + $ip = $url_result->ip; + $title = $url_result->title ? $url_result->title : ''; + $clicks = $url_result->clicks; + + echo yourls_table_add_row( $keyword, $url, $title, $ip, $clicks, $timestamp ); + } } $display = $found_rows ? 'display:none' : ''; @@ -317,8 +326,10 @@ yourls_do_action( 'admin_page_after_table' ); +yourls_delete_link_modal(); + if ( $is_bookmark ) - yourls_share_box( $url, $return['shorturl'], $title, $text ); + yourls_share_box( $url, $return['shorturl'], $title, $text ); ?> diff --git a/admin/install.php b/admin/install.php index bb20ed4b3..3d4b99a1a 100644 --- a/admin/install.php +++ b/admin/install.php @@ -2,7 +2,6 @@ define( 'YOURLS_ADMIN', true ); define( 'YOURLS_INSTALLING', true ); require_once( dirname( __DIR__ ).'/includes/load-yourls.php' ); -require_once( YOURLS_INC.'/functions-install.php' ); $error = array(); $warning = array(); @@ -10,44 +9,44 @@ // Check pre-requisites if ( !yourls_check_PDO() ) { - $error[] = yourls__( 'PHP extension for PDO not found' ); - yourls_debug_log( 'PHP PDO extension not found' ); + $error[] = yourls__( 'PHP extension for PDO not found' ); + yourls_debug_log( 'PHP PDO extension not found' ); } if ( !yourls_check_database_version() ) { - $error[] = yourls_s( '%s version is too old. Ask your server admin for an upgrade.', 'MySQL' ); - yourls_debug_log( 'MySQL version: ' . yourls_get_database_version() ); + $error[] = yourls_s( '%s version is too old. Ask your server admin for an upgrade.', 'MySQL' ); + yourls_debug_log( 'MySQL version: ' . yourls_get_database_version() ); } if ( !yourls_check_php_version() ) { - $error[] = yourls_s( '%s version is too old. Ask your server admin for an upgrade.', 'PHP' ); - yourls_debug_log( 'PHP version: ' . PHP_VERSION ); + $error[] = yourls_s( '%s version is too old. Ask your server admin for an upgrade.', 'PHP' ); + yourls_debug_log( 'PHP version: ' . PHP_VERSION ); } // Is YOURLS already installed ? if ( yourls_is_installed() ) { - $error[] = yourls__( 'YOURLS already installed.' ); - // check if .htaccess exists, recreate otherwise. No error checking. - if( !file_exists( YOURLS_ABSPATH.'/.htaccess' ) ) { - yourls_create_htaccess(); - } + $error[] = yourls__( 'YOURLS already installed.' ); + // check if .htaccess exists, recreate otherwise. No error checking. + if( !file_exists( YOURLS_ABSPATH.'/.htaccess' ) ) { + yourls_create_htaccess(); + } } // Start install if possible and needed if ( isset($_REQUEST['install']) && count( $error ) == 0 ) { - // Create/update .htaccess file - if ( yourls_create_htaccess() ) { - $success[] = yourls__( 'File .htaccess successfully created/updated.' ); - } else { - $warning[] = yourls__( 'Could not write file .htaccess in YOURLS root directory. You will have to do it manually. See how.' ); - } + // Create/update .htaccess file + if ( yourls_create_htaccess() ) { + $success[] = yourls__( 'File .htaccess successfully created/updated.' ); + } else { + $warning[] = yourls__( 'Could not write file .htaccess in YOURLS root directory. You will have to do it manually. See how.' ); + } - // Create SQL tables - $install = yourls_create_sql_tables(); - if ( isset( $install['error'] ) ) - $error = array_merge( $error, $install['error'] ); - if ( isset( $install['success'] ) ) - $success = array_merge( $success, $install['success'] ); + // Create SQL tables + $install = yourls_create_sql_tables(); + if ( isset( $install['error'] ) ) + $error = array_merge( $error, $install['error'] ); + if ( isset( $install['success'] ) ) + $success = array_merge( $success, $install['success'] ); } @@ -55,30 +54,30 @@ yourls_html_head( 'install', yourls__( 'Install YOURLS' ) ); ?>
-
-

- -

- 0 ) { - echo "
    "; - foreach( $$info as $msg ) { - echo '
  • '.$msg."
  • \n"; - } - echo '
'; - } - } + +

+ +

+ 0 ) { + echo "
    "; + foreach( $$info as $msg ) { + echo '
  • '.$msg."
  • \n"; + } + echo '
'; + } + } - // Display install button or link to admin area if applicable - if( !yourls_is_installed() && !isset($_REQUEST['install']) ) { - echo '

'; - } else { - if( count($error) == 0 ) - echo '

» ' . yourls__( 'YOURLS Administration Page') . '

'; - } - ?> -
+ // Display install button or link to admin area if applicable + if( !yourls_is_installed() && !isset($_REQUEST['install']) ) { + echo '

'; + } else { + if( count($error) == 0 ) + echo '

» ' . yourls__( 'YOURLS Administration Page') . '

'; + } + ?> +
diff --git a/admin/plugins.php b/admin/plugins.php index 123f63080..8d02b96dd 100644 --- a/admin/plugins.php +++ b/admin/plugins.php @@ -5,54 +5,56 @@ // Handle plugin administration pages if( isset( $_GET['page'] ) && !empty( $_GET['page'] ) ) { - yourls_plugin_admin_page( $_GET['page'] ); + yourls_plugin_admin_page( $_GET['page'] ); die(); } // Handle activation/deactivation of plugins if( isset( $_GET['action'] ) ) { - // Check nonce - yourls_verify_nonce( 'manage_plugins', $_REQUEST['nonce'] ); - - // Check plugin file is valid - if( isset( $_GET['plugin'] ) && yourls_validate_plugin_file( YOURLS_PLUGINDIR.'/'.$_GET['plugin'].'/plugin.php') ) { - - // Activate / Deactive - switch( $_GET['action'] ) { - case 'activate': - $result = yourls_activate_plugin( $_GET['plugin'].'/plugin.php' ); - if( $result === true ) - yourls_redirect( yourls_admin_url( 'plugins.php?success=activated' ), 302 ); - - break; - - case 'deactivate': - $result = yourls_deactivate_plugin( $_GET['plugin'].'/plugin.php' ); - if( $result === true ) - yourls_redirect( yourls_admin_url( 'plugins.php?success=deactivated' ), 302 ); - - break; - - default: - $result = yourls__( 'Unsupported action' ); - break; - } - } else { - $result = yourls__( 'No plugin specified, or not a valid plugin' ); - } - - yourls_add_notice( $result ); + // Check nonce + yourls_verify_nonce( 'manage_plugins', $_REQUEST['nonce'] ?? ''); + + // Check plugin file is valid + if(isset( $_GET['plugin'] ) && yourls_is_a_plugin_file(YOURLS_PLUGINDIR . '/' . $_GET['plugin'] . '/plugin.php') ) { + + // Activate / Deactive + switch( $_GET['action'] ) { + case 'activate': + $result = yourls_activate_plugin( $_GET['plugin'].'/plugin.php' ); + if( $result === true ) { + yourls_redirect(yourls_admin_url('plugins.php?success=activated'), 302); + exit(); + } + break; + + case 'deactivate': + $result = yourls_deactivate_plugin( $_GET['plugin'].'/plugin.php' ); + if( $result === true ) { + yourls_redirect(yourls_admin_url('plugins.php?success=deactivated'), 302); + exit(); + } + break; + + default: + $result = yourls__( 'Unsupported action' ); + break; + } + } else { + $result = yourls__( 'No plugin specified, or not a valid plugin' ); + } + + yourls_add_notice( $result ); } -// Handle message upon succesfull (de)activation +// Handle message upon successful (de)activation if( isset( $_GET['success'] ) && ( ( $_GET['success'] == 'activated' ) OR ( $_GET['success'] == 'deactivated' ) ) ) { - if( $_GET['success'] == 'activated' ) { - $message = yourls__( 'Plugin has been activated' ); - } elseif ( $_GET['success'] == 'deactivated' ) { - $message = yourls__( 'Plugin has been deactivated' ); - } - yourls_add_notice( $message ); + if( $_GET['success'] == 'activated' ) { + $message = yourls__( 'Plugin has been activated' ); + } elseif ( $_GET['success'] == 'deactivated' ) { + $message = yourls__( 'Plugin has been deactivated' ); + } + yourls_add_notice( $message ); } yourls_html_head( 'plugins', yourls__( 'Manage Plugins' ) ); @@ -60,106 +62,110 @@ yourls_html_menu(); ?> -
-

- - - -

%1$s installed, and %2$s activated', $plugins_count, $count_active ); ?>

- - - - - - - - - - - - - $plugin ) { - - // default fields to read from the plugin header - $fields = array( - 'name' => 'Plugin Name', - 'uri' => 'Plugin URI', - 'desc' => 'Description', - 'version' => 'Version', - 'author' => 'Author', - 'author_uri' => 'Author URI' - ); - - // Loop through all default fields, get value if any and reset it - foreach( $fields as $field=>$value ) { - if( isset( $plugin[ $value ] ) ) { - $data[ $field ] = $plugin[ $value ]; - } else { - $data[ $field ] = yourls__('(no info)'); - } - unset( $plugin[$value] ); - } - - $plugindir = trim( dirname( $file ), '/' ); - - if( yourls_is_active_plugin( $file ) ) { - $class = 'active'; - $action_url = yourls_nonce_url( 'manage_plugins', yourls_add_query_arg( array('action' => 'deactivate', 'plugin' => $plugindir ), yourls_admin_url('plugins.php') ) ); - $action_anchor = yourls__( 'Deactivate' ); - } else { - $class = 'inactive'; - $action_url = yourls_nonce_url( 'manage_plugins', yourls_add_query_arg( array('action' => 'activate', 'plugin' => $plugindir ), yourls_admin_url('plugins.php') ) ); - $action_anchor = yourls__( 'Activate' ); - } - - // Other "Fields: Value" in the header? Get them too - if( $plugin ) { - foreach( $plugin as $extra_field=>$extra_value ) { - $data['desc'] .= "
\n$extra_field: $extra_value"; - unset( $plugin[$extra_value] ); - } - } - - $data['desc'] .= '
' . yourls_s( 'plugin file location: %s', $file) . ''; - - printf( "", - $class, $data['uri'], $data['name'], $data['version'], $data['desc'], $data['author_uri'], $data['author'], $action_url, $action_anchor - ); - - } - ?> - -
%s%s%s%s%s
- - - -

plugin.php.' ); ?>

- -

- -

Plugin list.' ); ?>

-
+
+

+ + + +

%1$s installed, and %2$s activated', $plugins_count, $count_active ); ?>

+ + + + + + + + + + + + + $plugin ) { + + // default fields to read from the plugin header + $fields = array( + 'name' => 'Plugin Name', + 'uri' => 'Plugin URI', + 'desc' => 'Description', + 'version' => 'Version', + 'author' => 'Author', + 'author_uri' => 'Author URI' + ); + + // Loop through all default fields, get value if any and reset it + foreach( $fields as $field=>$value ) { + if( isset( $plugin[ $value ] ) ) { + $data[ $field ] = $plugin[ $value ]; + } else { + $data[ $field ] = yourls__('(no info)'); + # If it's a URL, set to # + if( in_array( $field, array('uri', 'author_uri') ) ) { + $data[$field] = '#' . $data[$field]; + } + } + unset( $plugin[$value] ); + } + + $plugindir = trim( dirname( $file ), '/' ); + + if( yourls_is_active_plugin( $file ) ) { + $class = 'active'; + $action_url = yourls_nonce_url( 'manage_plugins', yourls_add_query_arg( array('action' => 'deactivate', 'plugin' => $plugindir ), yourls_admin_url('plugins.php') ) ); + $action_anchor = yourls__( 'Deactivate' ); + } else { + $class = 'inactive'; + $action_url = yourls_nonce_url( 'manage_plugins', yourls_add_query_arg( array('action' => 'activate', 'plugin' => $plugindir ), yourls_admin_url('plugins.php') ) ); + $action_anchor = yourls__( 'Activate' ); + } + + // Other "Fields: Value" in the header? Get them too + if( $plugin ) { + foreach( $plugin as $extra_field=>$extra_value ) { + $data['desc'] .= "
\n$extra_field: $extra_value"; + unset( $plugin[$extra_value] ); + } + } + + $data['desc'] .= '
' . yourls_s( 'plugin file location: %s', $file) . ''; + + printf( "", + $class, $data['uri'], $data['name'], $data['version'], $data['desc'], $data['author_uri'], $data['author'], $action_url, $action_anchor + ); + + } + ?> + +
%s%s%s%s%s
+ + + +

plugin.php.' ); ?>

+ +

+ +

Plugin list.' ); ?>

+
diff --git a/admin/tools.php b/admin/tools.php index accb8c19f..b77206169 100644 --- a/admin/tools.php +++ b/admin/tools.php @@ -8,49 +8,49 @@ yourls_html_menu(); ?> -
+
-

+

-

bookmarklets for easier link shortening and sharing.' ); ?>

+

bookmarklets for easier link shortening and sharing.' ); ?>

-

+

-
    -
  • Standard Bookmarklets will take you to a page where you can easily edit or delete your brand new short URL.' ); ?>
  • +
      +
    • Standard Bookmarklets will take you to a page where you can easily edit or delete your brand new short URL.' ); ?>
    • -
    • Instant Bookmarklets will pop the short URL without leaving the page you are viewing (depending on the page and server configuration, they may silently fail)' ); ?>
    • +
    • Instant Bookmarklets will pop the short URL without leaving the page you are viewing (depending on the page and server configuration, they may silently fail)' ); ?>
    • -
    • Simple Bookmarklets will generate a short URL with a random or sequential keyword.' ); ?>
    • +
    • Simple Bookmarklets will generate a short URL with a random or sequential keyword.' ); ?>
    • -
    • Custom Keyword Bookmarklets will prompt you for a custom keyword first.' ); ?>
    • -
    +
  • Custom Keyword Bookmarklets will prompt you for a custom keyword first.' ); ?>
  • +
-

select text on the page you're viewing before clicking on your bookmarklet link" ); - ?>

+

select text on the page you're viewing before clicking on your bookmarklet link" ); + ?>

Important Note: bookmarklets may fail on websites with https, especially the "Instant" bookrmarklets. There is nothing you can do about this.'); ?>

-

+

-

+

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

+

-

-

+

+

-

+

- + -

+

-

+

-

%s\" to the beginning of the current URL (right before its 'http://' part) and hit enter.", preg_replace('@https?://@', '', yourls_get_yourls_site()) . '/' ); ?>

+

%s\" to the beginning of the current URL (right before its 'http://' part) and hit enter.", preg_replace('@https?://@', '', yourls_get_yourls_site()) . '/' ); ?>

-

.

+

.

- + -

+

-

username and password parameters.' ); - echo "\n"; - yourls_e( "If you're worried about sending your credentials into the wild, you can also make API calls without using your login or your password, using a secret signature token." ); - ?>

+

username and password parameters.' ); + echo "\n"; + yourls_e( "If you're worried about sending your credentials into the wild, you can also make API calls without using your login or your password, using a secret signature token." ); + ?>

-

%s', yourls_auth_signature() ); ?> +

%s', yourls_auth_signature() ); ?>

-

+

-
    -
  • -

    signature in your API requests. Example:' ); ?>

    -

    /yourls-api.php?signature=&action=...

    -
  • +
      +
    • +

      signature in your API requests. Example:' ); ?>

      +

      /yourls-api.php?signature=&action=...

      +
    • -
    • +
    • <?php
       $timestamp = time();
       //  $time = 
      @@ -322,19 +322,19 @@
       //  $signature = ""
       ?>
       
      -

      signature and timestamp in your API requests. Example:' ); ?>

      -

      /yourls-api.php?timestamp=$timestamp&signature=$signature&action=...

      -


      - /yourls-api.php?timestamp=&signature=&action=...

      -

      -
    • -
    +

    signature and timestamp in your API requests. Example:' ); ?>

    +

    /yourls-api.php?timestamp=$timestamp&signature=$signature&action=...

    +


    + /yourls-api.php?timestamp=&signature=&action=...

    +

    + +
-

Passwordless API page on the wiki.', 'https://yourls.org/passwordlessapi' ); ?> - API documentation for more', yourls_get_yourls_site() . '/readme.html#API' ); ?>

+

Passwordless API page on the wiki.', 'https://yourls.org/passwordlessapi' ); ?> + API documentation for more', yourls_get_yourls_site() . '/readme.html#API' ); ?>

-
+
- + diff --git a/admin/upgrade.php b/admin/upgrade.php index 81333244b..957870cda 100644 --- a/admin/upgrade.php +++ b/admin/upgrade.php @@ -2,81 +2,79 @@ define( 'YOURLS_ADMIN', true ); define( 'YOURLS_UPGRADING', true ); require_once( dirname( __DIR__ ).'/includes/load-yourls.php' ); -require_once( YOURLS_INC.'/functions-upgrade.php' ); -require_once( YOURLS_INC.'/functions-install.php' ); yourls_maybe_require_auth(); yourls_html_head( 'upgrade', yourls__( 'Upgrade YOURLS' ) ); yourls_html_logo(); yourls_html_menu(); ?> -

+

' . yourls_s( 'Upgrade not required. Go back to play!', yourls_admin_url('index.php') ) . '

'; + echo '

' . yourls_s( 'Upgrade not required. Go back to play!', yourls_admin_url('index.php') ) . '

'; } else { - /* - step 1: create new tables and populate them, update old tables structure, - step 2: convert each row of outdated tables if needed - step 3: - if applicable finish updating outdated tables (indexes etc) - - update version & db_version in options, this is all done! - */ + /* + step 1: create new tables and populate them, update old tables structure, + step 2: convert each row of outdated tables if needed + step 3: - if applicable finish updating outdated tables (indexes etc) + - update version & db_version in options, this is all done! + */ - // From what are we upgrading? - if ( isset( $_GET['oldver'] ) && isset( $_GET['oldsql'] ) ) { - $oldver = yourls_sanitize_version($_GET['oldver']); - $oldsql = (intval)($_GET['oldsql']); - } else { - list( $oldver, $oldsql ) = yourls_get_current_version_from_sql(); - } + // From what are we upgrading? + if ( isset( $_GET['oldver'] ) && isset( $_GET['oldsql'] ) ) { + $oldver = yourls_sanitize_version($_GET['oldver']); + $oldsql = intval($_GET['oldsql']); + } else { + list( $oldver, $oldsql ) = yourls_get_current_version_from_sql(); + } - // To what are we upgrading ? - $newver = YOURLS_VERSION; - $newsql = YOURLS_DB_VERSION; + // To what are we upgrading ? + $newver = YOURLS_VERSION; + $newsql = YOURLS_DB_VERSION; - // Verbose & ugly details - yourls_debug_mode(true); + // Verbose & ugly details + yourls_debug_mode(true); - // Let's go - $step = ( isset( $_GET['step'] ) ? intval( $_GET['step'] ) : 0 ); - switch( $step ) { + // Let's go + $step = ( isset( $_GET['step'] ) ? intval( $_GET['step'] ) : 0 ); + switch( $step ) { - default: - case 0: - ?> -

-

backup your database
(you should do this regularly anyway)' ); ?>

-

should happen, but this doesn't mean it won't happen, right? ;)" ); ?>

-

something goes wrong, you'll see a message and hopefully a way to fix." ); ?>

-

good for you, let it go :)' ); ?>

-

- - - - - - - - "; + default: + case 0: + ?> +

+

backup your database
(you should do this regularly anyway)' ); ?>

+

should happen, but this doesn't mean it won't happen, right? ;)" ); ?>

+

something goes wrong, you'll see a message and hopefully a way to fix." ); ?>

+

good for you, let it go :)' ); ?>

+

+ + + + + + + + "; - break; + break; - case 1: - case 2: - $upgrade = yourls_upgrade( $step, $oldver, $newver, $oldsql, $newsql ); - break; + case 1: + case 2: + $upgrade = yourls_upgrade( $step, $oldver, $newver, $oldsql, $newsql ); + break; - case 3: - $upgrade = yourls_upgrade( 3, $oldver, $newver, $oldsql, $newsql ); - echo '

' . yourls__( 'Your installation is now up to date ! ' ) . '

'; - echo '

' . yourls_s( 'Go back to the admin interface', yourls_admin_url('index.php') ) . '

'; - } + case 3: + $upgrade = yourls_upgrade( 3, $oldver, $newver, $oldsql, $newsql ); + echo '

' . yourls__( 'Your installation is now up to date ! ' ) . '

'; + echo '

' . yourls_s( 'Go back to the admin interface', yourls_admin_url('index.php') ) . '

'; + } } diff --git a/composer.json b/composer.json index 878baf42f..b77e8abb6 100644 --- a/composer.json +++ b/composer.json @@ -16,21 +16,31 @@ "source": "https://github.com/YOURLS/YOURLS" }, "require": { - "php": ">=7.2", + "php": "^8.1", + "ext-dom": "*", + "ext-filter": "*", + "ext-hash": "*", + "ext-pcre": "*", "ext-pdo": "*", - "ozh/bookmarkletgen": "1.2", - "ozh/phpass": "1.3.0", - "rmccue/requests" : "1.8.0", - "pomo/pomo" : "1.4.1", - "geoip2/geoip2" : "2.10.0", - "aura/sql": "~3.", - "jakeasmith/http_build_url": "1.0.1", - "symfony/polyfill-mbstring": "1.15.0", + "ext-pdo_mysql": "*", + "ozh/bookmarkletgen": "^1.2", + "rmccue/requests" : "^2.0", + "pomo/pomo" : "^1.4", + "geoip2/geoip2" : "^2.10", + "aura/sql": "^6.0", + "jakeasmith/http_build_url": "^1.0", + "symfony/polyfill-mbstring": "^1.15", "symfony/polyfill-intl-idn": "^1.17", - "spatie/array-to-xml": "^2.14" + "spatie/array-to-xml": "^3.4" + }, + "require-dev": { + "ext-ctype": "*" }, "config": { - "vendor-dir": "includes/vendor" + "vendor-dir": "includes/vendor", + "platform": { + "php": "8.1.0" + } }, "autoload": { "psr-4": { @@ -38,8 +48,15 @@ } }, "suggest": { + "ext-bcmath": "May be needed to read GeoIP database (or ext-gmp)", + "ext-curl": "Required for API usage", + "ext-gmp": "May be needed to read GeoIP database (or ext-bcmath)", + "ext-iconv": "For safer input handling", + "ext-json": "For faster API performance", "ext-mbstring": "For best performance", - "ext-curl": "Required for API usage" + "ext-openssl": "To fetch titles from HTTPS sites", + "ext-posix": "May be needed on certain PHP versions", + "ext-zlib": "For best performance" }, "scripts": { "post-update-cmd": "bash ./includes/vendor/build-script/yourls-build.sh ./includes/vendor" diff --git a/composer.lock b/composer.lock index 8bd14a671..27941b6f7 100644 --- a/composer.lock +++ b/composer.lock @@ -4,29 +4,30 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "70ceb8b1bf58da7e97bc5988e9b04f97", + "content-hash": "50804e4ad6386df5b147be4320a067e3", "packages": [ { "name": "aura/sql", - "version": "3.0.0", + "version": "6.0.0", "source": { "type": "git", "url": "https://github.com/auraphp/Aura.Sql.git", - "reference": "2be02d5dfd9fdee6df199de1a19572aa490bb744" + "reference": "8e2bb362e8953198df3682c9122e8b9edab5ff20" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/auraphp/Aura.Sql/zipball/2be02d5dfd9fdee6df199de1a19572aa490bb744", - "reference": "2be02d5dfd9fdee6df199de1a19572aa490bb744", + "url": "https://api.github.com/repos/auraphp/Aura.Sql/zipball/8e2bb362e8953198df3682c9122e8b9edab5ff20", + "reference": "8e2bb362e8953198df3682c9122e8b9edab5ff20", "shasum": "" }, "require": { - "php": ">=5.6.0", - "psr/log": "^1.0" + "ext-pdo": "*", + "php": "^8.4", + "psr/log": "^1.0 || ^2.0 || ^3.0" }, "require-dev": { "pds/skeleton": "~1.0", - "phpunit/phpunit": "~5.0" + "phpunit/phpunit": "^9.5" }, "type": "library", "autoload": { @@ -59,34 +60,34 @@ ], "support": { "issues": "https://github.com/auraphp/Aura.Sql/issues", - "source": "https://github.com/auraphp/Aura.Sql/tree/3.x" + "source": "https://github.com/auraphp/Aura.Sql/tree/6.0.0" }, - "time": "2018-06-11T12:57:42+00:00" + "time": "2025-01-22T06:43:21+00:00" }, { "name": "composer/ca-bundle", - "version": "1.2.9", + "version": "1.5.5", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5" + "reference": "08c50d5ec4c6ced7d0271d2862dec8c1033283e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/78a0e288fdcebf92aa2318a8d3656168da6ac1a5", - "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/08c50d5ec4c6ced7d0271d2862dec8c1033283e6", + "reference": "08c50d5ec4c6ced7d0271d2862dec8c1033283e6", "shasum": "" }, "require": { "ext-openssl": "*", "ext-pcre": "*", - "php": "^5.3.2 || ^7.0 || ^8.0" + "php": "^7.2 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^0.12.55", - "psr/log": "^1.0", - "symfony/phpunit-bridge": "^4.2 || ^5", - "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8 || ^9", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" }, "type": "library", "extra": { @@ -121,7 +122,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.2.9" + "source": "https://github.com/composer/ca-bundle/tree/1.5.5" }, "funding": [ { @@ -137,31 +138,32 @@ "type": "tidelift" } ], - "time": "2021-01-12T12:10:35+00:00" + "time": "2025-01-08T16:17:16+00:00" }, { "name": "geoip2/geoip2", - "version": "v2.10.0", + "version": "v2.13.0", "source": { "type": "git", "url": "https://github.com/maxmind/GeoIP2-php.git", - "reference": "419557cd21d9fe039721a83490701a58c8ce784a" + "reference": "6a41d8fbd6b90052bc34dff3b4252d0f88067b23" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maxmind/GeoIP2-php/zipball/419557cd21d9fe039721a83490701a58c8ce784a", - "reference": "419557cd21d9fe039721a83490701a58c8ce784a", + "url": "https://api.github.com/repos/maxmind/GeoIP2-php/zipball/6a41d8fbd6b90052bc34dff3b4252d0f88067b23", + "reference": "6a41d8fbd6b90052bc34dff3b4252d0f88067b23", "shasum": "" }, "require": { "ext-json": "*", - "maxmind-db/reader": "~1.5", - "maxmind/web-service-common": "~0.6", - "php": ">=5.6" + "maxmind-db/reader": "~1.8", + "maxmind/web-service-common": "~0.8", + "php": ">=7.2" }, "require-dev": { - "friendsofphp/php-cs-fixer": "2.*", - "phpunit/phpunit": "5.*", + "friendsofphp/php-cs-fixer": "3.*", + "phpstan/phpstan": "*", + "phpunit/phpunit": "^8.0 || ^9.0", "squizlabs/php_codesniffer": "3.*" }, "type": "library", @@ -192,9 +194,9 @@ ], "support": { "issues": "https://github.com/maxmind/GeoIP2-php/issues", - "source": "https://github.com/maxmind/GeoIP2-php/tree/master" + "source": "https://github.com/maxmind/GeoIP2-php/tree/v2.13.0" }, - "time": "2019-12-12T18:48:39+00:00" + "time": "2022-08-05T20:32:58+00:00" }, { "name": "jakeasmith/http_build_url", @@ -235,28 +237,27 @@ }, { "name": "maxmind-db/reader", - "version": "v1.9.0", + "version": "v1.12.0", "source": { "type": "git", "url": "https://github.com/maxmind/MaxMind-DB-Reader-php.git", - "reference": "9ee9ba9ee287b119e9f5a8e8dbfea0b49647cec4" + "reference": "5b2d7a721dedfaef9dc20822c5fe7d26f9f8eb90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/9ee9ba9ee287b119e9f5a8e8dbfea0b49647cec4", - "reference": "9ee9ba9ee287b119e9f5a8e8dbfea0b49647cec4", + "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/5b2d7a721dedfaef9dc20822c5fe7d26f9f8eb90", + "reference": "5b2d7a721dedfaef9dc20822c5fe7d26f9f8eb90", "shasum": "" }, "require": { "php": ">=7.2" }, "conflict": { - "ext-maxminddb": "<1.9.0,>=2.0.0" + "ext-maxminddb": "<1.11.1 || >=2.0.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "*", - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpcov": ">=6.0.0", + "friendsofphp/php-cs-fixer": "3.*", + "phpstan/phpstan": "*", "phpunit/phpunit": ">=8.0.0,<10.0.0", "squizlabs/php_codesniffer": "3.*" }, @@ -293,32 +294,33 @@ ], "support": { "issues": "https://github.com/maxmind/MaxMind-DB-Reader-php/issues", - "source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.9.0" + "source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.12.0" }, - "time": "2021-01-07T21:15:29+00:00" + "time": "2024-11-14T22:43:47+00:00" }, { "name": "maxmind/web-service-common", - "version": "v0.8.1", + "version": "v0.10.0", "source": { "type": "git", "url": "https://github.com/maxmind/web-service-common-php.git", - "reference": "32f274051c543fc865e5a84d3a2c703913641ea8" + "reference": "d7c7c42fc31bff26e0ded73a6e187bcfb193f9c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maxmind/web-service-common-php/zipball/32f274051c543fc865e5a84d3a2c703913641ea8", - "reference": "32f274051c543fc865e5a84d3a2c703913641ea8", + "url": "https://api.github.com/repos/maxmind/web-service-common-php/zipball/d7c7c42fc31bff26e0ded73a6e187bcfb193f9c4", + "reference": "d7c7c42fc31bff26e0ded73a6e187bcfb193f9c4", "shasum": "" }, "require": { "composer/ca-bundle": "^1.0.3", "ext-curl": "*", "ext-json": "*", - "php": ">=7.2" + "php": ">=8.1" }, "require-dev": { - "friendsofphp/php-cs-fixer": "2.*", + "friendsofphp/php-cs-fixer": "3.*", + "phpstan/phpstan": "*", "phpunit/phpunit": "^8.0 || ^9.0", "squizlabs/php_codesniffer": "3.*" }, @@ -343,26 +345,26 @@ "homepage": "https://github.com/maxmind/web-service-common-php", "support": { "issues": "https://github.com/maxmind/web-service-common-php/issues", - "source": "https://github.com/maxmind/web-service-common-php/tree/v0.8.1" + "source": "https://github.com/maxmind/web-service-common-php/tree/v0.10.0" }, - "time": "2020-11-02T17:00:53+00:00" + "time": "2024-11-14T23:14:52+00:00" }, { "name": "ozh/bookmarkletgen", - "version": "1.2", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/ozh/bookmarkletgen.git", - "reference": "3319b53c493a1474a03d1cc4e087617652284c20" + "reference": "65fffa64bb11f70470d398d7baf6d9bb84411cfc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ozh/bookmarkletgen/zipball/3319b53c493a1474a03d1cc4e087617652284c20", - "reference": "3319b53c493a1474a03d1cc4e087617652284c20", + "url": "https://api.github.com/repos/ozh/bookmarkletgen/zipball/65fffa64bb11f70470d398d7baf6d9bb84411cfc", + "reference": "65fffa64bb11f70470d398d7baf6d9bb84411cfc", "shasum": "" }, "require": { - "php": ">=5.3" + "php": ">=7.2" }, "type": "library", "autoload": { @@ -388,81 +390,30 @@ ], "support": { "issues": "https://github.com/ozh/bookmarkletgen/issues", - "source": "https://github.com/ozh/bookmarkletgen/tree/master" - }, - "time": "2017-05-18T12:46:21+00:00" - }, - { - "name": "ozh/phpass", - "version": "1.3.0", - "source": { - "type": "git", - "url": "https://github.com/ozh/phpass.git", - "reference": "44149d1ee06ccbda397f08f69d32c59802e4ce43" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ozh/phpass/zipball/44149d1ee06ccbda397f08f69d32c59802e4ce43", - "reference": "44149d1ee06ccbda397f08f69d32c59802e4ce43", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "phpunit/phpunit": ">=4.0" - }, - "type": "library", - "autoload": { - "psr-0": { - "Ozh\\Phpass\\": "src/" - } + "source": "https://github.com/ozh/bookmarkletgen/tree/1.2.2" }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Public Domain" - ], - "authors": [ - { - "name": "Solar Designer", - "email": "solar@openwall.com", - "homepage": "http://openwall.com/phpass/" - } - ], - "description": "Portable PHP password hashing framework", - "homepage": "http://github.com/ozh/phpass/", - "keywords": [ - "blowfish", - "crypt", - "password", - "security" - ], - "support": { - "issues": "https://github.com/ozh/phpass/issues", - "source": "https://github.com/ozh/phpass/tree/1.3.0" - }, - "time": "2020-03-29T10:39:31+00:00" + "time": "2022-05-04T13:05:16+00:00" }, { "name": "pomo/pomo", - "version": "v1.4.1", + "version": "v1.5.0", "source": { "type": "git", "url": "https://github.com/LeoColomb/pomo.git", - "reference": "1594bd1f90c89a45ffc3da2ee6d5d582bfac7542" + "reference": "b1e53a997850496369634d574fa6b508091fc353" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/LeoColomb/pomo/zipball/1594bd1f90c89a45ffc3da2ee6d5d582bfac7542", - "reference": "1594bd1f90c89a45ffc3da2ee6d5d582bfac7542", + "url": "https://api.github.com/repos/LeoColomb/pomo/zipball/b1e53a997850496369634d574fa6b508091fc353", + "reference": "b1e53a997850496369634d574fa6b508091fc353", "shasum": "" }, "require": { "php": ">=5.3.0" }, "require-dev": { - "phpunit/phpunit": ">=4.0", - "squizlabs/php_codesniffer": "^3.0 || ^2.9.1" + "phpunit/phpunit": "^4.0 || ^7.0", + "squizlabs/php_codesniffer": "^3.0" }, "type": "library", "autoload": { @@ -486,7 +437,7 @@ "role": "Maintainer" } ], - "description": "Gettext library to translate with I18n", + "description": "Gettext library to translate with i18n", "homepage": "https://github.com/LeoColomb/pomo", "keywords": [ "gettext", @@ -497,36 +448,46 @@ ], "support": { "issues": "https://github.com/LeoColomb/pomo/issues", - "source": "https://github.com/LeoColomb/pomo/tree/master" + "source": "https://github.com/LeoColomb/pomo/tree/v1.5.0" }, - "time": "2018-12-20T14:55:38+00:00" + "funding": [ + { + "url": "https://github.com/LeoColomb", + "type": "github" + }, + { + "url": "https://www.patreon.com/LeoColomb", + "type": "patreon" + } + ], + "time": "2023-01-06T01:05:43+00:00" }, { "name": "psr/log", - "version": "1.1.3", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", - "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=8.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "3.x-dev" } }, "autoload": { "psr-4": { - "Psr\\Log\\": "Psr/Log/" + "Psr\\Log\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -536,7 +497,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for logging libraries", @@ -547,42 +508,56 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/1.1.3" + "source": "https://github.com/php-fig/log/tree/3.0.2" }, - "time": "2020-03-23T09:12:05+00:00" + "time": "2024-09-11T13:17:53+00:00" }, { "name": "rmccue/requests", - "version": "v1.8.0", + "version": "v2.0.15", "source": { "type": "git", "url": "https://github.com/WordPress/Requests.git", - "reference": "afbe4790e4def03581c4a0963a1e8aa01f6030f1" + "reference": "877cd66169755899682f1595e057334b40d9d149" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/WordPress/Requests/zipball/afbe4790e4def03581c4a0963a1e8aa01f6030f1", - "reference": "afbe4790e4def03581c4a0963a1e8aa01f6030f1", + "url": "https://api.github.com/repos/WordPress/Requests/zipball/877cd66169755899682f1595e057334b40d9d149", + "reference": "877cd66169755899682f1595e057334b40d9d149", "shasum": "" }, "require": { - "php": ">=5.2" + "ext-json": "*", + "php": ">=5.6" }, "require-dev": { "dealerdirect/phpcodesniffer-composer-installer": "^0.7", "php-parallel-lint/php-console-highlighter": "^0.5.0", - "php-parallel-lint/php-parallel-lint": "^1.3", + "php-parallel-lint/php-parallel-lint": "^1.3.1", "phpcompatibility/php-compatibility": "^9.0", - "phpunit/phpunit": "^4.8 || ^5.7 || ^6.5 || ^7.5", - "requests/test-server": "dev-master", - "squizlabs/php_codesniffer": "^3.5", - "wp-coding-standards/wpcs": "^2.0" + "requests/test-server": "dev-main", + "roave/security-advisories": "dev-latest", + "squizlabs/php_codesniffer": "^3.6", + "wp-coding-standards/wpcs": "^2.0", + "yoast/phpunit-polyfills": "^1.0.0" + }, + "suggest": { + "art4/requests-psr18-adapter": "For using Requests as a PSR-18 HTTP Client", + "ext-curl": "For improved performance", + "ext-openssl": "For secure transport support", + "ext-zlib": "For improved performance when decompressing encoded streams" }, "type": "library", "autoload": { - "psr-0": { - "Requests": "library/" - } + "files": [ + "library/Deprecated.php" + ], + "psr-4": { + "WpOrg\\Requests\\": "src/" + }, + "classmap": [ + "library/Requests.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -591,11 +566,23 @@ "authors": [ { "name": "Ryan McCue", - "homepage": "http://ryanmccue.info" + "homepage": "https://rmccue.io/" + }, + { + "name": "Alain Schlesser", + "homepage": "https://github.com/schlessera" + }, + { + "name": "Juliette Reinders Folmer", + "homepage": "https://github.com/jrfnl" + }, + { + "name": "Contributors", + "homepage": "https://github.com/WordPress/Requests/graphs/contributors" } ], "description": "A HTTP library written in PHP, for human beings.", - "homepage": "http://github.com/WordPress/Requests", + "homepage": "https://requests.ryanmccue.info/", "keywords": [ "curl", "fsockopen", @@ -606,35 +593,41 @@ "sockets" ], "support": { + "docs": "https://requests.ryanmccue.info/", "issues": "https://github.com/WordPress/Requests/issues", - "source": "https://github.com/WordPress/Requests/tree/v1.8.0" + "source": "https://github.com/WordPress/Requests" }, - "time": "2021-04-27T11:05:25+00:00" + "time": "2025-01-21T10:13:31+00:00" }, { "name": "spatie/array-to-xml", - "version": "2.15.0", + "version": "3.4.4", "source": { "type": "git", "url": "https://github.com/spatie/array-to-xml.git", - "reference": "1795afad4e5a1f4b7af2e0e09802550eaa00a6f8" + "reference": "88b2f3852a922dd73177a68938f8eb2ec70c7224" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/1795afad4e5a1f4b7af2e0e09802550eaa00a6f8", - "reference": "1795afad4e5a1f4b7af2e0e09802550eaa00a6f8", + "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/88b2f3852a922dd73177a68938f8eb2ec70c7224", + "reference": "88b2f3852a922dd73177a68938f8eb2ec70c7224", "shasum": "" }, "require": { "ext-dom": "*", - "php": "^7.2" + "php": "^8.0" }, "require-dev": { - "mockery/mockery": "^1.0", - "phpunit/phpunit": "^8.0", - "spatie/phpunit-snapshot-assertions": "^2.0" + "mockery/mockery": "^1.2", + "pestphp/pest": "^1.21", + "spatie/pest-plugin-snapshots": "^1.1" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, "autoload": { "psr-4": { "Spatie\\ArrayToXml\\": "src" @@ -648,7 +641,7 @@ { "name": "Freek Van der Herten", "email": "freek@spatie.be", - "homepage": "https://murze.be", + "homepage": "https://freek.dev", "role": "Developer" } ], @@ -660,50 +653,55 @@ "xml" ], "support": { - "issues": "https://github.com/spatie/array-to-xml/issues", - "source": "https://github.com/spatie/array-to-xml/tree/2.15.0" + "source": "https://github.com/spatie/array-to-xml/tree/3.4.4" }, - "time": "2020-10-29T18:11:03+00:00" + "funding": [ + { + "url": "https://spatie.be/open-source/support-us", + "type": "custom" + }, + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2025-12-15T09:00:41+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.22.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "0eb8293dbbcd6ef6bf81404c9ce7d95bcdf34f44" + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/0eb8293dbbcd6ef6bf81404c9ce7d95bcdf34f44", - "reference": "0eb8293dbbcd6ef6bf81404c9ce7d95bcdf34f44", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773", + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773", "shasum": "" }, "require": { - "php": ">=7.1", - "symfony/polyfill-intl-normalizer": "^1.10", - "symfony/polyfill-php72": "^1.10" + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" }, "suggest": { "ext-intl": "For best performance" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.22-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Idn\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -734,7 +732,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0" }, "funding": [ { @@ -750,45 +748,42 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.22.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "6e971c891537eb617a00bb07a43d182a6915faba" + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/6e971c891537eb617a00bb07a43d182a6915faba", - "reference": "6e971c891537eb617a00bb07a43d182a6915faba", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.22-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -818,7 +813,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" }, "funding": [ { @@ -834,41 +829,45 @@ "type": "tidelift" } ], - "time": "2021-01-07T17:09:11+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.15.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac" + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/81ffd3a9c6d707be22e3012b827de1c9775fc5ac", - "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" }, "suggest": { "ext-mbstring": "For best performance" }, "type": "library", "extra": { - "branch-alias": { - "dev-master": "1.15-dev" + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -894,83 +893,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.15.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": "2020-03-09T19:04:49+00:00" - }, - { - "name": "symfony/polyfill-php72", - "version": "v1.22.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", - "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.22-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php72\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" }, "funding": [ { @@ -986,19 +909,29 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2024-09-09T11:45:10+00:00" } ], "packages-dev": [], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=7.2", - "ext-pdo": "*" + "php": "^8.1", + "ext-dom": "*", + "ext-filter": "*", + "ext-hash": "*", + "ext-pcre": "*", + "ext-pdo": "*", + "ext-pdo_mysql": "*" + }, + "platform-dev": { + "ext-ctype": "*" + }, + "platform-overrides": { + "php": "8.1" }, - "platform-dev": [], - "plugin-api-version": "2.0.0" + "plugin-api-version": "2.6.0" } diff --git a/css/style.css b/css/style.css index d7f50d971..1f108417d 100644 --- a/css/style.css +++ b/css/style.css @@ -18,8 +18,6 @@ body { border-right:3px solid #2a85b3; border-bottom:3px solid #2a85b3; border-top:3px solid #2a85b3; - -moz-border-radius:20px; - -webkit-border-radius:20px; border-radius:20px; } .hide-if-no-js {display: none;} @@ -68,8 +66,6 @@ tt { } input, textarea { - -moz-border-radius:3px; - -webkit-border-radius:3px; border-radius:3px; } Input.text, select, textarea { @@ -129,8 +125,11 @@ tr.edit-row td { td.url small a{ color:#bbc; } -body.desktop td.actions input,body.desktop td.actions a { - visibility:hidden; +/* Hide buttons visually but keep them accessible to screen readers */ +body.desktop td.actions input, body.desktop td.actions a { + opacity: 0; + pointer-events: none; + transition: opacity 0.2s ease; } td.timestamp span.timestamp { display:none; @@ -138,8 +137,20 @@ td.timestamp span.timestamp { td.actions input.disabled, td.actions input.loading { visibility:visible; } +/* Show buttons on row hover */ tr:hover td.actions input, tr:hover td.actions a { - visibility:visible; + opacity: 1; + pointer-events: auto; +} +/* Show buttons when any button in the actions cell receives focus */ +td.actions:focus-within input, td.actions:focus-within a { + opacity: 1; + pointer-events: auto; +} +/* Show all buttons when any element in the row receives focus (for keyboard nav through the entire row) */ +tr:focus-within td.actions input, tr:focus-within td.actions a { + opacity: 1; + pointer-events: auto; } td.actions .button { font-family: Verdana, Arial; @@ -148,8 +159,6 @@ td.actions .button { font-weight: bold; background-color: #FFFFFF; border: 1px solid #88c0eb; - -moz-border-radius:3px; - -webkit-border-radius:3px; border-radius:3px; cursor:pointer; height:22px; @@ -203,7 +212,7 @@ td.actions .button_stats { background:#efe; } #login { - width: 300px; + max-width: 300px; margin: 200px auto 0px auto; } #login p{ @@ -240,8 +249,6 @@ td.actions .button_stats { } a.bookmarklet { border:2px solid #2a85b3; - -moz-border-radius:3px; - -webkit-border-radius:3px; border-radius:3px; padding:5px 5px 5px 20px; background:#eef url(../images/favicon.svg) 2px center no-repeat; @@ -262,14 +269,8 @@ a.bookmarklet:hover { background:white; margin:0 auto; max-width:950px; - -moz-border-radius:10px; - -webkit-border-radius:10px; border-radius:10px; border:2px solid #2a85b3; - -moz-border-radius-bottomleft:30px; - -moz-border-radius-bottomright:30px; - -webkit-border-bottom-left-radius:25px; - -webkit-border-bottom-right-radius:25px; border-bottom-left-radius:25px; border-bottom-right-radius:25px; } @@ -281,8 +282,6 @@ a.bookmarklet:hover { .notice { border:1px solid #2a85b3; background: #F3FAFD; - -moz-border-radius:6px; - -webkit-border-radius:6px; border-radius:6px; width:70%; margin-left:15%; @@ -290,7 +289,6 @@ a.bookmarklet:hover { margin-bottom:5px; } - .jquery-notify-bar { width:100%; position:fixed; @@ -305,11 +303,7 @@ a.bookmarklet:hover { padding:20px 0px; border-bottom:1px solid #bbb; filter:alpha(opacity=95); - -moz-opacity:0.95; - -khtml-opacity:0.95; opacity:0.95; - -moz-box-shadow: 0 1px 5px rgba(0,0,0,0.5); - -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.5); text-shadow: 0 1px 1px rgba(0,0,0,0.1); } .jquery-notify-bar.error ,.jquery-notify-bar.fail { @@ -335,3 +329,59 @@ a.bookmarklet:hover { tr.plugin.active a{ font-weight:bolder;} body.desktop tr.plugin td.plugin_desc small{ visibility:hidden;} tr:hover.plugin td.plugin_desc small{ visibility:visible;} + +#delete-confirm-dialog { + background-color: #ffffff; + width: 50em; + height: 19em; + padding: 0px; + border: 3px solid #2a85b3; + border-radius: 20px; +} +#delete-confirm-dialog > div[name="dialog_title"] { + background-color: #c7e7ff; + font-size: 20px; + color: #026090; + text-align: center; + padding-top: 0.5em; + padding-bottom: 0.5em; + border-start-start-radius: 17px 17px; + border-start-end-radius: 17px 17px; +} +#delete-confirm-dialog div.confirm-message { + background-color: #ffffff; + width: calc(50em - 4em); + height: calc(20em - 50px - 5em - 2em + 6px); + float: none; + text-align: left; + padding: 1em 2em; + overflow: hidden; +} +#delete-confirm-dialog div.confirm-message ul { + border-left: 5px solid #026090; + list-style-type: none; + padding: 0 1em; +} +#delete-confirm-dialog div.confirm-message ul li { + margin-bottom: 0.5em; +} +#delete-confirm-dialog div.confirm-message ul li span { + border: 1px solid #c7e7ff; + border-radius: 3px; + padding: 1px 5px; + color:#333; +} +#delete-confirm-dialog div.button-group { + background-color: #e3f3ff; + width: calc(50em - 4em); + height: 2em; + float: none; + text-align: right; + padding: 1em 2em; + border-end-start-radius: 17px 17px; + border-end-end-radius: 17px 17px; +} +#delete-confirm-dialog::backdrop { + background-color: #666; + opacity: 80%; +} diff --git a/includes/Config/Config.php b/includes/Config/Config.php index 5958d70fe..cef031b26 100644 --- a/includes/Config/Config.php +++ b/includes/Config/Config.php @@ -11,20 +11,20 @@ class Config { /** - * @param string + * @var string */ protected $root; /** - * @param mixed + * @var string */ protected $config; /** * @since 1.7.3 - * @param mixed $config Optional user defined config path + * @param string $config Optional user defined config path */ - public function __construct($config = false) { + public function __construct($config = '') { $this->set_root( $this->fix_win32_path( dirname( dirname( __DIR__ ) ) ) ); $this->set_config($config); } @@ -42,7 +42,7 @@ public function fix_win32_path($path) { /** * @since 1.7.3 - * @param string path to config file + * @param string $config path to config file * @return void */ public function set_config($config) { @@ -51,7 +51,7 @@ public function set_config($config) { /** * @since 1.7.3 - * @param string path to YOURLS root directory + * @param string $root path to YOURLS root directory * @return void */ public function set_root($root) { diff --git a/includes/Config/Init.php b/includes/Config/Init.php index dce118d01..d97d9ae2f 100644 --- a/includes/Config/Init.php +++ b/includes/Config/Init.php @@ -9,7 +9,7 @@ class Init { /** - * @param InitDefaults + * @var InitDefaults */ protected $actions; @@ -32,11 +32,6 @@ public function __construct(InitDefaults $actions) { date_default_timezone_set( 'UTC' ); } - // Load locale - if ($actions->load_default_textdomain === true) { - yourls_load_default_textdomain(); - } - // Check if we are in maintenance mode - if yes, it will die here. if ($actions->check_maintenance_mode === true) { yourls_check_maintenance_mode(); @@ -57,7 +52,7 @@ public function __construct(InitDefaults $actions) { $this->include_db_files(); } - // Allow early inclusion of a cache layer + // Allow early and unconditional inclusion of custom code if ($actions->include_cache === true) { $this->include_cache_files(); } @@ -87,6 +82,7 @@ public function __construct(InitDefaults $actions) { if (!yourls_is_installed() && !yourls_is_installing()) { yourls_no_cache_headers(); yourls_redirect( yourls_admin_url('install.php'), 307 ); + exit(); } } @@ -95,6 +91,7 @@ public function __construct(InitDefaults $actions) { if (!yourls_is_upgrading() && !yourls_is_installing() && yourls_upgrade_is_needed()) { yourls_no_cache_headers(); yourls_redirect( yourls_admin_url('upgrade.php'), 307 ); + exit(); } } @@ -108,6 +105,11 @@ public function __construct(InitDefaults $actions) { yourls_do_action( 'plugins_loaded' ); } + // Load locale + if ($actions->load_default_textdomain === true) { + yourls_load_default_textdomain(); + } + // Is there a new version of YOURLS ? if ($actions->check_new_version === true) { if (yourls_is_installed() && !yourls_is_upgrading()) { @@ -143,22 +145,41 @@ public function redirect_ssl_if_needed() { * @return void */ public function include_db_files() { - // Allow drop-in replacement for the DB engine - if (file_exists(YOURLS_USERDIR.'/db.php')) { - require_once YOURLS_USERDIR.'/db.php'; - } else { - require_once YOURLS_INC.'/class-mysql.php'; + // Attempt to open drop-in replacement for the DB engine else default to core engine + $file = YOURLS_USERDIR . '/db.php'; + $attempt = false; + if(file_exists($file)) { + $attempt = yourls_include_file_sandbox( $file ); + // Check if we have an error to display + if ( is_string( $attempt ) ) { + yourls_add_notice( $attempt ); + } + } + + // Fallback to core DB engine + if ( $attempt !== true ) { + require_once YOURLS_INC . '/class-mysql.php'; yourls_db_connect(); } } /** + * Include custom extension file. + * + * "Cache" stands for "Custom Additional Code for Hazardous Extensions". + * * @since 1.7.3 * @return void */ public function include_cache_files() { - if (file_exists(YOURLS_USERDIR.'/cache.php')) { - require_once YOURLS_USERDIR.'/cache.php'; + $file = YOURLS_USERDIR . '/cache.php'; + $attempt = false; + if(file_exists($file)) { + $attempt = yourls_include_file_sandbox($file); + // Check if we have an error to display + if (is_string($attempt)) { + yourls_add_notice($attempt); + } } } @@ -185,12 +206,8 @@ public function include_core_functions() { require_once YOURLS_INC.'/functions-infos.php'; require_once YOURLS_INC.'/functions-deprecated.php'; require_once YOURLS_INC.'/functions-auth.php'; - - // Load install & upgrade functions if needed - if ($this->actions->include_install_upgrade_funcs === true) { - require_once YOURLS_INC.'/functions-upgrade.php'; - require_once YOURLS_INC.'/functions-install.php'; - } + require_once YOURLS_INC.'/functions-upgrade.php'; + require_once YOURLS_INC.'/functions-install.php'; } } diff --git a/includes/Config/InitDefaults.php b/includes/Config/InitDefaults.php index 7792e0113..791650c9d 100644 --- a/includes/Config/InitDefaults.php +++ b/includes/Config/InitDefaults.php @@ -20,12 +20,6 @@ class InitDefaults { */ public $include_core_funcs = true; - /** - * Whether to include auth function files - * @var bool - */ - public $include_install_upgrade_funcs = false; // by default do not load - /** * Whether to set default time zone * @var bool diff --git a/includes/Database/Logger.php b/includes/Database/Logger.php index 6f171b575..3c256dbda 100644 --- a/includes/Database/Logger.php +++ b/includes/Database/Logger.php @@ -47,9 +47,9 @@ class Logger extends AbstractLogger { * ) * See finish() in Aura\Sql\Profiler\Profiler * - * @return null + * @return void */ - public function log($level, $message, array $context = []) { + public function log($level, string|\Stringable $message, array $context = []): void { // if it's an internal SQL query, format the message, otherwise store a string if($level === 'query') { $this->messages[] = sprintf( diff --git a/includes/Database/Options.php b/includes/Database/Options.php index 2eebb641b..f175f08be 100644 --- a/includes/Database/Options.php +++ b/includes/Database/Options.php @@ -75,7 +75,7 @@ public function get_all_options() { $this->ydb->set_option($name, yourls_maybe_unserialize($value)); } - yourls_apply_filter('get_all_options', 'deprecated'); + yourls_do_action('get_all_options', $options); return true; } @@ -172,7 +172,7 @@ public function update($name, $newvalue) { // Cache option value to save a DB query if needed later $this->ydb->set_option($name, $newvalue); - yourls_do_action( 'update_option', $name, $oldvalue, $newvalue ); + yourls_do_action( 'update_option', $name, $oldvalue, $newvalue ); return true; } diff --git a/includes/Database/Profiler.php b/includes/Database/Profiler.php index 2b700b987..ea9e4d222 100644 --- a/includes/Database/Profiler.php +++ b/includes/Database/Profiler.php @@ -21,9 +21,9 @@ class Profiler extends \Aura\Sql\Profiler\Profiler { * * @param string $statement The statement being profiled, if any. * @param array $values The values bound to the statement, if any. - * @return null + * @return void */ - public function finish($statement = null, array $values = []) + public function finish(?string $statement = null, array $values = []): void { if (! $this->active) { return; diff --git a/includes/Database/YDB.php b/includes/Database/YDB.php index 30dac4355..803f34571 100644 --- a/includes/Database/YDB.php +++ b/includes/Database/YDB.php @@ -1,12 +1,12 @@ option, or $ydb->set_option(), use yourls_*_options() functions instead). + * function wrappers (e.g. don't use $ydb->option, or $ydb->set_option(), use yourls_*_options() functions instead). * * @since 1.7.3 */ @@ -33,7 +33,7 @@ class YDB extends ExtendedPdo { protected $context = ''; /** - * Information related to a short URL keyword (eg timestamp, long URL, ...) + * Information related to a short URL keyword (e.g. timestamp, long URL, ...) * * @var array * @@ -53,13 +53,13 @@ class YDB extends ExtendedPdo { protected $option = []; /** - * Plugin admin pages informations + * Plugin admin pages information * @var array */ protected $plugin_pages = []; /** - * Plugin informations + * Plugin information * @var array */ protected $plugins = []; @@ -78,15 +78,15 @@ class YDB extends ExtendedPdo { * @param array $options Driver-specific options * @param array $attributes Attributes to set after a connection */ - public function __construct($dsn, $user, $pass, $options, $attributes) { - parent::__construct($dsn, $user, $pass, $options, $attributes); + public function __construct($dsn, $user, $pass, $options) { + parent::__construct($dsn, $user, $pass, $options); } /** * Init everything needed * * Everything we need to set up is done here in init(), not in the constructor, so even - * when the connection fails (eg config error or DB dead), the constructor has worked + * when the connection fails (e.g. config error or DB dead), the constructor has worked, * and we have a $ydb object properly instantiated (and for instance yourls_die() can * correctly die, even if using $ydb methods) * @@ -140,7 +140,8 @@ public function get_emulate_state() { */ public function connect_to_DB() { try { - $this->connect(); + list($dsn, $_user, $_pwd, $_opt, $_queries) = $this->args; + $this->connect($dsn); } catch ( \Exception $e ) { $this->dead_or_error($e); } @@ -157,16 +158,18 @@ public function connect_to_DB() { */ public function dead_or_error(\Exception $exception) { // Use any /user/db_error.php file - if( file_exists( YOURLS_USERDIR . '/db_error.php' ) ) { - include_once( YOURLS_USERDIR . '/db_error.php' ); - die(); + $file = YOURLS_USERDIR . '/db_error.php'; + if(file_exists($file)) { + if(yourls_include_file_sandbox( $file ) === true) { + die(); + } } $message = yourls__( 'Incorrect DB config, or could not connect to DB' ); $message .= '
' . get_class($exception) .': ' . $exception->getMessage(); - yourls_die( yourls__( $message ), yourls__( 'Fatal error' ), 503 ); die(); + } /** @@ -192,6 +195,7 @@ public function start_profiler() { /** * @param string $context + * @return void */ public function set_html_context($context) { $this->context = $context; @@ -209,6 +213,7 @@ public function get_html_context() { /** * @param string $name * @param mixed $value + * @return void */ public function set_option($name, $value) { $this->option[$name] = $value; @@ -232,6 +237,7 @@ public function get_option($name) { /** * @param string $name + * @return void */ public function delete_option($name) { unset($this->option[$name]); @@ -243,6 +249,7 @@ public function delete_option($name) { /** * @param string $keyword * @param mixed $infos + * @return void */ public function set_infos($keyword, $infos) { $this->infos[$keyword] = $infos; @@ -266,9 +273,23 @@ public function get_infos($keyword) { /** * @param string $keyword + * @return void */ public function delete_infos($keyword) { - unset($this->infos[$keyword]); + if (isset($this->infos[$keyword])) { + unset($this->infos[$keyword]); + } + } + + /** + * @param string $keyword + * @param mixed $infos + * @return void + */ + public function update_infos_if_exists($keyword, $infos) { + if ($this->has_infos($keyword) && $this->infos[$keyword]) { + $this->infos[$keyword] = array_merge($this->infos[$keyword], $infos); + } } /** @@ -287,6 +308,7 @@ public function get_plugins() { /** * @param array $plugins + * @return void */ public function set_plugins(array $plugins) { $this->plugins = $plugins; @@ -294,6 +316,7 @@ public function set_plugins(array $plugins) { /** * @param string $plugin plugin filename + * @return void */ public function add_plugin($plugin) { $this->plugins[] = $plugin; @@ -301,6 +324,7 @@ public function add_plugin($plugin) { /** * @param string $plugin plugin filename + * @return void */ public function remove_plugin($plugin) { unset($this->plugins[$plugin]); @@ -318,6 +342,7 @@ public function get_plugin_pages() { /** * @param array $pages + * @return void */ public function set_plugin_pages(array $pages) { $this->plugin_pages = $pages; @@ -327,6 +352,7 @@ public function set_plugin_pages(array $pages) { * @param string $slug * @param string $title * @param callable $function + * @return void */ public function add_plugin_page( $slug, $title, $function ) { $this->plugin_pages[ $slug ] = [ @@ -338,6 +364,7 @@ public function add_plugin_page( $slug, $title, $function ) { /** * @param string $slug + * @return void */ public function remove_plugin_page( $slug ) { unset( $this->plugin_pages[ $slug ] ); @@ -391,77 +418,13 @@ public function is_installed() { } /** - * Return standardized DB version - * - * The regex removes everything that's not a number at the start of the string, or remove anything that's not a number and what - * follows after that. - * 'omgmysql-5.5-ubuntu-4.20' => '5.5' - * 'mysql5.5-ubuntu-4.20' => '5.5' - * '5.5-ubuntu-4.20' => '5.5' - * '5.5-beta2' => '5.5' - * '5.5' => '5.5' + * Return MySQL version * * @since 1.7.3 * @return string */ public function mysql_version() { - $version = $this->pdo->getAttribute(PDO::ATTR_SERVER_VERSION); - return $version; + return $this->pdo->getAttribute(PDO::ATTR_SERVER_VERSION); } - /** - * Deprecated properties since 1.7.3, unused in 3rd party plugins as far as I know - * - * $ydb->DB_driver - * $ydb->captured_errors - * $ydb->dbh - * $ydb->result - * $ydb->rows_affected - * $ydb->show_errors - */ - - /** - * Deprecated functions since 1.7.3 - */ - - // @codeCoverageIgnoreStart - - public function escape($string) { - yourls_deprecated_function( '$ydb->'.__FUNCTION__, '1.7.3', 'PDO' ); - // This will escape using PDO->quote(), but then remove the enclosing quotes - return substr($this->quote($string), 1, -1); - } - - public function get_col($query) { - yourls_deprecated_function( '$ydb->'.__FUNCTION__, '1.7.3', 'PDO' ); - yourls_debug_log('LEGACY SQL: '.$query); - return $this->fetchCol($query); - } - - public function get_results($query) { - yourls_deprecated_function( '$ydb->'.__FUNCTION__, '1.7.3', 'PDO' ); - yourls_debug_log('LEGACY SQL: '.$query); - $stm = parent::query($query); - return($stm->fetchAll(PDO::FETCH_OBJ)); - } - - public function get_row($query) { - yourls_deprecated_function( '$ydb->'.__FUNCTION__, '1.7.3', 'PDO' ); - yourls_debug_log('LEGACY SQL: '.$query); - $row = $this->fetchObjects($query); - return isset($row[0]) ? $row[0] : null; - } - - public function get_var($query) { - yourls_deprecated_function( '$ydb->'.__FUNCTION__, '1.7.3', 'PDO' ); - yourls_debug_log('LEGACY SQL: '.$query); - return $this->fetchValue($query); - } - - public function query($query, ...$unused) { - yourls_deprecated_function( '$ydb->'.__FUNCTION__, '1.7.3', 'PDO' ); - yourls_debug_log('LEGACY SQL: '.$query); - return $this->fetchAffected($query); - } - // @codeCoverageIgnoreEnd } diff --git a/includes/Views/AdminParams.php b/includes/Views/AdminParams.php index 4ceb0b854..892684da6 100644 --- a/includes/Views/AdminParams.php +++ b/includes/Views/AdminParams.php @@ -51,9 +51,12 @@ class AdminParams */ public function __construct() { - $this->possible_search_params = ['all', 'keyword', 'url', 'title', 'ip']; - $this->possible_sort_params = ['keyword', 'url', 'title', 'ip', 'timestamp', 'clicks']; - $this->params_translations = [ + // Cast return values of yourls_apply_filter() to array in case a hook would incorrectly return something else + $this->possible_search_params = (array)yourls_apply_filter('admin_params_possible_search', + ['all', 'keyword', 'url', 'title', 'ip']); + $this->possible_sort_params = (array)yourls_apply_filter('admin_params_possible_sort', + ['keyword', 'url', 'title', 'ip', 'timestamp', 'clicks']); + $this->params_translations = (array)yourls_apply_filter('admin_params_possible_translations',[ 'all' => yourls__('All fields'), 'keyword' => yourls__('Short URL'), 'url' => yourls__('URL'), @@ -61,8 +64,9 @@ public function __construct() 'ip' => yourls__('IP Address'), 'timestamp' => yourls__('Date'), 'clicks' => yourls__('Clicks'), - ]; - $this->possible_date_sorting = ['before', 'after', 'between']; + ]); + $this->possible_date_sorting = (array)yourls_apply_filter('admin_params_possible_date_sort', + ['before', 'after', 'between']); } /** @@ -152,7 +156,7 @@ public function get_search_in(): string * * @since 1.8.2 * - * @return mixed + * @return string */ public function get_sort_by(): string { @@ -218,8 +222,15 @@ public function get_click_filter() public function get_click_limit() { // @hook Default link click threshold (unset) - return (isset($_GET['click_limit']) && intval($_GET['click_limit'])) ? - intval($_GET['click_limit']) : yourls_apply_filter('admin_view_click_limit', ''); + if ( + isset($_GET['click_limit']) // Exists in the query string + && ($_GET['click_limit'] !== '') // Not empty (&stuff=&click_limit=&otherstuff=) + && intval($_GET['click_limit']) >= 0 // A number >= 0 + ) { + return intval($_GET['click_limit']); + } else { + return yourls_apply_filter('admin_view_click_limit', ''); + } } diff --git a/includes/auth.php b/includes/auth.php index d6b95a89d..be98a87da 100644 --- a/includes/auth.php +++ b/includes/auth.php @@ -6,23 +6,23 @@ if( $auth !== true ) { - // API mode, - if ( yourls_is_API() ) { - $format = ( isset($_REQUEST['format']) ? $_REQUEST['format'] : 'xml' ); - $callback = ( isset($_REQUEST['callback']) ? $_REQUEST['callback'] : '' ); - yourls_api_output( $format, array( - 'simple' => $auth, - 'message' => $auth, - 'errorCode' => 403, - 'callback' => $callback, - ) ); - - // Regular mode - } else { - yourls_login_screen( $auth ); - } - - die(); + // API mode, + if ( yourls_is_API() ) { + $format = ( isset($_REQUEST['format']) ? $_REQUEST['format'] : 'xml' ); + $callback = ( isset($_REQUEST['callback']) ? $_REQUEST['callback'] : '' ); + yourls_api_output( $format, array( + 'simple' => $auth, + 'message' => $auth, + 'errorCode' => '403', + 'callback' => $callback, + ) ); + + // Regular mode + } else { + yourls_login_screen( $auth ); + } + + die(); } yourls_do_action( 'auth_successful' ); @@ -36,15 +36,15 @@ // Did we just fail at encrypting passwords ? if ( isset( $_GET['dismiss'] ) && $_GET['dismiss'] == 'hasherror' ) { - yourls_update_option( 'defer_hashing_error', time() + 86400 * 7 ); // now + 1 week + yourls_update_option( 'defer_hashing_error', time() + 86400 * 7 ); // now + 1 week } else { - // Encrypt passwords that are clear text - if ( yourls_maybe_hash_passwords() ) { + // Encrypt passwords that are clear text + if ( yourls_maybe_hash_passwords() ) { $hash = yourls_hash_passwords_now( YOURLS_CONFIGFILE ); if ( $hash === true ) { - // Hashing succesful. Remove flag from DB if any. + // Hashing successful. Remove flag from DB if any. if( yourls_get_option( 'defer_hashing_error' ) ) yourls_delete_option( 'defer_hashing_error' ); } else { @@ -59,5 +59,5 @@ yourls_add_notice( $message ); } } - } + } } diff --git a/includes/class-mysql.php b/includes/class-mysql.php index d2ca2958e..603c87c83 100644 --- a/includes/class-mysql.php +++ b/includes/class-mysql.php @@ -4,8 +4,10 @@ * Connect to DB * * @since 1.0 + * @param string $context Optional context. Default: ''. + * @return \YOURLS\Database\YDB */ -function yourls_db_connect() { +function yourls_db_connect($context = '') { global $ydb; if ( !defined( 'YOURLS_DB_USER' ) @@ -25,12 +27,12 @@ function yourls_db_connect() { yourls_do_action( 'set_DB_driver', 'deprecated' ); // Get custom port if any - if ( false !== strpos( $dbhost, ':' ) ) { + if (str_contains($dbhost, ':')) { list( $dbhost, $dbport ) = explode( ':', $dbhost ); $dbhost = sprintf( '%1$s;port=%2$d', $dbhost, $dbport ); } - $charset = yourls_apply_filter( 'db_connect_charset', 'utf8mb4' ); + $charset = yourls_apply_filter( 'db_connect_charset', 'utf8mb4', $context ); /** * Data Source Name (dsn) used to connect the DB @@ -41,7 +43,7 @@ function yourls_db_connect() { * 'pgsql:host=192.168.13.37;port=5432;dbname=omgwtf' */ $dsn = sprintf( 'mysql:host=%s;dbname=%s;charset=%s', $dbhost, $dbname, $charset ); - $dsn = yourls_apply_filter( 'db_connect_custom_dsn', $dsn ); + $dsn = yourls_apply_filter( 'db_connect_custom_dsn', $dsn, $context ); /** * PDO driver options and attributes @@ -51,14 +53,18 @@ function yourls_db_connect() { * The driver options are passed to the PDO constructor, eg array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION) * The attribute options are then set in a foreach($attr as $k=>$v){$db->setAttribute($k, $v)} loop */ - $driver_options = yourls_apply_filter( 'db_connect_driver_option', [] ); // driver options as key-value pairs - $attributes = yourls_apply_filter( 'db_connect_attributes', [] ); // attributes as key-value pairs + $driver_options = yourls_apply_filter( 'db_connect_driver_option', [], $context ); // driver options as key-value pairs + $attributes = yourls_apply_filter( 'db_connect_attributes', [], $context ); // attributes as key-value pairs $ydb = new \YOURLS\Database\YDB( $dsn, $user, $pass, $driver_options, $attributes ); $ydb->init(); // Past this point, we're connected - yourls_debug_log( sprintf( 'Connected to database %s on %s ', $dbname, $dbhost ) ); + $msg = 'Connected to ' . $dsn; + if ($context !== '') { + $msg .= ', context: ' . $context; + } + yourls_debug_log( $msg ); yourls_debug_mode( YOURLS_DEBUG ); @@ -66,7 +72,7 @@ function yourls_db_connect() { } /** - * Helper function : return instance of the DB + * Helper function: return instance of the DB * * Instead of: * global $ydb; @@ -75,18 +81,46 @@ function yourls_db_connect() { * yourls_get_db()->do_stuff() * * @since 1.7.10 + * @param string $context Optional context. Default: ''. + * If not provided, the function will trigger a notice to encourage developers to provide a context while not + * breaking existing code. A context is a string describing the operation for which the DB is requested. + * Use a naming schema starting with a prefix describing the operation, followed by a short description: + * - Prefix should be either "read-" or "write-", as follows: + * * "read-" for operations that only read from the DB (eg get_keyword_infos) + * * "write-" for operations that write to the DB (eg insert_link_in_db) + * - The description should be lowercase, words separated with underscores, eg "insert_link_in_db". + * Examples: + * - read-fetch_keyword + * - write-insert_link_in_db * @return \YOURLS\Database\YDB */ -function yourls_get_db() { +function yourls_get_db($context = '') { // Allow plugins to short-circuit the whole function - $pre = yourls_apply_filter( 'shunt_get_db', false ); + $pre = yourls_apply_filter( 'shunt_get_db', false, $context ); if ( false !== $pre ) { return $pre; } + // Validate context and raise notice if missing or malformed + if ($context == '' || !preg_match('/^(read|write)-[a-z0-9_]+$/', $context)) { + $db = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); + $file = $db[0]['file']; + $line = $db[0]['line']; + + if ($context == '') { + $msg = 'Undefined yourls_get_db() context'; + } else { + $msg = 'Improperly formatted yourls_get_db() context ("' . $context . '")'; + } + + trigger_error( $msg . ' at ' . $file . ':' . $line .'', E_USER_NOTICE ); + } + + yourls_do_action( 'get_db_action', $context ); + global $ydb; - $ydb = ( isset( $ydb ) ) ? $ydb : yourls_db_connect(); - return yourls_apply_filter('get_db', $ydb); + $ydb = ( isset( $ydb ) ) ? $ydb : yourls_db_connect($context); + return yourls_apply_filter('get_db', $ydb, $context); } /** @@ -101,6 +135,7 @@ function yourls_get_db() { * * @since 1.7.10 * @param mixed $db Either a \YOURLS\Database\YDB instance, or anything. If null, the function will unset $ydb + * @return void */ function yourls_set_db($db) { global $ydb; diff --git a/includes/functions-api.php b/includes/functions-api.php index baf3cb10e..bd9723758 100644 --- a/includes/functions-api.php +++ b/includes/functions-api.php @@ -15,13 +15,13 @@ * @return array Result of API call */ function yourls_api_action_shorturl() { - $url = ( isset( $_REQUEST['url'] ) ? $_REQUEST['url'] : '' ); - $keyword = ( isset( $_REQUEST['keyword'] ) ? $_REQUEST['keyword'] : '' ); - $title = ( isset( $_REQUEST['title'] ) ? $_REQUEST['title'] : '' ); - $return = yourls_add_new_link( $url, $keyword, $title ); - $return['simple'] = ( isset( $return['shorturl'] ) ? $return['shorturl'] : '' ); // This one will be used in case output mode is 'simple' - unset( $return['html'] ); // in API mode, no need for our internal HTML output - return yourls_apply_filter( 'api_result_shorturl', $return ); + $url = ( isset( $_REQUEST['url'] ) ? $_REQUEST['url'] : '' ); + $keyword = ( isset( $_REQUEST['keyword'] ) ? $_REQUEST['keyword'] : '' ); + $title = ( isset( $_REQUEST['title'] ) ? $_REQUEST['title'] : '' ); + $return = yourls_add_new_link( $url, $keyword, $title ); + $return['simple'] = ( isset( $return['shorturl'] ) ? $return['shorturl'] : '' ); // This one will be used in case output mode is 'simple' + unset( $return['html'] ); // in API mode, no need for our internal HTML output + return yourls_apply_filter( 'api_result_shorturl', $return ); } /** @@ -31,10 +31,10 @@ function yourls_api_action_shorturl() { * @return array Result of API call */ function yourls_api_action_stats() { - $filter = ( isset( $_REQUEST['filter'] ) ? $_REQUEST['filter'] : '' ); - $limit = ( isset( $_REQUEST['limit'] ) ? $_REQUEST['limit'] : '' ); - $start = ( isset( $_REQUEST['start'] ) ? $_REQUEST['start'] : '' ); - return yourls_apply_filter( 'api_result_stats', yourls_api_stats( $filter, $limit, $start ) ); + $filter = ( isset( $_REQUEST['filter'] ) ? $_REQUEST['filter'] : '' ); + $limit = ( isset( $_REQUEST['limit'] ) ? $_REQUEST['limit'] : '' ); + $start = ( isset( $_REQUEST['start'] ) ? $_REQUEST['start'] : '' ); + return yourls_apply_filter( 'api_result_stats', yourls_api_stats( $filter, $limit, $start ) ); } /** @@ -44,7 +44,7 @@ function yourls_api_action_stats() { * @return array Result of API call */ function yourls_api_action_db_stats() { - return yourls_apply_filter( 'api_result_db_stats', yourls_api_db_stats() ); + return yourls_apply_filter( 'api_result_db_stats', yourls_api_db_stats() ); } /** @@ -54,8 +54,8 @@ function yourls_api_action_db_stats() { * @return array Result of API call */ function yourls_api_action_url_stats() { - $shorturl = ( isset( $_REQUEST['shorturl'] ) ? $_REQUEST['shorturl'] : '' ); - return yourls_apply_filter( 'api_result_url_stats', yourls_api_url_stats( $shorturl ) ); + $shorturl = ( isset( $_REQUEST['shorturl'] ) ? $_REQUEST['shorturl'] : '' ); + return yourls_apply_filter( 'api_result_url_stats', yourls_api_url_stats( $shorturl ) ); } /** @@ -65,8 +65,8 @@ function yourls_api_action_url_stats() { * @return array Result of API call */ function yourls_api_action_expand() { - $shorturl = ( isset( $_REQUEST['shorturl'] ) ? $_REQUEST['shorturl'] : '' ); - return yourls_apply_filter( 'api_result_expand', yourls_api_expand( $shorturl ) ); + $shorturl = ( isset( $_REQUEST['shorturl'] ) ? $_REQUEST['shorturl'] : '' ); + return yourls_apply_filter( 'api_result_expand', yourls_api_expand( $shorturl ) ); } /** @@ -76,10 +76,10 @@ function yourls_api_action_expand() { * @return array Result of API call */ function yourls_api_action_version() { - $return['version'] = $return['simple'] = YOURLS_VERSION; - if( isset( $_REQUEST['db'] ) && $_REQUEST['db'] == 1 ) - $return['db_version'] = YOURLS_DB_VERSION; - return yourls_apply_filter( 'api_result_version', $return ); + $return['version'] = $return['simple'] = YOURLS_VERSION; + if( isset( $_REQUEST['db'] ) && $_REQUEST['db'] == 1 ) + $return['db_version'] = YOURLS_DB_VERSION; + return yourls_apply_filter( 'api_result_version', $return ); } /** @@ -99,12 +99,12 @@ function yourls_api_action_version() { * @return string API output, as an XML / JSON / JSONP / raw text string */ function yourls_api_output( $mode, $output, $send_headers = true, $echo = true ) { - if( isset( $output['simple'] ) ) { - $simple = $output['simple']; - unset( $output['simple'] ); - } + if( isset( $output['simple'] ) ) { + $simple = $output['simple']; + unset( $output['simple'] ); + } - yourls_do_action( 'pre_api_output', $mode, $output, $send_headers, $echo ); + yourls_do_action( 'pre_api_output', $mode, $output, $send_headers, $echo ); if( $send_headers ) { if( isset( $output['statusCode'] ) ) { @@ -119,43 +119,49 @@ function yourls_api_output( $mode, $output, $send_headers = true, $echo = true ) $result = ''; - switch ( $mode ) { - case 'jsonp': + switch ( $mode ) { + case 'jsonp': if( $send_headers ) yourls_content_type_header( 'application/javascript' ); - $callback = isset( $output['callback'] ) ? $output['callback'] : ''; - $result = $callback . '(' . json_encode( $output ) . ')'; - break; + $callback = isset( $output['callback'] ) ? yourls_validate_jsonp_callback($output['callback'] ) : ''; + if( $callback === false ) { + yourls_status_header( 400 ); + $result = json_encode( ['errorCode' => '400', 'error' => 'Invalid callback parameter'] ); + } else { + $result = $callback . '(' . json_encode( $output ) . ')'; + } + + break; - case 'json': + case 'json': if( $send_headers ) yourls_content_type_header( 'application/json' ); - $result = json_encode( $output ); - break; + $result = json_encode( $output ); + break; - case 'xml': + case 'xml': if( $send_headers ) yourls_content_type_header( 'application/xml' ); - $result = yourls_xml_encode( $output ); - break; + $result = yourls_xml_encode( $output ); + break; - case 'simple': - default: + case 'simple': + default: if( $send_headers ) yourls_content_type_header( 'text/plain' ); - $result = isset( $simple ) ? $simple : ''; - break; - } + $result = isset( $simple ) ? $simple : ''; + break; + } if( $echo ) { echo $result; } - yourls_do_action( 'api_output', $mode, $output, $send_headers, $echo ); + yourls_do_action( 'api_output', $mode, $output, $send_headers, $echo ); return $result; } @@ -163,70 +169,79 @@ function yourls_api_output( $mode, $output, $send_headers = true, $echo = true ) /** * Return array for API stat requests * + * @param string $filter either "top", "bottom" , "rand" or "last" + * @param int $limit maximum number of links to return + * @param int $start offset + * @return array */ -function yourls_api_stats( $filter = 'top', $limit = 10, $start = 0 ) { - $return = yourls_get_stats( $filter, $limit, $start ); - $return['simple'] = 'Need either XML or JSON format for stats'; - $return['message'] = 'success'; - return yourls_apply_filter( 'api_stats', $return, $filter, $limit, $start ); +function yourls_api_stats($filter = 'top', $limit = 10, $start = 0 ) { + $return = yourls_get_stats( $filter, $limit, $start ); + $return['simple'] = 'Need either XML or JSON format for stats'; + $return['message'] = 'success'; + return yourls_apply_filter( 'api_stats', $return, $filter, $limit, $start ); } /** * Return array for counts of shorturls and clicks * + * @return array */ function yourls_api_db_stats() { - $return = array( - 'db-stats' => yourls_get_db_stats(), - 'statusCode' => 200, - 'simple' => 'Need either XML or JSON format for stats', - 'message' => 'success', - ); - - return yourls_apply_filter( 'api_db_stats', $return ); + $return = array( + 'db-stats' => yourls_get_db_stats(), + 'statusCode' => '200', + 'simple' => 'Need either XML or JSON format for stats', + 'message' => 'success', + ); + + return yourls_apply_filter( 'api_db_stats', $return ); } /** * Return array for API stat requests * + * @param string $shorturl Short URL to check + * @return array */ function yourls_api_url_stats( $shorturl ) { - $keyword = str_replace( yourls_get_yourls_site() . '/' , '', $shorturl ); // accept either 'http://ozh.in/abc' or 'abc' - $keyword = yourls_sanitize_keyword( $keyword ); + $keyword = str_replace( yourls_get_yourls_site() . '/' , '', $shorturl ); // accept either 'http://ozh.in/abc' or 'abc' + $keyword = yourls_sanitize_keyword( $keyword ); - $return = yourls_get_keyword_stats( $keyword ); - $return['simple'] = 'Need either XML or JSON format for stats'; - return yourls_apply_filter( 'api_url_stats', $return, $shorturl ); + $return = yourls_get_keyword_stats( $keyword ); + $return['simple'] = 'Need either XML or JSON format for stats'; + return yourls_apply_filter( 'api_url_stats', $return, $shorturl ); } /** * Expand short url to long url * + * @param string $shorturl Short URL to expand + * @return array */ function yourls_api_expand( $shorturl ) { - $keyword = str_replace( yourls_get_yourls_site() . '/' , '', $shorturl ); // accept either 'http://ozh.in/abc' or 'abc' - $keyword = yourls_sanitize_keyword( $keyword ); + $keyword = str_replace( yourls_get_yourls_site() . '/' , '', $shorturl ); // accept either 'http://ozh.in/abc' or 'abc' + $keyword = yourls_sanitize_keyword( $keyword ); - $longurl = yourls_get_keyword_longurl( $keyword ); + $longurl = yourls_get_keyword_longurl( $keyword ); - if( $longurl ) { - $return = array( - 'keyword' => $keyword, - 'shorturl' => yourls_link($keyword), - 'longurl' => $longurl, + if( $longurl ) { + $return = array( + 'keyword' => $keyword, + 'shorturl' => yourls_link($keyword), + 'longurl' => $longurl, 'title' => yourls_get_keyword_title( $keyword ), - 'simple' => $longurl, - 'message' => 'success', - 'statusCode' => 200, - ); - } else { - $return = array( - 'keyword' => $keyword, - 'simple' => 'not found', - 'message' => 'Error: short URL not found', - 'errorCode' => 404, - ); - } - - return yourls_apply_filter( 'api_expand', $return, $shorturl ); + 'simple' => $longurl, + 'message' => 'success', + 'statusCode' => '200', + ); + } else { + $return = array( + 'keyword' => $keyword, + 'simple' => 'not found', + 'message' => 'Error: short URL not found', + 'errorCode' => '404', + ); + } + + return yourls_apply_filter( 'api_expand', $return, $shorturl ); } diff --git a/includes/functions-auth.php b/includes/functions-auth.php index 44630e842..cadf538b4 100644 --- a/includes/functions-auth.php +++ b/includes/functions-auth.php @@ -7,262 +7,277 @@ /** * Show login form if required * + * @return void */ function yourls_maybe_require_auth() { - if( yourls_is_private() ) { - yourls_do_action( 'require_auth' ); - require_once( YOURLS_INC.'/auth.php' ); - } else { - yourls_do_action( 'require_no_auth' ); - } + if( yourls_is_private() ) { + yourls_do_action( 'require_auth' ); + require_once( YOURLS_INC.'/auth.php' ); + } else { + yourls_do_action( 'require_no_auth' ); + } } /** * Check for valid user via login form or stored cookie. Returns true or an error message * + * @return bool|string|mixed true if valid user, error message otherwise. Can also call yourls_die() or redirect to login page. Oh my. */ function yourls_is_valid_user() { - // Allow plugins to short-circuit the whole function - $pre = yourls_apply_filter( 'shunt_is_valid_user', null ); - if ( null !== $pre ) { - return $pre; - } - - // $unfiltered_valid : are credentials valid? Boolean value. It's "unfiltered" to allow plugins to eventually filter it. - $unfiltered_valid = false; - - // Logout request - if( isset( $_GET['action'] ) && $_GET['action'] == 'logout' ) { - yourls_do_action( 'logout' ); - yourls_store_cookie( null ); - return yourls__( 'Logged out successfully' ); - } - - // Check cookies or login request. Login form has precedence. - - yourls_do_action( 'pre_login' ); - - // Determine auth method and check credentials - if - // API only: Secure (no login or pwd) and time limited token - // ?timestamp=12345678&signature=md5(totoblah12345678) - ( yourls_is_API() && - isset( $_REQUEST['timestamp'] ) && !empty($_REQUEST['timestamp'] ) && - isset( $_REQUEST['signature'] ) && !empty($_REQUEST['signature'] ) - ) - { - yourls_do_action( 'pre_login_signature_timestamp' ); - $unfiltered_valid = yourls_check_signature_timestamp(); - } - - elseif - // API only: Secure (no login or pwd) - // ?signature=md5(totoblah) - ( yourls_is_API() && - !isset( $_REQUEST['timestamp'] ) && - isset( $_REQUEST['signature'] ) && !empty( $_REQUEST['signature'] ) - ) - { - yourls_do_action( 'pre_login_signature' ); - $unfiltered_valid = yourls_check_signature(); - } - - elseif - // API or normal: login with username & pwd - ( isset( $_REQUEST['username'] ) && isset( $_REQUEST['password'] ) - && !empty( $_REQUEST['username'] ) && !empty( $_REQUEST['password'] ) ) - { - yourls_do_action( 'pre_login_username_password' ); - $unfiltered_valid = yourls_check_username_password(); - } - - elseif - // Normal only: cookies - ( !yourls_is_API() && - isset( $_COOKIE[ yourls_cookie_name() ] ) ) - { - yourls_do_action( 'pre_login_cookie' ); - $unfiltered_valid = yourls_check_auth_cookie(); - } - - // Regardless of validity, allow plugins to filter the boolean and have final word - $valid = yourls_apply_filter( 'is_valid_user', $unfiltered_valid ); - - // Login for the win! - if ( $valid ) { - yourls_do_action( 'login' ); - - // (Re)store encrypted cookie if needed - if ( !yourls_is_API() ) { - yourls_store_cookie( YOURLS_USER ); - - // Login form : redirect to requested URL to avoid re-submitting the login form on page reload - if( isset( $_REQUEST['username'] ) && isset( $_REQUEST['password'] ) && isset( $_SERVER['REQUEST_URI'] ) ) { - // The return makes sure we exit this function before waiting for redirection. - // This fixes #3189 and honestly I'm not sure why. - return yourls_redirect( yourls_sanitize_url_safe($_SERVER['REQUEST_URI']) ); - } - } - - // Login successful - return true; - } - - // Login failed - yourls_do_action( 'login_failed' ); - - if ( isset( $_REQUEST['username'] ) || isset( $_REQUEST['password'] ) ) { - return yourls__( 'Invalid username or password' ); - } else { - return yourls__( 'Please log in' ); - } + // Allow plugins to short-circuit the whole function + $pre = yourls_apply_filter( 'shunt_is_valid_user', null ); + if ( null !== $pre ) { + return $pre; + } + + // $unfiltered_valid : are credentials valid? Boolean value. It's "unfiltered" to allow plugins to eventually filter it. + $unfiltered_valid = false; + + // Logout request + if( isset( $_GET['action'] ) && $_GET['action'] == 'logout' && isset( $_REQUEST['nonce'] ) ) { + // The logout nonce is associated to fake user 'logout' since at this point we don't know the real user + yourls_verify_nonce('admin_logout', $_REQUEST['nonce'], 'logout'); + yourls_do_action( 'logout' ); + yourls_store_cookie( '' ); + return yourls__( 'Logged out successfully' ); + } + + // Check cookies or login request. Login form has precedence. + + yourls_do_action( 'pre_login' ); + + // Determine auth method and check credentials + if + // API only: Secure (no login or pwd) and time limited token + // ?timestamp=12345678&signature=md5(totoblah12345678) + ( yourls_is_API() && + isset( $_REQUEST['timestamp'] ) && !empty($_REQUEST['timestamp'] ) && + isset( $_REQUEST['signature'] ) && !empty($_REQUEST['signature'] ) + ) + { + yourls_do_action( 'pre_login_signature_timestamp' ); + $unfiltered_valid = yourls_check_signature_timestamp(); + } + + elseif + // API only: Secure (no login or pwd) + // ?signature=md5(totoblah) + ( yourls_is_API() && + !isset( $_REQUEST['timestamp'] ) && + isset( $_REQUEST['signature'] ) && !empty( $_REQUEST['signature'] ) + ) + { + yourls_do_action( 'pre_login_signature' ); + $unfiltered_valid = yourls_check_signature(); + } + + elseif + // API or normal: login with username & pwd + ( isset( $_REQUEST['username'] ) && isset( $_REQUEST['password'] ) + && !empty( $_REQUEST['username'] ) && !empty( $_REQUEST['password'] ) ) + { + yourls_do_action( 'pre_login_username_password' ); + $unfiltered_valid = yourls_check_username_password(); + } + + elseif + // Normal only: cookies + ( !yourls_is_API() && + isset( $_COOKIE[ yourls_cookie_name() ] ) ) + { + yourls_do_action( 'pre_login_cookie' ); + $unfiltered_valid = yourls_check_auth_cookie(); + } + + // Regardless of validity, allow plugins to filter the boolean and have final word + $valid = yourls_apply_filter( 'is_valid_user', $unfiltered_valid ); + + // Login for the win! + if ( $valid ) { + yourls_do_action( 'login' ); + + // (Re)store encrypted cookie if needed + if ( !yourls_is_API() ) { + yourls_store_cookie( YOURLS_USER ); + + // Login form : redirect to requested URL to avoid re-submitting the login form on page reload + if( isset( $_REQUEST['username'] ) && isset( $_REQUEST['password'] ) && isset( $_SERVER['REQUEST_URI'] ) ) { + // The return makes sure we exit this function before waiting for redirection. + // See #3189 and note in yourls_redirect() + return yourls_redirect( yourls_sanitize_url_safe($_SERVER['REQUEST_URI']) ); + } + } + + // Login successful + return true; + } + + // Login failed + yourls_do_action( 'login_failed' ); + + if ( isset( $_REQUEST['username'] ) || isset( $_REQUEST['password'] ) ) { + return yourls__( 'Invalid username or password' ); + } else { + return yourls__( 'Please log in' ); + } } /** * Check auth against list of login=>pwd. Sets user if applicable, returns bool * + * @return bool true if login/pwd pair is valid (and sets user if applicable), false otherwise */ function yourls_check_username_password() { - global $yourls_user_passwords; + global $yourls_user_passwords; - // If login form (not API), check for nonce + // If login form (not API), check for nonce if(!yourls_is_API()) { yourls_verify_nonce('admin_login'); } - if( isset( $yourls_user_passwords[ $_REQUEST['username'] ] ) && yourls_check_password_hash( $_REQUEST['username'], $_REQUEST['password'] ) ) { - yourls_set_user( $_REQUEST['username'] ); - return true; - } - return false; + if( isset( $yourls_user_passwords[ $_REQUEST['username'] ] ) && yourls_check_password_hash( $_REQUEST['username'], $_REQUEST['password'] ) ) { + yourls_set_user( $_REQUEST['username'] ); + return true; + } + return false; } /** * Check a submitted password sent in plain text against stored password which can be a salted hash * + * @param string $user + * @param string $submitted_password + * @return bool */ -function yourls_check_password_hash( $user, $submitted_password ) { - global $yourls_user_passwords; +function yourls_check_password_hash($user, $submitted_password ) { + global $yourls_user_passwords; - if( !isset( $yourls_user_passwords[ $user ] ) ) - return false; + if( !isset( $yourls_user_passwords[ $user ] ) ) + return false; - if ( yourls_has_phpass_password( $user ) ) { - // Stored password is hashed with phpass - list( , $hash ) = explode( ':', $yourls_user_passwords[ $user ] ); - $hash = str_replace( '!', '$', $hash ); - return ( yourls_phpass_check( $submitted_password, $hash ) ); - } else if( yourls_has_md5_password( $user ) ) { - // Stored password is a salted md5 hash: "md5:<$r = rand(10000,99999)>:" - list( , $salt, ) = explode( ':', $yourls_user_passwords[ $user ] ); - return( $yourls_user_passwords[ $user ] == 'md5:'.$salt.':'.md5( $salt . $submitted_password ) ); - } else { - // Password stored in clear text - return( $yourls_user_passwords[ $user ] === $submitted_password ); - } + if ( yourls_has_phpass_password( $user ) ) { + // Stored password is hashed + list( , $hash ) = explode( ':', $yourls_user_passwords[ $user ] ); + $hash = str_replace( '!', '$', $hash ); + return ( yourls_phpass_check( $submitted_password, $hash ) ); + } else if( yourls_has_md5_password( $user ) ) { + // Stored password is a salted md5 hash: "md5:<$r = rand(10000,99999)>:" + list( , $salt, ) = explode( ':', $yourls_user_passwords[ $user ] ); + return( $yourls_user_passwords[ $user ] == 'md5:'.$salt.':'.md5( $salt . $submitted_password ) ); + } else { + // Password stored in clear text + return( $yourls_user_passwords[ $user ] === $submitted_password ); + } } /** - * Overwrite plaintext passwords in config file with phpassed versions. + * Overwrite plaintext passwords in config file with hashed versions. * * @since 1.7 * @param string $config_file Full path to file - * @return true if overwrite was successful, an error message otherwise + * @return true|string if overwrite was successful, an error message otherwise */ function yourls_hash_passwords_now( $config_file ) { - if( !is_readable( $config_file ) ) - return 'cannot read file'; // not sure that can actually happen... - - if( !is_writable( $config_file ) ) - return 'cannot write file'; - - // Include file to read value of $yourls_user_passwords - // Temporary suppress error reporting to avoid notices about redeclared constants - $errlevel = error_reporting(); - error_reporting( 0 ); - require $config_file; - error_reporting( $errlevel ); - - $configdata = file_get_contents( $config_file ); - if( $configdata == false ) - return 'could not read file'; - - $to_hash = 0; // keep track of number of passwords that need hashing - foreach ( $yourls_user_passwords as $user => $password ) { - if ( !yourls_has_phpass_password( $user ) && !yourls_has_md5_password( $user ) ) { - $to_hash++; - $hash = yourls_phpass_hash( $password ); - // PHP would interpret $ as a variable, so replace it in storage. - $hash = str_replace( '$', '!', $hash ); - $quotes = "'" . '"'; - $pattern = "/[$quotes]${user}[$quotes]\s*=>\s*[$quotes]" . preg_quote( $password, '/' ) . "[$quotes]/"; - $replace = "'$user' => 'phpass:$hash' /* Password encrypted by YOURLS */ "; - $count = 0; - $configdata = preg_replace( $pattern, $replace, $configdata, -1, $count ); - // There should be exactly one replacement. Otherwise, fast fail. - if ( $count != 1 ) { - yourls_debug_log( "Problem with preg_replace for password hash of user $user" ); - return 'preg_replace problem'; - } - } - } - - if( $to_hash == 0 ) - return 0; // There was no password to encrypt - - $success = file_put_contents( $config_file, $configdata ); - if ( $success === FALSE ) { - yourls_debug_log( 'Failed writing to ' . $config_file ); - return 'could not write file'; - } + if( !is_readable( $config_file ) ) { + yourls_debug_log( 'Cannot hash passwords: cannot read file ' . $config_file ); + return 'cannot read file'; // not sure that can actually happen... + } + + if( !is_writable( $config_file ) ) { + yourls_debug_log( 'Cannot hash passwords: cannot write file ' . $config_file ); + return 'cannot write file'; + } + + $yourls_user_passwords = []; + // Include file to read value of $yourls_user_passwords + // Temporary suppress error reporting to avoid notices about redeclared constants + $errlevel = error_reporting(); + error_reporting( 0 ); + require $config_file; + error_reporting( $errlevel ); + + $configdata = file_get_contents( $config_file ); + + if( $configdata == false ) { + yourls_debug_log('Cannot hash passwords: file_get_contents() false with ' . $config_file); + return 'could not read file'; + } + + $to_hash = 0; // keep track of number of passwords that need hashing + foreach ( $yourls_user_passwords as $user => $password ) { + // avoid "deprecated" warning when password is null -- see test case in tests/data/auth/preg_replace_problem.php + $password ??= ''; + if ( !yourls_has_phpass_password( $user ) && !yourls_has_md5_password( $user ) ) { + $to_hash++; + $hash = yourls_phpass_hash( $password ); + // PHP would interpret $ as a variable, so replace it in storage. + $hash = str_replace( '$', '!', $hash ); + $quotes = "'" . '"'; + $pattern = "/[$quotes]" . preg_quote( $user, '/' ) . "[$quotes]\s*=>\s*[$quotes]" . preg_quote( $password, '/' ) . "[$quotes]/"; + $replace = "'$user' => 'phpass:$hash' /* Password encrypted by YOURLS */ "; + $count = 0; + $configdata = preg_replace( $pattern, $replace, $configdata, -1, $count ); + // There should be exactly one replacement. Otherwise, fast fail. + if ( $count != 1 ) { + yourls_debug_log( "Problem with preg_replace for password hash of user $user" ); + return 'preg_replace problem'; + } + } + } + + if( $to_hash == 0 ) { + yourls_debug_log('Cannot hash passwords: no password found in ' . $config_file); + return 'no password found'; + } + + $success = file_put_contents( $config_file, $configdata ); + if ( $success === FALSE ) { + yourls_debug_log( 'Failed writing to ' . $config_file ); + return 'could not write file'; + } yourls_debug_log('Successfully encrypted passwords in ' . basename($config_file)); - return true; + return true; } /** - * Hash a password using phpass + * Create a password hash * * @since 1.7 * @param string $password password to hash * @return string hashed password */ function yourls_phpass_hash( $password ) { - $hasher = yourls_phpass_instance(); - return $hasher->HashPassword( $password ); + /** + * Filter for hashing algorithm. See https://www.php.net/manual/en/function.password-hash.php + * Hashing algos are available if PHP was compiled with it. + * PASSWORD_BCRYPT is always available. + */ + $algo = yourls_apply_filter('hash_algo', PASSWORD_BCRYPT); + + /** + * Filter for hashing options. See https://www.php.net/manual/en/function.password-hash.php + * A typical option for PASSWORD_BCRYPT would be ['cost' => ] + * We're leaving the options at default values, which means a cost of 10 for PASSWORD_BCRYPT. + * + * If willing to modify this, be warned about the computing time, as there is a 2^n factor. + * See https://gist.github.com/ozh/65a75392b7cb254131cc55afd28de99b for examples. + */ + $options = yourls_apply_filter('hash_options', [] ); + + return password_hash($password, $algo, $options); } /** - * Check a clear password against a phpass hash + * Verify that a password matches a hash * * @since 1.7 * @param string $password clear (eg submitted in a form) password - * @param string $hash hash supposedly generated by phpass - * @return bool true if the hash matches the password once hashed by phpass, false otherwise + * @param string $hash hash + * @return bool true if the hash matches the password, false otherwise */ function yourls_phpass_check( $password, $hash ) { - $hasher = yourls_phpass_instance(); - return $hasher->CheckPassword( $password, $hash ); -} - -/** - * Helper function: create new instance or return existing instance of phpass class - * - * @since 1.7 - * @param int $iteration iteration count - 8 is default in phpass - * @param bool $portable flag to force portable (cross platform and system independant) hashes - false to use whatever the system can do best - * @return object a PasswordHash instance - */ -function yourls_phpass_instance( $iteration = 8, $portable = false ) { - $iteration = yourls_apply_filter( 'phpass_new_instance_iteration', $iteration ); - $portable = yourls_apply_filter( 'phpass_new_instance_portable', $portable ); - - static $instance = false; - if( $instance == false ) { - $instance = new \Ozh\Phpass\PasswordHash( $iteration, $portable ); - } - - return $instance; + return password_verify($password, $hash); } @@ -273,17 +288,17 @@ function yourls_phpass_instance( $iteration = 8, $portable = false ) { * @return bool true if any passwords are cleartext */ function yourls_has_cleartext_passwords() { - global $yourls_user_passwords; - foreach ( $yourls_user_passwords as $user => $pwdata ) { - if ( !yourls_has_md5_password( $user ) && !yourls_has_phpass_password( $user ) ) { - return true; - } - } - return false; + global $yourls_user_passwords; + foreach ( $yourls_user_passwords as $user => $pwdata ) { + if ( !yourls_has_md5_password( $user ) && !yourls_has_phpass_password( $user ) ) { + return true; + } + } + return false; } /** - * Check if a user has a hashed password + * Check if a user has a md5 hashed password * * Check if a user password is 'md5:[38 chars]'. * TODO: deprecate this when/if we have proper user management with password hashes stored in the DB @@ -293,43 +308,45 @@ function yourls_has_cleartext_passwords() { * @return bool true if password hashed, false otherwise */ function yourls_has_md5_password( $user ) { - global $yourls_user_passwords; - return( isset( $yourls_user_passwords[ $user ] ) - && substr( $yourls_user_passwords[ $user ], 0, 4 ) == 'md5:' - && strlen( $yourls_user_passwords[ $user ] ) == 42 // http://www.google.com/search?q=the+answer+to+life+the+universe+and+everything - ); + global $yourls_user_passwords; + return( isset( $yourls_user_passwords[ $user ] ) + && substr( $yourls_user_passwords[ $user ], 0, 4 ) == 'md5:' + && strlen( $yourls_user_passwords[ $user ] ) == 42 // http://www.google.com/search?q=the+answer+to+life+the+universe+and+everything + ); } /** - * Check if a user's password is hashed with PHPASS. + * Check if a user's password is hashed with password_hash * * Check if a user password is 'phpass:[lots of chars]'. + * (For historical reason we're using 'phpass' as an identifier.) * TODO: deprecate this when/if we have proper user management with password hashes stored in the DB * * @since 1.7 * @param string $user user login - * @return bool true if password hashed with PHPASS, otherwise false + * @return bool true if password hashed with password_hash, otherwise false */ function yourls_has_phpass_password( $user ) { - global $yourls_user_passwords; - return( isset( $yourls_user_passwords[ $user ] ) - && substr( $yourls_user_passwords[ $user ], 0, 7 ) == 'phpass:' - ); + global $yourls_user_passwords; + return( isset( $yourls_user_passwords[ $user ] ) + && substr( $yourls_user_passwords[ $user ], 0, 7 ) == 'phpass:' + ); } /** * Check auth against encrypted COOKIE data. Sets user if applicable, returns bool * + * @return bool true if authenticated, false otherwise */ function yourls_check_auth_cookie() { - global $yourls_user_passwords; - foreach( $yourls_user_passwords as $valid_user => $valid_password ) { - if ( yourls_cookie_value( $valid_user ) === $_COOKIE[ yourls_cookie_name() ] ) { - yourls_set_user( $valid_user ); - return true; - } - } - return false; + global $yourls_user_passwords; + foreach( $yourls_user_passwords as $valid_user => $valid_password ) { + if ( yourls_cookie_value( $valid_user ) === $_COOKIE[ yourls_cookie_name() ] ) { + yourls_set_user( $valid_user ); + return true; + } + } + return false; } /** @@ -363,21 +380,21 @@ function yourls_check_signature_timestamp() { return false; } - // Check signature & timestamp against all possible users - global $yourls_user_passwords; - foreach( $yourls_user_passwords as $valid_user => $valid_password ) { - if ( + // Check signature & timestamp against all possible users + global $yourls_user_passwords; + foreach( $yourls_user_passwords as $valid_user => $valid_password ) { + if ( hash( $hash_function, $_REQUEST['timestamp'].yourls_auth_signature( $valid_user ) ) === $_REQUEST['signature'] or hash( $hash_function, yourls_auth_signature( $valid_user ).$_REQUEST['timestamp'] ) === $_REQUEST['signature'] - ) { - yourls_set_user( $valid_user ); - return true; - } - } + ) { + yourls_set_user( $valid_user ); + return true; + } + } // Signature doesn't match known user - return false; + return false; } /** @@ -390,70 +407,77 @@ function yourls_check_signature() { if( !isset( $_REQUEST['signature'] ) OR empty( $_REQUEST['signature'] ) ) return false; - // Check signature against all possible users + // Check signature against all possible users global $yourls_user_passwords; - foreach( $yourls_user_passwords as $valid_user => $valid_password ) { - if ( yourls_auth_signature( $valid_user ) === $_REQUEST['signature'] ) { - yourls_set_user( $valid_user ); - return true; - } - } + foreach( $yourls_user_passwords as $valid_user => $valid_password ) { + if ( yourls_auth_signature( $valid_user ) === $_REQUEST['signature'] ) { + yourls_set_user( $valid_user ); + return true; + } + } // Signature doesn't match known user - return false; + return false; } /** * Generate secret signature hash * + * @param false|string $username Username to generate signature for, or false to use current user + * @return string Signature */ function yourls_auth_signature( $username = false ) { - if( !$username && defined('YOURLS_USER') ) { - $username = YOURLS_USER; - } - return ( $username ? substr( yourls_salt( $username ), 0, 10 ) : 'Cannot generate auth signature: no username' ); + if( !$username && defined('YOURLS_USER') ) { + $username = YOURLS_USER; + } + return ( $username ? substr( yourls_salt( $username ), 0, 10 ) : 'Cannot generate auth signature: no username' ); } /** * Check if timestamp is not too old * + * @param int $time Timestamp to check + * @return bool True if timestamp is valid */ function yourls_check_timestamp( $time ) { - $now = time(); - // Allow timestamp to be a little in the future or the past -- see Issue 766 - return yourls_apply_filter( 'check_timestamp', abs( $now - (int)$time ) < yourls_get_nonce_life(), $time ); + $now = time(); + // Allow timestamp to be a little in the future or the past -- see Issue 766 + return yourls_apply_filter( 'check_timestamp', abs( $now - (int)$time ) < yourls_get_nonce_life(), $time ); } /** * Store new cookie. No $user will delete the cookie. * - * @param mixed $user String, user login, or null to delete cookie + * @param string $user User login, or empty string to delete cookie + * @return void */ -function yourls_store_cookie( $user = null ) { +function yourls_store_cookie( $user = '' ) { // No user will delete the cookie with a cookie time from the past - if( !$user ) { - $time = time() - 3600; - } else { - $time = time() + yourls_get_cookie_life(); - } + if( !$user ) { + $time = time() - 3600; + } else { + $time = time() + yourls_get_cookie_life(); + } $path = yourls_apply_filter( 'setcookie_path', '/' ); - $domain = yourls_apply_filter( 'setcookie_domain', parse_url( yourls_get_yourls_site(), PHP_URL_HOST ) ); - $secure = yourls_apply_filter( 'setcookie_secure', yourls_is_ssl() ); - $httponly = yourls_apply_filter( 'setcookie_httponly', true ); + $domain = yourls_apply_filter( 'setcookie_domain', parse_url( yourls_get_yourls_site(), PHP_URL_HOST ) ); + $secure = yourls_apply_filter( 'setcookie_secure', yourls_is_ssl() ); + $httponly = yourls_apply_filter( 'setcookie_httponly', true ); + + // Some browsers refuse to store localhost cookie + if ( $domain == 'localhost' ) + $domain = ''; - // Some browsers refuse to store localhost cookie - if ( $domain == 'localhost' ) - $domain = ''; + yourls_do_action( 'pre_setcookie', $user, $time, $path, $domain, $secure, $httponly ); if ( !headers_sent( $filename, $linenum ) ) { yourls_setcookie( yourls_cookie_name(), yourls_cookie_value( $user ), $time, $path, $domain, $secure, $httponly ); - } else { - // For some reason cookies were not stored: action to be able to debug that - yourls_do_action( 'setcookie_failed', $user ); + } else { + // For some reason cookies were not stored: action to be able to debug that + yourls_do_action( 'setcookie_failed', $user ); yourls_debug_log( "Could not store cookie: headers already sent in $filename on line $linenum" ); - } + } } /** @@ -461,7 +485,6 @@ function yourls_store_cookie( $user = null ) { * * @see https://github.com/GoogleChromeLabs/samesite-examples/blob/master/php.md * @see https://stackoverflow.com/a/59654832/36850 - * @see https://3v4l.org/uKEtH for compat tests * @see https://www.php.net/manual/en/function.setcookie.php * * @since 1.7.7 @@ -477,28 +500,25 @@ function yourls_store_cookie( $user = null ) { function yourls_setcookie($name, $value, $expire, $path, $domain, $secure, $httponly) { $samesite = yourls_apply_filter('setcookie_samesite', 'Lax' ); - if (PHP_VERSION_ID < 70300) { - return(setcookie($name, $value, $expire, "$path; samesite=$samesite", $domain, $secure, $httponly)); - } - else { - return(setcookie($name, $value, array( - 'expires' => $expire, - 'path' => $path, - 'domain' => $domain, - 'samesite' => $samesite, - 'secure' => $secure, - 'httponly' => $httponly, - ))); - } + return(setcookie($name, $value, array( + 'expires' => $expire, + 'path' => $path, + 'domain' => $domain, + 'samesite' => $samesite, + 'secure' => $secure, + 'httponly' => $httponly, + ))); } /** * Set user name * + * @param string $user Username + * @return void */ function yourls_set_user( $user ) { - if( !defined( 'YOURLS_USER' ) ) - define( 'YOURLS_USER', $user ); + if( !defined( 'YOURLS_USER' ) ) + define( 'YOURLS_USER', $user ); } /** @@ -512,7 +532,7 @@ function yourls_set_user( $user ) { * @return integer cookie life span, in seconds */ function yourls_get_cookie_life() { - return yourls_apply_filter( 'get_cookie_life', YOURLS_COOKIE_LIFE ); + return yourls_apply_filter( 'get_cookie_life', YOURLS_COOKIE_LIFE ); } /** @@ -527,7 +547,7 @@ function yourls_get_cookie_life() { * @return integer nonce life span, in seconds */ function yourls_get_nonce_life() { - return yourls_apply_filter( 'get_nonce_life', YOURLS_NONCE_LIFE ); + return yourls_apply_filter( 'get_nonce_life', YOURLS_NONCE_LIFE ); } /** @@ -552,7 +572,7 @@ function yourls_cookie_name() { * @return string cookie value */ function yourls_cookie_value( $user ) { - return yourls_apply_filter( 'set_cookie_value', yourls_salt( $user ), $user ); + return yourls_apply_filter( 'set_cookie_value', yourls_salt( $user ?? '' ), $user ); } /** @@ -560,95 +580,135 @@ function yourls_cookie_value( $user ) { * * Actually, this returns a float: ceil rounds up a value but is of type float, see https://www.php.net/ceil * + * @return float */ function yourls_tick() { - return ceil( time() / yourls_get_nonce_life() ); + return ceil( time() / yourls_get_nonce_life() ); } /** - * Return salted string + * Return hashed string + * + * This function is badly named, it's not a salt or a salted string : it's a cryptographic hash. * + * @since 1.4.1 + * @param string $string string to salt + * @return string hashed string */ function yourls_salt( $string ) { - $salt = defined('YOURLS_COOKIEKEY') ? YOURLS_COOKIEKEY : md5(__FILE__) ; - return yourls_apply_filter( 'yourls_salt', md5 ($string . $salt), $string ); + $salt = defined('YOURLS_COOKIEKEY') ? YOURLS_COOKIEKEY : md5(__FILE__) ; + return yourls_apply_filter( 'yourls_salt', hash_hmac( yourls_hmac_algo(), $string, $salt), $string ); +} + +/** + * Return an available hash_hmac() algorithm + * + * @since 1.8.3 + * @return string hash_hmac() algorithm + */ +function yourls_hmac_algo() { + $algo = yourls_apply_filter( 'hmac_algo', 'sha256' ); + if( !in_array( $algo, hash_hmac_algos() ) ) { + $algo = 'sha256'; + } + return $algo; } /** * Create a time limited, action limited and user limited token * + * @param string $action Action to create nonce for + * @param false|string $user Optional user string, false for current user + * @return string Nonce token */ -function yourls_create_nonce( $action, $user = false ) { - if( false == $user ) - $user = defined( 'YOURLS_USER' ) ? YOURLS_USER : '-1'; - $tick = yourls_tick(); - $nonce = substr( yourls_salt($tick . $action . $user), 0, 10 ); - // Allow plugins to alter the nonce - return yourls_apply_filter( 'create_nonce', $nonce, $action, $user ); +function yourls_create_nonce($action, $user = false ) { + if( false === $user ) { + $user = defined('YOURLS_USER') ? YOURLS_USER : '-1'; + } + $tick = yourls_tick(); + $nonce = substr( yourls_salt($tick . $action . $user), 0, 10 ); + // Allow plugins to alter the nonce + return yourls_apply_filter( 'create_nonce', $nonce, $action, $user ); } /** - * Create a nonce field for inclusion into a form + * Echoes or returns a nonce field for inclusion into a form * + * @param string $action Action to create nonce for + * @param string $name Optional name of nonce field -- defaults to 'nonce' + * @param false|string $user Optional user string, false if unspecified + * @param bool $echo True to echo, false to return nonce field + * @return string Nonce field */ -function yourls_nonce_field( $action, $name = 'nonce', $user = false, $echo = true ) { - $field = ''; - if( $echo ) - echo $field."\n"; - return $field; +function yourls_nonce_field($action, $name = 'nonce', $user = false, $echo = true ) { + $field = ''; + if( $echo ) + echo $field."\n"; + return $field; } /** * Add a nonce to a URL. If URL omitted, adds nonce to current URL * + * @param string $action Action to create nonce for + * @param string $url Optional URL to add nonce to -- defaults to current URL + * @param string $name Optional name of nonce field -- defaults to 'nonce' + * @param false|string $user Optional user string, false if unspecified + * @return string URL with nonce added */ -function yourls_nonce_url( $action, $url = false, $name = 'nonce', $user = false ) { - $nonce = yourls_create_nonce( $action, $user ); - return yourls_add_query_arg( $name, $nonce, $url ); +function yourls_nonce_url($action, $url = false, $name = 'nonce', $user = false ) { + $nonce = yourls_create_nonce( $action, $user ); + return yourls_add_query_arg( $name, $nonce, $url ); } /** * Check validity of a nonce (ie time span, user and action match). * - * Returns true if valid, dies otherwise (yourls_die() or die($return) if defined) - * if $nonce is false or unspecified, it will use $_REQUEST['nonce'] + * Returns true if valid, dies otherwise (yourls_die() or die($return) if defined). + * If $nonce is false or unspecified, it will use $_REQUEST['nonce'] * + * @param string $action + * @param false|string $nonce Optional, string: nonce value, or false to use $_REQUEST['nonce'] + * @param false|string $user Optional, string user, false for current user + * @param string $return Optional, string: message to die with if nonce is invalid + * @return bool|void True if valid, dies otherwise */ -function yourls_verify_nonce( $action, $nonce = false, $user = false, $return = '' ) { - // get user - if( false == $user ) - $user = defined( 'YOURLS_USER' ) ? YOURLS_USER : '-1'; +function yourls_verify_nonce($action, $nonce = false, $user = false, $return = '' ) { + // Get user + if( false === $user ) { + $user = defined('YOURLS_USER') ? YOURLS_USER : '-1'; + } - // get current nonce value - if( false == $nonce && isset( $_REQUEST['nonce'] ) ) - $nonce = $_REQUEST['nonce']; + // Get nonce value from $_REQUEST if not specified + if( false === $nonce && isset( $_REQUEST['nonce'] ) ) { + $nonce = $_REQUEST['nonce']; + } - // Allow plugins to short-circuit the rest of the function - $valid = yourls_apply_filter( 'verify_nonce', false, $action, $nonce, $user, $return ); - if ($valid) { - return true; - } + // Allow plugins to short-circuit the rest of the function + if (yourls_apply_filter( 'verify_nonce', false, $action, $nonce, $user, $return ) === true) { + return true; + } - // what nonce should be - $valid = yourls_create_nonce( $action, $user ); + // What nonce should be + $valid = yourls_create_nonce( $action, $user ); - if( $nonce == $valid ) { - return true; - } else { - if( $return ) - die( $return ); - yourls_die( yourls__( 'Unauthorized action or expired link' ), yourls__( 'Error' ), 403 ); - } + if( $nonce === $valid ) { + return true; + } else { + if( $return ) + die( $return ); + yourls_die( yourls__( 'Unauthorized action or expired link' ), yourls__( 'Error' ), 403 ); + } } /** * Check if YOURLS_USER comes from environment variables * * @since 1.8.2 - * @return bool true if YOURLS_USER and YOURLS_PASSWORD are defined as environment variables + * @return bool true if YOURLS_USER and YOURLS_PASSWORD are defined as environment variables */ function yourls_is_user_from_env() { - return yourls_apply_filter('is_user_from_env', getenv('YOURLS_USER') && getenv('YOURLS_PASSWORD')); + return yourls_apply_filter('is_user_from_env', getenv('YOURLS_USER') && getenv('YOURLS_PASSWORD')); } @@ -657,7 +717,7 @@ function yourls_is_user_from_env() { * * By default, passwords are hashed. They are not if * - there is no password in clear text in the config file (ie everything is already hashed) - * - the user defined constant YOURLS_NO_HASH_PASSWORD is true, see https://github.com/YOURLS/YOURLS/wiki/Username-Passwords#but-i-dont-want-to-encrypt-my-password- + * - the user defined constant YOURLS_NO_HASH_PASSWORD is true, see https://docs.yourls.org/guide/essentials/credentials.html#i-don-t-want-to-encrypt-my-password * - YOURLS_USER and YOURLS_PASSWORD are provided by the environment, not the config file * * @since 1.8.2 diff --git a/includes/functions-compat.php b/includes/functions-compat.php index 4bc1330e4..2dc17d342 100644 --- a/includes/functions-compat.php +++ b/includes/functions-compat.php @@ -11,9 +11,9 @@ * */ if( !function_exists( 'json_encode' ) ) { - function json_encode( $array ) { - return yourls_array_to_json( $array ); - } + function json_encode( $array ) { + return yourls_array_to_json( $array ); + } } /** @@ -26,60 +26,60 @@ function json_encode( $array ) { */ function yourls_array_to_json( $array ){ - if( !is_array( $array ) ){ - return false; - } + if( !is_array( $array ) ){ + return false; + } - $associative = count( array_diff( array_keys($array), array_keys( array_keys( $array )) )); - if( $associative ){ + $associative = count( array_diff( array_keys($array), array_keys( array_keys( $array )) )); + if( $associative ){ - $construct = array(); - foreach( $array as $key => $value ){ + $construct = array(); + foreach( $array as $key => $value ){ - // We first copy each key/value pair into a staging array, - // formatting each key and value properly as we go. + // We first copy each key/value pair into a staging array, + // formatting each key and value properly as we go. - // Format the key: - if( is_numeric( $key ) ){ - $key = "key_$key"; - } - $key = '"'.addslashes( $key ).'"'; + // Format the key: + if( is_numeric( $key ) ){ + $key = "key_$key"; + } + $key = '"'.addslashes( $key ).'"'; - // Format the value: - if( is_array( $value )){ - $value = yourls_array_to_json( $value ); - } else if( !is_numeric( $value ) || is_string( $value ) ){ - $value = '"'.addslashes( $value ).'"'; - } + // Format the value: + if( is_array( $value )){ + $value = yourls_array_to_json( $value ); + } else if( !is_numeric( $value ) || is_string( $value ) ){ + $value = '"'.addslashes( $value ).'"'; + } - // Add to staging array: - $construct[] = "$key: $value"; - } + // Add to staging array: + $construct[] = "$key: $value"; + } - // Then we collapse the staging array into the JSON form: - $result = "{ " . implode( ", ", $construct ) . " }"; + // Then we collapse the staging array into the JSON form: + $result = "{ " . implode( ", ", $construct ) . " }"; - } else { // If the array is a vector (not associative): + } else { // If the array is a vector (not associative): - $construct = array(); - foreach( $array as $value ){ + $construct = array(); + foreach( $array as $value ){ - // Format the value: - if( is_array( $value )){ - $value = yourls_array_to_json( $value ); - } else if( !is_numeric( $value ) || is_string( $value ) ){ - $value = '"'.addslashes($value).'"'; - } + // Format the value: + if( is_array( $value )){ + $value = yourls_array_to_json( $value ); + } else if( !is_numeric( $value ) || is_string( $value ) ){ + $value = '"'.addslashes($value).'"'; + } - // Add to staging array: - $construct[] = $value; - } + // Add to staging array: + $construct[] = $value; + } - // Then we collapse the staging array into the JSON form: - $result = "[ " . implode( ", ", $construct ) . " ]"; - } + // Then we collapse the staging array into the JSON form: + $result = "[ " . implode( ", ", $construct ) . " ]"; + } - return $result; + return $result; } @@ -88,23 +88,23 @@ function yourls_array_to_json( $array ){ * */ if ( !function_exists( 'bcdiv' ) ) { - function bcdiv( $dividend, $divisor ) { - $quotient = floor( $dividend/$divisor ); - return $quotient; - } - function bcmod( $dividend, $modulo ) { - $remainder = $dividend%$modulo; - return $remainder; - } - function bcmul( $left, $right ) { - return $left * $right; - } - function bcadd( $left, $right ) { - return $left + $right; - } - function bcpow( $base, $power ) { - return pow( $base, $power ); - } + function bcdiv( $dividend, $divisor ) { + $quotient = floor( $dividend/$divisor ); + return $quotient; + } + function bcmod( $dividend, $modulo ) { + $remainder = $dividend%$modulo; + return $remainder; + } + function bcmul( $left, $right ) { + return $left * $right; + } + function bcadd( $left, $right ) { + return $left + $right; + } + function bcpow( $base, $power ) { + return pow( $base, $power ); + } } // @codeCoverageIgnoreEnd diff --git a/includes/functions-debug.php b/includes/functions-debug.php index 85b4f0bbd..cac4f2d8b 100644 --- a/includes/functions-debug.php +++ b/includes/functions-debug.php @@ -6,8 +6,8 @@ /** * Add a message to the debug log * - * When in debug mode ( YOURLS_DEBUG == true ) the debug log is echoed in yourls_html_footer() - * Log messages are appended to $ydb->debug_log array, which is instanciated within class ezSQLcore_YOURLS + * When in debug mode (YOURLS_DEBUG == true) the debug log is echoed in yourls_html_footer() + * Log messages are appended to $ydb->debug_log array, which is instantiated within class Database\YDB * * @since 1.7 * @param string $msg Message to add to the debug log @@ -15,9 +15,7 @@ */ function yourls_debug_log( $msg ) { yourls_do_action( 'debug_log', $msg ); - // Get the DB object ($ydb), get its profiler (\Aura\Sql\Profiler\Profiler), its logger (\Aura\Sql\Profiler\MemoryLogger) and - // pass it a unused argument (loglevel) and the message - yourls_get_db()->getProfiler()->getLogger()->log( 'debug', $msg); + yourls_get_db('read-debug_log')->getProfiler()->getLogger()->log('debug', $msg); return $msg; } @@ -28,15 +26,16 @@ function yourls_debug_log( $msg ) { * @return array */ function yourls_get_debug_log() { - return yourls_get_db()->getProfiler()->getLogger()->getMessages(); + return yourls_get_db('read-get_debug_log')->getProfiler()->getLogger()->getMessages(); } /** * Get number of SQL queries performed * + * @return int */ function yourls_get_num_queries() { - return yourls_apply_filter( 'get_num_queries', yourls_get_db()->get_num_queries() ); + return yourls_apply_filter( 'get_num_queries', yourls_get_db('read-get_num_queries')->get_num_queries() ); } /** @@ -44,10 +43,11 @@ function yourls_get_num_queries() { * * @since 1.7.3 * @param bool $bool Debug on or off + * @return void */ function yourls_debug_mode( $bool ) { // log queries if true - yourls_get_db()->getProfiler()->setActive( (bool)$bool ); + yourls_get_db('read-debug_mode')->getProfiler()->setActive( (bool)$bool ); // report notices if true $level = $bool ? -1 : ( E_ERROR | E_PARSE ); diff --git a/includes/functions-deprecated.php b/includes/functions-deprecated.php index daa2308ad..662ffb210 100644 --- a/includes/functions-deprecated.php +++ b/includes/functions-deprecated.php @@ -5,10 +5,94 @@ * * Note to devs: when deprecating a function, move it here. Then check all the places * in core that might be using it, including core plugins. + * + * Usage : yourls_deprecated_function( 'function_name', 'version', 'replacement' ); + * Output: "{function_name} is deprecated since version {version}! Use {replacement} instead." + * + * Usage : yourls_deprecated_function( 'function_name', 'version' ); + * Output: "{function_name} is deprecated since version {version} with no alternative available." + * + * @see yourls_deprecated_function() */ // @codeCoverageIgnoreStart +/** + * Plugin activation sandbox + * + * @since 1.8.3 + * @deprecated 1.9.2 + * @param string $pluginfile Plugin filename (full path) + * @return string|true string if error or true if success + */ +function yourls_activate_plugin_sandbox( $pluginfile ) { + yourls_deprecated_function( __FUNCTION__, '1.9.1', 'yourls_include_file_sandbox'); + return yourls_include_file_sandbox($pluginfile); +} + +/** + * Return current admin page, or null if not an admin page. Was not used anywhere. + * + * @return mixed string if admin page, null if not an admin page + * @since 1.6 + * @deprecated 1.9.1 + */ +function yourls_current_admin_page() { + yourls_deprecated_function( __FUNCTION__, '1.9.1' ); + if( yourls_is_admin() ) { + $current = substr( yourls_get_request(), 6 ); + if( $current === false ) + $current = 'index.php'; // if current page is http://sho.rt/admin/ instead of http://sho.rt/admin/index.php + + return $current; + } + return null; +} + +/** + * PHP emulation of JS's encodeURI + * + * @link https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/encodeURI + * @deprecated 1.9.1 + * @param string $url + * @return string + */ +function yourls_encodeURI($url) { + yourls_deprecated_function( __FUNCTION__, '1.9.1', '' ); + // Decode URL all the way + $result = yourls_rawurldecode_while_encoded( $url ); + // Encode once + $result = strtr( rawurlencode( $result ), array ( + '%3B' => ';', '%2C' => ',', '%2F' => '/', '%3F' => '?', '%3A' => ':', '%40' => '@', + '%26' => '&', '%3D' => '=', '%2B' => '+', '%24' => '$', '%21' => '!', '%2A' => '*', + '%27' => '\'', '%28' => '(', '%29' => ')', '%23' => '#', + ) ); + // @TODO: + // Known limit: this will most likely break IDN URLs such as http://www.académie-française.fr/ + // To fully support IDN URLs, advocate use of a plugin. + return yourls_apply_filter( 'encodeURI', $result, $url ); +} + +/** + * Check if a file is a plugin file + * + * @deprecated 1.8.3 + */ +function yourls_validate_plugin_file( $file ) { + yourls_deprecated_function( __FUNCTION__, '1.8.3', 'yourls_is_a_plugin_file' ); + return yourls_is_a_plugin_file($file); +} + +/** + * Return a unique(ish) hash for a string to be used as a valid HTML id + * + * @deprecated 1.8.3 + */ +function yourls_string2htmlid( $string ) { + yourls_deprecated_function( __FUNCTION__, '1.8.3', 'yourls_unique_element_id' ); + return yourls_apply_filter( 'string2htmlid', 'y'.abs( crc32( $string ) ) ); +} + /** * Get search text from query string variables search_protocol, search_slashes and search * @@ -45,12 +129,12 @@ function yourls_get_search_text() { */ function yourls_current_time( $type, $gmt = 0 ) { yourls_deprecated_function( __FUNCTION__, '1.7.10', 'yourls_get_timestamp' ); - switch ( $type ) { - case 'mysql': - return ( $gmt ) ? gmdate( 'Y-m-d H:i:s' ) : gmdate( 'Y-m-d H:i:s', yourls_get_timestamp( time() )); - case 'timestamp': - return ( $gmt ) ? time() : yourls_get_timestamp( time() ); - } + switch ( $type ) { + case 'mysql': + return ( $gmt ) ? gmdate( 'Y-m-d H:i:s' ) : gmdate( 'Y-m-d H:i:s', yourls_get_timestamp( time() )); + case 'timestamp': + return ( $gmt ) ? time() : yourls_get_timestamp( time() ); + } } /** @@ -85,8 +169,8 @@ function yourls_sanitize_string( $string, $restrict_to_shorturl_charset = false * */ function yourls_favicon( $echo = true ) { - yourls_deprecated_function( __FUNCTION__, '1.7.10', 'yourls_get_yourls_favicon_url' ); - return yourls_get_yourls_favicon_url( $echo ); + yourls_deprecated_function( __FUNCTION__, '1.7.10', 'yourls_get_yourls_favicon_url' ); + return yourls_get_yourls_favicon_url( $echo ); } /** @@ -96,8 +180,8 @@ function yourls_favicon( $echo = true ) { * */ function yourls_get_link_stats( $url ) { - yourls_deprecated_function( __FUNCTION__, '1.7.10', 'yourls_get_keyword_stats' ); - return yourls_get_keyword_stats( $url ); + yourls_deprecated_function( __FUNCTION__, '1.7.10', 'yourls_get_keyword_stats' ); + return yourls_get_keyword_stats( $url ); } /** @@ -108,8 +192,8 @@ function yourls_get_link_stats( $url ) { * */ function yourls_url_exists( $url ) { - yourls_deprecated_function( __FUNCTION__, '1.7.10', 'yourls_long_url_exists' ); - return yourls_long_url_exists( $url ); + yourls_deprecated_function( __FUNCTION__, '1.7.10', 'yourls_long_url_exists' ); + return yourls_long_url_exists( $url ); } /** @@ -117,8 +201,8 @@ function yourls_url_exists( $url ) { * */ function yourls_plural( $word, $count=1 ) { - yourls_deprecated_function( __FUNCTION__, '1.6', 'yourls_n' ); - return $word . ($count > 1 ? 's' : ''); + yourls_deprecated_function( __FUNCTION__, '1.6', 'yourls_n' ); + return $word . ($count > 1 ? 's' : ''); } /** @@ -126,10 +210,10 @@ function yourls_plural( $word, $count=1 ) { * */ function yourls_get_duplicate_keywords( $longurl ) { - yourls_deprecated_function( __FUNCTION__, '1.7', 'yourls_get_longurl_keywords' ); - if( !yourls_allow_duplicate_longurls() ) - return NULL; - return yourls_apply_filter( 'get_duplicate_keywords', yourls_get_longurl_keywords ( $longurl ), $longurl ); + yourls_deprecated_function( __FUNCTION__, '1.7', 'yourls_get_longurl_keywords' ); + if( !yourls_allow_duplicate_longurls() ) + return NULL; + return yourls_apply_filter( 'get_duplicate_keywords', yourls_get_longurl_keywords ( $longurl ), $longurl ); } /** @@ -139,8 +223,8 @@ function yourls_get_duplicate_keywords( $longurl ) { * */ function yourls_intval( $int ) { - yourls_deprecated_function( __FUNCTION__, '1.7', 'yourls_sanitize_int' ); - return yourls_escape( $int ); + yourls_deprecated_function( __FUNCTION__, '1.7', 'yourls_sanitize_int' ); + return yourls_escape( $int ); } /** @@ -148,8 +232,8 @@ function yourls_intval( $int ) { * */ function yourls_get_remote_content( $url, $maxlen = 4096, $timeout = 5 ) { - yourls_deprecated_function( __FUNCTION__, '1.7', 'yourls_http_get_body' ); - return yourls_http_get_body( $url ); + yourls_deprecated_function( __FUNCTION__, '1.7', 'yourls_http_get_body' ); + return yourls_http_get_body( $url ); } /** @@ -166,8 +250,8 @@ function yourls_get_remote_content( $url, $maxlen = 4096, $timeout = 5 ) { * @return mixed */ function yourls_apply_filters( $hook, $value = '' ) { - yourls_deprecated_function( __FUNCTION__, '1.7.1', 'yourls_apply_filter' ); - return yourls_apply_filter( $hook, $value ); + yourls_deprecated_function( __FUNCTION__, '1.7.1', 'yourls_apply_filter' ); + return yourls_apply_filter( $hook, $value ); } /** @@ -175,23 +259,22 @@ function yourls_apply_filters( $hook, $value = '' ) { * */ function yourls_has_interface() { - yourls_deprecated_function( __FUNCTION__, '1.7.1' ); - if( yourls_is_API() or yourls_is_GO() ) - return false; - return true; + yourls_deprecated_function( __FUNCTION__, '1.7.1' ); + if( yourls_is_API() or yourls_is_GO() ) + return false; + return true; } /** * Check if a proxy is defined for HTTP requests * - * @uses YOURLS_PROXY * @since 1.7 * @deprecated 1.7.1 * @return bool true if a proxy is defined, false otherwise */ function yourls_http_proxy_is_defined() { - yourls_deprecated_function( __FUNCTION__, '1.7.1', 'yourls_http_get_proxy' ); - return yourls_apply_filter( 'http_proxy_is_defined', defined( 'YOURLS_PROXY' ) ); + yourls_deprecated_function( __FUNCTION__, '1.7.1', 'yourls_http_get_proxy' ); + return yourls_apply_filter( 'http_proxy_is_defined', defined( 'YOURLS_PROXY' ) ); } /** @@ -209,8 +292,8 @@ function yourls_http_proxy_is_defined() { * @return string Translated context string without pipe */ function yourls_ex( $text, $context, $domain = 'default' ) { - yourls_deprecated_function( __FUNCTION__, '1.7.1', 'yourls_xe' ); - echo yourls_xe( $text, $context, $domain ); + yourls_deprecated_function( __FUNCTION__, '1.7.1', 'yourls_xe' ); + echo yourls_xe( $text, $context, $domain ); } /** @@ -224,20 +307,20 @@ function yourls_ex( $text, $context, $domain = 'default' ) { * @return string|array escaped data */ function yourls_escape( $data ) { - yourls_deprecated_function( __FUNCTION__, '1.7.3', 'PDO' ); - if( is_array( $data ) ) { - foreach( $data as $k => $v ) { - if( is_array( $v ) ) { - $data[ $k ] = yourls_escape( $v ); - } else { - $data[ $k ] = yourls_escape_real( $v ); - } - } - } else { - $data = yourls_escape_real( $data ); - } + yourls_deprecated_function( __FUNCTION__, '1.7.3', 'PDO' ); + if( is_array( $data ) ) { + foreach( $data as $k => $v ) { + if( is_array( $v ) ) { + $data[ $k ] = yourls_escape( $v ); + } else { + $data[ $k ] = yourls_escape_real( $v ); + } + } + } else { + $data = yourls_escape_real( $data ); + } - return $data; + return $data; } /** @@ -254,13 +337,13 @@ function yourls_escape( $data ) { * @return string escaped string */ function yourls_escape_real( $string ) { - yourls_deprecated_function( __FUNCTION__, '1.7.3', 'PDO' ); - global $ydb; - if( isset( $ydb ) && ( $ydb instanceof \YOURLS\Database\YDB ) ) - return $ydb->escape( $string ); + yourls_deprecated_function( __FUNCTION__, '1.7.3', 'PDO' ); + global $ydb; + if( isset( $ydb ) && ( $ydb instanceof \YOURLS\Database\YDB ) ) + return $ydb->escape( $string ); - // YOURLS DB classes have been bypassed by a custom DB engine or a custom cache layer - return yourls_apply_filter( 'custom_escape_real', addslashes( $string ), $string ); + // YOURLS DB classes have been bypassed by a custom DB engine or a custom cache layer + return yourls_apply_filter( 'custom_escape_real', addslashes( $string ), $string ); } // @codeCoverageIgnoreEnd diff --git a/includes/functions-formatting.php b/includes/functions-formatting.php index cb826b74a..e0c7f495d 100644 --- a/includes/functions-formatting.php +++ b/includes/functions-formatting.php @@ -7,47 +7,61 @@ /** * Convert an integer (1337) to a string (3jk). * - */ -function yourls_int2string( $num, $chars = null ) { - if( $chars == null ) - $chars = yourls_get_shorturl_charset(); - $string = ''; - $len = strlen( $chars ); - while( $num >= $len ) { - $mod = bcmod( $num, $len ); - $num = bcdiv( $num, $len ); - $string = $chars[ $mod ] . $string; - } - $string = $chars[ intval( $num ) ] . $string; + * @param int $num Number to convert + * @param string $chars Characters to use for conversion + * @return string Converted number + */ +function yourls_int2string($num, $chars = null) { + if( $chars == null ) + $chars = yourls_get_shorturl_charset(); + $string = ''; + $len = strlen( $chars ); + while( $num >= $len ) { + $mod = bcmod( (string)$num, (string)$len ); + $num = bcdiv( (string)$num, (string)$len ); + $string = $chars[ $mod ] . $string; + } + $string = $chars[ intval( $num ) ] . $string; - return yourls_apply_filter( 'int2string', $string, $num, $chars ); + return yourls_apply_filter( 'int2string', $string, $num, $chars ); } /** * Convert a string (3jk) to an integer (1337) * - */ -function yourls_string2int( $string, $chars = null ) { - if( $chars == null ) - $chars = yourls_get_shorturl_charset(); - $integer = 0; - $string = strrev( $string ); - $baselen = strlen( $chars ); - $inputlen = strlen( $string ); - for ($i = 0; $i < $inputlen; $i++) { - $index = strpos( $chars, $string[$i] ); - $integer = bcadd( $integer, bcmul( $index, bcpow( $baselen, $i ) ) ); - } + * @param string $string String to convert + * @param string $chars Characters to use for conversion + * @return string Number (as a string) + */ +function yourls_string2int($string, $chars = null) { + if( $chars == null ) + $chars = yourls_get_shorturl_charset(); + $integer = 0; + $string = strrev( $string ); + $baselen = strlen( $chars ); + $inputlen = strlen( $string ); + for ($i = 0; $i < $inputlen; $i++) { + $index = strpos( $chars, $string[$i] ); + $integer = bcadd( (string)$integer, bcmul( (string)$index, bcpow( (string)$baselen, (string)$i ) ) ); + } - return yourls_apply_filter( 'string2int', $integer, $string, $chars ); + return yourls_apply_filter( 'string2int', $integer, $string, $chars ); } /** - * Return a unique(ish) hash for a string to be used as a valid HTML id + * Return a unique string to be used as a valid HTML id * + * @since 1.8.3 + * @param string $prefix Optional prefix + * @param int $initial_val The initial counter value (defaults to one) + * @return string The unique string */ -function yourls_string2htmlid( $string ) { - return yourls_apply_filter( 'string2htmlid', 'y'.abs( crc32( $string ) ) ); +function yourls_unique_element_id($prefix = 'yid', $initial_val = 1) { + static $id_counter = 1; + if ($initial_val > 1) { + $id_counter = (int) $initial_val; + } + return yourls_apply_filter( 'unique_element_id', $prefix . (string) $id_counter++ ); } /** @@ -72,7 +86,7 @@ function yourls_sanitize_keyword( $keyword, $restrict_to_shorturl_charset = fals $valid = yourls_sanitize_url( $keyword ); } - return yourls_apply_filter( 'sanitize_string', $valid, $keyword, $restrict_to_shorturl_charset ); + return yourls_apply_filter( 'sanitize_string', $valid, $keyword, $restrict_to_shorturl_charset ); } /** @@ -85,15 +99,15 @@ function yourls_sanitize_keyword( $keyword, $restrict_to_shorturl_charset = fals * @return string Safe title */ function yourls_sanitize_title( $unsafe_title, $fallback = '' ) { - $title = $unsafe_title; - $title = strip_tags( $title ); - $title = preg_replace( "/\s+/", ' ', trim( $title ) ); + $title = $unsafe_title; + $title = strip_tags( $title ); + $title = preg_replace( "/\s+/", ' ', trim( $title ) ); if ( '' === $title || false === $title ) { $title = $fallback; } - return yourls_apply_filter( 'sanitize_title', $title, $unsafe_title, $fallback ); + return yourls_apply_filter( 'sanitize_title', $title, $unsafe_title, $fallback ); } /** @@ -106,8 +120,8 @@ function yourls_sanitize_title( $unsafe_title, $fallback = '' ) { * @return string Safe URL */ function yourls_sanitize_url( $unsafe_url, $protocols = array() ) { - $url = yourls_esc_url( $unsafe_url, 'redirection', $protocols ); - return yourls_apply_filter( 'sanitize_url', $url, $unsafe_url ); + $url = yourls_esc_url( $unsafe_url, 'redirection', $protocols ); + return yourls_apply_filter( 'sanitize_url', $url, $unsafe_url ); } /** @@ -125,8 +139,8 @@ function yourls_sanitize_url( $unsafe_url, $protocols = array() ) { * @return string Safe URL */ function yourls_sanitize_url_safe( $unsafe_url, $protocols = array() ) { - $url = yourls_esc_url( $unsafe_url, 'safe', $protocols ); - return yourls_apply_filter( 'sanitize_url_safe', $url, $unsafe_url ); + $url = yourls_esc_url( $unsafe_url, 'safe', $protocols ); + return yourls_apply_filter( 'sanitize_url_safe', $url, $unsafe_url ); } /** @@ -134,69 +148,85 @@ function yourls_sanitize_url_safe( $unsafe_url, $protocols = array() ) { * * Stolen from WP's _deep_replace * - */ -function yourls_deep_replace( $search, $subject ){ - $found = true; - while($found) { - $found = false; - foreach( (array) $search as $val ) { - while( strpos( $subject, $val ) !== false ) { - $found = true; - $subject = str_replace( $val, '', $subject ); - } - } - } + * @param string|array $search Needle, or array of needles. + * @param string $subject Haystack. + * @return string The string with the replaced values. + */ +function yourls_deep_replace($search, $subject ){ + $found = true; + while($found) { + $found = false; + foreach( (array) $search as $val ) { + while( strpos( $subject, $val ) !== false ) { + $found = true; + $subject = str_replace( $val, '', $subject ); + } + } + } - return $subject; + return $subject; } /** * Make sure an integer is a valid integer (PHP's intval() limits to too small numbers) * + * @param int $int Integer to check + * @return string Integer as a string */ -function yourls_sanitize_int( $int ) { - return ( substr( preg_replace( '/[^0-9]/', '', strval( $int ) ), 0, 20 ) ); +function yourls_sanitize_int($int ) { + return ( substr( preg_replace( '/[^0-9]/', '', strval( $int ) ), 0, 20 ) ); } /** * Sanitize an IP address + * No check on validity, just return a sanitized string * + * @param string $ip IP address + * @return string IP address */ -function yourls_sanitize_ip( $ip ) { - return preg_replace( '/[^0-9a-fA-F:., ]/', '', $ip ); +function yourls_sanitize_ip($ip ) { + return preg_replace( '/[^0-9a-fA-F:., ]/', '', $ip ); } /** * Make sure a date is m(m)/d(d)/yyyy, return false otherwise * + * @param string $date Date to check + * @return false|mixed Date in format m(m)/d(d)/yyyy or false if invalid */ -function yourls_sanitize_date( $date ) { - if( !preg_match( '!^\d{1,2}/\d{1,2}/\d{4}$!' , $date ) ) { - return false; - } - return $date; +function yourls_sanitize_date($date ) { + if( !preg_match( '!^\d{1,2}/\d{1,2}/\d{4}$!' , $date ) ) { + return false; + } + return $date; } /** * Sanitize a date for SQL search. Return false if malformed input. * + * @param string $date Date + * @return false|string String in Y-m-d format for SQL search or false if malformed input */ -function yourls_sanitize_date_for_sql( $date ) { - if( !yourls_sanitize_date( $date ) ) - return false; - return date( 'Y-m-d', strtotime( $date ) ); +function yourls_sanitize_date_for_sql($date) { + if( !yourls_sanitize_date( $date ) ) + return false; + return date( 'Y-m-d', strtotime( $date ) ); } /** - * Return trimmed string + * Return trimmed string, optionally append '[...]' if string is too long * + * @param string $string String to trim + * @param int $length Maximum length of string + * @param string $append String to append if trimmed + * @return string Trimmed string */ -function yourls_trim_long_string( $string, $length = 60, $append = '[...]' ) { - $newstring = $string; +function yourls_trim_long_string($string, $length = 60, $append = '[...]') { + $newstring = $string; if ( mb_strlen( $newstring ) > $length ) { $newstring = mb_substr( $newstring, 0, $length - mb_strlen( $append ), 'UTF-8' ) . $append; } - return yourls_apply_filter( 'trim_long_string', $newstring, $string, $length, $append ); + return yourls_apply_filter( 'trim_long_string', $newstring, $string, $length, $append ); } /** @@ -204,7 +234,12 @@ function yourls_trim_long_string( $string, $length = 60, $append = '[...]' ) { * * The regexp searches for the first digits, then a period, then more digits and periods, and discards * all the rest. - * For instance, 'mysql-5.5-beta' and '5.5-RC1' return '5.5' + * Examples: + * 'omgmysql-5.5-ubuntu-4.20' => '5.5' + * 'mysql5.5-ubuntu-4.20' => '5.5' + * '5.5-ubuntu-4.20' => '5.5' + * '5.5-beta2' => '5.5' + * '5.5' => '5.5' * * @since 1.4.1 * @param string $version Version number @@ -220,34 +255,71 @@ function yourls_sanitize_version( $version ) { /** * Sanitize a filename (no Win32 stuff) * + * @param string $file File name + * @return string|null Sanitized file name (or null if it's just backslashes, ok...) */ -function yourls_sanitize_filename( $file ) { - $file = str_replace( '\\', '/', $file ); // sanitize for Win32 installs - $file = preg_replace( '|/+|' ,'/', $file ); // remove any duplicate slash - return $file; +function yourls_sanitize_filename($file) { + $file = str_replace( '\\', '/', $file ); // sanitize for Win32 installs + $file = preg_replace( '|/+|' ,'/', $file ); // remove any duplicate slash + return $file; } /** - * Check if a string seems to be UTF-8. Stolen from WP. + * Validate a JSONP callback name + * + * Check if the callback contains only safe characters: [a-zA-Z0-9_$.] + * Returns the original callback if valid, or false if invalid. * + * Examples: + * - 'myCallback' => 'myCallback' + * - 'alert(1)' => false + * See tests/tests/format/JsonpCallbackTest.php for various cases covered + * + * @since 1.10.3 + * @param string $callback Raw callback value + * @return string|false Original callback if valid, false otherwise */ -function yourls_seems_utf8( $str ) { - $length = strlen( $str ); - for ( $i=0; $i < $length; $i++ ) { - $c = ord( $str[ $i ] ); - if ( $c < 0x80 ) $n = 0; # 0bbbbbbb - elseif (($c & 0xE0) == 0xC0) $n=1; # 110bbbbb - elseif (($c & 0xF0) == 0xE0) $n=2; # 1110bbbb - elseif (($c & 0xF8) == 0xF0) $n=3; # 11110bbb - elseif (($c & 0xFC) == 0xF8) $n=4; # 111110bb - elseif (($c & 0xFE) == 0xFC) $n=5; # 1111110b - else return false; # Does not match any model - for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ? - if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80)) - return false; - } - } - return true; +function yourls_validate_jsonp_callback($callback ) { + $callback = (string) $callback; + + // First, check for JavaScript unicode escape sequences like \u2028 or u2028 + // They are sometimes used to smuggle line/paragraph separators. + if ( preg_match( '/\\\\?u[0-9a-fA-F]{4}/', $callback ) ) { + return yourls_apply_filter( 'validate_jsonp_callback_error', false, $callback ); + } + + // Check if callback contains only safe characters [a-zA-Z0-9_$.] + if ( !preg_match( '/^[a-zA-Z0-9_$.]+$/', $callback ) ) { + return yourls_apply_filter( 'validate_jsonp_callback_error', false, $callback ); + } + + // Callback is valid, return original value + return yourls_apply_filter( 'validate_jsonp_callback', $callback ); +} + +/** + * Check if a string seems to be UTF-8. Stolen from WP. + * + * @param string $str String to check + * @return bool Whether string seems valid UTF-8 + */ +function yourls_seems_utf8($str) { + $length = strlen( $str ); + for ( $i=0; $i < $length; $i++ ) { + $c = ord( $str[ $i ] ); + if ( $c < 0x80 ) $n = 0; # 0bbbbbbb + elseif (($c & 0xE0) == 0xC0) $n=1; # 110bbbbb + elseif (($c & 0xF0) == 0xE0) $n=2; # 1110bbbb + elseif (($c & 0xF8) == 0xF0) $n=3; # 11110bbb + elseif (($c & 0xFC) == 0xF8) $n=4; # 111110bb + elseif (($c & 0xFE) == 0xFC) $n=5; # 1111110b + else return false; # Does not match any model + for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ? + if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80)) + return false; + } + } + return true; } @@ -279,28 +351,28 @@ function yourls_supports_pcre_u() { * @return string The checked text. */ function yourls_check_invalid_utf8( $string, $strip = false ) { - $string = (string) $string; + $string = (string) $string; - if ( 0 === strlen( $string ) ) { - return ''; - } + if ( 0 === strlen( $string ) ) { + return ''; + } - // We can't demand utf8 in the PCRE installation, so just return the string in those cases - if ( ! yourls_supports_pcre_u() ) { - return $string; - } + // We can't demand utf8 in the PCRE installation, so just return the string in those cases + if ( ! yourls_supports_pcre_u() ) { + return $string; + } - // preg_match fails when it encounters invalid UTF8 in $string - if ( 1 === @preg_match( '/^./us', $string ) ) { - return $string; - } + // preg_match fails when it encounters invalid UTF8 in $string + if ( 1 === @preg_match( '/^./us', $string ) ) { + return $string; + } - // Attempt to strip the bad chars if requested (not recommended) - if ( $strip && function_exists( 'iconv' ) ) { - return iconv( 'utf-8', 'utf-8', $string ); - } + // Attempt to strip the bad chars if requested (not recommended) + if ( $strip && function_exists( 'iconv' ) ) { + return iconv( 'utf-8', 'utf-8', $string ); + } - return ''; + return ''; } /** @@ -319,56 +391,56 @@ function yourls_check_invalid_utf8( $string, $strip = false ) { * @return string The encoded text with HTML entities. */ function yourls_specialchars( $string, $quote_style = ENT_NOQUOTES, $double_encode = false ) { - $string = (string) $string; + $string = (string) $string; - if ( 0 === strlen( $string ) ) - return ''; + if ( 0 === strlen( $string ) ) + return ''; - // Don't bother if there are no specialchars - saves some processing - if ( ! preg_match( '/[&<>"\']/', $string ) ) - return $string; + // Don't bother if there are no specialchars - saves some processing + if ( ! preg_match( '/[&<>"\']/', $string ) ) + return $string; - // Account for the previous behaviour of the function when the $quote_style is not an accepted value - if ( empty( $quote_style ) ) - $quote_style = ENT_NOQUOTES; - elseif ( ! in_array( $quote_style, array( 0, 2, 3, 'single', 'double' ), true ) ) - $quote_style = ENT_QUOTES; + // Account for the previous behaviour of the function when the $quote_style is not an accepted value + if ( empty( $quote_style ) ) + $quote_style = ENT_NOQUOTES; + elseif ( ! in_array( $quote_style, array( 0, 2, 3, 'single', 'double' ), true ) ) + $quote_style = ENT_QUOTES; - $charset = 'UTF-8'; + $charset = 'UTF-8'; - $_quote_style = $quote_style; + $_quote_style = $quote_style; - if ( $quote_style === 'double' ) { - $quote_style = ENT_COMPAT; - $_quote_style = ENT_COMPAT; - } elseif ( $quote_style === 'single' ) { - $quote_style = ENT_NOQUOTES; - } + if ( $quote_style === 'double' ) { + $quote_style = ENT_COMPAT; + $_quote_style = ENT_COMPAT; + } elseif ( $quote_style === 'single' ) { + $quote_style = ENT_NOQUOTES; + } - // Handle double encoding ourselves - if ( $double_encode ) { - $string = @htmlspecialchars( $string, $quote_style, $charset ); - } else { - // Decode & into & - $string = yourls_specialchars_decode( $string, $_quote_style ); + // Handle double encoding ourselves + if ( $double_encode ) { + $string = @htmlspecialchars( $string, $quote_style, $charset ); + } else { + // Decode & into & + $string = yourls_specialchars_decode( $string, $_quote_style ); - // Guarantee every &entity; is valid or re-encode the & - $string = yourls_kses_normalize_entities( $string ); + // Guarantee every &entity; is valid or re-encode the & + $string = yourls_kses_normalize_entities( $string ); - // Now re-encode everything except &entity; - $string = preg_split( '/(&#?x?[0-9a-z]+;)/i', $string, -1, PREG_SPLIT_DELIM_CAPTURE ); + // Now re-encode everything except &entity; + $string = preg_split( '/(&#?x?[0-9a-z]+;)/i', $string, -1, PREG_SPLIT_DELIM_CAPTURE ); - for ( $i = 0; $i < count( $string ); $i += 2 ) - $string[$i] = @htmlspecialchars( $string[$i], $quote_style, $charset ); + for ( $i = 0; $i < count( $string ); $i += 2 ) + $string[$i] = @htmlspecialchars( $string[$i], $quote_style, $charset ); - $string = implode( '', $string ); - } + $string = implode( '', $string ); + } - // Backwards compatibility - if ( 'single' === $_quote_style ) - $string = str_replace( "'", ''', $string ); + // Backwards compatibility + if ( 'single' === $_quote_style ) + $string = str_replace( "'", ''', $string ); - return $string; + return $string; } /** @@ -386,51 +458,53 @@ function yourls_specialchars( $string, $quote_style = ENT_NOQUOTES, $double_enco * @return string The decoded text without HTML entities. */ function yourls_specialchars_decode( $string, $quote_style = ENT_NOQUOTES ) { - $string = (string) $string; - - if ( 0 === strlen( $string ) ) { - return ''; - } - - // Don't bother if there are no entities - saves a lot of processing - if ( strpos( $string, '&' ) === false ) { - return $string; - } - - // Match the previous behaviour of _wp_specialchars() when the $quote_style is not an accepted value - if ( empty( $quote_style ) ) { - $quote_style = ENT_NOQUOTES; - } elseif ( !in_array( $quote_style, array( 0, 2, 3, 'single', 'double' ), true ) ) { - $quote_style = ENT_QUOTES; - } - - // More complete than get_html_translation_table( HTML_SPECIALCHARS ) - $single = array( ''' => '\'', ''' => '\'' ); - $single_preg = array( '/�*39;/' => ''', '/�*27;/i' => ''' ); - $double = array( '"' => '"', '"' => '"', '"' => '"' ); - $double_preg = array( '/�*34;/' => '"', '/�*22;/i' => '"' ); - $others = array( '<' => '<', '<' => '<', '>' => '>', '>' => '>', '&' => '&', '&' => '&', '&' => '&' ); - $others_preg = array( '/�*60;/' => '<', '/�*62;/' => '>', '/�*38;/' => '&', '/�*26;/i' => '&' ); - - if ( $quote_style === ENT_QUOTES ) { - $translation = array_merge( $single, $double, $others ); - $translation_preg = array_merge( $single_preg, $double_preg, $others_preg ); - } elseif ( $quote_style === ENT_COMPAT || $quote_style === 'double' ) { - $translation = array_merge( $double, $others ); - $translation_preg = array_merge( $double_preg, $others_preg ); - } elseif ( $quote_style === 'single' ) { - $translation = array_merge( $single, $others ); - $translation_preg = array_merge( $single_preg, $others_preg ); - } elseif ( $quote_style === ENT_NOQUOTES ) { - $translation = $others; - $translation_preg = $others_preg; - } - - // Remove zero padding on numeric entities - $string = preg_replace( array_keys( $translation_preg ), array_values( $translation_preg ), $string ); - - // Replace characters according to translation table - return strtr( $string, $translation ); + $string = (string) $string; + + if ( 0 === strlen( $string ) ) { + return ''; + } + + // Don't bother if there are no entities - saves a lot of processing + if ( strpos( $string, '&' ) === false ) { + return $string; + } + + // Match the previous behaviour of _wp_specialchars() when the $quote_style is not an accepted value + if ( empty( $quote_style ) ) { + $quote_style = ENT_NOQUOTES; + } elseif ( !in_array( $quote_style, array( 0, 2, 3, 'single', 'double' ), true ) ) { + $quote_style = ENT_QUOTES; + } + + // More complete than get_html_translation_table( HTML_SPECIALCHARS ) + $single = array( ''' => '\'', ''' => '\'' ); + $single_preg = array( '/�*39;/' => ''', '/�*27;/i' => ''' ); + $double = array( '"' => '"', '"' => '"', '"' => '"' ); + $double_preg = array( '/�*34;/' => '"', '/�*22;/i' => '"' ); + $others = array( '<' => '<', '<' => '<', '>' => '>', '>' => '>', '&' => '&', '&' => '&', '&' => '&' ); + $others_preg = array( '/�*60;/' => '<', '/�*62;/' => '>', '/�*38;/' => '&', '/�*26;/i' => '&' ); + + $translation = $translation_preg = []; + + if ( $quote_style === ENT_QUOTES ) { + $translation = array_merge( $single, $double, $others ); + $translation_preg = array_merge( $single_preg, $double_preg, $others_preg ); + } elseif ( $quote_style === ENT_COMPAT || $quote_style === 'double' ) { + $translation = array_merge( $double, $others ); + $translation_preg = array_merge( $double_preg, $others_preg ); + } elseif ( $quote_style === 'single' ) { + $translation = array_merge( $single, $others ); + $translation_preg = array_merge( $single_preg, $others_preg ); + } elseif ( $quote_style === ENT_NOQUOTES ) { + $translation = $others; + $translation_preg = $others_preg; + } + + // Remove zero padding on numeric entities + $string = preg_replace( array_keys( $translation_preg ), array_values( $translation_preg ), $string ); + + // Replace characters according to translation table + return strtr( $string, $translation ); } @@ -443,9 +517,9 @@ function yourls_specialchars_decode( $string, $quote_style = ENT_NOQUOTES ) { * @return string */ function yourls_esc_html( $text ) { - $safe_text = yourls_check_invalid_utf8( $text ); - $safe_text = yourls_specialchars( $safe_text, ENT_QUOTES ); - return yourls_apply_filter( 'esc_html', $safe_text, $text ); + $safe_text = yourls_check_invalid_utf8( $text ); + $safe_text = yourls_specialchars( $safe_text, ENT_QUOTES ); + return yourls_apply_filter( 'esc_html', $safe_text, $text ); } /** @@ -457,9 +531,9 @@ function yourls_esc_html( $text ) { * @return string */ function yourls_esc_attr( $text ) { - $safe_text = yourls_check_invalid_utf8( $text ); - $safe_text = yourls_specialchars( $safe_text, ENT_QUOTES ); - return yourls_apply_filter( 'esc_attr', $safe_text, $text ); + $safe_text = yourls_check_invalid_utf8( $text ); + $safe_text = yourls_specialchars( $safe_text, ENT_QUOTES ); + return yourls_apply_filter( 'esc_attr', $safe_text, $text ); } /** @@ -482,38 +556,41 @@ function yourls_esc_url( $url, $context = 'display', $protocols = array() ) { // trim first -- see #1931 $url = trim( $url ); - // make sure there's only one 'http://' at the beginning (prevents pasting a URL right after the default 'http://') - $url = str_replace( - array( 'http://http://', 'http://https://' ), - array( 'http://', 'https://' ), - $url - ); + // make sure there's only one 'http://' at the beginning (prevents pasting a URL right after the default 'http://') + $url = str_replace( + array( 'http://http://', 'http://https://' ), + array( 'http://', 'https://' ), + $url + ); - if ( '' == $url ) - return $url; + if ( '' == $url ) + return $url; - $original_url = $url; + $original_url = $url; - // force scheme and domain to lowercase - see issues 591 and 1630 + // force scheme and domain to lowercase - see issues 591 and 1630 $url = yourls_normalize_uri( $url ); - $url = preg_replace( '|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\[\]\\x80-\\xff]|i', '', $url ); - // Previous regexp in YOURLS was '|[^a-z0-9-~+_.?\[\]\^#=!&;,/:%@$\|*`\'<>"()\\x80-\\xff\{\}]|i' - // TODO: check if that was it too destructive + $url = preg_replace( '|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\[\]\\\\\x80-\\xff]|i', '', $url ); + // The replace above allows backslashes now, but we only should only allow them after a query string or a fragment identifier + $url = yourls_remove_backslashes_before_query_fragment($url); + + // Previous regexp in YOURLS was '|[^a-z0-9-~+_.?\[\]\^#=!&;,/:%@$\|*`\'<>"()\\x80-\\xff\{\}]|i' + // TODO: check if that was it too destructive // If $context is 'safe', an extra step is taken to make sure no CRLF injection is possible. // To be used when $url can be forged by evil user (eg it's from a $_SERVER variable, a query string, etc..) - if ( 'safe' == $context ) { + if ( 'safe' == $context ) { $strip = array( '%0d', '%0a', '%0D', '%0A' ); $url = yourls_deep_replace( $strip, $url ); } - // Replace ampersands and single quotes only when displaying. - if ( 'display' == $context ) { - $url = yourls_kses_normalize_entities( $url ); - $url = str_replace( '&', '&', $url ); - $url = str_replace( "'", ''', $url ); - } + // Replace ampersands and single quotes only when displaying. + if ( 'display' == $context ) { + $url = yourls_kses_normalize_entities( $url ); + $url = str_replace( '&', '&', $url ); + $url = str_replace( "'", ''', $url ); + } // If there's a protocol, make sure it's OK if( yourls_get_protocol($url) !== '' ) { @@ -529,9 +606,45 @@ function yourls_esc_url( $url, $context = 'display', $protocols = array() ) { // I didn't use KSES function kses_bad_protocol() because it doesn't work the way I liked (returns //blah from illegal://blah) } - return yourls_apply_filter( 'esc_url', $url, $original_url, $context ); + return yourls_apply_filter( 'esc_url', $url, $original_url, $context ); } +/** + * Remove backslashes before query string or fragment identifier + * + * This function removes backslashes before the first ? or #, if any. + * If there's no ? or #, all backslashes are removed. + * See issue #3802 and PR #3998 + * + * @since 1.10.3 + * @param string $url URL + * @return string URL without backslashes before query string or fragment identifier + */ +function yourls_remove_backslashes_before_query_fragment(string $url): string { + $posQ = strpos($url, '?'); + $posH = strpos($url, '#'); + + if ($posQ === false && $posH === false) { + // no ? or # -> remove all backslashes + return str_replace('\\', '', $url); + } + + // chose the first of ? or # + if ($posQ === false) { + $pos = $posH; + } elseif ($posH === false) { + $pos = $posQ; + } else { + $pos = min($posQ, $posH); + } + + $before = substr($url, 0, $pos); + $after = substr($url, $pos); + + $before = str_replace('\\', '', $before); + + return $before . $after; +} /** * Normalize a URI : lowercase scheme and domain, convert IDN to UTF8 @@ -603,7 +716,7 @@ function yourls_normalize_uri( $url ) { $lower['host'] = mb_strtolower($parts['host']); /** * Convert IDN domains to their UTF8 form so that طارق.net and xn--mgbuq0c.net - * are considered the same. Explicitely mention option and variant to avoid notice + * are considered the same. Explicitly mention option and variant to avoid notice * on PHP 7.2 and 7.3 */ $lower['host'] = idn_to_utf8($lower['host'], IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46); @@ -628,12 +741,12 @@ function yourls_normalize_uri( $url ) { * @return string Escaped text. */ function yourls_esc_js( $text ) { - $safe_text = yourls_check_invalid_utf8( $text ); - $safe_text = yourls_specialchars( $safe_text, ENT_COMPAT ); - $safe_text = preg_replace( '/&#(x)?0*(?(1)27|39);?/i', "'", stripslashes( $safe_text ) ); - $safe_text = str_replace( "\r", '', $safe_text ); - $safe_text = str_replace( "\n", '\\n', addslashes( $safe_text ) ); - return yourls_apply_filter( 'esc_js', $safe_text, $text ); + $safe_text = yourls_check_invalid_utf8( $text ); + $safe_text = yourls_specialchars( $safe_text, ENT_COMPAT ); + $safe_text = preg_replace( '/&#(x)?0*(?(1)27|39);?/i', "'", stripslashes( $safe_text ) ); + $safe_text = str_replace( "\r", '', $safe_text ); + $safe_text = str_replace( "\n", '\\n', addslashes( $safe_text ) ); + return yourls_apply_filter( 'esc_js', $safe_text, $text ); } /** @@ -645,44 +758,20 @@ function yourls_esc_js( $text ) { * @return string */ function yourls_esc_textarea( $text ) { - $safe_text = htmlspecialchars( $text, ENT_QUOTES ); - return yourls_apply_filter( 'esc_textarea', $safe_text, $text ); -} - - -/** -* PHP emulation of JS's encodeURI -* -* @link https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/encodeURI -* @param $url -* @return string -*/ -function yourls_encodeURI( $url ) { - // Decode URL all the way - $result = yourls_rawurldecode_while_encoded( $url ); - // Encode once - $result = strtr( rawurlencode( $result ), array ( - '%3B' => ';', '%2C' => ',', '%2F' => '/', '%3F' => '?', '%3A' => ':', '%40' => '@', - '%26' => '&', '%3D' => '=', '%2B' => '+', '%24' => '$', '%21' => '!', '%2A' => '*', - '%27' => '\'', '%28' => '(', '%29' => ')', '%23' => '#', - ) ); - // @TODO: - // Known limit: this will most likely break IDN URLs such as http://www.académie-française.fr/ - // To fully support IDN URLs, advocate use of a plugin. - return yourls_apply_filter( 'encodeURI', $result, $url ); + $safe_text = htmlspecialchars( $text, ENT_QUOTES ); + return yourls_apply_filter( 'esc_textarea', $safe_text, $text ); } /** * Adds backslashes before letters and before a number at the start of a string. Stolen from WP. * * @since 1.6 - * * @param string $string Value to which backslashes will be added. * @return string String with backslashes inserted. */ function yourls_backslashit($string) { - $string = preg_replace('/^([0-9])/', '\\\\\\\\\1', $string); - $string = preg_replace('/([a-z])/i', '\\\\\1', $string); + $string = preg_replace('/^([0-9])/', '\\\\\\\\\1', (string)$string); + $string = preg_replace('/([a-z])/i', '\\\\\1', (string)$string); return $string; } @@ -696,7 +785,7 @@ function yourls_backslashit($string) { * @return bool */ function yourls_is_rawurlencoded( $string ) { - return rawurldecode( $string ) != $string; + return rawurldecode( $string ) != $string; } /** @@ -710,11 +799,11 @@ function yourls_is_rawurlencoded( $string ) { * @return string */ function yourls_rawurldecode_while_encoded( $string ) { - $string = rawurldecode( $string ); - if( yourls_is_rawurlencoded( $string ) ) { - $string = yourls_rawurldecode_while_encoded( $string ); - } - return $string; + $string = rawurldecode( $string ); + if( yourls_is_rawurlencoded( $string ) ) { + $string = yourls_rawurldecode_while_encoded( $string ); + } + return $string; } /** @@ -740,7 +829,7 @@ function yourls_make_bookmarklet( $code ) { */ function yourls_get_timestamp( $timestamp ) { $offset = yourls_get_time_offset(); - $timestamp_offset = $timestamp + ($offset * 3600); + $timestamp_offset = (int)$timestamp + ($offset * 3600); return yourls_apply_filter( 'get_timestamp', $timestamp_offset, $timestamp, $offset ); } @@ -788,4 +877,3 @@ function yourls_get_date_format( $format ) { function yourls_get_time_format( $format ) { return yourls_apply_filter( 'get_time_format', (string)$format ); } - diff --git a/includes/functions-html.php b/includes/functions-html.php index 46432f0c7..aadf6f696 100644 --- a/includes/functions-html.php +++ b/includes/functions-html.php @@ -3,18 +3,19 @@ /** * Display

header and logo * + * @return void */ function yourls_html_logo() { - yourls_do_action( 'pre_html_logo' ); - ?> -
-

- YOURLS: Your Own URL Shortener
-
-

-
- +
+

+ YOURLS: Your Own URL Shortener
+
+

+
+ + ?> > - <?php echo $title ?> - - - - + <?php echo $title ?> + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
- -
-

- YOURLS v ' . YOURLS_VERSION ); - $footer .= $num_queries; - echo yourls_apply_filter( 'html_footer_text', $footer ); - ?> -

-
';
-		echo join( "\n", yourls_get_debug_log() );
-		echo '
'; - } ?> - - - - + +

+ YOURLS v ' . YOURLS_VERSION ); + $footer .= $num_queries; + echo yourls_apply_filter( 'html_footer_text', $footer ); + ?> +

+
';
+        echo join( "\n", yourls_get_debug_log() );
+        echo '
'; + } ?> + + + + -
-
-
-
-
+ ?> +
+
+
+ +
: : @@ -191,11 +198,39 @@ function yourls_html_addnew( $url = '', $keyword = '' ) {
- - -
- -
+ + +
+ +
+ + +
+
+

+
    +
  • :
  • +
  • :
  • +
  • :
  • +
+
+
+ + + +
+
- - - -
-
-
- '; - $_options = array( + ?> + + + +
+ +
+ '; + $_options = array( 'all' => yourls__( 'All fields' ), - 'keyword' => yourls__( 'Short URL' ), - 'url' => yourls__( 'URL' ), - 'title' => yourls__( 'Title' ), - 'ip' => yourls__( 'IP' ), - ); - $_select = yourls_html_select( 'search_in', $_options, $search_in, false, yourls__( 'Search in' ) ); - /* //translators: "Search for in in '; - yourls_se( 'Show %s rows', $_input ); - echo "
\n"; - - // Fourth search control: Show links with more than XX clicks - $_options = array( - 'more' => yourls__( 'more' ), - 'less' => yourls__( 'less' ), - ); - $_select = yourls_html_select( 'click_filter', $_options, $click_filter, false, yourls__( 'Show links with' ) ); - $_input = ' '; - /* //translators: "Show links with than clicks" */ - yourls_se( 'Show links with %1$s than %2$s clicks', $_select, $_input ); - echo "
\n"; - - // Fifth search control: Show links created before/after/between ... - $_options = array( - 'before' => yourls__('before'), - 'after' => yourls__('after'), - 'between' => yourls__('between'), - ); - $_select = yourls_html_select( 'date_filter', $_options, $date_filter, false, yourls__('Show links created') ); - $_input = ''; - $_and = ' & '; - $_input2 = ''; - /* //translators: "Show links created <"and" if applicable> " */ - yourls_se( 'Show links created %1$s %2$s %3$s %4$s', $_select, $_input, $_and, $_input2 ); - ?> - -
- -   - -
- -
- -
- - - - - - - - - \n"; + + // Fourth search control: Show links with more than XX clicks + $_options = array( + 'more' => yourls__( 'more' ), + 'less' => yourls__( 'less' ), + ); + $_select = yourls_html_select( 'click_filter', $_options, $click_filter, false, yourls__( 'Show links with' ) ); + $_input = ' '; + /* //translators: "Show links with than clicks" */ + yourls_se( 'Show links with %1$s than %2$s clicks', $_select, $_input ); + echo "
\n"; + + // Fifth search control: Show links created before/after/between ... + $_options = array( + 'before' => yourls__('before'), + 'after' => yourls__('after'), + 'between' => yourls__('between'), + ); + $_select = yourls_html_select( 'date_filter', $_options, $date_filter, false, yourls__('Show links created') ); + $_input = ''; + $_and = ' & '; + $_input2 = ''; + /* //translators: "Show links created <"and" if applicable> " */ + yourls_se( 'Show links created %1$s %2$s %3$s %4$s', $_select, $_input, $_and, $_input2 ); + ?> + +
+ +   + +
+ +
+ +
+ + + + + + + + + \n"; - foreach( $options as $value => $text ) { - $html .= "

" ); - echo yourls_apply_filter( 'die_message', "

$message

" ); + if( !yourls_did_action( 'html_head' ) ) { + yourls_html_head(); + yourls_html_logo(); + } + echo yourls_apply_filter( 'die_title', "

$title

" ); + echo yourls_apply_filter( 'die_message', "

$message

" ); // Hook into 'yourls_die' to add more elements or messages to that page - yourls_do_action( 'yourls_die' ); - if( !yourls_did_action( 'html_footer' ) ) { - yourls_html_footer(false); - } + yourls_do_action( 'yourls_die' ); + if( !yourls_did_action( 'html_footer' ) ) { + yourls_html_footer(false); + } - // die with a value in case we're running tests, so PHPUnit doesn't exit with 0 as if success - die(1); + // die with a value in case we're running tests, so PHPUnit doesn't exit with 0 as if success + die(1); } /** * Return an "Edit" row for the main table * * @param string $keyword Keyword to edit + * @param string $id * @return string HTML of the edit row */ -function yourls_table_edit_row( $keyword ) { +function yourls_table_edit_row( $keyword, $id ) { $keyword = yourls_sanitize_keyword($keyword); - $id = yourls_string2htmlid( $keyword ); // used as HTML #id - $url = yourls_get_keyword_longurl( $keyword ); - $title = htmlspecialchars( yourls_get_keyword_title( $keyword ) ); - $safe_url = yourls_esc_attr( $url ); - $safe_title = yourls_esc_attr( $title ); - $safe_keyword = yourls_esc_attr( $keyword ); + $url = yourls_get_keyword_longurl( $keyword ); + $title = htmlspecialchars( yourls_get_keyword_title( $keyword ) ); + $safe_url = yourls_esc_attr( $url ); + $safe_title = yourls_esc_attr( $title ); + $safe_keyword = yourls_esc_attr( $keyword ); // Make strings sprintf() safe: '%' -> '%%' $safe_url = str_replace( '%', '%%', $safe_url ); $safe_title = str_replace( '%', '%%', $safe_title ); - $www = yourls_link(); + $www = yourls_link(); - $nonce = yourls_create_nonce( 'edit-save_'.$id ); + $nonce = yourls_create_nonce( 'edit-save_'.$id ); - if( $url ) { - $return = <<%s:
%s: $www
%s:   RETURN; - $return = sprintf( $return, yourls__( 'Long URL' ), yourls__( 'Short URL' ), yourls__( 'Title' ), yourls__( 'Save' ), yourls__( 'Save new values' ), yourls__( 'Cancel' ), yourls__( 'Cancel editing' ) ); - } else { - $return = '' . yourls__( 'Error, URL not found' ) . ''; - } + $return = sprintf( $return, yourls__( 'Long URL' ), yourls__( 'Short URL' ), yourls__( 'Title' ), yourls__( 'Save' ), yourls__( 'Save new values' ), yourls__( 'Cancel' ), yourls__( 'Cancel editing' ) ); + } else { + $return = '' . yourls__( 'Error, URL not found' ) . ''; + } - $return = yourls_apply_filter( 'table_edit_row', $return, $keyword, $url, $title ); + $return = yourls_apply_filter( 'table_edit_row', $return, $keyword, $url, $title ); - return $return; + return $return; } /** * Return an "Add" row for the main table * - * @return string HTML of the edit row + * @param string $keyword Keyword (short URL) + * @param string $url URL (long URL) + * @param string $title Title + * @param string $ip IP + * @param string|int $clicks Number of clicks + * @param string $timestamp Timestamp + * @param int $row_id Numeric value used to form row IDs, defaults to one + * @return string HTML of the row */ -function yourls_table_add_row( $keyword, $url, $title, $ip, $clicks, $timestamp ) { - $keyword = yourls_sanitize_keyword($keyword); - $id = yourls_string2htmlid( $keyword ); // used as HTML #id - $shorturl = yourls_link( $keyword ); - - $statlink = yourls_statlink( $keyword ); - - $delete_link = yourls_nonce_url( 'delete-link_'.$id, - yourls_add_query_arg( array( 'id' => $id, 'action' => 'delete', 'keyword' => $keyword ), yourls_admin_url( 'admin-ajax.php' ) ) - ); - - $edit_link = yourls_nonce_url( 'edit-link_'.$id, - yourls_add_query_arg( array( 'id' => $id, 'action' => 'edit', 'keyword' => $keyword ), yourls_admin_url( 'admin-ajax.php' ) ) - ); - - // Action link buttons: the array - $actions = array( - 'stats' => array( - 'href' => $statlink, - 'id' => "statlink-$id", - 'title' => yourls_esc_attr__( 'Stats' ), - 'anchor' => yourls__( 'Stats' ), - ), - 'share' => array( - 'href' => '', - 'id' => "share-button-$id", - 'title' => yourls_esc_attr__( 'Share' ), - 'anchor' => yourls__( 'Share' ), - 'onclick' => "toggle_share('$id');return false;", - ), - 'edit' => array( - 'href' => $edit_link, - 'id' => "edit-button-$id", - 'title' => yourls_esc_attr__( 'Edit' ), - 'anchor' => yourls__( 'Edit' ), - 'onclick' => "edit_link_display('$id');return false;", - ), - 'delete' => array( - 'href' => $delete_link, - 'id' => "delete-button-$id", - 'title' => yourls_esc_attr__( 'Delete' ), - 'anchor' => yourls__( 'Delete' ), - 'onclick' => "remove_link('$id');return false;", - ) - ); - $actions = yourls_apply_filter( 'table_add_row_action_array', $actions, $keyword ); - - // Action link buttons: the HTML - $action_links = ''; - foreach( $actions as $key => $action ) { - $onclick = isset( $action['onclick'] ) ? 'onclick="' . $action['onclick'] . '"' : '' ; - $action_links .= sprintf( '%s', - $action['href'], $action['id'], $action['title'], 'button button_'.$key, $onclick, $action['anchor'] - ); - } - $action_links = yourls_apply_filter( 'action_links', $action_links, $keyword, $url, $ip, $clicks, $timestamp ); - - if( ! $title ) - $title = $url; - - $protocol_warning = ''; - if( ! in_array( yourls_get_protocol( $url ) , array( 'http://', 'https://' ) ) ) - $protocol_warning = yourls_apply_filter( 'add_row_protocol_warning', '' ); - - // Row cells: the array - $cells = array( - 'keyword' => array( - 'template' => '%keyword_html%', - 'shorturl' => yourls_esc_url( $shorturl ), - 'keyword_html' => yourls_esc_html( $keyword ), - ), - 'url' => array( - 'template' => '%title_html%
%warning%%long_url_html%', - 'long_url' => yourls_esc_url( $url ), - 'title_attr' => yourls_esc_attr( $title ), - 'title_html' => yourls_esc_html( yourls_trim_long_string( $title ) ), - 'long_url_html' => yourls_esc_html( yourls_trim_long_string( urldecode( $url ) ) ), - 'warning' => $protocol_warning, - ), - 'timestamp' => array( - 'template' => ' %date%', +function yourls_table_add_row( $keyword, $url, $title, $ip, $clicks, $timestamp, $row_id = 1 ) { + $keyword = yourls_sanitize_keyword($keyword); + $id = yourls_unique_element_id('yid', $row_id); + $shorturl = yourls_link( $keyword ); + + $statlink = yourls_statlink( $keyword ); + + $delete_link = yourls_nonce_url( 'delete-link_'.$id, + yourls_add_query_arg( array( 'id' => $id, 'action' => 'delete', 'keyword' => $keyword ), yourls_admin_url( 'admin-ajax.php' ) ) + ); + + $edit_link = yourls_nonce_url( 'edit-link_'.$id, + yourls_add_query_arg( array( 'id' => $id, 'action' => 'edit', 'keyword' => $keyword ), yourls_admin_url( 'admin-ajax.php' ) ) + ); + + // Action link buttons: the array + $actions = array( + 'stats' => array( + 'href' => $statlink, + 'id' => "statlink-$id", + 'title' => yourls_esc_attr__( 'Stats' ), + 'anchor' => yourls__( 'Stats' ), + ), + 'share' => array( + 'href' => '', + 'id' => "share-button-$id", + 'title' => yourls_esc_attr__( 'Share' ), + 'anchor' => yourls__( 'Share' ), + 'onclick' => "toggle_share('$id');return false;", + ), + 'edit' => array( + 'href' => $edit_link, + 'id' => "edit-button-$id", + 'title' => yourls_esc_attr__( 'Edit' ), + 'anchor' => yourls__( 'Edit' ), + 'onclick' => "edit_link_display('$id');return false;", + ), + 'delete' => array( + 'href' => $delete_link, + 'id' => "delete-button-$id", + 'title' => yourls_esc_attr__( 'Delete' ), + 'anchor' => yourls__( 'Delete' ), + 'onclick' => "remove_link('$id');return false;", + ) + ); + $actions = yourls_apply_filter( 'table_add_row_action_array', $actions, $keyword ); + + // Action link buttons: the HTML + $action_links = ''; + foreach( $actions as $key => $action ) { + $onclick = isset( $action['onclick'] ) ? 'onclick="' . $action['onclick'] . '"' : '' ; + $action_links .= sprintf( '%s', + $action['href'], $action['id'], $action['title'], 'button button_'.$key, $onclick, $action['anchor'] + ); + } + $action_links = yourls_apply_filter( 'action_links', $action_links, $keyword, $url, $ip, $clicks, $timestamp ); + + if( ! $title ) + $title = $url; + + $protocol_warning = ''; + if( ! in_array( yourls_get_protocol( $url ) , array( 'http://', 'https://' ) ) ) + $protocol_warning = yourls_apply_filter( 'add_row_protocol_warning', '' ); + + // Row cells: the array + $cells = array( + 'keyword' => array( + 'template' => '%keyword_html%', + 'shorturl' => yourls_esc_url( $shorturl ), + 'keyword_html' => yourls_esc_html( $keyword ), + ), + 'url' => array( + 'template' => '%title_html%
%warning%%long_url_html%', + 'long_url' => yourls_esc_url( $url ), + 'title_attr' => yourls_esc_attr( $title ), + 'title_html' => yourls_esc_html( yourls_trim_long_string( $title ) ), + 'long_url_html' => yourls_esc_html( yourls_trim_long_string( urldecode( $url ) ) ), + 'warning' => $protocol_warning, + ), + 'timestamp' => array( + 'template' => ' %date%', 'timestamp' => $timestamp, - 'date' => yourls_date_i18n( yourls_get_datetime_format('M d, Y H:i'), yourls_get_timestamp( $timestamp )), - ), - 'ip' => array( - 'template' => '%ip%', - 'ip' => $ip, - ), - 'clicks' => array( - 'template' => '%clicks%', - 'clicks' => yourls_number_format_i18n( $clicks, 0, '', '' ), - ), - 'actions' => array( - 'template' => '%actions% ', - 'actions' => $action_links, - 'id' => $id, - 'keyword' => $keyword, - ), - ); - $cells = yourls_apply_filter( 'table_add_row_cell_array', $cells, $keyword, $url, $title, $ip, $clicks, $timestamp ); - - // Row cells: the HTML. Replace every %stuff% in 'template' with 'stuff' value. - $row = ""; - foreach( $cells as $cell_id => $elements ) { - $row .= sprintf( '', $cell_id, $cell_id . '-' . $id ); - $row .= preg_replace_callback( '/%([^%]+)?%/', function( $match ) use ( $elements ) { return $elements[ $match[1] ]; }, $elements['template'] ); - $row .= ''; - } - $row .= ""; - $row = yourls_apply_filter( 'table_add_row', $row, $keyword, $url, $title, $ip, $clicks, $timestamp ); - - return $row; + 'date' => yourls_date_i18n( yourls_get_datetime_format('M d, Y H:i'), yourls_get_timestamp( $timestamp )), + ), + 'ip' => array( + 'template' => '%ip%', + 'ip' => $ip, + ), + 'clicks' => array( + 'template' => '%clicks%', + 'clicks' => yourls_number_format_i18n( $clicks, 0 ), + ), + 'actions' => array( + 'template' => '%actions% ', + 'actions' => $action_links, + 'id' => $id, + 'keyword' => $keyword, + ), + ); + $cells = yourls_apply_filter( 'table_add_row_cell_array', $cells, $keyword, $url, $title, $ip, $clicks, $timestamp ); + + // Row cells: the HTML. Replace every %stuff% in 'template' with 'stuff' value. + $row = ""; + foreach( $cells as $cell_id => $elements ) { + $row .= sprintf( '', $cell_id, $cell_id . '-' . $id ); + $row .= preg_replace_callback( '/%([^%]+)?%/', function( $match ) use ( $elements ) { return $elements[ $match[1] ]; }, $elements['template'] ); + $row .= ''; + } + $row .= ""; + $row = yourls_apply_filter( 'table_add_row', $row, $keyword, $url, $title, $ip, $clicks, $timestamp ); + + return $row; } /** * Echo the main table head * + * @return void */ function yourls_table_head() { - $start = ''."\n"; - echo yourls_apply_filter( 'table_head_start', $start ); - - $cells = yourls_apply_filter( 'table_head_cells', array( - 'shorturl' => yourls__( 'Short URL' ), - 'longurl' => yourls__( 'Original URL' ), - 'date' => yourls__( 'Date' ), - 'ip' => yourls__( 'IP' ), - 'clicks' => yourls__( 'Clicks' ), - 'actions' => yourls__( 'Actions' ) - ) ); - foreach( $cells as $k => $v ) { - echo "\n"; - } - - $end = "\n"; - echo yourls_apply_filter( 'table_head_end', $end ); + $start = '
$v
'."\n"; + echo yourls_apply_filter( 'table_head_start', $start ); + + $cells = yourls_apply_filter( 'table_head_cells', array( + 'shorturl' => yourls__( 'Short URL' ), + 'longurl' => yourls__( 'Original URL' ), + 'date' => yourls__( 'Date' ), + 'ip' => yourls__( 'IP' ), + 'clicks' => yourls__( 'Clicks' ), + 'actions' => yourls__( 'Actions' ) + ) ); + foreach( $cells as $k => $v ) { + echo "\n"; + } + + $end = "\n"; + echo yourls_apply_filter( 'table_head_end', $end ); } /** * Echo the tbody start tag * + * @return void */ function yourls_table_tbody_start() { - echo yourls_apply_filter( 'table_tbody_start', '' ); + echo yourls_apply_filter( 'table_tbody_start', '' ); } /** * Echo the tbody end tag * + * @return void */ function yourls_table_tbody_end() { - echo yourls_apply_filter( 'table_tbody_end', '' ); + echo yourls_apply_filter( 'table_tbody_end', '' ); } /** * Echo the table start tag * + * @return void */ function yourls_table_end() { - echo yourls_apply_filter( 'table_end', '
$v
' ); + echo yourls_apply_filter( 'table_end', '' ); } + + /** * Echo HTML tag for a link * - */ -function yourls_html_link( $href, $title = '', $element = '' ) { - if( !$title ) - $title = $href; - if( $element ) - $element = sprintf( 'id="%s"', yourls_esc_attr( $element ) ); - $link = sprintf( '%s', yourls_esc_url( $href ), $element, yourls_esc_html( $title ) ); - echo yourls_apply_filter( 'html_link', $link ); + * @param string $href URL to link to + * @param string $anchor Anchor text + * @param string $element Element id + * @return void +*/ +function yourls_html_link( $href, $anchor = '', $element = '' ) { + if( !$anchor ) + $anchor = $href; + if( $element ) + $element = sprintf( 'id="%s"', yourls_esc_attr( $element ) ); + $link = sprintf( '%s', yourls_esc_url( $href ), $element, yourls_esc_html( $anchor ) ); + echo yourls_apply_filter( 'html_link', $link ); } /** * Display the login screen. Nothing past this point. * + * @param string $error_msg Optional error message to display + * @return void */ function yourls_login_screen( $error_msg = '' ) { - yourls_html_head( 'login' ); - - $action = ( isset( $_GET['action'] ) && $_GET['action'] == 'logout' ? '?' : '' ); - - yourls_html_logo(); - ?> -
-
- '.$error_msg.'

'; - } - yourls_do_action( 'login_form_top' ); - ?> -

-
- -

-

-
- -

- -

- - -

- -
- -
- +
+
+
+ '.$error_msg.'

'; + } + yourls_do_action( 'login_form_top' ); + ?> +

+
+ +

+

+
+ +

+ +

+ + +

+ +
+ +
+
+ 'logout'], yourls_admin_url('index.php')), 'nonce', 'logout'); + $logout_link = yourls_apply_filter('logout_link', sprintf( yourls__('Hello %s'), YOURLS_USER ) . ' (' . yourls__( 'Logout' ) . ')' ); + } else { + $logout_link = yourls_apply_filter( 'logout_link', '' ); + } + $help_link = yourls_apply_filter( 'help_link', '' . yourls__( 'Help' ) . '' ); + + $admin_links = array(); + $admin_sublinks = array(); + + $admin_links['admin'] = array( + 'url' => yourls_admin_url( 'index.php' ), + 'title' => yourls__( 'Go to the admin interface' ), + 'anchor' => yourls__( 'Admin interface' ) + ); + + if( yourls_is_admin() ) { + $admin_links['tools'] = array( + 'url' => yourls_admin_url( 'tools.php' ), + 'anchor' => yourls__( 'Tools' ) + ); + $admin_links['plugins'] = array( + 'url' => yourls_admin_url( 'plugins.php' ), + 'anchor' => yourls__( 'Manage Plugins' ) + ); + $admin_sublinks['plugins'] = yourls_list_plugin_admin_pages(); + } + + $admin_links = yourls_apply_filter( 'admin_links', $admin_links ); + $admin_sublinks = yourls_apply_filter( 'admin_sublinks', $admin_sublinks ); + + // Now output menu + echo '\n"; + yourls_do_action( 'admin_notices' ); + yourls_do_action( 'admin_notice' ); // because I never remember if it's 'notices' or 'notice' + /* + To display a notice: + $message = "
OMG, dude, I mean!
" ); + yourls_add_action( 'admin_notices', function() use ( $message ) { echo (string) $message; } ); + */ } /** * Wrapper function to display admin notices * + * @param string $message Message to display + * @param string $style Message style (default: 'notice') + * @return void */ function yourls_add_notice( $message, $style = 'notice' ) { - // Escape single quotes in $message to avoid breaking the anonymous function - $message = yourls_notice_box( strtr( $message, array( "'" => "\'" ) ), $style ); - yourls_add_action( 'admin_notices', function() use ( $message ) { echo (string) $message; } ); + // Escape single quotes in $message to avoid breaking the anonymous function + $message = yourls_notice_box( strtr( $message, array( "'" => "\'" ) ), $style ); + yourls_add_action( 'admin_notices', function() use ( $message ) { echo (string) $message; } ); } /** * Return a formatted notice * + * @param string $message Message to display + * @param string $style CSS class to use for the notice + * @return string HTML of the notice */ function yourls_notice_box( $message, $style = 'notice' ) { - return << -

$message

- + return << +

$message

+ HTML; } /** - * Display a page + * Display a page * - * Includes content of a PHP file from the YOURLS_PAGEDIR directory, as if it - * were a standard short URL (ie http://sho.rt/$page) + * Includes content of a PHP file from the YOURLS_PAGEDIR directory, as if it + * were a standard short URL (ie http://sho.rt/$page) * - * @since 1.0 - * @param $page PHP file to display + * @since 1.0 + * @param string $page PHP file to display + * @return void */ function yourls_page( $page ) { if( !yourls_is_page($page)) { - yourls_die( yourls_s('Page "%1$s" not found', $page), yourls__('Not found'), 404 ); + yourls_die( yourls_s('Page "%1$s" not found', $page), yourls__('Not found'), 404 ); } - yourls_do_action( 'pre_page', $page ); - include_once( YOURLS_PAGEDIR . "/$page.php" ); - yourls_do_action( 'post_page', $page ); + yourls_do_action( 'pre_page', $page ); + $load = yourls_include_file_sandbox(YOURLS_PAGEDIR . "/$page.php"); + if (is_string($load)) { + yourls_die( $load, yourls__('Not found'), 404 ); + } + yourls_do_action( 'post_page', $page ); } /** @@ -867,44 +954,46 @@ function yourls_page( $page ) { * information for the page. Stolen from WP. * * @since 1.6 + * @return void */ function yourls_html_language_attributes() { - $attributes = array(); - $output = ''; - - $attributes[] = ( yourls_is_rtl() ? 'dir="rtl"' : 'dir="ltr"' ); - - $doctype = yourls_apply_filter( 'html_language_attributes_doctype', 'html' ); - // Experimental: get HTML lang from locale. Should work. Convert fr_FR -> fr-FR - if ( $lang = str_replace( '_', '-', yourls_get_locale() ) ) { - if( $doctype == 'xhtml' ) { - $attributes[] = "xml:lang=\"$lang\""; - } else { - $attributes[] = "lang=\"$lang\""; - } - } - - $output = implode( ' ', $attributes ); - $output = yourls_apply_filter( 'html_language_attributes', $output ); - echo $output; + $attributes = array(); + $output = ''; + + $attributes[] = ( yourls_is_rtl() ? 'dir="rtl"' : 'dir="ltr"' ); + + $doctype = yourls_apply_filter( 'html_language_attributes_doctype', 'html' ); + // Experimental: get HTML lang from locale. Should work. Convert fr_FR -> fr-FR + if ( $lang = str_replace( '_', '-', yourls_get_locale() ) ) { + if( $doctype == 'xhtml' ) { + $attributes[] = "xml:lang=\"$lang\""; + } else { + $attributes[] = "lang=\"$lang\""; + } + } + + $output = implode( ' ', $attributes ); + $output = yourls_apply_filter( 'html_language_attributes', $output ); + echo $output; } /** * Output translated strings used by the Javascript calendar * * @since 1.6 + * @return void */ function yourls_l10n_calendar_strings() { - echo "\n\n"; - - // Dummy returns, to initialize l10n strings used in the calendar - yourls__( 'Today' ); - yourls__( 'Close' ); + echo "\n\n"; + + // Dummy returns, to initialize l10n strings used in the calendar + yourls__( 'Today' ); + yourls__( 'Close' ); } @@ -912,16 +1001,20 @@ function yourls_l10n_calendar_strings() { * Display a notice if there is a newer version of YOURLS available * * @since 1.7 + * @param string $compare_with Optional, YOURLS version to compare to + * @return void */ -function yourls_new_core_version_notice() { +function yourls_new_core_version_notice($compare_with = null) { + $compare_with = $compare_with ?: YOURLS_VERSION; - $checks = yourls_get_option( 'core_version_checks' ); + $checks = yourls_get_option( 'core_version_checks' ); $latest = isset($checks->last_result->latest) ? yourls_sanitize_version($checks->last_result->latest) : false; - if( $latest AND version_compare( $latest, YOURLS_VERSION, '>' ) ) { - $msg = yourls_s( 'YOURLS version %s is available. Please update!', 'http://yourls.org/download', $latest ); - yourls_add_notice( $msg ); - } + if( $latest AND version_compare( $latest, $compare_with, '>' ) ) { + yourls_do_action('new_core_version_notice', $latest); + $msg = yourls_s( 'YOURLS version %s is available. Please update!', 'http://yourls.org/download', $latest ); + yourls_add_notice( $msg ); + } } /** @@ -952,7 +1045,7 @@ function yourls_bookmarklet_link( $href, $anchor, $echo = true ) { * @return void */ function yourls_set_html_context($context) { - yourls_get_db()->set_html_context($context); + yourls_get_db('read-set_html_context')->set_html_context($context); } /** @@ -962,7 +1055,7 @@ function yourls_set_html_context($context) { * @return string */ function yourls_get_html_context() { - yourls_get_db()->get_html_context(); + return yourls_get_db('read-get_html_context')->get_html_context(); } /** @@ -980,4 +1073,3 @@ function yourls_html_favicon() { printf( '', yourls_get_yourls_favicon_url(false) ); } - diff --git a/includes/functions-http.php b/includes/functions-http.php index e3a330723..b1bb20891 100644 --- a/includes/functions-http.php +++ b/includes/functions-http.php @@ -1,4 +1,5 @@ body ) ? $return->body : null; + $return = yourls_http_get( $url, $headers, $data, $options ); + return isset( $return->body ) ? $return->body : null; } /** @@ -46,10 +57,14 @@ function yourls_http_get_body( $url, $headers = array(), $data = array(), $optio * * @since 1.7 * @see yourls_http_request + * @param string $url URL to request + * @param array $headers HTTP headers to send + * @param array $data POST data + * @param array $options Options to pass to Requests * @return mixed Response object, or error string */ function yourls_http_post( $url, $headers = array(), $data = array(), $options = array() ) { - return yourls_http_request( 'POST', $url, $headers, $data, $options ); + return yourls_http_request( 'POST', $url, $headers, $data, $options ); } /** @@ -59,17 +74,20 @@ function yourls_http_post( $url, $headers = array(), $data = array(), $options = * * @since 1.7 * @see yourls_http_request + * @param string $url URL to request + * @param array $headers HTTP headers to send + * @param array $data POST data + * @param array $options Options to pass to Requests * @return mixed String (page body) or null if error */ function yourls_http_post_body( $url, $headers = array(), $data = array(), $options = array() ) { - $return = yourls_http_post( $url, $headers, $data, $options ); - return isset( $return->body ) ? $return->body : null; + $return = yourls_http_post( $url, $headers, $data, $options ); + return isset( $return->body ) ? $return->body : null; } /** * Get proxy information * - * @uses YOURLS_PROXY YOURLS_PROXY_USERNAME YOURLS_PROXY_PASSWORD * @since 1.7.1 * @return mixed false if no proxy is defined, or string like '10.0.0.201:3128' or array like ('10.0.0.201:3128', 'username', 'password') */ @@ -89,7 +107,6 @@ function yourls_http_get_proxy() { /** * Get list of hosts that should bypass the proxy * - * @uses YOURLS_PROXY_BYPASS_HOSTS * @since 1.7.1 * @return mixed false if no host defined, or string like "example.com, *.mycorp.com" */ @@ -108,18 +125,18 @@ function yourls_http_get_proxy_bypass_host() { * @return array Options */ function yourls_http_default_options() { - $options = array( - 'timeout' => yourls_apply_filter( 'http_default_options_timeout', 3 ), - 'useragent' => yourls_http_user_agent(), - 'follow_redirects' => true, - 'redirects' => 3, - ); - - if( yourls_http_get_proxy() ) { + $options = array( + 'timeout' => yourls_apply_filter( 'http_default_options_timeout', 3 ), + 'useragent' => yourls_http_user_agent(), + 'follow_redirects' => true, + 'redirects' => 3, + ); + + if( yourls_http_get_proxy() ) { $options['proxy'] = yourls_http_get_proxy(); - } + } - return yourls_apply_filter( 'http_default_options', $options ); + return yourls_apply_filter( 'http_default_options', $options ); } /** @@ -128,35 +145,33 @@ function yourls_http_default_options() { * Concept stolen from WordPress. The idea is to allow some URLs, including localhost and the YOURLS install itself, * to be requested directly and bypassing any defined proxy. * - * @uses YOURLS_PROXY - * @uses YOURLS_PROXY_BYPASS_HOSTS * @since 1.7 * @param string $url URL to check * @return bool true to request through proxy, false to request directly */ function yourls_send_through_proxy( $url ) { - // Allow plugins to short-circuit the whole function - $pre = yourls_apply_filter( 'shunt_send_through_proxy', null, $url ); - if ( null !== $pre ) - return $pre; + // Allow plugins to short-circuit the whole function + $pre = yourls_apply_filter( 'shunt_send_through_proxy', null, $url ); + if ( null !== $pre ) + return $pre; - $check = @parse_url( $url ); + $check = @parse_url( $url ); if( !isset( $check['host'] ) ) { return false; } - // Malformed URL, can not process, but this could mean ssl, so let through anyway. - if ( $check === false ) - return true; + // Malformed URL, can not process, but this could mean ssl, so let through anyway. + if ( $check === false ) + return true; - // Self and loopback URLs are considered local (':' is parse_url() host on '::1') - $home = parse_url( yourls_get_yourls_site() ); - $local = array( 'localhost', '127.0.0.1', '127.1', '[::1]', ':', $home['host'] ); + // Self and loopback URLs are considered local (':' is parse_url() host on '::1') + $home = parse_url( yourls_get_yourls_site() ); + $local = array( 'localhost', '127.0.0.1', '127.1', '[::1]', ':', $home['host'] ); - if( in_array( $check['host'], $local ) ) - return false; + if( in_array( $check['host'], $local ) ) + return false; $bypass = yourls_http_get_proxy_bypass_host(); @@ -164,10 +179,10 @@ function yourls_send_through_proxy( $url ) { return true; } - // Build array of hosts to bypass - static $bypass_hosts; - static $wildcard_regex = false; - if ( null == $bypass_hosts ) { + // Build array of hosts to bypass + static $bypass_hosts; + static $wildcard_regex = false; + if ( null == $bypass_hosts ) { $bypass_hosts = preg_split( '|\s*,\s*|', $bypass ); if ( false !== strpos( $bypass, '*' ) ) { @@ -180,12 +195,12 @@ function yourls_send_through_proxy( $url ) { } $wildcard_regex = '/^(' . implode( '|', $wildcard_regex ) . ')$/i'; } - } + } - if ( !empty( $wildcard_regex ) ) - return !preg_match( $wildcard_regex, $check['host'] ); - else - return !in_array( $check['host'], $bypass_hosts ); + if ( !empty( $wildcard_regex ) ) + return !preg_match( $wildcard_regex, $check['host'] ); + else + return !in_array( $check['host'], $bypass_hosts ); } /** @@ -197,22 +212,20 @@ function yourls_send_through_proxy( $url ) { * @param array $headers Extra headers to send with the request * @param array $data Data to send either as a query string for GET requests, or in the body for POST requests * @param array $options Options for the request (see /includes/Requests/Requests.php:request()) - * @return object Requests_Response object + * @return object WpOrg\Requests\Response object */ function yourls_http_request( $type, $url, $headers, $data, $options ) { - // Allow plugins to short-circuit the whole function - $pre = yourls_apply_filter( 'shunt_yourls_http_request', null, $type, $url, $headers, $data, $options ); - if ( null !== $pre ) - return $pre; - - yourls_http_load_library(); + // Allow plugins to short-circuit the whole function + $pre = yourls_apply_filter( 'shunt_yourls_http_request', null, $type, $url, $headers, $data, $options ); + if ( null !== $pre ) + return $pre; - $options = array_merge( yourls_http_default_options(), $options ); + $options = array_merge( yourls_http_default_options(), $options ); - if( yourls_http_get_proxy() && !yourls_send_through_proxy( $url ) ) { - unset( $options['proxy'] ); - } + if( yourls_http_get_proxy() && !yourls_send_through_proxy( $url ) ) { + unset( $options['proxy'] ); + } // filter everything $type = yourls_apply_filter('http_request_type', $type); @@ -221,25 +234,13 @@ function yourls_http_request( $type, $url, $headers, $data, $options ) { $data = yourls_apply_filter('http_request_data', $data); $options = yourls_apply_filter('http_request_options', $options); - try { - $result = Requests::request( $url, $headers, $data, $type, $options ); - } catch( Requests_Exception $e ) { - $result = yourls_debug_log( $e->getMessage() . ' (' . $type . ' on ' . $url . ')' ); - }; + try { + $result = Requests::request( $url, $headers, $data, $type, $options ); + } catch( \WpOrg\Requests\Exception $e ) { + $result = yourls_debug_log( $e->getMessage() . ' (' . $type . ' on ' . $url . ')' ); + }; - return $result; -} - -/** - * Include Requests library if need be - * - * This is to avoid include()-ing all the Requests files on every YOURLS instance - * disregarding whether needed or not. - * - * @since 1.7 - */ -function yourls_http_load_library() { - Requests::register_autoloader(); + return $result; } /** @@ -249,7 +250,7 @@ function yourls_http_load_library() { * @return string UA string */ function yourls_http_user_agent() { - return yourls_apply_filter( 'http_user_agent', 'YOURLS v'.YOURLS_VERSION.' +http://yourls.org/ (running on '.yourls_get_yourls_site().')' ); + return yourls_apply_filter( 'http_user_agent', 'YOURLS v'.YOURLS_VERSION.' +http://yourls.org/ (running on '.yourls_get_yourls_site().')' ); } /** @@ -269,114 +270,172 @@ function yourls_http_user_agent() { */ function yourls_check_core_version() { - global $yourls_user_passwords; + global $yourls_user_passwords; - $checks = yourls_get_option( 'core_version_checks' ); + $checks = yourls_get_option( 'core_version_checks' ); - // Invalidate check data when YOURLS version changes - if ( is_object( $checks ) && YOURLS_VERSION != $checks->version_checked ) { - $checks = false; - } + // Invalidate check data when YOURLS version changes + if ( is_object( $checks ) && YOURLS_VERSION != $checks->version_checked ) { + $checks = false; + } - if( !is_object( $checks ) ) { - $checks = new stdClass; - $checks->failed_attempts = 0; - $checks->last_attempt = 0; - $checks->last_result = ''; - $checks->version_checked = YOURLS_VERSION; - } + if( !is_object( $checks ) ) { + $checks = new stdClass; + $checks->failed_attempts = 0; + $checks->last_attempt = 0; + $checks->last_result = ''; + $checks->version_checked = YOURLS_VERSION; + } - // Config file location ('u' for '/user' or 'i' for '/includes') - $conf_loc = str_replace( YOURLS_ABSPATH, '', YOURLS_CONFIGFILE ); - $conf_loc = str_replace( '/config.php', '', $conf_loc ); - $conf_loc = ( $conf_loc == '/user' ? 'u' : 'i' ); + // Total number of links and clicks + list( $total_urls, $total_clicks ) = array_values(yourls_get_db_stats()); - // The collection of stuff to report - $stuff = array( - // Globally uniquish site identifier + // The collection of stuff to report + $stuff = array( + // Globally uniquish site identifier // This uses const YOURLS_SITE and not yourls_get_yourls_site() to prevent creating another id for an already known install - 'md5' => md5( YOURLS_SITE . YOURLS_ABSPATH ), - - // Install information - 'failed_attempts' => $checks->failed_attempts, - 'yourls_site' => defined( 'YOURLS_SITE' ) ? yourls_get_yourls_site() : 'unknown', - 'yourls_version' => defined( 'YOURLS_VERSION' ) ? YOURLS_VERSION : 'unknown', - 'php_version' => PHP_VERSION, - 'mysql_version' => yourls_get_db()->mysql_version(), - 'locale' => yourls_get_locale(), - - // custom DB driver if any, and useful common PHP extensions - 'db_driver' => defined( 'YOURLS_DB_DRIVER' ) ? YOURLS_DB_DRIVER : 'unset', - 'db_ext_pdo' => extension_loaded( 'PDO' ) ? 1 : 0, - 'db_ext_mysql' => extension_loaded( 'mysql' ) ? 1 : 0, - 'db_ext_mysqli' => extension_loaded( 'mysqli' ) ? 1 : 0, - 'ext_curl' => extension_loaded( 'curl' ) ? 1 : 0, - - // Config information - 'num_users' => count( $yourls_user_passwords ), - 'config_location' => $conf_loc, - 'yourls_private' => defined( 'YOURLS_PRIVATE' ) && YOURLS_PRIVATE ? 1 : 0, - 'yourls_unique' => defined( 'YOURLS_UNIQUE_URLS' ) && YOURLS_UNIQUE_URLS ? 1 : 0, - 'yourls_url_convert' => defined( 'YOURLS_URL_CONVERT' ) ? YOURLS_URL_CONVERT : 'unknown', - 'num_active_plugins' => yourls_has_active_plugins(), - 'num_pages' => defined( 'YOURLS_PAGEDIR' ) ? count( (array) glob( YOURLS_PAGEDIR .'/*.php') ) : 0, - ); - - $stuff = yourls_apply_filter( 'version_check_stuff', $stuff ); - - // Send it in - $url = 'http://api.yourls.org/core/version/1.0/'; - if( yourls_can_http_over_ssl() ) - $url = yourls_set_url_scheme( $url, 'https' ); - $req = yourls_http_post( $url, array(), $stuff ); - - $checks->last_attempt = time(); - $checks->version_checked = YOURLS_VERSION; - - // Unexpected results ? - if( is_string( $req ) or !$req->success ) { - $checks->failed_attempts = $checks->failed_attempts + 1; - yourls_update_option( 'core_version_checks', $checks ); - return false; - } - - // Parse response - $json = json_decode( trim( $req->body ) ); - - if( yourls_validate_core_version_response($json) ) { - // All went OK - mark this down - $checks->failed_attempts = 0; - $checks->last_result = $json; - yourls_update_option( 'core_version_checks', $checks ); - - return $json; - } - - // Request returned actual result, but not what we expected - return false; + 'md5' => md5( YOURLS_SITE . YOURLS_ABSPATH ), + + // Install information + 'failed_attempts' => $checks->failed_attempts, + 'yourls_site' => defined( 'YOURLS_SITE' ) ? yourls_get_yourls_site() : 'unknown', + 'yourls_version' => defined( 'YOURLS_VERSION' ) ? YOURLS_VERSION : 'unknown', + 'php_version' => PHP_VERSION, + 'mysql_version' => yourls_get_db('read-check_core_version')->mysql_version(), + 'locale' => yourls_get_locale(), + + // custom DB driver if any, and useful common PHP extensions + 'db_driver' => defined( 'YOURLS_DB_DRIVER' ) ? YOURLS_DB_DRIVER : 'unset', + 'db_ext_pdo' => extension_loaded( 'PDO' ) ? 1 : 0, + 'db_ext_mysql' => extension_loaded( 'mysql' ) ? 1 : 0, + 'db_ext_mysqli' => extension_loaded( 'mysqli' ) ? 1 : 0, + 'ext_curl' => extension_loaded( 'curl' ) ? 1 : 0, + + // Config information + 'yourls_private' => defined( 'YOURLS_PRIVATE' ) && YOURLS_PRIVATE ? 1 : 0, + 'yourls_unique' => defined( 'YOURLS_UNIQUE_URLS' ) && YOURLS_UNIQUE_URLS ? 1 : 0, + 'yourls_url_convert' => defined( 'YOURLS_URL_CONVERT' ) ? YOURLS_URL_CONVERT : 'unknown', + + // Usage information + 'num_users' => count( $yourls_user_passwords ), + 'num_active_plugins' => yourls_has_active_plugins(), + 'num_pages' => defined( 'YOURLS_PAGEDIR' ) ? count( (array) glob( YOURLS_PAGEDIR .'/*.php') ) : 0, + 'num_links' => $total_urls, + 'num_clicks' => $total_clicks, + ); + + $stuff = yourls_apply_filter( 'version_check_stuff', $stuff ); + + // Send it in + $url = 'http://api.yourls.org/core/version/1.1/'; + if( yourls_can_http_over_ssl() ) { + $url = yourls_set_url_scheme($url, 'https'); + } + $req = yourls_http_post( $url, array(), $stuff ); + + $checks->last_attempt = time(); + $checks->version_checked = YOURLS_VERSION; + + // Unexpected results ? + if( is_string( $req ) or !$req->success ) { + $checks->failed_attempts = $checks->failed_attempts + 1; + yourls_update_option( 'core_version_checks', $checks ); + if( is_string($req) ) { + yourls_debug_log('Version check failed: ' . $req); + } + return false; + } + + // Parse response + $json = json_decode( trim( $req->body ) ); + + if( yourls_validate_core_version_response($json) ) { + // All went OK - mark this down + $checks->failed_attempts = 0; + $checks->last_result = $json; + yourls_update_option( 'core_version_checks', $checks ); + + return $json; + } + + // Request returned actual result, but not what we expected + return false; } /** * Make sure response from api.yourls.org is valid * - * we should get a json object with two following properties: + * 1) we should get a json object with two following properties: * 'latest' => a string representing a YOURLS version number, eg '1.2.3' * 'zipurl' => a string for a zip package URL, from github, eg 'https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3' + * 2) 'latest' and version extracted from 'zipurl' should match + * 3) the object should not contain any other key * * @since 1.7.7 - * @param $json JSON object to check - * @return bool true if seems legit, false otherwise + * @param object $json JSON object to check + * @return bool true if seems legit, false otherwise */ function yourls_validate_core_version_response($json) { return ( - isset($json->latest) - && isset($json->zipurl) + yourls_validate_core_version_response_keys($json) && $json->latest === yourls_sanitize_version($json->latest) && $json->zipurl === yourls_sanitize_url($json->zipurl) - && join('.',array_slice(explode('.',parse_url($json->zipurl, PHP_URL_HOST)), -2, 2)) === 'github.com' - // this last bit get the host ('api.github.com'), explodes on '.' (['api','github','com']) and keeps the last two elements - // to make sure domain is either github.com or one of its subdomain (api.github.com for instance) - // TODO: keep an eye on Github API to make sure it doesn't change some day to another domain (githubapi.com, ...) + && $json->latest === yourls_get_version_from_zipball_url($json->zipurl) + && yourls_is_valid_github_repo_url($json->zipurl) + ); +} + +/** + * Get version number from Github zipball URL (last part of URL, really) + * + * @since 1.8.3 + * @param string $zipurl eg 'https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3' + * @return string + */ +function yourls_get_version_from_zipball_url($zipurl) { + $version = ''; + $parts = explode('/', parse_url(yourls_sanitize_url($zipurl), PHP_URL_PATH) ?? ''); + // expect at least 1 slash in path, return last part + if( count($parts) > 1 ) { + $version = end($parts); + } + return $version; +} + +/** + * Check if URL is from YOURLS/YOURLS repo on github + * + * @since 1.8.3 + * @param string $url URL to check + * @return bool + */ +function yourls_is_valid_github_repo_url($url) { + $url = yourls_sanitize_url($url); + return ( + join('.',array_slice(explode('.', parse_url($url, PHP_URL_HOST) ?? ''), -2, 2)) === 'github.com' + // explodes on '.' (['api','github','com']) and keeps the last two elements + // to make sure domain is either github.com or one of its subdomain (api.github.com for instance) + // TODO: keep an eye on Github API to make sure it doesn't change some day to another domain (githubapi.com, ...) + && substr( parse_url($url, PHP_URL_PATH), 0, 21 ) === '/repos/YOURLS/YOURLS/' + // make sure path starts with '/repos/YOURLS/YOURLS/' + ); +} + +/** + * Check if object has only expected keys 'latest' and 'zipurl' containing strings + * + * @since 1.8.3 + * @param object $json + * @return bool + */ +function yourls_validate_core_version_response_keys($json) { + $keys = array('latest', 'zipurl'); + return ( + count(array_diff(array_keys((array)$json), $keys)) === 0 + && isset($json->latest) + && isset($json->zipurl) + && is_string($json->latest) + && is_string($json->zipurl) ); } @@ -404,33 +463,33 @@ function yourls_maybe_check_core_version() { return false; } - $checks = yourls_get_option( 'core_version_checks' ); - - /* We don't want to check if : - - last_result is set (a previous check was performed) - - and it was less than 24h ago (or less than 2h ago if it wasn't successful) - - and version checked matched version running - Otherwise, we want to check. - */ - if( !empty( $checks->last_result ) - AND - ( - ( $checks->failed_attempts == 0 && ( ( time() - $checks->last_attempt ) < 24 * 3600 ) ) - OR - ( $checks->failed_attempts > 0 && ( ( time() - $checks->last_attempt ) < 2 * 3600 ) ) - ) - AND ( $checks->version_checked == YOURLS_VERSION ) - ) - return false; - - // We want to check if there's a new version - $new_check = yourls_check_core_version(); - - // Could not check for a new version, and we don't have ancient data - if( false == $new_check && !isset( $checks->last_result->latest ) ) - return false; - - return true; + $checks = yourls_get_option( 'core_version_checks' ); + + /* We don't want to check if : + - last_result is set (a previous check was performed) + - and it was less than 24h ago (or less than 2h ago if it wasn't successful) + - and version checked matched version running + Otherwise, we want to check. + */ + if( !empty( $checks->last_result ) + AND + ( + ( $checks->failed_attempts == 0 && ( ( time() - $checks->last_attempt ) < 24 * 3600 ) ) + OR + ( $checks->failed_attempts > 0 && ( ( time() - $checks->last_attempt ) < 2 * 3600 ) ) + ) + AND ( $checks->version_checked == YOURLS_VERSION ) + ) + return false; + + // We want to check if there's a new version + $new_check = yourls_check_core_version(); + + // Could not check for a new version, and we don't have ancient data + if( false == $new_check && !isset( $checks->last_result->latest ) ) + return false; + + return true; } /** @@ -463,4 +522,3 @@ function yourls_can_http_over_ssl() { return ( $ssl_curl OR $ssl_socket ); } - diff --git a/includes/functions-infos.php b/includes/functions-infos.php index 8c10fd934..4cbe8956c 100644 --- a/includes/functions-infos.php +++ b/includes/functions-infos.php @@ -3,337 +3,389 @@ /** * Echoes an image tag of Google Charts map from sorted array of 'country_code' => 'number of visits' (sort by DESC) * + * @param array $countries Array of 'country_code' => 'number of visits' + * @param string $id Optional HTML element ID + * @return void */ -function yourls_stats_countries_map( $countries, $id = null ) { +function yourls_stats_countries_map($countries, $id = null) { - yourls_do_action( 'pre_stats_countries_map' ); + yourls_do_action( 'pre_stats_countries_map' ); - // if $id is null then assign a random string - if( $id === null ) - $id = uniqid ( 'yourls_stats_map_' ); + // if $id is null then assign a random string + if( $id === null ) + $id = uniqid ( 'yourls_stats_map_' ); - $data = array_merge( array( 'Country' => 'Hits' ), $countries ); - $data = yourls_google_array_to_data_table( $data ); + $data = array_merge( array( 'Country' => 'Hits' ), $countries ); + $data = yourls_google_array_to_data_table( $data ); - $options = array( - 'backgroundColor' => "white", - 'colorAxis' => "{colors:['A8D0ED','99C4E4','8AB8DB','7BACD2','6BA1C9','5C95C0','4D89B7','3E7DAE','2E72A5','1F669C']}", - 'width' => "550", - 'height' => "340", - 'theme' => 'maximized' - ); - $options = yourls_apply_filter( 'stats_countries_map_options', $options ); + $options = array( + 'backgroundColor' => "white", + 'colorAxis' => "{colors:['A8D0ED','99C4E4','8AB8DB','7BACD2','6BA1C9','5C95C0','4D89B7','3E7DAE','2E72A5','1F669C']}", + 'width' => "550", + 'height' => "340", + 'theme' => 'maximized' + ); + $options = yourls_apply_filter( 'stats_countries_map_options', $options ); - $map = yourls_google_viz_code( 'GeoChart', $data, $options, $id ); + $map = yourls_google_viz_code( 'GeoChart', $data, $options, $id ); - echo yourls_apply_filter( 'stats_countries_map', $map, $countries, $options, $id ); + echo yourls_apply_filter( 'stats_countries_map', $map, $countries, $options, $id ); } + /** * Echoes an image tag of Google Charts pie from sorted array of 'data' => 'value' (sort by DESC). Optional $limit = (integer) limit list of X first countries, sorted by most visits * + * @param array $data Array of 'data' => 'value' + * @param int $limit Optional limit list of X first countries + * @param $size Optional size of the image + * @param $id Optional HTML element ID + * @return void */ -function yourls_stats_pie( $data, $limit = 10, $size = '340x220', $id = null ) { - - yourls_do_action( 'pre_stats_pie' ); - - // if $id is null then assign a random string - if( $id === null ) - $id = uniqid ( 'yourls_stats_pie_' ); - - // Trim array: $limit first item + the sum of all others - if ( count( $data ) > $limit ) { - $i= 0; - $trim_data = array( 'Others' => 0 ); - foreach( $data as $item=>$value ) { - $i++; - if( $i <= $limit ) { - $trim_data[$item] = $value; - } else { - $trim_data['Others'] += $value; - } - } - $data = $trim_data; - } - - // Scale items - $_data = yourls_scale_data( $data ); - - list($width, $height) = explode( 'x', $size ); - - $options = array( - 'theme' => 'maximized', - 'width' => $width, - 'height' => $height, - 'colors' => "['A8D0ED','99C4E4','8AB8DB','7BACD2','6BA1C9','5C95C0','4D89B7','3E7DAE','2E72A5','1F669C']", - 'legend' => 'none', - 'chartArea' => '{top: "5%", height: "90%"}', - 'pieSliceText' => 'label', - ); - $options = yourls_apply_filter( 'stats_pie_options', $options ); - - $script_data = array_merge( array( 'Country' => 'Value' ), $_data ); - $script_data = yourls_google_array_to_data_table( $script_data ); - - $pie = yourls_google_viz_code( 'PieChart', $script_data, $options, $id ); - - echo yourls_apply_filter( 'stats_pie', $pie, $data, $limit, $size, $options, $id ); +function yourls_stats_pie($data, $limit = 10, $size = '340x220', $id = null) { + + yourls_do_action( 'pre_stats_pie' ); + + // if $id is null then assign a random string + if( $id === null ) + $id = uniqid ( 'yourls_stats_pie_' ); + + // Trim array: $limit first item + the sum of all others + if ( count( $data ) > $limit ) { + $i= 0; + $trim_data = array( 'Others' => 0 ); + foreach( $data as $item=>$value ) { + $i++; + if( $i <= $limit ) { + $trim_data[$item] = $value; + } else { + $trim_data['Others'] += $value; + } + } + $data = $trim_data; + } + + // Scale items + $_data = yourls_scale_data( $data ); + + list($width, $height) = explode( 'x', $size ); + + $options = array( + 'theme' => 'maximized', + 'width' => $width, + 'height' => $height, + 'colors' => "['A8D0ED','99C4E4','8AB8DB','7BACD2','6BA1C9','5C95C0','4D89B7','3E7DAE','2E72A5','1F669C']", + 'legend' => 'none', + 'chartArea' => '{top: "5%", height: "90%"}', + 'pieSliceText' => 'label', + ); + $options = yourls_apply_filter( 'stats_pie_options', $options ); + + $script_data = array_merge( array( 'Country' => 'Value' ), $_data ); + $script_data = yourls_google_array_to_data_table( $script_data ); + + $pie = yourls_google_viz_code( 'PieChart', $script_data, $options, $id ); + + echo yourls_apply_filter( 'stats_pie', $pie, $data, $limit, $size, $options, $id ); } + /** * Build a list of all daily values between d1/m1/y1 to d2/m2/y2. * + * @param array $dates + * @return array[] Array of arrays of days, months, years */ -function yourls_build_list_of_days( $dates ) { - /* Say we have an array like: - $dates = array ( - 2009 => array ( - '08' => array ( - 29 => 15, - 30 => 5, - ), - '09' => array ( - '02' => 3, - '03' => 5, - '04' => 2, - '05' => 99, - ), - ), - ) - */ - - if( !$dates ) - return array(); - - // Get first & last years from our range. In our example: 2009 & 2009 - $first_year = key( $dates ); - $_keys = array_keys( $dates ); - $last_year = end( $_keys ); - reset( $dates ); - - // Get first & last months from our range. In our example: 08 & 09 - $first_month = key( $dates[ $first_year ] ); - $_keys = array_keys( $dates[ $last_year ] ); - $last_month = end( $_keys ); - reset( $dates ); - - // Get first & last days from our range. In our example: 29 & 05 - $first_day = key( $dates[ $first_year ][ $first_month ] ); - $_keys = array_keys( $dates[ $last_year ][ $last_month ] ); - $last_day = end( $_keys ); - - unset( $_keys ); - - // Now build a list of all years (2009), month (08 & 09) and days (all from 2009-08-29 to 2009-09-05) - $list_of_years = array(); - $list_of_months = array(); - $list_of_days = array(); - for ( $year = $first_year; $year <= $last_year; $year++ ) { - $_year = sprintf( '%04d', $year ); - $list_of_years[ $_year ] = $_year; - $current_first_month = ( $year == $first_year ? $first_month : '01' ); - $current_last_month = ( $year == $last_year ? $last_month : '12' ); - for ( $month = $current_first_month; $month <= $current_last_month; $month++ ) { - $_month = sprintf( '%02d', $month ); - $list_of_months[ $_month ] = $_month; - $current_first_day = ( $year == $first_year && $month == $first_month ? $first_day : '01' ); - $current_last_day = ( $year == $last_year && $month == $last_month ? $last_day : yourls_days_in_month( $month, $year) ); - for ( $day = $current_first_day; $day <= $current_last_day; $day++ ) { - $day = sprintf( '%02d', $day ); - $key = date( 'M d, Y', mktime( 0, 0, 0, $_month, $day, $_year ) ); - $list_of_days[ $key ] = isset( $dates[$_year][$_month][$day] ) ? $dates[$_year][$_month][$day] : 0; - } - } - } - - return array( - 'list_of_days' => $list_of_days, - 'list_of_months' => $list_of_months, - 'list_of_years' => $list_of_years, - ); +function yourls_build_list_of_days($dates) { + /* Say we have an array like: + $dates = array ( + 2009 => array ( + '08' => array ( + 29 => 15, + 30 => 5, + ), + '09' => array ( + '02' => 3, + '03' => 5, + '04' => 2, + '05' => 99, + ), + ), + ) + */ + + if( !$dates ) + return array(); + + // Get first & last years from our range. In our example: 2009 & 2009 + $first_year = key( $dates ); + $_keys = array_keys( $dates ); + $last_year = end( $_keys ); + reset( $dates ); + + // Get first & last months from our range. In our example: 08 & 09 + $first_month = key( $dates[ $first_year ] ); + $_keys = array_keys( $dates[ $last_year ] ); + $last_month = end( $_keys ); + reset( $dates ); + + // Get first & last days from our range. In our example: 29 & 05 + $first_day = key( $dates[ $first_year ][ $first_month ] ); + $_keys = array_keys( $dates[ $last_year ][ $last_month ] ); + $last_day = end( $_keys ); + + unset( $_keys ); + + // Extend to today + $today = new DateTime(); + $today->setTime( 0, 0, 0 ); // Start of today + $today_year = $today->format( 'Y' ); + $today_month = $today->format( 'm' ); + $today_day = $today->format( 'd' ); + + // Now build a list of all years (2009), month (08 & 09) and days (all from 2009-08-29 to 2009-09-05) + $list_of_years = array(); + $list_of_months = array(); + $list_of_days = array(); + for ( $year = $first_year; $year <= $today_year; $year++ ) { + $_year = sprintf( '%04d', $year ); + $list_of_years[ $_year ] = $_year; + $current_first_month = ( $year == $first_year ? $first_month : '01' ); + $current_last_month = ( $year == $today_year ? $today_month : '12' ); + for ( $month = $current_first_month; $month <= $current_last_month; $month++ ) { + $_month = sprintf( '%02d', $month ); + $list_of_months[ $_month ] = $_month; + $current_first_day = ( $year == $first_year && $month == $first_month ? $first_day : '01' ); + $current_last_day = ( $year == $today_year && $month == $today_month ? $today_day : yourls_days_in_month( $month, $year ) ); + for ( $day = $current_first_day; $day <= $current_last_day; $day++ ) { + $day = sprintf( '%02d', $day ); + $key = date( 'M d, Y', mktime( 0, 0, 0, $_month, $day, $_year ) ); + $list_of_days[ $key ] = isset( $dates[$_year][$_month][$day] ) ? $dates[$_year][$_month][$day] : 0; + } + } + } + + return array( + 'list_of_days' => $list_of_days, + 'list_of_months' => $list_of_months, + 'list_of_years' => $list_of_years, + ); } + /** * Echoes an image tag of Google Charts line graph from array of values (eg 'number of clicks'). * * $legend1_list & legend2_list are values used for the 2 x-axis labels. $id is an HTML/JS id * + * @param array $values Array of values (eg 'number of clicks') + * @param string $id HTML element id + * @return void */ -function yourls_stats_line( $values, $id = null ) { +function yourls_stats_line($values, $id = null) { - yourls_do_action( 'pre_stats_line' ); + yourls_do_action( 'pre_stats_line' ); - // if $id is null then assign a random string - if( $id === null ) - $id = uniqid ( 'yourls_stats_line_' ); + // if $id is null then assign a random string + if( $id === null ) + $id = uniqid ( 'yourls_stats_line_' ); - // If we have only 1 day of data, prepend a fake day with 0 hits for a prettier graph - if ( count( $values ) == 1 ) - array_unshift( $values, 0 ); + // If we have only 1 day of data, prepend a fake day with 0 hits for a prettier graph + if ( count( $values ) == 1 ) + array_unshift( $values, 0 ); - // Keep only a subset of values to keep graph smooth - $values = yourls_array_granularity( $values, 30 ); + // Keep only a subset of values to keep graph smooth + $values = yourls_array_granularity( $values, 30 ); - $data = array_merge( array( 'Time' => 'Hits' ), $values ); - $data = yourls_google_array_to_data_table( $data ); + $data = array_merge( array( 'Time' => 'Hits' ), $values ); + $data = yourls_google_array_to_data_table( $data ); - $options = array( - "legend" => "none", - "pointSize" => "3", - "theme" => "maximized", - "curveType" => "function", - "width" => 430, - "height" => 220, - "hAxis" => "{minTextSpacing: 80, maxTextLines: 1, maxAlternation: 1}", - "vAxis" => "{minValue: 0, format: '#'}", - "colors" => "['#2a85b3']", - ); - $options = yourls_apply_filter( 'stats_line_options', $options ); + $options = array( + "legend" => "none", + "pointSize" => "3", + "theme" => "maximized", + "curveType" => "function", + "width" => 430, + "height" => 220, + "hAxis" => "{minTextSpacing: 80, maxTextLines: 1, maxAlternation: 1}", + "vAxis" => "{minValue: 0, format: '#'}", + "colors" => "['#2a85b3']", + ); + $options = yourls_apply_filter( 'stats_line_options', $options ); - $lineChart = yourls_google_viz_code( 'LineChart', $data, $options, $id ); + $lineChart = yourls_google_viz_code( 'LineChart', $data, $options, $id ); - echo yourls_apply_filter( 'stats_line', $lineChart, $values, $options, $id ); + echo yourls_apply_filter( 'stats_line', $lineChart, $values, $options, $id ); } + /** - * Return the number of days in a month. From php.net, used if PHP built without calendar functions + * Return the number of days in a month. From php.net. * + * @param int $month + * @param int $year + * @return int */ -function yourls_days_in_month( $month, $year ) { - // calculate number of days in a month - return $month == 2 ? ( $year % 4 ? 28 : ( $year % 100 ? 29 : ( $year % 400 ? 28 : 29 ) ) ) : ( ( $month - 1 ) % 7 % 2 ? 30 : 31 ); +function yourls_days_in_month($month, $year) { + // calculate number of days in a month + return $month == 2 ? ( $year % 4 ? 28 : ( $year % 100 ? 29 : ( $year % 400 ? 28 : 29 ) ) ) : ( ( $month - 1 ) % 7 % 2 ? 30 : 31 ); } + /** * Get max value from date array of 'Aug 12, 2012' = '1337' * + * @param array $list_of_days + * @return array */ -function yourls_stats_get_best_day( $list_of_days ) { - $max = max( $list_of_days ); - foreach( $list_of_days as $k=>$v ) { - if ( $v == $max ) - return array( 'day' => $k, 'max' => $max ); - } +function yourls_stats_get_best_day($list_of_days) { + $max = max( $list_of_days ); + foreach( $list_of_days as $k=>$v ) { + if ( $v == $max ) + return array( 'day' => $k, 'max' => $max ); + } } /** * Return domain of a URL * + * @param string $url + * @param bool $include_scheme + * @return string */ -function yourls_get_domain( $url, $include_scheme = false ) { - $parse = @parse_url( $url ); // Hiding ugly stuff coming from malformed referrer URLs +function yourls_get_domain($url, $include_scheme = false) { + $parse = @parse_url( $url ); // Hiding ugly stuff coming from malformed referrer URLs - // Get host & scheme. Fall back to path if not found. - $host = isset( $parse['host'] ) ? $parse['host'] : ''; - $scheme = isset( $parse['scheme'] ) ? $parse['scheme'] : ''; - $path = isset( $parse['path'] ) ? $parse['path'] : ''; - if( !$host ) - $host = $path; + // Get host & scheme. Fall back to path if not found. + $host = isset( $parse['host'] ) ? $parse['host'] : ''; + $scheme = isset( $parse['scheme'] ) ? $parse['scheme'] : ''; + $path = isset( $parse['path'] ) ? $parse['path'] : ''; + if( !$host ) + $host = $path; - if ( $include_scheme && $scheme ) - $host = $scheme.'://'.$host; + if ( $include_scheme && $scheme ) + $host = $scheme.'://'.$host; - return $host; + return $host; } + /** * Return favicon URL * + * @param string $url + * @return string */ -function yourls_get_favicon_url( $url ) { - return yourls_match_current_protocol( '//www.google.com/s2/favicons?domain=' . yourls_get_domain( $url, false ) ); +function yourls_get_favicon_url($url) { + return yourls_match_current_protocol( '//www.google.com/s2/favicons?domain=' . yourls_get_domain( $url, false ) ); } /** * Scale array of data from 0 to 100 max * + * @param array $data + * @return array */ -function yourls_scale_data( $data ) { - $max = max( $data ); - if( $max > 100 ) { - foreach( $data as $k=>$v ) { - $data[$k] = intval( $v / $max * 100 ); - } - } - return $data; +function yourls_scale_data($data ) { + $max = max( $data ); + if( $max > 100 ) { + foreach( $data as $k=>$v ) { + $data[$k] = intval( $v / $max * 100 ); + } + } + return $data; } + /** - * Tweak granularity of array $array: keep only $grain values. This make less accurate but less messy graphs when too much values. See http://code.google.com/apis/chart/formats.html#granularity + * Tweak granularity of array $array: keep only $grain values. * + * This make less accurate but less messy graphs when too much values. + * See https://developers.google.com/chart/image/docs/gallery/line_charts?hl=en#data-granularity + * + * @param array $array + * @param int $grain + * @param bool $preserve_max + * @return array */ -function yourls_array_granularity( $array, $grain = 100, $preserve_max = true ) { - if ( count( $array ) > $grain ) { - $max = max( $array ); - $step = intval( count( $array ) / $grain ); - $i = 0; - // Loop through each item and unset except every $step (optional preserve the max value) - foreach( $array as $k=>$v ) { - $i++; - if ( $i % $step != 0 ) { - if ( $preserve_max == false ) { - unset( $array[$k] ); - } else { - if ( $v < $max ) - unset( $array[$k] ); - } - } - } - } - return $array; +function yourls_array_granularity($array, $grain = 100, $preserve_max = true) { + if ( count( $array ) > $grain ) { + $max = max( $array ); + $step = intval( count( $array ) / $grain ); + $i = 0; + // Loop through each item and unset except every $step (optional preserve the max value) + foreach( $array as $k=>$v ) { + $i++; + if ( $i % $step != 0 ) { + if ( $preserve_max == false ) { + unset( $array[$k] ); + } else { + if ( $v < $max ) + unset( $array[$k] ); + } + } + } + } + return $array; } /** * Transform data array to data table for Google API * + * @param array $data + * @return string */ -function yourls_google_array_to_data_table( $data ){ - $str = "var data = google.visualization.arrayToDataTable([\n"; - foreach( $data as $label => $values ){ - if( !is_array( $values ) ) { - $values = array( $values ); - } - $str .= "\t['$label',"; - foreach( $values as $value ){ - if( !is_numeric( $value ) && strpos( $value, '[' ) !== 0 && strpos( $value, '{' ) !== 0 ) { - $value = "'$value'"; - } - $str .= "$value"; - } - $str .= "],\n"; - } - $str = substr( $str, 0, -2 ) . "\n"; // remove the trailing comma/return, reappend the return - $str .= "]);\n"; // wrap it up - return $str; +function yourls_google_array_to_data_table($data){ + $str = "var data = google.visualization.arrayToDataTable([\n"; + foreach( $data as $label => $values ){ + if( !is_array( $values ) ) { + $values = array( $values ); + } + $str .= "\t['$label',"; + foreach( $values as $value ){ + if( !is_numeric( $value ) && strpos( $value, '[' ) !== 0 && strpos( $value, '{' ) !== 0 ) { + $value = "'$value'"; + } + $str .= "$value"; + } + $str .= "],\n"; + } + $str = substr( $str, 0, -2 ) . "\n"; // remove the trailing comma/return, reappend the return + $str .= "]);\n"; // wrap it up + return $str; } /** * Return javascript code that will display the Google Chart * + * @param string $graph_type + * @param string $data + * @param var $options + * @param string $id + * @return string */ -function yourls_google_viz_code( $graph_type, $data, $options, $id ) { - $function_name = 'yourls_graph' . $id; - $code = "\n\n"; - $code .= "
\n"; - - return $code; +function yourls_google_viz_code($graph_type, $data, $options, $id ) { + $function_name = 'yourls_graph' . $id; + $code = "\n\n"; + $code .= "
\n"; + + return $code; } - diff --git a/includes/functions-install.php b/includes/functions-install.php index c9dab2caf..bbf3e26e5 100644 --- a/includes/functions-install.php +++ b/includes/functions-install.php @@ -13,25 +13,26 @@ function yourls_check_PDO() { /** * Check if server has MySQL 5.0+ * + * @return bool */ function yourls_check_database_version() { return ( version_compare( '5.0', yourls_get_database_version() ) <= 0 ); } /** - * Get DB version + * Get DB server version * * @since 1.7 * @return string sanitized DB version */ function yourls_get_database_version() { - // Allow plugins to short-circuit the whole function - $pre = yourls_apply_filter( 'shunt_get_database_version', false ); - if ( false !== $pre ) { - return $pre; + // Allow plugins to short-circuit the whole function + $pre = yourls_apply_filter( 'shunt_get_database_version', false ); + if ( false !== $pre ) { + return $pre; } - return yourls_sanitize_version(yourls_get_db()->mysql_version()); + return yourls_sanitize_version(yourls_get_db('read-get_database_version')->mysql_version()); } /** @@ -40,6 +41,7 @@ function yourls_get_database_version() { * As of 1.8 we advertise YOURLS as being 7.4+ but it should work on 7.2 (although untested) * so we don't want to strictly enforce a limitation that may not be necessary. * + * @return bool */ function yourls_check_php_version() { return version_compare( PHP_VERSION, '7.2.0', '>=' ); @@ -48,79 +50,82 @@ function yourls_check_php_version() { /** * Check if server is an Apache * + * @return bool */ function yourls_is_apache() { - if( !array_key_exists( 'SERVER_SOFTWARE', $_SERVER ) ) - return false; - return ( - strpos( $_SERVER['SERVER_SOFTWARE'], 'Apache' ) !== false - || strpos( $_SERVER['SERVER_SOFTWARE'], 'LiteSpeed' ) !== false - ); + if( !array_key_exists( 'SERVER_SOFTWARE', $_SERVER ) ) + return false; + return ( + strpos( $_SERVER['SERVER_SOFTWARE'], 'Apache' ) !== false + || strpos( $_SERVER['SERVER_SOFTWARE'], 'LiteSpeed' ) !== false + ); } /** * Check if server is running IIS * + * @return bool */ function yourls_is_iis() { - return ( array_key_exists( 'SERVER_SOFTWARE', $_SERVER ) ? ( strpos( $_SERVER['SERVER_SOFTWARE'], 'IIS' ) !== false ) : false ); + return ( array_key_exists( 'SERVER_SOFTWARE', $_SERVER ) ? ( strpos( $_SERVER['SERVER_SOFTWARE'], 'IIS' ) !== false ) : false ); } /** * Create .htaccess or web.config. Returns boolean * + * @return bool */ function yourls_create_htaccess() { - $host = parse_url( yourls_get_yourls_site() ); - $path = ( isset( $host['path'] ) ? $host['path'] : '' ); - - if ( yourls_is_iis() ) { - // Prepare content for a web.config file - $content = array( - '', - '', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - '', - ); - - $filename = YOURLS_ABSPATH.'/web.config'; - $marker = 'none'; - - } else { - // Prepare content for a .htaccess file - $content = array( - '', - 'RewriteEngine On', - 'RewriteBase '.$path.'/', - 'RewriteCond %{REQUEST_FILENAME} !-f', - 'RewriteCond %{REQUEST_FILENAME} !-d', - 'RewriteRule ^.*$ '.$path.'/yourls-loader.php [L]', - '', - ); - - $filename = YOURLS_ABSPATH.'/.htaccess'; - $marker = 'YOURLS'; - - } - - return ( yourls_insert_with_markers( $filename, $marker, $content ) ); + $host = parse_url( yourls_get_yourls_site() ); + $path = ( isset( $host['path'] ) ? $host['path'] : '' ); + + if ( yourls_is_iis() ) { + // Prepare content for a web.config file + $content = array( + '', + '', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + '', + ); + + $filename = YOURLS_ABSPATH.'/web.config'; + $marker = 'none'; + + } else { + // Prepare content for a .htaccess file + $content = array( + '', + 'RewriteEngine On', + 'RewriteBase '.$path.'/', + 'RewriteCond %{REQUEST_FILENAME} !-f', + 'RewriteCond %{REQUEST_FILENAME} !-d', + 'RewriteRule ^.*$ '.$path.'/yourls-loader.php [L]', + '', + ); + + $filename = YOURLS_ABSPATH.'/.htaccess'; + $marker = 'YOURLS'; + + } + + return ( yourls_insert_with_markers( $filename, $marker, $content ) ); } /** @@ -138,54 +143,54 @@ function yourls_create_htaccess() { * @return bool True on write success, false on failure. */ function yourls_insert_with_markers( $filename, $marker, $insertion ) { - if ( !file_exists( $filename ) || is_writeable( $filename ) ) { - if ( !file_exists( $filename ) ) { - $markerdata = ''; - } else { - $markerdata = explode( "\n", implode( '', file( $filename ) ) ); - } - - if ( !$f = @fopen( $filename, 'w' ) ) - return false; - - $foundit = false; - if ( $markerdata ) { - $state = true; - foreach ( $markerdata as $n => $markerline ) { - if ( strpos( $markerline, '# BEGIN ' . $marker ) !== false ) - $state = false; - if ( $state ) { - if ( $n + 1 < count( $markerdata ) ) - fwrite( $f, "{$markerline}\n" ); - else - fwrite( $f, "{$markerline}" ); - } - if ( strpos( $markerline, '# END ' . $marker ) !== false ) { - if ( $marker != 'none' ) - fwrite( $f, "# BEGIN {$marker}\n" ); - if ( is_array( $insertion ) ) - foreach ( $insertion as $insertline ) - fwrite( $f, "{$insertline}\n" ); - if ( $marker != 'none' ) - fwrite( $f, "# END {$marker}\n" ); - $state = true; - $foundit = true; - } - } - } - if ( !$foundit ) { - if ( $marker != 'none' ) - fwrite( $f, "\n\n# BEGIN {$marker}\n" ); - foreach ( $insertion as $insertline ) - fwrite( $f, "{$insertline}\n" ); - if ( $marker != 'none' ) - fwrite( $f, "# END {$marker}\n\n" ); - } - fclose( $f ); - return true; - } else { - return false; - } + if ( !file_exists( $filename ) || is_writeable( $filename ) ) { + if ( !file_exists( $filename ) ) { + $markerdata = ''; + } else { + $markerdata = explode( "\n", implode( '', file( $filename ) ) ); + } + + if ( !$f = @fopen( $filename, 'w' ) ) + return false; + + $foundit = false; + if ( $markerdata ) { + $state = true; + foreach ( $markerdata as $n => $markerline ) { + if ( strpos( $markerline, '# BEGIN ' . $marker ) !== false ) + $state = false; + if ( $state ) { + if ( $n + 1 < count( $markerdata ) ) + fwrite( $f, "{$markerline}\n" ); + else + fwrite( $f, "{$markerline}" ); + } + if ( strpos( $markerline, '# END ' . $marker ) !== false ) { + if ( $marker != 'none' ) + fwrite( $f, "# BEGIN {$marker}\n" ); + if ( is_array( $insertion ) ) + foreach ( $insertion as $insertline ) + fwrite( $f, "{$insertline}\n" ); + if ( $marker != 'none' ) + fwrite( $f, "# END {$marker}\n" ); + $state = true; + $foundit = true; + } + } + } + if ( !$foundit ) { + if ( $marker != 'none' ) + fwrite( $f, "\n\n# BEGIN {$marker}\n" ); + foreach ( $insertion as $insertline ) + fwrite( $f, "{$insertline}\n" ); + if ( $marker != 'none' ) + fwrite( $f, "# END {$marker}\n\n" ); + } + fclose( $f ); + return true; + } else { + return false; + } } /** @@ -202,16 +207,16 @@ function yourls_create_sql_tables() { return $pre; } - $ydb = yourls_get_db(); + $ydb = yourls_get_db('write-create_sql_tables'); - $error_msg = array(); - $success_msg = array(); + $error_msg = array(); + $success_msg = array(); - // Create Table Query - $create_tables = array(); - $create_tables[YOURLS_DB_TABLE_URL] = + // Create Table Query + $create_tables = array(); + $create_tables[YOURLS_DB_TABLE_URL] = 'CREATE TABLE IF NOT EXISTS `'.YOURLS_DB_TABLE_URL.'` ('. - '`keyword` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT "",'. + '`keyword` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT \'\','. '`url` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,'. '`title` text COLLATE utf8mb4_unicode_ci DEFAULT NULL,'. '`timestamp` timestamp NOT NULL DEFAULT current_timestamp(),'. @@ -219,64 +224,65 @@ function yourls_create_sql_tables() { '`clicks` int(10) unsigned NOT NULL,'. 'PRIMARY KEY (`keyword`),'. 'KEY `ip` (`ip`),'. - 'KEY `timestamp` (`timestamp`)'. + 'KEY `timestamp` (`timestamp`),'. + 'KEY `url_idx` (`url`(30))'. ') DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;'; - $create_tables[YOURLS_DB_TABLE_OPTIONS] = - 'CREATE TABLE IF NOT EXISTS `'.YOURLS_DB_TABLE_OPTIONS.'` ('. - '`option_id` bigint(20) unsigned NOT NULL auto_increment,'. - '`option_name` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL default "",'. - '`option_value` longtext COLLATE utf8mb4_unicode_ci NOT NULL,'. - 'PRIMARY KEY (`option_id`,`option_name`),'. - 'KEY `option_name` (`option_name`)'. - ') AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;'; - - $create_tables[YOURLS_DB_TABLE_LOG] = - 'CREATE TABLE IF NOT EXISTS `'.YOURLS_DB_TABLE_LOG.'` ('. - '`click_id` int(11) NOT NULL auto_increment,'. - '`click_time` datetime NOT NULL,'. - '`shorturl` varchar(100) BINARY NOT NULL,'. - '`referrer` varchar(200) NOT NULL,'. - '`user_agent` varchar(255) NOT NULL,'. - '`ip_address` varchar(41) NOT NULL,'. - '`country_code` char(2) NOT NULL,'. - 'PRIMARY KEY (`click_id`),'. - 'KEY `shorturl` (`shorturl`)'. - ') AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;'; - - - $create_table_count = 0; + $create_tables[YOURLS_DB_TABLE_OPTIONS] = + 'CREATE TABLE IF NOT EXISTS `'.YOURLS_DB_TABLE_OPTIONS.'` ('. + '`option_id` bigint(20) unsigned NOT NULL auto_increment,'. + '`option_name` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL default \'\','. + '`option_value` longtext COLLATE utf8mb4_unicode_ci NOT NULL,'. + 'PRIMARY KEY (`option_id`,`option_name`),'. + 'KEY `option_name` (`option_name`)'. + ') AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;'; + + $create_tables[YOURLS_DB_TABLE_LOG] = + 'CREATE TABLE IF NOT EXISTS `'.YOURLS_DB_TABLE_LOG.'` ('. + '`click_id` int(11) NOT NULL auto_increment,'. + '`click_time` datetime NOT NULL,'. + '`shorturl` varchar(100) BINARY NOT NULL,'. + '`referrer` varchar(200) NOT NULL,'. + '`user_agent` varchar(255) NOT NULL,'. + '`ip_address` varchar(41) NOT NULL,'. + '`country_code` char(2) NOT NULL,'. + 'PRIMARY KEY (`click_id`),'. + 'KEY `shorturl` (`shorturl`)'. + ') AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;'; + + + $create_table_count = 0; yourls_debug_mode(true); - // Create tables - foreach ( $create_tables as $table_name => $table_query ) { - $ydb->perform( $table_query ); - $create_success = $ydb->fetchAffected( "SHOW TABLES LIKE '$table_name'" ); - if( $create_success ) { - $create_table_count++; - $success_msg[] = yourls_s( "Table '%s' created.", $table_name ); - } else { - $error_msg[] = yourls_s( "Error creating table '%s'.", $table_name ); - } - } - - // Initializes the option table - if( !yourls_initialize_options() ) - $error_msg[] = yourls__( 'Could not initialize options' ); - - // Insert sample links - if( !yourls_insert_sample_links() ) - $error_msg[] = yourls__( 'Could not insert sample short URLs' ); - - // Check results of operations - if ( sizeof( $create_tables ) == $create_table_count ) { - $success_msg[] = yourls__( 'YOURLS tables successfully created.' ); - } else { - $error_msg[] = yourls__( 'Error creating YOURLS tables.' ); - } - - return array( 'success' => $success_msg, 'error' => $error_msg ); + // Create tables + foreach ( $create_tables as $table_name => $table_query ) { + $ydb->perform( $table_query ); + $create_success = $ydb->fetchAffected( "SHOW TABLES LIKE '$table_name'" ); + if( $create_success ) { + $create_table_count++; + $success_msg[] = yourls_s( "Table '%s' created.", $table_name ); + } else { + $error_msg[] = yourls_s( "Error creating table '%s'.", $table_name ); + } + } + + // Initializes the option table + if( !yourls_initialize_options() ) + $error_msg[] = yourls__( 'Could not initialize options' ); + + // Insert sample links + if( !yourls_insert_sample_links() ) + $error_msg[] = yourls__( 'Could not insert sample short URLs' ); + + // Check results of operations + if ( sizeof( $create_tables ) == $create_table_count ) { + $success_msg[] = yourls__( 'YOURLS tables successfully created.' ); + } else { + $error_msg[] = yourls__( 'Error creating YOURLS tables.' ); + } + + return array( 'success' => $success_msg, 'error' => $error_msg ); } /** @@ -290,12 +296,12 @@ function yourls_create_sql_tables() { * @return bool */ function yourls_initialize_options() { - return ( bool ) ( - yourls_update_option( 'version', YOURLS_VERSION ) - & yourls_update_option( 'db_version', YOURLS_DB_VERSION ) - & yourls_update_option( 'next_id', 1 ) + return ( bool ) ( + yourls_update_option( 'version', YOURLS_VERSION ) + & yourls_update_option( 'db_version', YOURLS_DB_VERSION ) + & yourls_update_option( 'next_id', 1 ) & yourls_update_option( 'active_plugins', array() ) - ); + ); } /** @@ -305,41 +311,42 @@ function yourls_initialize_options() { * @return bool */ function yourls_insert_sample_links() { - $link1 = yourls_add_new_link( 'http://blog.yourls.org/', 'yourlsblog', 'YOURLS\' Blog' ); - $link2 = yourls_add_new_link( 'http://yourls.org/', 'yourls', 'YOURLS: Your Own URL Shortener' ); - $link3 = yourls_add_new_link( 'http://ozh.org/', 'ozh', 'ozh.org' ); - return ( bool ) ( - $link1['status'] == 'success' - & $link2['status'] == 'success' - & $link3['status'] == 'success' - ); + $link1 = yourls_add_new_link( 'https://blog.yourls.org/', 'yourlsblog', 'YOURLS\' Blog' ); + $link2 = yourls_add_new_link( 'https://yourls.org/', 'yourls', 'YOURLS: Your Own URL Shortener' ); + $link3 = yourls_add_new_link( 'https://ozh.org/', 'ozh', 'ozh.org' ); + return ( bool ) ( + $link1['status'] == 'success' + & $link2['status'] == 'success' + & $link3['status'] == 'success' + ); } /** * Toggle maintenance mode. Inspired from WP. Returns true for success, false otherwise * + * @param bool $maintenance True to enable, false to disable + * @return bool True on success, false on failure */ function yourls_maintenance_mode( $maintenance = true ) { - $file = YOURLS_ABSPATH . '/.maintenance' ; + $file = YOURLS_ABSPATH . '/.maintenance' ; - // Turn maintenance mode on : create .maintenance file - if ( (bool)$maintenance ) { - if ( ! ( $fp = @fopen( $file, 'w' ) ) ) - return false; + // Turn maintenance mode on : create .maintenance file + if ( (bool)$maintenance ) { + if ( ! ( $fp = @fopen( $file, 'w' ) ) ) + return false; - $maintenance_string = ''; - @fwrite( $fp, $maintenance_string ); - @fclose( $fp ); - @chmod( $file, 0644 ); // Read and write for owner, read for everybody else + $maintenance_string = ''; + @fwrite( $fp, $maintenance_string ); + @fclose( $fp ); + @chmod( $file, 0644 ); // Read and write for owner, read for everybody else - // Not sure why the fwrite would fail if the fopen worked... Just in case - return( is_readable( $file ) ); + // Not sure why the fwrite would fail if the fopen worked... Just in case + return( is_readable( $file ) ); - // Turn maintenance mode off : delete the .maintenance file - } else { - return @unlink($file); - } + // Turn maintenance mode off : delete the .maintenance file + } else { + return @unlink($file); + } } - diff --git a/includes/functions-kses.php b/includes/functions-kses.php index fac0cf62e..7a81ffdb8 100644 --- a/includes/functions-kses.php +++ b/includes/functions-kses.php @@ -39,52 +39,52 @@ * - $yourls_allowedentitynames is used internally in KSES functions to sanitize HTML entities * - $yourls_allowedprotocols is used in various parts of YOURLS, not just in KSES, albeit being defined here * Two globals are not defined and unused at this moment: $yourls_allowedtags_all and $yourls_allowedtags - * The code for these vars is here and ready for any future use + * The code for these vars is here and ready for any future use */ // Populate after plugins have loaded to allow user defined values yourls_add_action( 'plugins_loaded', 'yourls_kses_init' ); - + /** * Init KSES globals if not already defined (by a plugin) * * @since 1.6 - * + * @return void */ function yourls_kses_init() { - global $yourls_allowedentitynames, $yourls_allowedprotocols; - - if( ! $yourls_allowedentitynames ) { - $yourls_allowedentitynames = yourls_apply_filter( 'kses_allowed_entities', yourls_kses_allowed_entities() ); - } - - if( ! $yourls_allowedprotocols ) { - $yourls_allowedprotocols = yourls_apply_filter( 'kses_allowed_protocols', yourls_kses_allowed_protocols() ); - } - - /** See NOTE ABOUT GLOBALS ** - - if( ! $yourls_allowedtags_all ) { - $yourls_allowedtags_all = yourls_kses_allowed_tags_all(); - $yourls_allowedtags_all = array_map( '_yourls_add_global_attributes', $yourls_allowedtags_all ); - $yourls_allowedtags_all = yourls_apply_filter( 'kses_allowed_tags_all', $yourls_allowedtags_all ); - } else { - // User defined: let's sanitize - $yourls_allowedtags_all = yourls_kses_array_lc( $yourls_allowedtags_all ); - } - - if( ! $yourls_allowedtags ) { - $yourls_allowedtags = yourls_kses_allowed_tags(); - $yourls_allowedtags = array_map( '_yourls_add_global_attributes', $yourls_allowedtags ); - $yourls_allowedtags = yourls_apply_filter( 'kses_allowed_tags', $yourls_allowedtags ); - } else { - // User defined: let's sanitize - $yourls_allowedtags = yourls_kses_array_lc( $yourls_allowedtags ); - } - - /**/ + global $yourls_allowedentitynames, $yourls_allowedprotocols; + + if( ! $yourls_allowedentitynames ) { + $yourls_allowedentitynames = yourls_apply_filter( 'kses_allowed_entities', yourls_kses_allowed_entities() ); + } + + if( ! $yourls_allowedprotocols ) { + $yourls_allowedprotocols = yourls_apply_filter( 'kses_allowed_protocols', yourls_kses_allowed_protocols() ); + } + + /** See NOTE ABOUT GLOBALS ** + + if( ! $yourls_allowedtags_all ) { + $yourls_allowedtags_all = yourls_kses_allowed_tags_all(); + $yourls_allowedtags_all = array_map( '_yourls_add_global_attributes', $yourls_allowedtags_all ); + $yourls_allowedtags_all = yourls_apply_filter( 'kses_allowed_tags_all', $yourls_allowedtags_all ); + } else { + // User defined: let's sanitize + $yourls_allowedtags_all = yourls_kses_array_lc( $yourls_allowedtags_all ); + } + + if( ! $yourls_allowedtags ) { + $yourls_allowedtags = yourls_kses_allowed_tags(); + $yourls_allowedtags = array_map( '_yourls_add_global_attributes', $yourls_allowedtags ); + $yourls_allowedtags = yourls_apply_filter( 'kses_allowed_tags', $yourls_allowedtags ); + } else { + // User defined: let's sanitize + $yourls_allowedtags = yourls_kses_array_lc( $yourls_allowedtags ); + } + + /**/ } - + /** * Kses global for all allowable HTML tags. * @@ -96,322 +96,322 @@ function yourls_kses_init() { * @return array All tags */ function yourls_kses_allowed_tags_all() { - return array( - 'address' => array(), - 'a' => array( - 'href' => true, - 'rel' => true, - 'rev' => true, - 'name' => true, - 'target' => true, - ), - 'abbr' => array(), - 'acronym' => array(), - 'area' => array( - 'alt' => true, - 'coords' => true, - 'href' => true, - 'nohref' => true, - 'shape' => true, - 'target' => true, - ), - 'article' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'aside' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'b' => array(), - 'big' => array(), - 'blockquote' => array( - 'cite' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'br' => array(), - 'button' => array( - 'disabled' => true, - 'name' => true, - 'type' => true, - 'value' => true, - ), - 'caption' => array( - 'align' => true, - ), - 'cite' => array( - 'dir' => true, - 'lang' => true, - ), - 'code' => array(), - 'col' => array( - 'align' => true, - 'char' => true, - 'charoff' => true, - 'span' => true, - 'dir' => true, - 'valign' => true, - 'width' => true, - ), - 'del' => array( - 'datetime' => true, - ), - 'dd' => array(), - 'details' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'open' => true, - 'xml:lang' => true, - ), - 'div' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'dl' => array(), - 'dt' => array(), - 'em' => array(), - 'fieldset' => array(), - 'figure' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'figcaption' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'font' => array( - 'color' => true, - 'face' => true, - 'size' => true, - ), - 'footer' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'form' => array( - 'action' => true, - 'accept' => true, - 'accept-charset' => true, - 'enctype' => true, - 'method' => true, - 'name' => true, - 'target' => true, - ), - 'h1' => array( - 'align' => true, - ), - 'h2' => array( - 'align' => true, - ), - 'h3' => array( - 'align' => true, - ), - 'h4' => array( - 'align' => true, - ), - 'h5' => array( - 'align' => true, - ), - 'h6' => array( - 'align' => true, - ), - 'header' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'hgroup' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'hr' => array( - 'align' => true, - 'noshade' => true, - 'size' => true, - 'width' => true, - ), - 'i' => array(), - 'img' => array( - 'alt' => true, - 'align' => true, - 'border' => true, - 'height' => true, - 'hspace' => true, - 'longdesc' => true, - 'vspace' => true, - 'src' => true, - 'usemap' => true, - 'width' => true, - ), - 'ins' => array( - 'datetime' => true, - 'cite' => true, - ), - 'kbd' => array(), - 'label' => array( - 'for' => true, - ), - 'legend' => array( - 'align' => true, - ), - 'li' => array( - 'align' => true, - ), - 'map' => array( - 'name' => true, - ), - 'menu' => array( - 'type' => true, - ), - 'nav' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'p' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'pre' => array( - 'width' => true, - ), - 'q' => array( - 'cite' => true, - ), - 's' => array(), - 'span' => array( - 'dir' => true, - 'align' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'section' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'small' => array(), - 'strike' => array(), - 'strong' => array(), - 'sub' => array(), - 'summary' => array( - 'align' => true, - 'dir' => true, - 'lang' => true, - 'xml:lang' => true, - ), - 'sup' => array(), - 'table' => array( - 'align' => true, - 'bgcolor' => true, - 'border' => true, - 'cellpadding' => true, - 'cellspacing' => true, - 'dir' => true, - 'rules' => true, - 'summary' => true, - 'width' => true, - ), - 'tbody' => array( - 'align' => true, - 'char' => true, - 'charoff' => true, - 'valign' => true, - ), - 'td' => array( - 'abbr' => true, - 'align' => true, - 'axis' => true, - 'bgcolor' => true, - 'char' => true, - 'charoff' => true, - 'colspan' => true, - 'dir' => true, - 'headers' => true, - 'height' => true, - 'nowrap' => true, - 'rowspan' => true, - 'scope' => true, - 'valign' => true, - 'width' => true, - ), - 'textarea' => array( - 'cols' => true, - 'rows' => true, - 'disabled' => true, - 'name' => true, - 'readonly' => true, - ), - 'tfoot' => array( - 'align' => true, - 'char' => true, - 'charoff' => true, - 'valign' => true, - ), - 'th' => array( - 'abbr' => true, - 'align' => true, - 'axis' => true, - 'bgcolor' => true, - 'char' => true, - 'charoff' => true, - 'colspan' => true, - 'headers' => true, - 'height' => true, - 'nowrap' => true, - 'rowspan' => true, - 'scope' => true, - 'valign' => true, - 'width' => true, - ), - 'thead' => array( - 'align' => true, - 'char' => true, - 'charoff' => true, - 'valign' => true, - ), - 'title' => array(), - 'tr' => array( - 'align' => true, - 'bgcolor' => true, - 'char' => true, - 'charoff' => true, - 'valign' => true, - ), - 'tt' => array(), - 'u' => array(), - 'ul' => array( - 'type' => true, - ), - 'ol' => array( - 'start' => true, - 'type' => true, - ), - 'var' => array(), - ); + return array( + 'address' => array(), + 'a' => array( + 'href' => true, + 'rel' => true, + 'rev' => true, + 'name' => true, + 'target' => true, + ), + 'abbr' => array(), + 'acronym' => array(), + 'area' => array( + 'alt' => true, + 'coords' => true, + 'href' => true, + 'nohref' => true, + 'shape' => true, + 'target' => true, + ), + 'article' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'aside' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'b' => array(), + 'big' => array(), + 'blockquote' => array( + 'cite' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'br' => array(), + 'button' => array( + 'disabled' => true, + 'name' => true, + 'type' => true, + 'value' => true, + ), + 'caption' => array( + 'align' => true, + ), + 'cite' => array( + 'dir' => true, + 'lang' => true, + ), + 'code' => array(), + 'col' => array( + 'align' => true, + 'char' => true, + 'charoff' => true, + 'span' => true, + 'dir' => true, + 'valign' => true, + 'width' => true, + ), + 'del' => array( + 'datetime' => true, + ), + 'dd' => array(), + 'details' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'open' => true, + 'xml:lang' => true, + ), + 'div' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'dl' => array(), + 'dt' => array(), + 'em' => array(), + 'fieldset' => array(), + 'figure' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'figcaption' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'font' => array( + 'color' => true, + 'face' => true, + 'size' => true, + ), + 'footer' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'form' => array( + 'action' => true, + 'accept' => true, + 'accept-charset' => true, + 'enctype' => true, + 'method' => true, + 'name' => true, + 'target' => true, + ), + 'h1' => array( + 'align' => true, + ), + 'h2' => array( + 'align' => true, + ), + 'h3' => array( + 'align' => true, + ), + 'h4' => array( + 'align' => true, + ), + 'h5' => array( + 'align' => true, + ), + 'h6' => array( + 'align' => true, + ), + 'header' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'hgroup' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'hr' => array( + 'align' => true, + 'noshade' => true, + 'size' => true, + 'width' => true, + ), + 'i' => array(), + 'img' => array( + 'alt' => true, + 'align' => true, + 'border' => true, + 'height' => true, + 'hspace' => true, + 'longdesc' => true, + 'vspace' => true, + 'src' => true, + 'usemap' => true, + 'width' => true, + ), + 'ins' => array( + 'datetime' => true, + 'cite' => true, + ), + 'kbd' => array(), + 'label' => array( + 'for' => true, + ), + 'legend' => array( + 'align' => true, + ), + 'li' => array( + 'align' => true, + ), + 'map' => array( + 'name' => true, + ), + 'menu' => array( + 'type' => true, + ), + 'nav' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'p' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'pre' => array( + 'width' => true, + ), + 'q' => array( + 'cite' => true, + ), + 's' => array(), + 'span' => array( + 'dir' => true, + 'align' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'section' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'small' => array(), + 'strike' => array(), + 'strong' => array(), + 'sub' => array(), + 'summary' => array( + 'align' => true, + 'dir' => true, + 'lang' => true, + 'xml:lang' => true, + ), + 'sup' => array(), + 'table' => array( + 'align' => true, + 'bgcolor' => true, + 'border' => true, + 'cellpadding' => true, + 'cellspacing' => true, + 'dir' => true, + 'rules' => true, + 'summary' => true, + 'width' => true, + ), + 'tbody' => array( + 'align' => true, + 'char' => true, + 'charoff' => true, + 'valign' => true, + ), + 'td' => array( + 'abbr' => true, + 'align' => true, + 'axis' => true, + 'bgcolor' => true, + 'char' => true, + 'charoff' => true, + 'colspan' => true, + 'dir' => true, + 'headers' => true, + 'height' => true, + 'nowrap' => true, + 'rowspan' => true, + 'scope' => true, + 'valign' => true, + 'width' => true, + ), + 'textarea' => array( + 'cols' => true, + 'rows' => true, + 'disabled' => true, + 'name' => true, + 'readonly' => true, + ), + 'tfoot' => array( + 'align' => true, + 'char' => true, + 'charoff' => true, + 'valign' => true, + ), + 'th' => array( + 'abbr' => true, + 'align' => true, + 'axis' => true, + 'bgcolor' => true, + 'char' => true, + 'charoff' => true, + 'colspan' => true, + 'headers' => true, + 'height' => true, + 'nowrap' => true, + 'rowspan' => true, + 'scope' => true, + 'valign' => true, + 'width' => true, + ), + 'thead' => array( + 'align' => true, + 'char' => true, + 'charoff' => true, + 'valign' => true, + ), + 'title' => array(), + 'tr' => array( + 'align' => true, + 'bgcolor' => true, + 'char' => true, + 'charoff' => true, + 'valign' => true, + ), + 'tt' => array(), + 'u' => array(), + 'ul' => array( + 'type' => true, + ), + 'ol' => array( + 'start' => true, + 'type' => true, + ), + 'var' => array(), + ); } - + /** * Kses global for default allowable HTML tags. TODO: trim down to necessary only. * @@ -422,34 +422,34 @@ function yourls_kses_allowed_tags_all() { * @return array Allowed tags */ function yourls_kses_allowed_tags() { - return array( - 'a' => array( - 'href' => true, - 'title' => true, - ), - 'abbr' => array( - 'title' => true, - ), - 'acronym' => array( - 'title' => true, - ), - 'b' => array(), - 'blockquote' => array( - 'cite' => true, - ), - 'cite' => array(), - 'code' => array(), - 'del' => array( - 'datetime' => true, - ), - 'em' => array(), - 'i' => array(), - 'q' => array( - 'cite' => true, - ), - 'strike' => array(), - 'strong' => array(), - ); + return array( + 'a' => array( + 'href' => true, + 'title' => true, + ), + 'abbr' => array( + 'title' => true, + ), + 'acronym' => array( + 'title' => true, + ), + 'b' => array(), + 'blockquote' => array( + 'cite' => true, + ), + 'cite' => array(), + 'code' => array(), + 'del' => array( + 'datetime' => true, + ), + 'em' => array(), + 'i' => array(), + 'q' => array( + 'cite' => true, + ), + 'strike' => array(), + 'strong' => array(), + ); } /** @@ -460,49 +460,49 @@ function yourls_kses_allowed_tags() { * @return array Allowed entities */ function yourls_kses_allowed_entities() { - return array( - 'nbsp', 'iexcl', 'cent', 'pound', 'curren', 'yen', - 'brvbar', 'sect', 'uml', 'copy', 'ordf', 'laquo', - 'not', 'shy', 'reg', 'macr', 'deg', 'plusmn', - 'acute', 'micro', 'para', 'middot', 'cedil', 'ordm', - 'raquo', 'iquest', 'Agrave', 'Aacute', 'Acirc', 'Atilde', - 'Auml', 'Aring', 'AElig', 'Ccedil', 'Egrave', 'Eacute', - 'Ecirc', 'Euml', 'Igrave', 'Iacute', 'Icirc', 'Iuml', - 'ETH', 'Ntilde', 'Ograve', 'Oacute', 'Ocirc', 'Otilde', - 'Ouml', 'times', 'Oslash', 'Ugrave', 'Uacute', 'Ucirc', - 'Uuml', 'Yacute', 'THORN', 'szlig', 'agrave', 'aacute', - 'acirc', 'atilde', 'auml', 'aring', 'aelig', 'ccedil', - 'egrave', 'eacute', 'ecirc', 'euml', 'igrave', 'iacute', - 'icirc', 'iuml', 'eth', 'ntilde', 'ograve', 'oacute', - 'ocirc', 'otilde', 'ouml', 'divide', 'oslash', 'ugrave', - 'uacute', 'ucirc', 'uuml', 'yacute', 'thorn', 'yuml', - 'quot', 'amp', 'lt', 'gt', 'apos', 'OElig', - 'oelig', 'Scaron', 'scaron', 'Yuml', 'circ', 'tilde', - 'ensp', 'emsp', 'thinsp', 'zwnj', 'zwj', 'lrm', - 'rlm', 'ndash', 'mdash', 'lsquo', 'rsquo', 'sbquo', - 'ldquo', 'rdquo', 'bdquo', 'dagger', 'Dagger', 'permil', - 'lsaquo', 'rsaquo', 'euro', 'fnof', 'Alpha', 'Beta', - 'Gamma', 'Delta', 'Epsilon', 'Zeta', 'Eta', 'Theta', - 'Iota', 'Kappa', 'Lambda', 'Mu', 'Nu', 'Xi', - 'Omicron', 'Pi', 'Rho', 'Sigma', 'Tau', 'Upsilon', - 'Phi', 'Chi', 'Psi', 'Omega', 'alpha', 'beta', - 'gamma', 'delta', 'epsilon', 'zeta', 'eta', 'theta', - 'iota', 'kappa', 'lambda', 'mu', 'nu', 'xi', - 'omicron', 'pi', 'rho', 'sigmaf', 'sigma', 'tau', - 'upsilon', 'phi', 'chi', 'psi', 'omega', 'thetasym', - 'upsih', 'piv', 'bull', 'hellip', 'prime', 'Prime', - 'oline', 'frasl', 'weierp', 'image', 'real', 'trade', - 'alefsym', 'larr', 'uarr', 'rarr', 'darr', 'harr', - 'crarr', 'lArr', 'uArr', 'rArr', 'dArr', 'hArr', - 'forall', 'part', 'exist', 'empty', 'nabla', 'isin', - 'notin', 'ni', 'prod', 'sum', 'minus', 'lowast', - 'radic', 'prop', 'infin', 'ang', 'and', 'or', - 'cap', 'cup', 'int', 'sim', 'cong', 'asymp', - 'ne', 'equiv', 'le', 'ge', 'sub', 'sup', - 'nsub', 'sube', 'supe', 'oplus', 'otimes', 'perp', - 'sdot', 'lceil', 'rceil', 'lfloor', 'rfloor', 'lang', - 'rang', 'loz', 'spades', 'clubs', 'hearts', 'diams', - ); + return array( + 'nbsp', 'iexcl', 'cent', 'pound', 'curren', 'yen', + 'brvbar', 'sect', 'uml', 'copy', 'ordf', 'laquo', + 'not', 'shy', 'reg', 'macr', 'deg', 'plusmn', + 'acute', 'micro', 'para', 'middot', 'cedil', 'ordm', + 'raquo', 'iquest', 'Agrave', 'Aacute', 'Acirc', 'Atilde', + 'Auml', 'Aring', 'AElig', 'Ccedil', 'Egrave', 'Eacute', + 'Ecirc', 'Euml', 'Igrave', 'Iacute', 'Icirc', 'Iuml', + 'ETH', 'Ntilde', 'Ograve', 'Oacute', 'Ocirc', 'Otilde', + 'Ouml', 'times', 'Oslash', 'Ugrave', 'Uacute', 'Ucirc', + 'Uuml', 'Yacute', 'THORN', 'szlig', 'agrave', 'aacute', + 'acirc', 'atilde', 'auml', 'aring', 'aelig', 'ccedil', + 'egrave', 'eacute', 'ecirc', 'euml', 'igrave', 'iacute', + 'icirc', 'iuml', 'eth', 'ntilde', 'ograve', 'oacute', + 'ocirc', 'otilde', 'ouml', 'divide', 'oslash', 'ugrave', + 'uacute', 'ucirc', 'uuml', 'yacute', 'thorn', 'yuml', + 'quot', 'amp', 'lt', 'gt', 'apos', 'OElig', + 'oelig', 'Scaron', 'scaron', 'Yuml', 'circ', 'tilde', + 'ensp', 'emsp', 'thinsp', 'zwnj', 'zwj', 'lrm', + 'rlm', 'ndash', 'mdash', 'lsquo', 'rsquo', 'sbquo', + 'ldquo', 'rdquo', 'bdquo', 'dagger', 'Dagger', 'permil', + 'lsaquo', 'rsaquo', 'euro', 'fnof', 'Alpha', 'Beta', + 'Gamma', 'Delta', 'Epsilon', 'Zeta', 'Eta', 'Theta', + 'Iota', 'Kappa', 'Lambda', 'Mu', 'Nu', 'Xi', + 'Omicron', 'Pi', 'Rho', 'Sigma', 'Tau', 'Upsilon', + 'Phi', 'Chi', 'Psi', 'Omega', 'alpha', 'beta', + 'gamma', 'delta', 'epsilon', 'zeta', 'eta', 'theta', + 'iota', 'kappa', 'lambda', 'mu', 'nu', 'xi', + 'omicron', 'pi', 'rho', 'sigmaf', 'sigma', 'tau', + 'upsilon', 'phi', 'chi', 'psi', 'omega', 'thetasym', + 'upsih', 'piv', 'bull', 'hellip', 'prime', 'Prime', + 'oline', 'frasl', 'weierp', 'image', 'real', 'trade', + 'alefsym', 'larr', 'uarr', 'rarr', 'darr', 'harr', + 'crarr', 'lArr', 'uArr', 'rArr', 'dArr', 'hArr', + 'forall', 'part', 'exist', 'empty', 'nabla', 'isin', + 'notin', 'ni', 'prod', 'sum', 'minus', 'lowast', + 'radic', 'prop', 'infin', 'ang', 'and', 'or', + 'cap', 'cup', 'int', 'sim', 'cong', 'asymp', + 'ne', 'equiv', 'le', 'ge', 'sub', 'sup', + 'nsub', 'sube', 'supe', 'oplus', 'otimes', 'perp', + 'sdot', 'lceil', 'rceil', 'lfloor', 'rfloor', 'lang', + 'rang', 'loz', 'spades', 'clubs', 'hearts', 'diams', + ); } /** @@ -513,51 +513,51 @@ function yourls_kses_allowed_entities() { * @return array Allowed protocols */ function yourls_kses_allowed_protocols() { - // More or less common stuff in links. From http://en.wikipedia.org/wiki/URI_scheme - return array( - // Common - 'http://', 'https://', 'ftp://', - 'file://', 'smb://', - 'sftp://', - 'feed:', 'feed://', - 'mailto:', - 'news:', 'nntp://', - - // Old school bearded geek - 'gopher://', 'telnet://', 'finger://', - 'nntp://', 'worldwind://', - - // Dev - 'ssh://', 'svn://', 'svn+ssh://', 'git://', 'cvs://', - 'apt:', - 'market://', // Google Play - 'view-source:', - - // P2P - 'ed2k://', 'magnet:', 'udp://', - - // Streaming stuff - 'mms://', 'lastfm://', 'spotify:', 'rtsp://', - - // Text & voice - 'aim:', 'facetime://', 'gtalk:', 'xmpp:', - 'irc://', 'ircs://', 'mumble://', - 'callto:', 'skype:', 'sip:', - 'teamspeak://', 'tel:', 'ventrilo://', 'xfire:', - 'ymsgr:', 'tg://', 'whatsapp://', - - // Misc - 'steam:', 'steam://', - 'bitcoin:', - 'ldap://', 'ldaps://', - - // Purposedly removed for security - /* - 'about:', 'chrome://', 'chrome-extension://', - 'javascript:', - 'data:', - */ - ); + // More or less common stuff in links. From http://en.wikipedia.org/wiki/URI_scheme + return array( + // Common + 'http://', 'https://', 'ftp://', + 'file://', 'smb://', + 'sftp://', + 'feed:', 'feed://', + 'mailto:', + 'news:', 'nntp://', + + // Old school bearded geek + 'gopher://', 'telnet://', 'finger://', + 'nntp://', 'worldwind://', + + // Dev + 'ssh://', 'svn://', 'svn+ssh://', 'git://', 'cvs://', + 'apt:', + 'market://', // Google Play + 'view-source:', + + // P2P + 'ed2k://', 'magnet:', 'udp://', + + // Streaming stuff + 'mms://', 'lastfm://', 'spotify:', 'rtsp://', + + // Text & voice + 'aim:', 'facetime://', 'gtalk:', 'xmpp:', + 'irc://', 'ircs://', 'mumble://', + 'callto:', 'skype:', 'sip:', + 'teamspeak://', 'tel:', 'ventrilo://', 'xfire:', + 'ymsgr:', 'tg://', 'whatsapp://', + + // Misc + 'steam:', 'steam://', + 'bitcoin:', + 'ldap://', 'ldaps://', + + // Purposedly removed for security + /* + 'about:', 'chrome://', 'chrome-extension://', + 'javascript:', + 'data:', + */ + ); } @@ -573,17 +573,17 @@ function yourls_kses_allowed_protocols() { * @return string Content with normalized entities */ function yourls_kses_normalize_entities($string) { - # Disarm all entities by converting & to & + # Disarm all entities by converting & to & - $string = str_replace('&', '&', $string); + $string = str_replace('&', '&', $string); - # Change back the allowed entities in our entity whitelist + # Change back the allowed entities in our entity whitelist - $string = preg_replace_callback('/&([A-Za-z]{2,8});/', 'yourls_kses_named_entities', $string); - $string = preg_replace_callback('/&#(0*[0-9]{1,7});/', 'yourls_kses_normalize_entities2', $string); - $string = preg_replace_callback('/&#[Xx](0*[0-9A-Fa-f]{1,6});/', 'yourls_kses_normalize_entities3', $string); + $string = preg_replace_callback('/&([A-Za-z]{2,8});/', 'yourls_kses_named_entities', $string); + $string = preg_replace_callback('/&#(0*[0-9]{1,7});/', 'yourls_kses_normalize_entities2', $string); + $string = preg_replace_callback('/&#[Xx](0*[0-9A-Fa-f]{1,6});/', 'yourls_kses_normalize_entities3', $string); - return $string; + return $string; } /** @@ -598,13 +598,13 @@ function yourls_kses_normalize_entities($string) { * @return string Correctly encoded entity */ function yourls_kses_named_entities($matches) { - global $yourls_allowedentitynames; + global $yourls_allowedentitynames; - if ( empty($matches[1]) ) - return ''; + if ( empty($matches[1]) ) + return ''; - $i = $matches[1]; - return ( ( ! in_array($i, $yourls_allowedentitynames) ) ? "&$i;" : "&$i;" ); + $i = $matches[1]; + return ( ( ! in_array($i, $yourls_allowedentitynames) ) ? "&$i;" : "&$i;" ); } /** @@ -620,18 +620,18 @@ function yourls_kses_named_entities($matches) { * @return string Correctly encoded entity */ function yourls_kses_normalize_entities2($matches) { - if ( empty($matches[1]) ) - return ''; - - $i = $matches[1]; - if (yourls_valid_unicode($i)) { - $i = str_pad(ltrim($i,'0'), 3, '0', STR_PAD_LEFT); - $i = "&#$i;"; - } else { - $i = "&#$i;"; - } - - return $i; + if ( empty($matches[1]) ) + return ''; + + $i = $matches[1]; + if (yourls_valid_unicode($i)) { + $i = str_pad(ltrim($i,'0'), 3, '0', STR_PAD_LEFT); + $i = "&#$i;"; + } else { + $i = "&#$i;"; + } + + return $i; } /** @@ -647,11 +647,11 @@ function yourls_kses_normalize_entities2($matches) { * @return string Correctly encoded entity */ function yourls_kses_normalize_entities3($matches) { - if ( empty($matches[1]) ) - return ''; + if ( empty($matches[1]) ) + return ''; - $hexchars = $matches[1]; - return ( ( ! yourls_valid_unicode(hexdec($hexchars)) ) ? "&#x$hexchars;" : '&#x'.ltrim($hexchars,'0').';' ); + $hexchars = $matches[1]; + return ( ( ! yourls_valid_unicode(hexdec($hexchars)) ) ? "&#x$hexchars;" : '&#x'.ltrim($hexchars,'0').';' ); } /** @@ -664,20 +664,20 @@ function yourls_kses_normalize_entities3($matches) { * @return array The array of attributes with global attributes added. */ function _yourls_add_global_attributes( $value ) { - $global_attributes = array( - 'class' => true, - 'id' => true, - 'style' => true, - 'title' => true, - ); + $global_attributes = array( + 'class' => true, + 'id' => true, + 'style' => true, + 'title' => true, + ); - if ( true === $value ) - $value = array(); + if ( true === $value ) + $value = array(); - if ( is_array( $value ) ) - return array_merge( $value, $global_attributes ); + if ( is_array( $value ) ) + return array_merge( $value, $global_attributes ); - return $value; + return $value; } /** @@ -689,10 +689,10 @@ function _yourls_add_global_attributes( $value ) { * @return bool True if the value was a valid Unicode number */ function yourls_valid_unicode($i) { - return ( $i == 0x9 || $i == 0xa || $i == 0xd || - ($i >= 0x20 && $i <= 0xd7ff) || - ($i >= 0xe000 && $i <= 0xfffd) || - ($i >= 0x10000 && $i <= 0x10ffff) ); + return ( $i == 0x9 || $i == 0xa || $i == 0xd || + ($i >= 0x20 && $i <= 0xd7ff) || + ($i >= 0xe000 && $i <= 0xfffd) || + ($i >= 0x10000 && $i <= 0x10ffff) ); } /** @@ -704,19 +704,19 @@ function yourls_valid_unicode($i) { * @return array Fixed array with all lowercase keys */ function yourls_kses_array_lc($inarray) { - $outarray = array (); + $outarray = array (); - foreach ( (array) $inarray as $inkey => $inval) { - $outkey = strtolower($inkey); - $outarray[$outkey] = array (); + foreach ( (array) $inarray as $inkey => $inval) { + $outkey = strtolower($inkey); + $outarray[$outkey] = array (); - foreach ( (array) $inval as $inkey2 => $inval2) { - $outkey2 = strtolower($inkey2); - $outarray[$outkey][$outkey2] = $inval2; - } # foreach $inval - } # foreach $inarray + foreach ( (array) $inval as $inkey2 => $inval2) { + $outkey2 = strtolower($inkey2); + $outarray[$outkey][$outkey2] = $inval2; + } # foreach $inval + } # foreach $inarray - return $outarray; + return $outarray; } /** @@ -732,10 +732,10 @@ function yourls_kses_array_lc($inarray) { * @return string Content after decoded entities */ function yourls_kses_decode_entities($string) { - $string = preg_replace_callback('/&#([0-9]+);/', '_yourls_kses_decode_entities_chr', $string); - $string = preg_replace_callback('/&#[Xx]([0-9A-Fa-f]+);/', '_yourls_kses_decode_entities_chr_hexdec', $string); + $string = preg_replace_callback('/&#([0-9]+);/', '_yourls_kses_decode_entities_chr', $string); + $string = preg_replace_callback('/&#[Xx]([0-9A-Fa-f]+);/', '_yourls_kses_decode_entities_chr_hexdec', $string); - return $string; + return $string; } /** @@ -747,7 +747,7 @@ function yourls_kses_decode_entities($string) { * @return string */ function _yourls_kses_decode_entities_chr( $match ) { - return chr( $match[1] ); + return chr( $match[1] ); } /** @@ -759,7 +759,7 @@ function _yourls_kses_decode_entities_chr( $match ) { * @return string */ function _yourls_kses_decode_entities_chr_hexdec( $match ) { - return chr( hexdec( $match[1] ) ); + return chr( hexdec( $match[1] ) ); } /** @@ -771,8 +771,8 @@ function _yourls_kses_decode_entities_chr_hexdec( $match ) { * @return string */ function yourls_kses_no_null($string) { - $string = preg_replace( '/\0+/', '', $string ); - $string = preg_replace( '/(\\\\0)+/', '', $string ); + $string = preg_replace( '/\0+/', '', $string ); + $string = preg_replace( '/(\\\\0)+/', '', $string ); - return $string; + return $string; } diff --git a/includes/functions-l10n.php b/includes/functions-l10n.php index ead4c3c71..377a775a3 100644 --- a/includes/functions-l10n.php +++ b/includes/functions-l10n.php @@ -12,7 +12,7 @@ /** * Load POMO files required to run library */ -use \POMO\MO; +use POMO\MO; use POMO\Translations\NOOPTranslations; /** @@ -29,24 +29,22 @@ * always be filtered using the 'get_locale' hook. * * @since 1.6 - * @uses yourls_apply_filter() Calls 'get_locale' hook on locale value. - * @uses $yourls_locale Gets the locale stored in the global. * - * @return string The locale of the blog or from the 'get_locale' hook. + * @return string The locale of the YOURLS instance */ function yourls_get_locale() { - global $yourls_locale; + global $yourls_locale; - if ( !isset( $yourls_locale ) ) { - // YOURLS_LANG is defined in config. - if ( defined( 'YOURLS_LANG' ) ) - $yourls_locale = YOURLS_LANG; - } + if ( !isset( $yourls_locale ) ) { + // YOURLS_LANG is defined in config. + if ( defined( 'YOURLS_LANG' ) ) + $yourls_locale = YOURLS_LANG; + } if ( !$yourls_locale ) $yourls_locale = ''; - return yourls_apply_filter( 'get_locale', $yourls_locale ); + return yourls_apply_filter( 'get_locale', $yourls_locale ); } /** @@ -55,16 +53,14 @@ function yourls_get_locale() { * * @see yourls__() Don't use yourls_translate() directly, use yourls__() * @since 1.6 - * @uses yourls_apply_filter() Calls 'translate' on domain translated text - * with the untranslated text as second parameter. * * @param string $text Text to translate. * @param string $domain Domain to retrieve the translated text. * @return string Translated text */ function yourls_translate( $text, $domain = 'default' ) { - $translations = yourls_get_translations_for_domain( $domain ); - return yourls_apply_filter( 'translate', $translations->translate( $text ), $text, $domain ); + $translations = yourls_get_translations_for_domain( $domain ); + return yourls_apply_filter( 'translate', $translations->translate( $text ), $text, $domain ); } /** @@ -84,8 +80,8 @@ function yourls_translate( $text, $domain = 'default' ) { * @return string Translated text */ function yourls_translate_with_context( $text, $context, $domain = 'default' ) { - $translations = yourls_get_translations_for_domain( $domain ); - return yourls_apply_filter( 'translate_with_context', $translations->translate( $text, $context ), $text, $context, $domain ); + $translations = yourls_get_translations_for_domain( $domain ); + return yourls_apply_filter( 'translate_with_context', $translations->translate( $text, $context ), $text, $context, $domain ); } /** @@ -100,7 +96,7 @@ function yourls_translate_with_context( $text, $context, $domain = 'default' ) { * @return string Translated text */ function yourls__( $text, $domain = 'default' ) { - return yourls_translate( $text, $domain ); + return yourls_translate( $text, $domain ); } /** @@ -116,32 +112,31 @@ function yourls__( $text, $domain = 'default' ) { * @see sprintf() * @since 1.6 * - * @param string $pattern Text to translate - * @param string $arg1, $arg2... Optional: sprintf tokens, and translation domain + * @param mixed ...$pattern Text to translate, then $arg1: optional sprintf tokens, and $arg2: translation domain * @return string Translated text */ function yourls_s( $pattern ) { - // Get pattern and pattern arguments - $args = func_get_args(); - // If yourls_s() called by yourls_se(), all arguments are wrapped in the same array key - if( count( $args ) == 1 && is_array( $args[0] ) ) { - $args = $args[0]; - } - $pattern = $args[0]; - - // get list of sprintf tokens (%s and such) - $num_of_tokens = substr_count( $pattern, '%' ) - 2 * substr_count( $pattern, '%%' ); - - $domain = 'default'; - // More arguments passed than needed for the sprintf? The last one will be the domain - if( $num_of_tokens < ( count( $args ) - 1 ) ) { - $domain = array_pop( $args ); - } - - // Translate text - $args[0] = yourls__( $pattern, $domain ); - - return call_user_func_array( 'sprintf', $args ); + // Get pattern and pattern arguments + $args = func_get_args(); + // If yourls_s() called by yourls_se(), all arguments are wrapped in the same array key + if( count( $args ) == 1 && is_array( $args[0] ) ) { + $args = $args[0]; + } + $pattern = $args[0]; + + // get list of sprintf tokens (%s and such) + $num_of_tokens = substr_count( $pattern, '%' ) - 2 * substr_count( $pattern, '%%' ); + + $domain = 'default'; + // More arguments passed than needed for the sprintf? The last one will be the domain + if( $num_of_tokens < ( count( $args ) - 1 ) ) { + $domain = array_pop( $args ); + } + + // Translate text + $args[0] = yourls__( $pattern, $domain ); + + return call_user_func_array( 'sprintf', $args ); } /** @@ -158,12 +153,11 @@ function yourls_s( $pattern ) { * @see sprintf() * @since 1.6 * - * @param string $pattern Text to translate - * @param string $arg1, $arg2... Optional: sprintf tokens, and translation domain - * @return string Translated text + * @param string ...$pattern Text to translate, then optional sprintf tokens, and optional translation domain + * @return void Translated text */ function yourls_se( $pattern ) { - echo yourls_s( func_get_args() ); + echo yourls_s( func_get_args() ); } @@ -180,7 +174,7 @@ function yourls_se( $pattern ) { * @return string Translated text */ function yourls_esc_attr__( $text, $domain = 'default' ) { - return yourls_esc_attr( yourls_translate( $text, $domain ) ); + return yourls_esc_attr( yourls_translate( $text, $domain ) ); } /** @@ -196,7 +190,7 @@ function yourls_esc_attr__( $text, $domain = 'default' ) { * @return string Translated text */ function yourls_esc_html__( $text, $domain = 'default' ) { - return yourls_esc_html( yourls_translate( $text, $domain ) ); + return yourls_esc_html( yourls_translate( $text, $domain ) ); } /** @@ -207,9 +201,10 @@ function yourls_esc_html__( $text, $domain = 'default' ) { * * @param string $text Text to translate * @param string $domain Optional. Domain to retrieve the translated text + * @return void */ function yourls_e( $text, $domain = 'default' ) { - echo yourls_translate( $text, $domain ); + echo yourls_translate( $text, $domain ); } /** @@ -221,9 +216,10 @@ function yourls_e( $text, $domain = 'default' ) { * * @param string $text Text to translate * @param string $domain Optional. Domain to retrieve the translated text + * @return void */ function yourls_esc_attr_e( $text, $domain = 'default' ) { - echo yourls_esc_attr( yourls_translate( $text, $domain ) ); + echo yourls_esc_attr( yourls_translate( $text, $domain ) ); } /** @@ -235,9 +231,10 @@ function yourls_esc_attr_e( $text, $domain = 'default' ) { * * @param string $text Text to translate * @param string $domain Optional. Domain to retrieve the translated text + * @return void */ function yourls_esc_html_e( $text, $domain = 'default' ) { - echo yourls_esc_html( yourls_translate( $text, $domain ) ); + echo yourls_esc_html( yourls_translate( $text, $domain ) ); } /** @@ -257,7 +254,7 @@ function yourls_esc_html_e( $text, $domain = 'default' ) { * @return string Translated context string */ function yourls_x( $text, $context, $domain = 'default' ) { - return yourls_translate_with_context( $text, $context, $domain ); + return yourls_translate_with_context( $text, $context, $domain ); } /** @@ -269,10 +266,10 @@ function yourls_x( $text, $context, $domain = 'default' ) { * @param string $text Text to translate * @param string $context Context information for the translators * @param string $domain Optional. Domain to retrieve the translated text - * @return string Translated context string + * @return void Echoes translated context string */ function yourls_xe( $text, $context, $domain = 'default' ) { - echo yourls_x( $text, $context, $domain ); + echo yourls_x( $text, $context, $domain ); } @@ -287,11 +284,10 @@ function yourls_xe( $text, $context, $domain = 'default' ) { * @param string $single * @param string $context * @param string $domain Optional. Domain to retrieve the translated text - * @internal param string $text Text to translate * @return string */ function yourls_esc_attr_x( $single, $context, $domain = 'default' ) { - return yourls_esc_attr( yourls_translate_with_context( $single, $context, $domain ) ); + return yourls_esc_attr( yourls_translate_with_context( $single, $context, $domain ) ); } /** @@ -305,11 +301,10 @@ function yourls_esc_attr_x( $single, $context, $domain = 'default' ) { * @param string $single * @param string $context * @param string $domain Optional. Domain to retrieve the translated text - * @internal param string $text Text to translate * @return string */ function yourls_esc_html_x( $single, $context, $domain = 'default' ) { - return yourls_esc_html( yourls_translate_with_context( $single, $context, $domain ) ); + return yourls_esc_html( yourls_translate_with_context( $single, $context, $domain ) ); } /** @@ -324,9 +319,6 @@ function yourls_esc_html_x( $single, $context, $domain = 'default' ) { * type will be a string. * * @since 1.6 - * @uses $yourls_l10n Gets list of domain translated string (gettext_reader) objects - * @uses yourls_apply_filter() Calls 'translate_n' hook on domains text returned, - * along with $single, $plural, and $number parameters. Expected to return string. * * @param string $single The text that will be used if $number is 1 * @param string $plural The text that will be used if $number is not 1 @@ -335,9 +327,9 @@ function yourls_esc_html_x( $single, $context, $domain = 'default' ) { * @return string Either $single or $plural translated text */ function yourls_n( $single, $plural, $number, $domain = 'default' ) { - $translations = yourls_get_translations_for_domain( $domain ); - $translation = $translations->translate_plural( $single, $plural, $number ); - return yourls_apply_filter( 'translate_n', $translation, $single, $plural, $number, $domain ); + $translations = yourls_get_translations_for_domain( $domain ); + $translation = $translations->translate_plural( $single, $plural, $number ); + return yourls_apply_filter( 'translate_n', $translation, $single, $plural, $number, $domain ); } /** @@ -347,11 +339,17 @@ function yourls_n( $single, $plural, $number, $domain = 'default' ) { * @see yourls_n() * @see yourls_x() * + * @param string $single The text that will be used if $number is 1 + * @param string $plural The text that will be used if $number is not 1 + * @param int $number The number to compare against to use either $single or $plural + * @param string $context Context information for the translators + * @param string $domain Optional. The domain identifier the text should be retrieved in + * @return string Either $single or $plural translated text */ function yourls_nx($single, $plural, $number, $context, $domain = 'default') { - $translations = yourls_get_translations_for_domain( $domain ); - $translation = $translations->translate_plural( $single, $plural, $number, $context ); - return yourls_apply_filter( 'translate_nx', $translation, $single, $plural, $number, $context, $domain ); + $translations = yourls_get_translations_for_domain( $domain ); + $translation = $translations->translate_plural( $single, $plural, $number, $context ); + return yourls_apply_filter( 'translate_nx', $translation, $single, $plural, $number, $context, $domain ); } /** @@ -362,8 +360,8 @@ function yourls_nx($single, $plural, $number, $context, $domain = 'default') { * * Example: * $messages = array( - * 'post' => yourls_n_noop('%s post', '%s posts'), - * 'page' => yourls_n_noop('%s pages', '%s pages') + * 'post' => yourls_n_noop('%s post', '%s posts'), + * 'page' => yourls_n_noop('%s pages', '%s pages') * ); * ... * $message = $messages[$type]; @@ -376,14 +374,14 @@ function yourls_nx($single, $plural, $number, $context, $domain = 'default') { * @return array array($singular, $plural) */ function yourls_n_noop( $singular, $plural, $domain = null ) { - return array( - 0 => $singular, - 1 => $plural, - 'singular' => $singular, - 'plural' => $plural, - 'context' => null, - 'domain' => $domain - ); + return array( + 0 => $singular, + 1 => $plural, + 'singular' => $singular, + 'plural' => $plural, + 'context' => null, + 'domain' => $domain + ); } /** @@ -391,17 +389,23 @@ function yourls_n_noop( $singular, $plural, $domain = null ) { * * @since 1.6 * @see yourls_n_noop() + * + * @param string $singular Single form to be i18ned + * @param string $plural Plural form to be i18ned + * @param string $context Context information for the translators + * @param string $domain Optional. The domain identifier the text will be retrieved in + * @return array array($singular, $plural) */ function yourls_nx_noop( $singular, $plural, $context, $domain = null ) { - return array( - 0 => $singular, - 1 => $plural, - 2 => $context, - 'singular' => $singular, - 'plural' => $plural, - 'context' => $context, - 'domain' => $domain - ); + return array( + 0 => $singular, + 1 => $plural, + 2 => $context, + 'singular' => $singular, + 'plural' => $plural, + 'context' => $context, + 'domain' => $domain + ); } /** @@ -411,17 +415,17 @@ function yourls_nx_noop( $singular, $plural, $context, $domain = null ) { * @param array $nooped_plural Array with singular, plural and context keys, usually the result of yourls_n_noop() or yourls_nx_noop() * @param int $count Number of objects * @param string $domain Optional. The domain identifier the text should be retrieved in. If $nooped_plural contains - * a domain passed to yourls_n_noop() or yourls_nx_noop(), it will override this value. + * a domain passed to yourls_n_noop() or yourls_nx_noop(), it will override this value. * @return string */ function yourls_translate_nooped_plural( $nooped_plural, $count, $domain = 'default' ) { - if ( $nooped_plural['domain'] ) - $domain = $nooped_plural['domain']; + if ( $nooped_plural['domain'] ) + $domain = $nooped_plural['domain']; - if ( $nooped_plural['context'] ) - return yourls_nx( $nooped_plural['singular'], $nooped_plural['plural'], $count, $nooped_plural['context'], $domain ); - else - return yourls_n( $nooped_plural['singular'], $nooped_plural['plural'], $count, $domain ); + if ( $nooped_plural['context'] ) + return yourls_nx( $nooped_plural['singular'], $nooped_plural['plural'], $count, $nooped_plural['context'], $domain ); + else + return yourls_n( $nooped_plural['singular'], $nooped_plural['plural'], $count, $domain ); } /** @@ -434,41 +438,40 @@ function yourls_translate_nooped_plural( $nooped_plural, $count, $domain = 'defa * and will be a MO object. * * @since 1.6 - * @uses $yourls_l10n Gets list of domain translated string objects * * @param string $domain Unique identifier for retrieving translated strings * @param string $mofile Path to the .mo file * @return bool True on success, false on failure */ function yourls_load_textdomain( $domain, $mofile ) { - global $yourls_l10n; + global $yourls_l10n; - $plugin_override = yourls_apply_filter( 'override_load_textdomain', false, $domain, $mofile ); + $plugin_override = yourls_apply_filter( 'override_load_textdomain', false, $domain, $mofile ); - if ( true == $plugin_override ) { - return true; - } + if ( true == $plugin_override ) { + return true; + } - yourls_do_action( 'load_textdomain', $domain, $mofile ); + yourls_do_action( 'load_textdomain', $domain, $mofile ); - $mofile = yourls_apply_filter( 'load_textdomain_mofile', $mofile, $domain ); + $mofile = yourls_apply_filter( 'load_textdomain_mofile', $mofile, $domain ); - if ( !is_readable( $mofile ) ) { + if ( !is_readable( $mofile ) ) { trigger_error( 'Cannot read file ' . str_replace( YOURLS_ABSPATH.'/', '', $mofile ) . '.' . ' Make sure there is a language file installed. More info: http://yourls.org/translations' ); return false; } - $mo = new MO(); - if ( !$mo->import_from_file( $mofile ) ) + $mo = new MO(); + if ( !$mo->import_from_file( $mofile ) ) return false; - if ( isset( $yourls_l10n[$domain] ) ) - $mo->merge_with( $yourls_l10n[$domain] ); + if ( isset( $yourls_l10n[$domain] ) ) + $mo->merge_with( $yourls_l10n[$domain] ); - $yourls_l10n[$domain] = &$mo; + $yourls_l10n[$domain] = &$mo; - return true; + return true; } /** @@ -479,21 +482,21 @@ function yourls_load_textdomain( $domain, $mofile ) { * @return bool Whether textdomain was unloaded */ function yourls_unload_textdomain( $domain ) { - global $yourls_l10n; + global $yourls_l10n; - $plugin_override = yourls_apply_filter( 'override_unload_textdomain', false, $domain ); + $plugin_override = yourls_apply_filter( 'override_unload_textdomain', false, $domain ); - if ( $plugin_override ) - return true; + if ( $plugin_override ) + return true; - yourls_do_action( 'unload_textdomain', $domain ); + yourls_do_action( 'unload_textdomain', $domain ); - if ( isset( $yourls_l10n[$domain] ) ) { - unset( $yourls_l10n[$domain] ); - return true; - } + if ( isset( $yourls_l10n[$domain] ) ) { + unset( $yourls_l10n[$domain] ); + return true; + } - return false; + return false; } /** @@ -506,10 +509,12 @@ function yourls_unload_textdomain( $domain ) { * @return bool True on success, false on failure */ function yourls_load_default_textdomain() { - $yourls_locale = yourls_get_locale(); + $yourls_locale = yourls_get_locale(); if( !empty( $yourls_locale ) ) return yourls_load_textdomain( 'default', YOURLS_LANG_DIR . "/$yourls_locale.mo" ); + + return false; } /** @@ -520,11 +525,11 @@ function yourls_load_default_textdomain() { * @return NOOPTranslations An NOOPTranslations translation instance */ function yourls_get_translations_for_domain( $domain ) { - global $yourls_l10n; - if ( !isset( $yourls_l10n[$domain] ) ) { - $yourls_l10n[$domain] = new NOOPTranslations; - } - return $yourls_l10n[$domain]; + global $yourls_l10n; + if ( !isset( $yourls_l10n[$domain] ) ) { + $yourls_l10n[$domain] = new NOOPTranslations; + } + return $yourls_l10n[$domain]; } /** @@ -535,8 +540,8 @@ function yourls_get_translations_for_domain( $domain ) { * @return bool Whether there are translations */ function yourls_is_textdomain_loaded( $domain ) { - global $yourls_l10n; - return isset( $yourls_l10n[$domain] ); + global $yourls_l10n; + return isset( $yourls_l10n[$domain] ); } /** @@ -548,9 +553,11 @@ function yourls_is_textdomain_loaded( $domain ) { * file and this function properly translates them back. * * @since 1.6 + * @param string $name The role name + * @return string Translated role name */ function yourls_translate_user_role( $name ) { - return yourls_translate_with_context( $name, 'User role' ); + return yourls_translate_with_context( $name, 'User role' ); } /** @@ -562,15 +569,15 @@ function yourls_translate_user_role( $name ) { * @return array Array of language codes or an empty array if no languages are present. Language codes are formed by stripping the .mo extension from the language file names. */ function yourls_get_available_languages( $dir = null ) { - $languages = array(); + $languages = array(); - $dir = is_null( $dir) ? YOURLS_LANG_DIR : $dir; + $dir = is_null( $dir) ? YOURLS_LANG_DIR : $dir; - foreach( (array) glob( $dir . '/*.mo' ) as $lang_file ) { - $languages[] = basename( $lang_file, '.mo' ); - } + foreach( (array) glob( $dir . '/*.mo' ) as $lang_file ) { + $languages[] = basename( $lang_file, '.mo' ); + } - return yourls_apply_filter( 'get_available_languages', $languages ); + return yourls_apply_filter( 'get_available_languages', $languages ); } /** @@ -583,12 +590,12 @@ function yourls_get_available_languages( $dir = null ) { * @return string Converted number in string format. */ function yourls_number_format_i18n( $number, $decimals = 0 ) { - global $yourls_locale_formats; - if( !isset( $yourls_locale_formats ) ) - $yourls_locale_formats = new YOURLS_Locale_Formats(); + global $yourls_locale_formats; + if( !isset( $yourls_locale_formats ) ) + $yourls_locale_formats = new YOURLS_Locale_Formats(); - $formatted = number_format( $number, abs( intval( $decimals ) ), $yourls_locale_formats->number_format['decimal_point'], $yourls_locale_formats->number_format['thousands_sep'] ); - return yourls_apply_filter( 'number_format_i18n', $formatted ); + $formatted = number_format( $number, abs( intval( $decimals ) ), $yourls_locale_formats->number_format['decimal_point'], $yourls_locale_formats->number_format['thousands_sep'] ); + return yourls_apply_filter( 'number_format_i18n', $formatted ); } /** @@ -605,46 +612,49 @@ function yourls_number_format_i18n( $number, $decimals = 0 ) { * @return string The date, translated if locale specifies it. */ function yourls_date_i18n( $dateformatstring, $timestamp = false ) { - global $yourls_locale_formats; - if( !isset( $yourls_locale_formats ) ) - $yourls_locale_formats = new YOURLS_Locale_Formats(); - - if ( false === $timestamp ) { + /** + * @var YOURLS_Locale_Formats $yourls_locale_formats + */ + global $yourls_locale_formats; + if( !isset( $yourls_locale_formats ) ) + $yourls_locale_formats = new YOURLS_Locale_Formats(); + + if ( false === $timestamp ) { $timestamp = yourls_get_timestamp( time() ); - } - - // store original value for language with untypical grammars - $req_format = $dateformatstring; - - /** - * Replace the date format characters with their translatation, if found - * Example: - * 'l d F Y' gets replaced with '\L\u\n\d\i d \M\a\i Y' in French - * We deliberately don't deal with 'I', 'O', 'P', 'T', 'Z' and 'e' in date format (timezones) - */ - if ( ( !empty( $yourls_locale_formats->month ) ) && ( !empty( $yourls_locale_formats->weekday ) ) ) { - $datemonth = $yourls_locale_formats->get_month( date( 'm', $timestamp ) ); - $datemonth_abbrev = $yourls_locale_formats->get_month_abbrev( $datemonth ); - $dateweekday = $yourls_locale_formats->get_weekday( date( 'w', $timestamp ) ); - $dateweekday_abbrev = $yourls_locale_formats->get_weekday_abbrev( $dateweekday ); - $datemeridiem = $yourls_locale_formats->get_meridiem( date( 'a', $timestamp ) ); - $datemeridiem_capital = $yourls_locale_formats->get_meridiem( date( 'A', $timestamp ) ); - - $dateformatstring = ' '.$dateformatstring; - $dateformatstring = preg_replace( "/([^\\\])D/", "\\1" . yourls_backslashit( $dateweekday_abbrev ), $dateformatstring ); - $dateformatstring = preg_replace( "/([^\\\])F/", "\\1" . yourls_backslashit( $datemonth ), $dateformatstring ); - $dateformatstring = preg_replace( "/([^\\\])l/", "\\1" . yourls_backslashit( $dateweekday ), $dateformatstring ); - $dateformatstring = preg_replace( "/([^\\\])M/", "\\1" . yourls_backslashit( $datemonth_abbrev ), $dateformatstring ); - $dateformatstring = preg_replace( "/([^\\\])a/", "\\1" . yourls_backslashit( $datemeridiem ), $dateformatstring ); - $dateformatstring = preg_replace( "/([^\\\])A/", "\\1" . yourls_backslashit( $datemeridiem_capital ), $dateformatstring ); - - $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 ); - } - - $date = date( $dateformatstring, $timestamp ); - - // Allow plugins to redo this entirely for languages with untypical grammars - return yourls_apply_filter('date_i18n', $date, $req_format, $timestamp); + } + + // store original value for language with untypical grammars + $req_format = $dateformatstring; + + /** + * Replace the date format characters with their translatation, if found + * Example: + * 'l d F Y' gets replaced with '\L\u\n\d\i d \M\a\i Y' in French + * We deliberately don't deal with 'I', 'O', 'P', 'T', 'Z' and 'e' in date format (timezones) + */ + if ( ( !empty( $yourls_locale_formats->month ) ) && ( !empty( $yourls_locale_formats->weekday ) ) ) { + $datemonth = $yourls_locale_formats->get_month( date( 'm', $timestamp ) ); + $datemonth_abbrev = $yourls_locale_formats->get_month_abbrev( $datemonth ); + $dateweekday = $yourls_locale_formats->get_weekday( date( 'w', $timestamp ) ); + $dateweekday_abbrev = $yourls_locale_formats->get_weekday_abbrev( $dateweekday ); + $datemeridiem = $yourls_locale_formats->get_meridiem( date( 'a', $timestamp ) ); + $datemeridiem_capital = $yourls_locale_formats->get_meridiem( date( 'A', $timestamp ) ); + + $dateformatstring = ' '.$dateformatstring; + $dateformatstring = preg_replace( "/([^\\\])D/", "\\1" . yourls_backslashit( $dateweekday_abbrev ), $dateformatstring ); + $dateformatstring = preg_replace( "/([^\\\])F/", "\\1" . yourls_backslashit( $datemonth ), $dateformatstring ); + $dateformatstring = preg_replace( "/([^\\\])l/", "\\1" . yourls_backslashit( $dateweekday ), $dateformatstring ); + $dateformatstring = preg_replace( "/([^\\\])M/", "\\1" . yourls_backslashit( $datemonth_abbrev ), $dateformatstring ); + $dateformatstring = preg_replace( "/([^\\\])a/", "\\1" . yourls_backslashit( $datemeridiem ), $dateformatstring ); + $dateformatstring = preg_replace( "/([^\\\])A/", "\\1" . yourls_backslashit( $datemeridiem_capital ), $dateformatstring ); + + $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 ); + } + + $date = date( $dateformatstring, $timestamp ); + + // Allow plugins to redo this entirely for languages with untypical grammars + return yourls_apply_filter('date_i18n', $date, $req_format, $timestamp); } /** @@ -653,330 +663,328 @@ function yourls_date_i18n( $dateformatstring, $timestamp = false ) { * @since 1.6 */ class YOURLS_Locale_Formats { - /** - * Stores the translated strings for the full weekday names. - * - * @since 1.6 - * @var array - * @access private - */ - var $weekday; - - /** - * Stores the translated strings for the one character weekday names. - * - * There is a hack to make sure that Tuesday and Thursday, as well - * as Sunday and Saturday, don't conflict. See init() method for more. - * - * @see YOURLS_Locale_Formats::init() for how to handle the hack. - * - * @since 1.6 - * @var array - * @access private - */ - var $weekday_initial; - - /** - * Stores the translated strings for the abbreviated weekday names. - * - * @since 1.6 - * @var array - * @access private - */ - var $weekday_abbrev; - - /** - * Stores the translated strings for the full month names. - * - * @since 1.6 - * @var array - * @access private - */ - var $month; - - /** - * Stores the translated strings for the abbreviated month names. - * - * @since 1.6 - * @var array - * @access private - */ - var $month_abbrev; - - /** - * Stores the translated strings for 'am' and 'pm'. - * - * Also the capitalized versions. - * - * @since 1.6 - * @var array - * @access private - */ - var $meridiem; - - /** - * Stores the translated number format - * - * @since 1.6 - * @var array - * @access private - */ - var $number_format; - - /** - * The text direction of the locale language. - * - * Default is left to right 'ltr'. - * - * @since 1.6 - * @var string - * @access private - */ - var $text_direction = 'ltr'; - - /** - * Sets up the translated strings and object properties. - * - * The method creates the translatable strings for various - * calendar elements. Which allows for specifying locale - * specific calendar names and text direction. - * - * @since 1.6 - * @access private - */ - function init() { - // The Weekdays - $this->weekday[0] = /* //translators: weekday */ yourls__( 'Sunday' ); - $this->weekday[1] = /* //translators: weekday */ yourls__( 'Monday' ); - $this->weekday[2] = /* //translators: weekday */ yourls__( 'Tuesday' ); - $this->weekday[3] = /* //translators: weekday */ yourls__( 'Wednesday' ); - $this->weekday[4] = /* //translators: weekday */ yourls__( 'Thursday' ); - $this->weekday[5] = /* //translators: weekday */ yourls__( 'Friday' ); - $this->weekday[6] = /* //translators: weekday */ yourls__( 'Saturday' ); - - // The first letter of each day. The _%day%_initial suffix is a hack to make - // sure the day initials are unique. - $this->weekday_initial[yourls__( 'Sunday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'S_Sunday_initial' ); - $this->weekday_initial[yourls__( 'Monday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'M_Monday_initial' ); - $this->weekday_initial[yourls__( 'Tuesday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'T_Tuesday_initial' ); - $this->weekday_initial[yourls__( 'Wednesday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'W_Wednesday_initial' ); - $this->weekday_initial[yourls__( 'Thursday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'T_Thursday_initial' ); - $this->weekday_initial[yourls__( 'Friday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'F_Friday_initial' ); - $this->weekday_initial[yourls__( 'Saturday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'S_Saturday_initial' ); - - foreach ($this->weekday_initial as $weekday_ => $weekday_initial_) { - $this->weekday_initial[$weekday_] = preg_replace('/_.+_initial$/', '', $weekday_initial_); - } - - // Abbreviations for each day. - $this->weekday_abbrev[ yourls__( 'Sunday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Sun' ); - $this->weekday_abbrev[ yourls__( 'Monday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Mon' ); - $this->weekday_abbrev[ yourls__( 'Tuesday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Tue' ); - $this->weekday_abbrev[ yourls__( 'Wednesday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Wed' ); - $this->weekday_abbrev[ yourls__( 'Thursday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Thu' ); - $this->weekday_abbrev[ yourls__( 'Friday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Fri' ); - $this->weekday_abbrev[ yourls__( 'Saturday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Sat' ); - - // The Months - $this->month['01'] = /* //translators: month name */ yourls__( 'January' ); - $this->month['02'] = /* //translators: month name */ yourls__( 'February' ); - $this->month['03'] = /* //translators: month name */ yourls__( 'March' ); - $this->month['04'] = /* //translators: month name */ yourls__( 'April' ); - $this->month['05'] = /* //translators: month name */ yourls__( 'May' ); - $this->month['06'] = /* //translators: month name */ yourls__( 'June' ); - $this->month['07'] = /* //translators: month name */ yourls__( 'July' ); - $this->month['08'] = /* //translators: month name */ yourls__( 'August' ); - $this->month['09'] = /* //translators: month name */ yourls__( 'September' ); - $this->month['10'] = /* //translators: month name */ yourls__( 'October' ); - $this->month['11'] = /* //translators: month name */ yourls__( 'November' ); - $this->month['12'] = /* //translators: month name */ yourls__( 'December' ); - - // Abbreviations for each month. Uses the same hack as above to get around the - // 'May' duplication. - $this->month_abbrev[ yourls__( 'January' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Jan_January_abbreviation' ); - $this->month_abbrev[ yourls__( 'February' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Feb_February_abbreviation' ); - $this->month_abbrev[ yourls__( 'March' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Mar_March_abbreviation' ); - $this->month_abbrev[ yourls__( 'April' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Apr_April_abbreviation' ); - $this->month_abbrev[ yourls__( 'May' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'May_May_abbreviation' ); - $this->month_abbrev[ yourls__( 'June' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Jun_June_abbreviation' ); - $this->month_abbrev[ yourls__( 'July' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Jul_July_abbreviation' ); - $this->month_abbrev[ yourls__( 'August' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Aug_August_abbreviation' ); - $this->month_abbrev[ yourls__( 'September' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Sep_September_abbreviation' ); - $this->month_abbrev[ yourls__( 'October' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Oct_October_abbreviation' ); - $this->month_abbrev[ yourls__( 'November' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Nov_November_abbreviation' ); - $this->month_abbrev[ yourls__( 'December' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Dec_December_abbreviation' ); - - foreach ($this->month_abbrev as $month_ => $month_abbrev_) { - $this->month_abbrev[$month_] = preg_replace('/_.+_abbreviation$/', '', $month_abbrev_); - } - - // The Meridiems - $this->meridiem['am'] = yourls__( 'am' ); - $this->meridiem['pm'] = yourls__( 'pm' ); - $this->meridiem['AM'] = yourls__( 'AM' ); - $this->meridiem['PM'] = yourls__( 'PM' ); - - // Numbers formatting - // See http://php.net/number_format - - /* //translators: $thousands_sep argument for http://php.net/number_format, default is , */ - $trans = yourls__( 'number_format_thousands_sep' ); - $this->number_format['thousands_sep'] = ('number_format_thousands_sep' == $trans) ? ',' : $trans; - - /* //translators: $dec_point argument for http://php.net/number_format, default is . */ - $trans = yourls__( 'number_format_decimal_point' ); - $this->number_format['decimal_point'] = ('number_format_decimal_point' == $trans) ? '.' : $trans; - - // Set text direction. - if ( isset( $GLOBALS['text_direction'] ) ) - $this->text_direction = $GLOBALS['text_direction']; - /* //translators: 'rtl' or 'ltr'. This sets the text direction for YOURLS. */ - elseif ( 'rtl' == yourls_x( 'ltr', 'text direction' ) ) - $this->text_direction = 'rtl'; - } - - /** - * Retrieve the full translated weekday word. - * - * Week starts on translated Sunday and can be fetched - * by using 0 (zero). So the week starts with 0 (zero) - * and ends on Saturday with is fetched by using 6 (six). - * - * @since 1.6 - * @access public - * - * @param int $weekday_number 0 for Sunday through 6 Saturday - * @return string Full translated weekday - */ - function get_weekday( $weekday_number ) { - return $this->weekday[ $weekday_number ]; - } - - /** - * Retrieve the translated weekday initial. - * - * The weekday initial is retrieved by the translated - * full weekday word. When translating the weekday initial - * pay attention to make sure that the starting letter does - * not conflict. - * - * @since 1.6 - * @access public - * - * @param string $weekday_name - * @return string - */ - function get_weekday_initial( $weekday_name ) { - return $this->weekday_initial[ $weekday_name ]; - } - - /** - * Retrieve the translated weekday abbreviation. - * - * The weekday abbreviation is retrieved by the translated - * full weekday word. - * - * @since 1.6 - * @access public - * - * @param string $weekday_name Full translated weekday word - * @return string Translated weekday abbreviation - */ - function get_weekday_abbrev( $weekday_name ) { - return $this->weekday_abbrev[ $weekday_name ]; - } - - /** - * Retrieve the full translated month by month number. - * - * The $month_number parameter has to be a string - * because it must have the '0' in front of any number - * that is less than 10. Starts from '01' and ends at - * '12'. - * - * You can use an integer instead and it will add the - * '0' before the numbers less than 10 for you. - * - * @since 1.6 - * @access public - * - * @param string|int $month_number '01' through '12' - * @return string Translated full month name - */ - function get_month( $month_number ) { - return $this->month[ sprintf( '%02s', $month_number ) ]; - } - - /** - * Retrieve translated version of month abbreviation string. - * - * The $month_name parameter is expected to be the translated or - * translatable version of the month. - * - * @since 1.6 - * @access public - * - * @param string $month_name Translated month to get abbreviated version - * @return string Translated abbreviated month - */ - function get_month_abbrev( $month_name ) { - return $this->month_abbrev[ $month_name ]; - } - - /** - * Retrieve translated version of meridiem string. - * - * The $meridiem parameter is expected to not be translated. - * - * @since 1.6 - * @access public - * - * @param string $meridiem Either 'am', 'pm', 'AM', or 'PM'. Not translated version. - * @return string Translated version - */ - function get_meridiem( $meridiem ) { - return $this->meridiem[ $meridiem ]; - } - - /** - * Global variables are deprecated. For backwards compatibility only. - * - * @deprecated For backwards compatibility only. - * @access private - * - * @since 1.6 - */ - function register_globals() { - $GLOBALS['weekday'] = $this->weekday; - $GLOBALS['weekday_initial'] = $this->weekday_initial; - $GLOBALS['weekday_abbrev'] = $this->weekday_abbrev; - $GLOBALS['month'] = $this->month; - $GLOBALS['month_abbrev'] = $this->month_abbrev; - } - - /** - * Constructor which calls helper methods to set up object variables - * - * @uses YOURLS_Locale_Formats::init() - * @uses YOURLS_Locale_Formats::register_globals() - * @since 1.6 - * - * @return YOURLS_Locale_Formats - */ - function __construct() { - $this->init(); - $this->register_globals(); - } - - /** - * Checks if current locale is RTL. - * - * @since 1.6 - * @return bool Whether locale is RTL. - */ - function is_rtl() { - return 'rtl' == $this->text_direction; - } + /** + * Stores the translated strings for the full weekday names. + * + * @since 1.6 + * @var array + * @access private + */ + var $weekday; + + /** + * Stores the translated strings for the one character weekday names. + * + * There is a hack to make sure that Tuesday and Thursday, as well + * as Sunday and Saturday, don't conflict. See init() method for more. + * + * @see YOURLS_Locale_Formats::init() for how to handle the hack. + * + * @since 1.6 + * @var array + * @access private + */ + var $weekday_initial; + + /** + * Stores the translated strings for the abbreviated weekday names. + * + * @since 1.6 + * @var array + * @access private + */ + var $weekday_abbrev; + + /** + * Stores the translated strings for the full month names. + * + * @since 1.6 + * @var array + * @access private + */ + var $month; + + /** + * Stores the translated strings for the abbreviated month names. + * + * @since 1.6 + * @var array + * @access private + */ + var $month_abbrev; + + /** + * Stores the translated strings for 'am' and 'pm'. + * + * Also the capitalized versions. + * + * @since 1.6 + * @var array + * @access private + */ + var $meridiem; + + /** + * Stores the translated number format + * + * @since 1.6 + * @var array + * @access private + */ + var $number_format; + + /** + * The text direction of the locale language. + * + * Default is left to right 'ltr'. + * + * @since 1.6 + * @var string + * @access private + */ + var $text_direction = 'ltr'; + + /** + * Sets up the translated strings and object properties. + * + * The method creates the translatable strings for various + * calendar elements. Which allows for specifying locale + * specific calendar names and text direction. + * + * @since 1.6 + * @access private + * @return void + */ + function init() { + // The Weekdays + $this->weekday[0] = /* //translators: weekday */ yourls__( 'Sunday' ); + $this->weekday[1] = /* //translators: weekday */ yourls__( 'Monday' ); + $this->weekday[2] = /* //translators: weekday */ yourls__( 'Tuesday' ); + $this->weekday[3] = /* //translators: weekday */ yourls__( 'Wednesday' ); + $this->weekday[4] = /* //translators: weekday */ yourls__( 'Thursday' ); + $this->weekday[5] = /* //translators: weekday */ yourls__( 'Friday' ); + $this->weekday[6] = /* //translators: weekday */ yourls__( 'Saturday' ); + + // The first letter of each day. The _%day%_initial suffix is a hack to make + // sure the day initials are unique. + $this->weekday_initial[yourls__( 'Sunday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'S_Sunday_initial' ); + $this->weekday_initial[yourls__( 'Monday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'M_Monday_initial' ); + $this->weekday_initial[yourls__( 'Tuesday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'T_Tuesday_initial' ); + $this->weekday_initial[yourls__( 'Wednesday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'W_Wednesday_initial' ); + $this->weekday_initial[yourls__( 'Thursday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'T_Thursday_initial' ); + $this->weekday_initial[yourls__( 'Friday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'F_Friday_initial' ); + $this->weekday_initial[yourls__( 'Saturday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'S_Saturday_initial' ); + + foreach ($this->weekday_initial as $weekday_ => $weekday_initial_) { + $this->weekday_initial[$weekday_] = preg_replace('/_.+_initial$/', '', $weekday_initial_); + } + + // Abbreviations for each day. + $this->weekday_abbrev[ yourls__( 'Sunday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Sun' ); + $this->weekday_abbrev[ yourls__( 'Monday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Mon' ); + $this->weekday_abbrev[ yourls__( 'Tuesday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Tue' ); + $this->weekday_abbrev[ yourls__( 'Wednesday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Wed' ); + $this->weekday_abbrev[ yourls__( 'Thursday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Thu' ); + $this->weekday_abbrev[ yourls__( 'Friday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Fri' ); + $this->weekday_abbrev[ yourls__( 'Saturday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Sat' ); + + // The Months + $this->month['01'] = /* //translators: month name */ yourls__( 'January' ); + $this->month['02'] = /* //translators: month name */ yourls__( 'February' ); + $this->month['03'] = /* //translators: month name */ yourls__( 'March' ); + $this->month['04'] = /* //translators: month name */ yourls__( 'April' ); + $this->month['05'] = /* //translators: month name */ yourls__( 'May' ); + $this->month['06'] = /* //translators: month name */ yourls__( 'June' ); + $this->month['07'] = /* //translators: month name */ yourls__( 'July' ); + $this->month['08'] = /* //translators: month name */ yourls__( 'August' ); + $this->month['09'] = /* //translators: month name */ yourls__( 'September' ); + $this->month['10'] = /* //translators: month name */ yourls__( 'October' ); + $this->month['11'] = /* //translators: month name */ yourls__( 'November' ); + $this->month['12'] = /* //translators: month name */ yourls__( 'December' ); + + // Abbreviations for each month. Uses the same hack as above to get around the + // 'May' duplication. + $this->month_abbrev[ yourls__( 'January' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Jan_January_abbreviation' ); + $this->month_abbrev[ yourls__( 'February' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Feb_February_abbreviation' ); + $this->month_abbrev[ yourls__( 'March' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Mar_March_abbreviation' ); + $this->month_abbrev[ yourls__( 'April' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Apr_April_abbreviation' ); + $this->month_abbrev[ yourls__( 'May' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'May_May_abbreviation' ); + $this->month_abbrev[ yourls__( 'June' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Jun_June_abbreviation' ); + $this->month_abbrev[ yourls__( 'July' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Jul_July_abbreviation' ); + $this->month_abbrev[ yourls__( 'August' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Aug_August_abbreviation' ); + $this->month_abbrev[ yourls__( 'September' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Sep_September_abbreviation' ); + $this->month_abbrev[ yourls__( 'October' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Oct_October_abbreviation' ); + $this->month_abbrev[ yourls__( 'November' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Nov_November_abbreviation' ); + $this->month_abbrev[ yourls__( 'December' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Dec_December_abbreviation' ); + + foreach ($this->month_abbrev as $month_ => $month_abbrev_) { + $this->month_abbrev[$month_] = preg_replace('/_.+_abbreviation$/', '', $month_abbrev_); + } + + // The Meridiems + $this->meridiem['am'] = yourls__( 'am' ); + $this->meridiem['pm'] = yourls__( 'pm' ); + $this->meridiem['AM'] = yourls__( 'AM' ); + $this->meridiem['PM'] = yourls__( 'PM' ); + + // Numbers formatting + // See http://php.net/number_format + + /* //translators: $thousands_sep argument for http://php.net/number_format, default is , */ + $trans = yourls__( 'number_format_thousands_sep' ); + $this->number_format['thousands_sep'] = ('number_format_thousands_sep' == $trans) ? ',' : $trans; + + /* //translators: $dec_point argument for http://php.net/number_format, default is . */ + $trans = yourls__( 'number_format_decimal_point' ); + $this->number_format['decimal_point'] = ('number_format_decimal_point' == $trans) ? '.' : $trans; + + // Set text direction. + if ( isset( $GLOBALS['text_direction'] ) ) + $this->text_direction = $GLOBALS['text_direction']; + /* //translators: 'rtl' or 'ltr'. This sets the text direction for YOURLS. */ + elseif ( 'rtl' == yourls_x( 'ltr', 'text direction' ) ) + $this->text_direction = 'rtl'; + } + + /** + * Retrieve the full translated weekday word. + * + * Week starts on translated Sunday and can be fetched + * by using 0 (zero). So the week starts with 0 (zero) + * and ends on Saturday with is fetched by using 6 (six). + * + * @since 1.6 + * @access public + * + * @param int|string $weekday_number 0 for Sunday through 6 Saturday + * @return string Full translated weekday + */ + function get_weekday( $weekday_number ) { + return $this->weekday[ $weekday_number ]; + } + + /** + * Retrieve the translated weekday initial. + * + * The weekday initial is retrieved by the translated + * full weekday word. When translating the weekday initial + * pay attention to make sure that the starting letter does + * not conflict. + * + * @since 1.6 + * @access public + * + * @param string $weekday_name + * @return string + */ + function get_weekday_initial( $weekday_name ) { + return $this->weekday_initial[ $weekday_name ]; + } + + /** + * Retrieve the translated weekday abbreviation. + * + * The weekday abbreviation is retrieved by the translated + * full weekday word. + * + * @since 1.6 + * @access public + * + * @param string $weekday_name Full translated weekday word + * @return string Translated weekday abbreviation + */ + function get_weekday_abbrev( $weekday_name ) { + return $this->weekday_abbrev[ $weekday_name ]; + } + + /** + * Retrieve the full translated month by month number. + * + * The $month_number parameter has to be a string + * because it must have the '0' in front of any number + * that is less than 10. Starts from '01' and ends at + * '12'. + * + * You can use an integer instead and it will add the + * '0' before the numbers less than 10 for you. + * + * @since 1.6 + * @access public + * + * @param string|int $month_number '01' through '12' + * @return string Translated full month name + */ + function get_month( $month_number ) { + return $this->month[ sprintf( '%02s', $month_number ) ]; + } + + /** + * Retrieve translated version of month abbreviation string. + * + * The $month_name parameter is expected to be the translated or + * translatable version of the month. + * + * @since 1.6 + * @access public + * + * @param string $month_name Translated month to get abbreviated version + * @return string Translated abbreviated month + */ + function get_month_abbrev( $month_name ) { + return $this->month_abbrev[ $month_name ]; + } + + /** + * Retrieve translated version of meridiem string. + * + * The $meridiem parameter is expected to not be translated. + * + * @since 1.6 + * @access public + * + * @param string $meridiem Either 'am', 'pm', 'AM', or 'PM'. Not translated version. + * @return string Translated version + */ + function get_meridiem( $meridiem ) { + return $this->meridiem[ $meridiem ]; + } + + /** + * Global variables are deprecated. For backwards compatibility only. + * + * @deprecated For backwards compatibility only. + * @access private + * + * @since 1.6 + * @return void + */ + function register_globals() { + $GLOBALS['weekday'] = $this->weekday; + $GLOBALS['weekday_initial'] = $this->weekday_initial; + $GLOBALS['weekday_abbrev'] = $this->weekday_abbrev; + $GLOBALS['month'] = $this->month; + $GLOBALS['month_abbrev'] = $this->month_abbrev; + } + + /** + * Constructor which calls helper methods to set up object variables + * + * @since 1.6 + */ + function __construct() { + $this->init(); + $this->register_globals(); + } + + /** + * Checks if current locale is RTL. + * + * @since 1.6 + * @return bool Whether locale is RTL. + */ + function is_rtl() { + return 'rtl' == $this->text_direction; + } } /** @@ -989,10 +997,10 @@ function is_rtl() { * * @param string $domain Unique identifier (the "domain") for retrieving translated strings * @param string $path Full path to directory containing MO files. - * @return mixed Returns nothing if locale undefined, otherwise return bool: true on success, false on failure + * @return mixed|void Returns nothing if locale undefined, otherwise return bool: true on success, false on failure */ function yourls_load_custom_textdomain( $domain, $path ) { - $locale = yourls_apply_filter( 'load_custom_textdomain', yourls_get_locale(), $domain ); + $locale = yourls_apply_filter( 'load_custom_textdomain', yourls_get_locale(), $domain ); if( !empty( $locale ) ) { $mofile = rtrim( $path, '/' ) . '/'. $domain . '-' . $locale . '.mo'; return yourls_load_textdomain( $domain, $mofile ); @@ -1006,11 +1014,11 @@ function yourls_load_custom_textdomain( $domain, $path ) { * @return bool Whether locale is RTL. */ function yourls_is_rtl() { - global $yourls_locale_formats; - if( !isset( $yourls_locale_formats ) ) - $yourls_locale_formats = new YOURLS_Locale_Formats(); + global $yourls_locale_formats; + if( !isset( $yourls_locale_formats ) ) + $yourls_locale_formats = new YOURLS_Locale_Formats(); - return $yourls_locale_formats->is_rtl(); + return $yourls_locale_formats->is_rtl(); } /** @@ -1024,19 +1032,19 @@ function yourls_is_rtl() { * @return mixed Translated weekday abbreviation, eg "Ven" (abbrev of "Vendredi") for "Friday" or 5, or array of all weekday abbrev */ function yourls_l10n_weekday_abbrev( $weekday = '' ){ - global $yourls_locale_formats; - if( !isset( $yourls_locale_formats ) ) - $yourls_locale_formats = new YOURLS_Locale_Formats(); - - if( $weekday === '' ) - return $yourls_locale_formats->weekday_abbrev; - - if( is_int( $weekday ) ) { - $day = $yourls_locale_formats->weekday[ $weekday ]; - return $yourls_locale_formats->weekday_abbrev[ $day ]; - } else { - return $yourls_locale_formats->weekday_abbrev[ yourls__( $weekday ) ]; - } + global $yourls_locale_formats; + if( !isset( $yourls_locale_formats ) ) + $yourls_locale_formats = new YOURLS_Locale_Formats(); + + if( $weekday === '' ) + return $yourls_locale_formats->weekday_abbrev; + + if( is_int( $weekday ) ) { + $day = $yourls_locale_formats->weekday[ $weekday ]; + return $yourls_locale_formats->weekday_abbrev[ $day ]; + } else { + return $yourls_locale_formats->weekday_abbrev[ yourls__( $weekday ) ]; + } } /** @@ -1050,19 +1058,19 @@ function yourls_l10n_weekday_abbrev( $weekday = '' ){ * @return mixed Translated weekday initial, eg "V" (initial of "Vendredi") for "Friday" or 5, or array of all weekday initials */ function yourls_l10n_weekday_initial( $weekday = '' ){ - global $yourls_locale_formats; - if( !isset( $yourls_locale_formats ) ) - $yourls_locale_formats = new YOURLS_Locale_Formats(); - - if( $weekday === '' ) - return $yourls_locale_formats->weekday_initial; - - if( is_int( $weekday ) ) { - $weekday = $yourls_locale_formats->weekday[ $weekday ]; - return $yourls_locale_formats->weekday_initial[ $weekday ]; - } else { - return $yourls_locale_formats->weekday_initial[ yourls__( $weekday ) ]; - } + global $yourls_locale_formats; + if( !isset( $yourls_locale_formats ) ) + $yourls_locale_formats = new YOURLS_Locale_Formats(); + + if( $weekday === '' ) + return $yourls_locale_formats->weekday_initial; + + if( is_int( $weekday ) ) { + $weekday = $yourls_locale_formats->weekday[ $weekday ]; + return $yourls_locale_formats->weekday_initial[ $weekday ]; + } else { + return $yourls_locale_formats->weekday_initial[ yourls__( $weekday ) ]; + } } /** @@ -1076,20 +1084,20 @@ function yourls_l10n_weekday_initial( $weekday = '' ){ * @return mixed Translated month abbrev (eg "Nov"), or array of all translated abbrev months */ function yourls_l10n_month_abbrev( $month = '' ){ - global $yourls_locale_formats; - if( !isset( $yourls_locale_formats ) ) - $yourls_locale_formats = new YOURLS_Locale_Formats(); + global $yourls_locale_formats; + if( !isset( $yourls_locale_formats ) ) + $yourls_locale_formats = new YOURLS_Locale_Formats(); - if( $month === '' ) - return $yourls_locale_formats->month_abbrev; + if( $month === '' ) + return $yourls_locale_formats->month_abbrev; - if( intval( $month ) > 0 ) { + if( intval( $month ) > 0 ) { $month = sprintf('%02d', intval( $month ) ); - $month = $yourls_locale_formats->month[ $month ]; - return $yourls_locale_formats->month_abbrev[ $month ]; - } else { - return $yourls_locale_formats->month_abbrev[ yourls__( $month ) ]; - } + $month = $yourls_locale_formats->month[ $month ]; + return $yourls_locale_formats->month_abbrev[ $month ]; + } else { + return $yourls_locale_formats->month_abbrev[ yourls__( $month ) ]; + } } /** @@ -1099,9 +1107,9 @@ function yourls_l10n_month_abbrev( $month = '' ){ * @return array Array of all translated months */ function yourls_l10n_months(){ - global $yourls_locale_formats; - if( !isset( $yourls_locale_formats ) ) - $yourls_locale_formats = new YOURLS_Locale_Formats(); + global $yourls_locale_formats; + if( !isset( $yourls_locale_formats ) ) + $yourls_locale_formats = new YOURLS_Locale_Formats(); - return $yourls_locale_formats->month; + return $yourls_locale_formats->month; } diff --git a/includes/functions-links.php b/includes/functions-links.php index e8050681b..3bb994b13 100644 --- a/includes/functions-links.php +++ b/includes/functions-links.php @@ -93,6 +93,8 @@ function yourls_add_query_arg() { /** * Navigates through an array and encodes the values to be used in a URL. Stolen from WP, used in yourls_add_query_arg() * + * @param array|string $value The array or string to be encoded. + * @return array|string */ function yourls_urlencode_deep( $value ) { $value = is_array( $value ) ? array_map( 'yourls_urlencode_deep', $value ) : urlencode( $value ); @@ -147,6 +149,8 @@ function yourls_link( $keyword = '', $stats = false ) { * * This function does not make sure the keyword matches an actual short URL * + * @param string $keyword Short URL keyword + * @return string Short URL stat link */ function yourls_statlink( $keyword = '' ) { $link = yourls_link( $keyword, true ); @@ -156,6 +160,8 @@ function yourls_statlink( $keyword = '' ) { /** * Return admin link, with SSL preference if applicable. * + * @param string $page Page name, eg "index.php" + * @return string */ function yourls_admin_url( $page = '' ) { $admin = yourls_get_yourls_site() . '/admin/' . $page; @@ -168,8 +174,11 @@ function yourls_admin_url( $page = '' ) { /** * Return YOURLS_SITE or URL under YOURLS setup, with SSL preference * + * @param bool $echo Echo if true, or return if false + * @param string $url + * @return string */ -function yourls_site_url( $echo = true, $url = '' ) { +function yourls_site_url($echo = true, $url = '' ) { $url = yourls_get_relative_url( $url ); $url = trim( yourls_get_yourls_site() . '/' . $url, '/' ); diff --git a/includes/functions-options.php b/includes/functions-options.php index 42e88109a..30fce603c 100644 --- a/includes/functions-options.php +++ b/includes/functions-options.php @@ -21,7 +21,7 @@ function yourls_get_option( $option_name, $default = false ) { return $pre; } - $option = new \YOURLS\Database\Options(yourls_get_db()); + $option = new \YOURLS\Database\Options(yourls_get_db('read-get_option')); $value = $option->get($option_name, $default); return yourls_apply_filter( 'get_option_'.$option_name, $value ); @@ -36,6 +36,7 @@ function yourls_get_option( $option_name, $default = false ) { * a check for DB server reachability has been performed * * @since 1.4 + * @return void */ function yourls_get_all_options() { // Allow plugins to short-circuit all options. (Note: regular plugins are loaded after all options) @@ -44,7 +45,7 @@ function yourls_get_all_options() { return $pre; } - $options = new \YOURLS\Database\Options(yourls_get_db()); + $options = new \YOURLS\Database\Options(yourls_get_db('read-get_all_options')); if ($options->get_all_options() === false) { // Zero option found but no unexpected error so far: YOURLS isn't installed @@ -66,7 +67,7 @@ function yourls_get_all_options() { * @return bool False if value was not updated, true otherwise. */ function yourls_update_option( $option_name, $newvalue ) { - $option = new \YOURLS\Database\Options(yourls_get_db()); + $option = new \YOURLS\Database\Options(yourls_get_db('write-update_option')); $update = $option->update($option_name, $newvalue); return $update; @@ -83,7 +84,7 @@ function yourls_update_option( $option_name, $newvalue ) { * @return bool False if option was not added and true otherwise. */ function yourls_add_option( $name, $value = '' ) { - $option = new \YOURLS\Database\Options(yourls_get_db()); + $option = new \YOURLS\Database\Options(yourls_get_db('write-add_option')); $add = $option->add($name, $value); return $add; @@ -99,7 +100,7 @@ function yourls_add_option( $name, $value = '' ) { * @return bool True, if option is successfully deleted. False on failure. */ function yourls_delete_option( $name ) { - $option = new \YOURLS\Database\Options(yourls_get_db()); + $option = new \YOURLS\Database\Options(yourls_get_db('write-delete_option')); $delete = $option->delete($name); return $delete; diff --git a/includes/functions-plugins.php b/includes/functions-plugins.php index 5b1f51bc5..107a18417 100644 --- a/includes/functions-plugins.php +++ b/includes/functions-plugins.php @@ -55,7 +55,7 @@ * ) * ) * - * @var array + * @var array $yourls_filters */ if ( !isset( $yourls_filters ) ) { $yourls_filters = []; @@ -65,7 +65,7 @@ * This global var will collect 'done' actions with the following structure: * $yourls_actions['hook'] => number of time this action was done * - * @var array + * @var array $yourls_actions */ if ( !isset( $yourls_actions ) ) { $yourls_actions = []; @@ -77,9 +77,9 @@ * Typical use: * yourls_add_filter('some_hook', 'function_handler_for_hook'); * - * @link https://github.com/YOURLS/YOURLS/wiki/How-to-make-Plugins + * @link https://docs.yourls.org/development/plugins.html * @param string $hook the name of the YOURLS element to be filtered or YOURLS action to be triggered - * @param callback $function_name the name of the function that is to be called. + * @param callable $function_name the name of the function that is to be called. * @param int $priority optional. Used to specify the order in which the functions associated with a * particular action are executed (default=10, lower=earlier execution, and functions * with the same priority are executed in the order in which they were added to the @@ -87,12 +87,12 @@ * @param int $accepted_args optional. The number of arguments the function accept (default is the number * provided). * @param string $type - * @global array $yourls_filters Storage for all of the filters + * @return void */ function yourls_add_filter( $hook, $function_name, $priority = 10, $accepted_args = NULL, $type = 'filter' ) { global $yourls_filters; // At this point, we cannot check if the function exists, as it may well be defined later (which is OK) - $id = yourls_filter_unique_id( $hook, $function_name, $priority ); + $id = yourls_filter_unique_id($function_name); $yourls_filters[ $hook ][ $priority ][ $id ] = [ 'function' => $function_name, @@ -112,16 +112,17 @@ function yourls_add_filter( $hook, $function_name, $priority = 10, $accepted_arg * Typical use: * yourls_add_action('some_hook', 'function_handler_for_hook'); * - * @link https://github.com/YOURLS/YOURLS/wiki/How-to-make-Plugins + * @link https://docs.yourls.org/development/plugins.html * @param string $hook The name of the action to which the $function_to_add is hooked. - * @param callback $function_name The name of the function you wish to be called. + * @param callable $function_name The name of the function you wish to be called. * @param int $priority Optional. Used to specify the order in which the functions associated with a particular action * are executed (default: 10). Lower numbers correspond with earlier execution, and functions * with the same priority are executed in the order in which they were added to the action. * @param int $accepted_args Optional. The number of arguments the function accept (default 1). + * @return void */ function yourls_add_action( $hook, $function_name, $priority = 10, $accepted_args = 1 ) { - yourls_add_filter( $hook, $function_name, $priority, $accepted_args, 'action' ); + yourls_add_filter( $hook, $function_name, $priority, $accepted_args, 'action' ); } /** @@ -141,15 +142,12 @@ function yourls_add_action( $hook, $function_name, $priority = 10, $accepted_arg * yourls_add_filter('my_hook_test', $class_instance_with_invoke_method); * yourls_add_filter('my_hook_test', $my_callback_function); * - * @link https://github.com/YOURLS/YOURLS/wiki/Advanced-Hook-Syntax - * @param string $hook Hook to which the function is attached - * @param string|array $function Used for creating unique id - * @param int|bool $priority Used in counting how many hooks were applied. If === false and $function is an object reference, - * we return the unique id only if it already has one, false otherwise. + * @link https://docs.yourls.org/development/hooks.html + * @param string|array|object $function The callable used in a filter or action. * @return string unique ID for usage as array key */ -function yourls_filter_unique_id( $hook, $function, $priority ) { - // If function then just skip all of the tests and not overwrite the following. +function yourls_filter_unique_id($function) { + // If given a string (function name) if ( is_string( $function ) ) { return $function; } @@ -167,37 +165,28 @@ function yourls_filter_unique_id( $hook, $function, $priority ) { return spl_object_hash( $function[0] ).$function[1]; } - // Static Calling - if ( is_string( $function[0] ) ) { - return $function[0].'::'.$function[1]; - } - - /** - * There is no other possible case as of PHP 7.2-8.0 callables. Still, we're leaving the final - * `if` block (which could be remove to simply `return $function[0].'::'.$function[1]`) for readability - * and understanding the logic. - */ + // Last case, static Calling : $function[0] is a string (Class Name) and $function[1] is a string (Method Name) + return $function[0].'::'.$function[1]; } /** - * Performs a filtering operation on a YOURLS element or event. + * Performs a filtering operation on a value or an event. * * Typical use: * - * 1) Modify a variable if a function is attached to hook 'yourls_hook' - * $yourls_var = "default value"; - * $yourls_var = yourls_apply_filter( 'yourls_hook', $yourls_var ); + * 1) Modify a variable if a function is attached to hook 'yourls_hook' + * $yourls_var = "default value"; + * $yourls_var = yourls_apply_filter( 'yourls_hook', $yourls_var ); * - * 2) Trigger functions is attached to event 'yourls_event' - * yourls_apply_filter( 'yourls_event' ); + * 2) Trigger functions is attached to event 'yourls_event' + * yourls_apply_filter( 'yourls_event' ); * (see yourls_do_action() ) * - * Returns an element which may have been filtered by a filter. + * Returns a value which may have been modified by a filter. * - * @global array $yourls_filters storage for all of the filters * @param string $hook the name of the YOURLS element or action * @param mixed $value the value of the element before filtering - * @param bool $is_action true if the function is called by yourls_do_action() + * @param true|mixed $is_action true if the function is called by yourls_do_action() - otherwise may be the second parameter of an arbitrary number of parameters * @return mixed */ function yourls_apply_filter( $hook, $value = '', $is_action = false ) { @@ -222,6 +211,7 @@ function yourls_apply_filter( $hook, $value = '', $is_action = false ) { reset( $yourls_filters[ $hook ] ); do { foreach ( (array)current( $yourls_filters[ $hook ] ) as $the_ ) { + $_value = ''; if ( !is_null($the_[ 'function' ]) ) { $args[ 1 ] = $value; $count = $the_[ 'accepted_args' ]; @@ -247,6 +237,7 @@ function yourls_apply_filter( $hook, $value = '', $is_action = false ) { * * @param string $hook the name of the YOURLS action * @param mixed $arg action arguments + * @return void */ function yourls_do_action( $hook, $arg = '' ) { global $yourls_actions, $yourls_filters; @@ -299,13 +290,14 @@ function yourls_did_action( $hook ) { * Internal function used by yourls_do_action() and yourls_apply_filter() - not meant to be used from * outside these functions. * This is mostly a debugging function to understand the flow of events. - * See https://github.com/YOURLS/YOURLS/wiki/Debugging-YOURLS to learn how to use the 'all' hook + * See https://docs.yourls.org/development/debugging.html to learn how to use the 'all' hook * - * @link https://github.com/YOURLS/YOURLS/wiki/Debugging-YOURLS + * @link https://docs.yourls.org/development/debugging.html * @since 1.8.1 * @param string $type Either 'action' or 'filter' * @param string $hook The hook name, eg 'plugins_loaded' * @param mixed $args Variable-length argument lists that were passed to the action or filter + * @return void */ function yourls_call_all_hooks($type, $hook, ...$args) { global $yourls_filters; @@ -338,16 +330,15 @@ function yourls_call_all_hooks($type, $hook, ...$args) { * To remove a hook, the $function_to_remove and $priority arguments must match * when the hook was added. * - * @global array $yourls_filters storage for all of the filters * @param string $hook The filter hook to which the function to be removed is hooked. - * @param callback $function_to_remove The name of the function which should be removed. + * @param callable $function_to_remove The name of the function which should be removed. * @param int $priority optional. The priority of the function (default: 10). * @return bool Whether the function was registered as a filter before it was removed. */ function yourls_remove_filter( $hook, $function_to_remove, $priority = 10 ) { global $yourls_filters; - $function_to_remove = yourls_filter_unique_id( $hook, $function_to_remove, $priority ); + $function_to_remove = yourls_filter_unique_id($function_to_remove); $remove = isset( $yourls_filters[ $hook ][ $priority ][ $function_to_remove ] ); @@ -410,6 +401,31 @@ function yourls_remove_all_filters( $hook, $priority = false ) { return true; } +/** + * Return filters for a specific hook. + * + * If hook has filters (or actions, see yourls_has_action()), this will return an array priorities => callbacks. + * See the structure of yourls_filters on top of this file for details. + * + * @since 1.8.3 + * @param string $hook The hook to retrieve filters for + * @return array + */ +function yourls_get_filters($hook) { + global $yourls_filters; + return $yourls_filters[$hook] ?? array(); +} + +/** + * Return actions for a specific hook. + * + * @since 1.8.3 + * @param string $hook The hook to retrieve actions for + * @return array + */ +function yourls_get_actions($hook) { + return yourls_get_filters($hook); +} /** * Check if any filter has been registered for a hook. * @@ -417,7 +433,6 @@ function yourls_remove_all_filters( $hook, $priority = false ) { * @param string $hook The name of the filter hook. * @param callable|false $function_to_check optional. If specified, return the priority of that function on this hook or false if not attached. * @return int|bool Optionally returns the priority on that hook for the specified function. - * @global array $yourls_filters storage for all of the filters */ function yourls_has_filter( $hook, $function_to_check = false ) { global $yourls_filters; @@ -427,7 +442,7 @@ function yourls_has_filter( $hook, $function_to_check = false ) { return $has; } - if ( !$idx = yourls_filter_unique_id( $hook, $function_to_check, false ) ) { + if ( !$idx = yourls_filter_unique_id($function_to_check) ) { return false; } @@ -439,6 +454,7 @@ function yourls_has_filter( $hook, $function_to_check = false ) { return false; } + /** * Check if any action has been registered for a hook. * @@ -457,7 +473,7 @@ function yourls_has_action( $hook, $function_to_check = false ) { * @return int Number of activated plugins */ function yourls_has_active_plugins() { - return count( yourls_get_db()->get_plugins() ); + return count( yourls_get_db('read-has_active_plugins')->get_plugins() ); } /** @@ -486,7 +502,7 @@ function yourls_get_plugins() { */ function yourls_is_active_plugin( $plugin ) { return yourls_has_active_plugins() > 0 ? - in_array( yourls_plugin_basename( $plugin ), yourls_get_db()->get_plugins() ) + in_array( yourls_plugin_basename( $plugin ), yourls_get_db('read-is_active_plugin')->get_plugins() ) : false; } @@ -574,18 +590,18 @@ function yourls_load_plugins() { $plugins = []; foreach ( $active_plugins as $key => $plugin ) { - if ( yourls_validate_plugin_file( YOURLS_PLUGINDIR.'/'.$plugin ) ) { - include_once( YOURLS_PLUGINDIR.'/'.$plugin ); + $file = YOURLS_PLUGINDIR . '/' . $plugin; + if ( yourls_is_a_plugin_file($file) && yourls_include_file_sandbox( $file ) === true ) { $plugins[] = $plugin; unset( $active_plugins[ $key ] ); } } // Replace active plugin list with list of plugins we just activated - yourls_get_db()->set_plugins( $plugins ); + yourls_get_db('read-load_plugins')->set_plugins( $plugins ); $info = count( $plugins ).' activated'; - // $active_plugins should be empty now, if not, a plugin could not be find: remove it + // $active_plugins should be empty now, if not, a plugin could not be found, or is erroneous : remove it $missing_count = count( $active_plugins ); if ( $missing_count > 0 ) { yourls_update_option( 'active_plugins', $plugins ); @@ -602,13 +618,15 @@ function yourls_load_plugins() { } /** - * Check if a file is safe for inclusion (well, "safe", no guarantee) + * Check if a file is a plugin file + * + * This doesn't check if the file is a valid PHP file, only that it's correctly named. * * @since 1.5 * @param string $file Full pathname to a file * @return bool */ -function yourls_validate_plugin_file( $file ) { +function yourls_is_a_plugin_file($file) { return false === strpos( $file, '..' ) && false === strpos( $file, './' ) && 'plugin.php' === substr( $file, -10 ) @@ -626,27 +644,21 @@ function yourls_activate_plugin( $plugin ) { // validate file $plugin = yourls_plugin_basename( $plugin ); $plugindir = yourls_sanitize_filename( YOURLS_PLUGINDIR ); - if ( !yourls_validate_plugin_file( $plugindir.'/'.$plugin ) ) { + if ( !yourls_is_a_plugin_file($plugindir . '/' . $plugin ) ) { return yourls__( 'Not a valid plugin file' ); } // check not activated already - $ydb = yourls_get_db(); + $ydb = yourls_get_db('read-activate_plugin'); if ( yourls_is_active_plugin( $plugin ) ) { return yourls__( 'Plugin already activated' ); } - // attempt activation. TODO: uber cool fail proof sandbox like in WP. - ob_start(); - include_once( $plugindir.'/'.$plugin ); - if ( ob_get_length() > 0 ) { - // there was some output: error - // @codeCoverageIgnoreStart - $output = ob_get_clean(); - return yourls_s( 'Plugin generated unexpected output. Error was:
%s
', $output ); - // @codeCoverageIgnoreEnd + // attempt activation. + $attempt = yourls_include_file_sandbox( $plugindir.'/'.$plugin ); + if( $attempt !== true ) { + return yourls_s( 'Plugin generated unexpected output. Error was:
%s
', $attempt ); } - ob_end_clean(); // so far, so good: update active plugin list $ydb->add_plugin( $plugin ); @@ -672,8 +684,22 @@ function yourls_deactivate_plugin( $plugin ) { return yourls__( 'Plugin not active' ); } + // Check if we have an uninstall file - load if so + $uninst_file = YOURLS_PLUGINDIR . '/' . dirname($plugin) . '/uninstall.php'; + $attempt = yourls_include_file_sandbox( $uninst_file ); + + // Check if we have an error to display + if ( is_string( $attempt ) ) { + $message = yourls_s( 'Loading %s generated unexpected output. Error was:
%s
', $uninst_file, $attempt ); + return( $message ); + } + + if ( $attempt === true ) { + define('YOURLS_UNINSTALL_PLUGIN', true); + } + // Deactivate the plugin - $ydb = yourls_get_db(); + $ydb = yourls_get_db('read-deactivate_plugin'); $plugins = $ydb->get_plugins(); $key = array_search( $plugin, $plugins ); if ( $key !== false ) { @@ -696,7 +722,7 @@ function yourls_deactivate_plugin( $plugin ) { * @return string */ function yourls_plugin_basename( $file ) { - return trim( str_replace( yourls_sanitize_filename( YOURLS_PLUGINDIR ), '', yourls_sanitize_filename( $file ) ), '/' ); + return trim( str_replace( yourls_sanitize_filename( YOURLS_PLUGINDIR ), '', yourls_sanitize_filename( $file ) ), '/' ); } /** @@ -722,7 +748,7 @@ function yourls_plugin_url( $file ) { */ function yourls_list_plugin_admin_pages() { $plugin_links = []; - foreach ( yourls_get_db()->get_plugin_pages() as $plugin => $page ) { + foreach ( yourls_get_db('read-list_plugin_admin_pages')->get_plugin_pages() as $plugin => $page ) { $plugin_links[ $plugin ] = [ 'url' => yourls_admin_url( 'plugins.php?page='.$page[ 'slug' ] ), 'anchor' => $page[ 'title' ], @@ -738,9 +764,10 @@ function yourls_list_plugin_admin_pages() { * @param string $slug * @param string $title * @param callable $function + * @return void */ function yourls_register_plugin_page( $slug, $title, $function ) { - yourls_get_db()->add_plugin_page( $slug, $title, $function ); + yourls_get_db('read-register_plugin_page')->add_plugin_page( $slug, $title, $function ); } /** @@ -748,10 +775,11 @@ function yourls_register_plugin_page( $slug, $title, $function ) { * * @since 1.5 * @param string $plugin_page + * @return void */ function yourls_plugin_admin_page( $plugin_page ) { // Check the plugin page is actually registered - $pages = yourls_get_db()->get_plugin_pages(); + $pages = yourls_get_db('read-plugin_admin_page')->get_plugin_pages(); if ( !isset( $pages[ $plugin_page ] ) ) { yourls_die( yourls__( 'This page does not exist. Maybe a plugin you thought was activated is inactive?' ), yourls__( 'Invalid link' ) ); } @@ -818,6 +846,7 @@ function yourls_plugins_sort_callback( $plugin_a, $plugin_b ) { * * @codeCoverageIgnore * @since 1.5.1 + * @return void */ function yourls_shutdown() { yourls_do_action( 'shutdown' ); diff --git a/includes/functions-shorturls.php b/includes/functions-shorturls.php index 87e46f641..d1fc918b2 100644 --- a/includes/functions-shorturls.php +++ b/includes/functions-shorturls.php @@ -12,31 +12,50 @@ * status: string, 'success' or 'fail' * message: string, a descriptive localized message of what happened in any case * code: string, a short descriptivish and untranslated message describing what happened - * - * Depending on the operation, it will contain any of the following keys: * errorCode: string, a HTTP status code - * url: array, the short URL creation information, with the following keys: 'keyword', 'url', 'title', 'date', 'ip' + * statusCode: string, a HTTP status code + * Depending on the operation, it will contain any of the following keys: + * url: array, the short URL creation information, with keys: 'keyword', 'url', 'title', 'date', 'ip', 'clicks' * title: string, the URL title * shorturl: string, the proper short URL in full (eg 'http://sho.rt/abc') * html: string, the HTML part used by the ajax to update the page display if any * + * For compatibility with early consumers and third parties, when people asked for various data and data formats + * before the internal API was really structured, the return array now collects several redundant information. + * * @param string $url URL to shorten * @param string $keyword optional "keyword" * @param string $title option title + * @param int $row_id used to form unique IDs in the generated HTML * @return array array with error/success state and short URL information */ -function yourls_add_new_link( $url, $keyword = '', $title = '' ) { +function yourls_add_new_link( $url, $keyword = '', $title = '', $row_id = 1 ) { // Allow plugins to short-circuit the whole function $pre = yourls_apply_filter( 'shunt_add_new_link', false, $url, $keyword, $title ); - if ( false !== $pre ) + if ( false !== $pre ) { return $pre; + } + /** + * The result array. + */ + $return = [ + // Always present : + 'status' => '', + 'code' => '', + 'message' => '', + 'errorCode' => '', + 'statusCode' => '', + ]; + + // Sanitize URL $url = yourls_sanitize_url( $url ); if ( !$url || $url == 'http://' || $url == 'https://' ) { $return['status'] = 'fail'; $return['code'] = 'error:nourl'; $return['message'] = yourls__( 'Missing or malformed URL' ); - $return['errorCode'] = '400'; + $return['errorCode'] = $return['statusCode'] = '400'; // 400 Bad Request + return yourls_apply_filter( 'add_new_link_fail_nourl', $return, $url, $keyword, $title ); } @@ -45,117 +64,112 @@ function yourls_add_new_link( $url, $keyword = '', $title = '' ) { yourls_check_IP_flood( $ip ); // Prevent internal redirection loops: cannot shorten a shortened URL - if( yourls_get_relative_url( $url ) ) { - if( yourls_is_shorturl( $url ) ) { - $return['status'] = 'fail'; - $return['code'] = 'error:noloop'; - $return['message'] = yourls__( 'URL is a short URL' ); - $return['errorCode'] = '400'; - return yourls_apply_filter( 'add_new_link_fail_noloop', $return, $url, $keyword, $title ); - } + if (yourls_is_shorturl($url)) { + $return['status'] = 'fail'; + $return['code'] = 'error:noloop'; + $return['message'] = yourls__( 'URL is a short URL' ); + $return['errorCode'] = $return['statusCode'] = '400'; // 400 Bad Request + return yourls_apply_filter( 'add_new_link_fail_noloop', $return, $url, $keyword, $title ); } yourls_do_action( 'pre_add_new_link', $url, $keyword, $title ); - $return = array(); + // Check if URL was already stored and we don't accept duplicates + if ( !yourls_allow_duplicate_longurls() && ($url_exists = yourls_long_url_exists( $url )) ) { + yourls_do_action( 'add_new_link_already_stored', $url, $keyword, $title ); - // duplicates allowed or new URL => store it - if( yourls_allow_duplicate_longurls() || !( $url_exists = yourls_long_url_exists( $url ) ) ) { + $return['status'] = 'fail'; + $return['code'] = 'error:url'; + $return['url'] = array( 'keyword' => $url_exists->keyword, 'url' => $url, 'title' => $url_exists->title, 'date' => $url_exists->timestamp, 'ip' => $url_exists->ip, 'clicks' => $url_exists->clicks ); + $return['message'] = /* //translators: eg "http://someurl/ already exists (short URL: sho.rt/abc)" */ yourls_s('%s already exists in database (short URL: %s)', + yourls_trim_long_string($url), preg_replace('!https?://!', '', yourls_get_yourls_site()) . '/'. $url_exists->keyword ); + $return['title'] = $url_exists->title; + $return['shorturl'] = yourls_link($url_exists->keyword); + $return['errorCode'] = $return['statusCode'] = '400'; // 400 Bad Request - if( isset( $title ) && !empty( $title ) ) { - $title = yourls_sanitize_title( $title ); - } else { - $title = yourls_get_remote_title( $url ); - } - $title = yourls_apply_filter( 'add_new_title', $title, $url, $keyword ); - - // Custom keyword provided - if ( $keyword ) { - - yourls_do_action( 'add_new_link_custom_keyword', $url, $keyword, $title ); - - $keyword = yourls_sanitize_keyword( $keyword, true ); - $keyword = yourls_apply_filter( 'custom_keyword', $keyword, $url, $title ); - - if ( !yourls_keyword_is_free( $keyword ) ) { - // This shorturl either reserved or taken already - $return['status'] = 'fail'; - $return['code'] = 'error:keyword'; - $return['message'] = yourls_s( 'Short URL %s already exists in database or is reserved', $keyword ); - } else { - // all clear, store ! - yourls_insert_link_in_db( $url, $keyword, $title ); - $return['url'] = array('keyword' => $keyword, 'url' => $url, 'title' => $title, 'date' => date('Y-m-d H:i:s'), 'ip' => $ip ); - $return['status'] = 'success'; - $return['message'] = /* //translators: eg "http://someurl/ added to DB" */ yourls_s( '%s added to database', yourls_trim_long_string( $url ) ); - $return['title'] = $title; - $return['html'] = yourls_table_add_row( $keyword, $url, $title, $ip, 0, time() ); - $return['shorturl'] = yourls_link($keyword); - } + return yourls_apply_filter( 'add_new_link_already_stored_filter', $return, $url, $keyword, $title ); + } - // Create random keyword - } else { + // Sanitize provided title, or fetch one + if( isset( $title ) && !empty( $title ) ) { + $title = yourls_sanitize_title( $title ); + } else { + $title = yourls_get_remote_title( $url ); + } + $title = yourls_apply_filter( 'add_new_title', $title, $url, $keyword ); - yourls_do_action( 'add_new_link_create_keyword', $url, $keyword, $title ); - - $timestamp = date( 'Y-m-d H:i:s' ); - $id = yourls_get_next_decimal(); - $ok = false; - do { - $keyword = yourls_int2string( $id ); - $keyword = yourls_apply_filter( 'random_keyword', $keyword, $url, $title ); - if ( yourls_keyword_is_free($keyword) ) { - if (yourls_insert_link_in_db( $url, $keyword, $title )){ - // everything ok, populate needed vars - $return['url'] = array('keyword' => $keyword, 'url' => $url, 'title' => $title, 'date' => $timestamp, 'ip' => $ip ); - $return['status'] = 'success'; - $return['message'] = /* //translators: eg "http://someurl/ added to DB" */ yourls_s( '%s added to database', yourls_trim_long_string( $url ) ); - $return['title'] = $title; - $return['html'] = yourls_table_add_row( $keyword, $url, $title, $ip, 0, time() ); - $return['shorturl'] = yourls_link($keyword); - } else { - // database error, couldnt store result - $return['status'] = 'fail'; - $return['code'] = 'error:db'; - $return['message'] = yourls_s( 'Error saving url to database' ); - } - $ok = true; - } - $id++; - } while ( !$ok ); - @yourls_update_next_decimal( $id ); + // Custom keyword provided : sanitize and make sure it's free + if ($keyword) { + yourls_do_action( 'add_new_link_custom_keyword', $url, $keyword, $title ); + + $keyword = yourls_sanitize_keyword( $keyword, true ); + $keyword = yourls_apply_filter( 'custom_keyword', $keyword, $url, $title ); + + if ( !yourls_keyword_is_free( $keyword ) ) { + // This shorturl either reserved or taken already + $return['status'] = 'fail'; + $return['code'] = 'error:keyword'; + $return['message'] = yourls_s( 'Short URL %s already exists in database or is reserved', $keyword ); + $return['errorCode'] = $return['statusCode'] = '400'; // 400 Bad Request + + return yourls_apply_filter( 'add_new_link_keyword_exists', $return, $url, $keyword, $title ); } - // URL was already stored + // Create random keyword } else { + yourls_do_action( 'add_new_link_create_keyword', $url, $keyword, $title ); - yourls_do_action( 'add_new_link_already_stored', $url, $keyword, $title ); + $id = yourls_get_next_decimal(); - $return['status'] = 'fail'; - $return['code'] = 'error:url'; - $return['url'] = array( 'keyword' => $url_exists->keyword, 'url' => $url, 'title' => $url_exists->title, 'date' => $url_exists->timestamp, 'ip' => $url_exists->ip, 'clicks' => $url_exists->clicks ); - $return['message'] = /* //translators: eg "http://someurl/ already exists" */ yourls_s( '%s already exists in database', yourls_trim_long_string( $url ) ); - $return['title'] = $url_exists->title; - $return['shorturl'] = yourls_link($url_exists->keyword); + do { + $keyword = yourls_int2string( $id ); + $keyword = yourls_apply_filter( 'random_keyword', $keyword, $url, $title ); + $id++; + } while ( !yourls_keyword_is_free($keyword) ); + + yourls_update_next_decimal($id); + } + + // We should be all set now. Store the short URL ! + + $timestamp = date( 'Y-m-d H:i:s' ); + + try { + if (yourls_insert_link_in_db( $url, $keyword, $title )){ + // everything ok, populate needed vars + $return['url'] = array('keyword' => $keyword, 'url' => $url, 'title' => $title, 'date' => $timestamp, 'ip' => $ip ); + $return['status'] = 'success'; + $return['message'] = /* //translators: eg "http://someurl/ added to DB" */ yourls_s( '%s added to database', yourls_trim_long_string( $url ) ); + $return['title'] = $title; + $return['html'] = yourls_table_add_row( $keyword, $url, $title, $ip, 0, time(), $row_id ); + $return['shorturl'] = yourls_link($keyword); + $return['statusCode'] = '200'; // 200 OK + } else { + // unknown database error, couldn't store result + $return['status'] = 'fail'; + $return['code'] = 'error:db'; + $return['message'] = yourls_s( 'Error saving url to database' ); + $return['errorCode'] = $return['statusCode'] = '500'; // 500 Internal Server Error + } + } catch (Exception $e) { + // Keyword supposed to be free but the INSERT caused an exception: most likely we're facing a + // concurrency problem. See Issue 2538. + $return['status'] = 'fail'; + $return['code'] = 'error:concurrency'; + $return['message'] = $e->getMessage(); + $return['errorCode'] = $return['statusCode'] = '503'; // 503 Service Unavailable } yourls_do_action( 'post_add_new_link', $url, $keyword, $title, $return ); - $return['statusCode'] = 200; // regardless of result, this is still a valid request return yourls_apply_filter( 'add_new_link', $return, $url, $keyword, $title ); } - /** * Determine the allowed character set in short URLs * * @return string Acceptable charset for short URLS keywords */ function yourls_get_shorturl_charset() { - static $charset = null; - if ( $charset !== null ) { - return $charset; - } - if ( defined( 'YOURLS_URL_CONVERT' ) && in_array( YOURLS_URL_CONVERT, [ 62, 64 ] ) ) { $charset = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; } @@ -193,6 +207,20 @@ function yourls_is_shorturl( $shorturl ) { return yourls_apply_filter( 'is_shorturl', $is_short, $shorturl ); } +/** + * Get the list of reserved keywords for URLs. + * + * @return array Array of reserved keywords + */ +function yourls_get_reserved_URL() { + global $yourls_reserved_URL; + if ( ! isset( $yourls_reserved_URL ) || ! is_array( $yourls_reserved_URL ) ) { + return array(); + } + + return $yourls_reserved_URL; +} + /** * Check to see if a given keyword is reserved (ie reserved URL or an existing page). Returns bool * @@ -200,11 +228,10 @@ function yourls_is_shorturl( $shorturl ) { * @return bool True if keyword reserved, false if free to be used */ function yourls_keyword_is_reserved( $keyword ) { - global $yourls_reserved_URL; $keyword = yourls_sanitize_keyword( $keyword ); $reserved = false; - if ( in_array( $keyword, $yourls_reserved_URL) + if ( in_array( $keyword, yourls_get_reserved_URL() ) or yourls_is_page($keyword) or is_dir( YOURLS_ABSPATH ."/$keyword" ) ) @@ -216,6 +243,8 @@ function yourls_keyword_is_reserved( $keyword ) { /** * Delete a link in the DB * + * @param string $keyword Short URL keyword + * @return int Number of links deleted */ function yourls_delete_link_by_keyword( $keyword ) { // Allow plugins to short-circuit the whole function @@ -226,7 +255,9 @@ function yourls_delete_link_by_keyword( $keyword ) { $table = YOURLS_DB_TABLE_URL; $keyword = yourls_sanitize_keyword($keyword); - $delete = yourls_get_db()->fetchAffected("DELETE FROM `$table` WHERE `keyword` = :keyword", array('keyword' => $keyword)); + $ydb = yourls_get_db('write-delete_link_by_keyword'); + $delete = $ydb->fetchAffected("DELETE FROM `$table` WHERE `keyword` = :keyword", array('keyword' => $keyword)); + $ydb->delete_infos($keyword); // Clear the cache. yourls_do_action( 'delete_link', $keyword, $delete ); return $delete; } @@ -234,8 +265,12 @@ function yourls_delete_link_by_keyword( $keyword ) { /** * SQL query to insert a new link in the DB. Returns boolean for success or failure of the inserting * + * @param string $url + * @param string $keyword + * @param string $title + * @return bool true if insert succeeded, false if failed */ -function yourls_insert_link_in_db( $url, $keyword, $title = '' ) { +function yourls_insert_link_in_db($url, $keyword, $title = '' ) { $url = yourls_sanitize_url($url); $keyword = yourls_sanitize_keyword($keyword); $title = yourls_sanitize_title($title); @@ -250,7 +285,14 @@ function yourls_insert_link_in_db( $url, $keyword, $title = '' ) { 'timestamp' => $timestamp, 'ip' => $ip, ); - $insert = yourls_get_db()->fetchAffected("INSERT INTO `$table` (`keyword`, `url`, `title`, `timestamp`, `ip`, `clicks`) VALUES(:keyword, :url, :title, :timestamp, :ip, 0);", $binds); + $ydb = yourls_get_db('write-insert_link_in_db'); + $insert = $ydb->fetchAffected("INSERT INTO `$table` (`keyword`, `url`, `title`, `timestamp`, `ip`, `clicks`) VALUES(:keyword, :url, :title, :timestamp, :ip, 0);", $binds); + + if ( $insert ) { + $infos = $binds; + $infos['clicks'] = 0; + $ydb->set_infos($keyword, $infos); + } yourls_do_action( 'insert_link', (bool)$insert, $url, $keyword, $title, $timestamp, $ip ); @@ -275,7 +317,7 @@ function yourls_long_url_exists( $url ) { $table = YOURLS_DB_TABLE_URL; $url = yourls_sanitize_url($url); - $url_exists = yourls_get_db()->fetchObject("SELECT * FROM `$table` WHERE `url` = :url", array('url'=>$url)); + $url_exists = yourls_get_db('read-long_url_exists')->fetchObject("SELECT * FROM `$table` WHERE `url` = :url", array('url'=>$url)); if ($url_exists === false) { $url_exists = NULL; @@ -287,14 +329,19 @@ function yourls_long_url_exists( $url ) { /** * Edit a link * + * @param string $url + * @param string $keyword + * @param string $newkeyword + * @param string $title + * @return array Result of the edit and link information if successful */ -function yourls_edit_link( $url, $keyword, $newkeyword='', $title='' ) { +function yourls_edit_link($url, $keyword, $newkeyword='', $title='' ) { // Allow plugins to short-circuit the whole function $pre = yourls_apply_filter( 'shunt_edit_link', null, $keyword, $url, $keyword, $newkeyword, $title ); if ( null !== $pre ) return $pre; - $ydb = yourls_get_db(); + $ydb = yourls_get_db('write-edit_link'); $table = YOURLS_DB_TABLE_URL; $url = yourls_sanitize_url($url); @@ -341,6 +388,10 @@ function yourls_edit_link( $url, $keyword, $newkeyword='', $title='' ) { ); $return['status'] = 'success'; $return['message'] = yourls__( 'Link updated in database' ); + $ydb->update_infos_if_exists($newkeyword, array('url' => $url, 'title' => $title)); // Clear the cache. + if ($keyword != $newkeyword) { + $ydb->delete_infos($keyword); // Clear the cache on the old keyword. + } } else { $return['status'] = 'fail'; $return['message'] = /* //translators: "Error updating http://someurl/ (Shorturl: http://sho.rt/blah)" */ yourls_s( 'Error updating %s (Short URL: %s)', yourls_esc_html(yourls_trim_long_string($url)), $keyword ) ; @@ -358,6 +409,9 @@ function yourls_edit_link( $url, $keyword, $newkeyword='', $title='' ) { /** * Update a title link (no checks for duplicates etc..) * + * @param string $keyword + * @param string $title + * @return int number of rows updated */ function yourls_edit_link_title( $keyword, $title ) { // Allow plugins to short-circuit the whole function @@ -370,7 +424,12 @@ function yourls_edit_link_title( $keyword, $title ) { $title = yourls_sanitize_title( $title ); $table = YOURLS_DB_TABLE_URL; - $update = yourls_get_db()->fetchAffected("UPDATE `$table` SET `title` = :title WHERE `keyword` = :keyword;", array('title' => $title, 'keyword' => $keyword)); + $ydb = yourls_get_db('write-edit_link_title'); + $update = $ydb->fetchAffected("UPDATE `$table` SET `title` = :title WHERE `keyword` = :keyword;", array('title' => $title, 'keyword' => $keyword)); + + if ( $update ) { + $ydb->update_infos_if_exists( $keyword, array('title' => $title) ); + } return $update; } @@ -393,7 +452,7 @@ function yourls_keyword_is_free( $keyword ) { /** * Check if a keyword matches a "page" * - * @see https://github.com/YOURLS/YOURLS/wiki/Pages + * @see https://docs.yourls.org/guide/extend/pages.html * @since 1.7.10 * @param string $keyword Short URL $keyword * @return bool true if is page, false otherwise @@ -443,7 +502,7 @@ function yourls_keyword_is_taken( $keyword, $use_cache = true ) { * @return false|object false if not found, object with URL properties if found */ function yourls_get_keyword_infos( $keyword, $use_cache = true ) { - $ydb = yourls_get_db(); + $ydb = yourls_get_db('read-get_keyword_infos'); $keyword = yourls_sanitize_keyword( $keyword ); yourls_do_action( 'pre_get_keyword', $keyword, $use_cache ); @@ -470,10 +529,14 @@ function yourls_get_keyword_infos( $keyword, $use_cache = true ) { } /** - * Return (string) selected information associated with a keyword. Optional $notfound = string default message if nothing found + * Return information associated with a keyword (eg clicks, URL, title...). Optional $notfound = string default message if nothing found * + * @param string $keyword Short URL keyword + * @param string $field Field to return (eg 'url', 'title', 'ip', 'clicks', 'timestamp', 'keyword') + * @param false|string $notfound Optional string to return if keyword not found + * @return mixed|string */ -function yourls_get_keyword_info( $keyword, $field, $notfound = false ) { +function yourls_get_keyword_info($keyword, $field, $notfound = false ) { // Allow plugins to short-circuit the whole function $pre = yourls_apply_filter( 'shunt_get_keyword_info', false, $keyword, $field, $notfound ); @@ -493,6 +556,9 @@ function yourls_get_keyword_info( $keyword, $field, $notfound = false ) { /** * Return title associated with keyword. Optional $notfound = string default message if nothing found * + * @param string $keyword Short URL keyword + * @param false|string $notfound Optional string to return if keyword not found + * @return mixed|string */ function yourls_get_keyword_title( $keyword, $notfound = false ) { return yourls_get_keyword_info( $keyword, 'title', $notfound ); @@ -501,6 +567,9 @@ function yourls_get_keyword_title( $keyword, $notfound = false ) { /** * Return long URL associated with keyword. Optional $notfound = string default message if nothing found * + * @param string $keyword Short URL keyword + * @param false|string $notfound Optional string to return if keyword not found + * @return mixed|string */ function yourls_get_keyword_longurl( $keyword, $notfound = false ) { return yourls_get_keyword_info( $keyword, 'url', $notfound ); @@ -509,6 +578,9 @@ function yourls_get_keyword_longurl( $keyword, $notfound = false ) { /** * Return number of clicks on a keyword. Optional $notfound = string default message if nothing found * + * @param string $keyword Short URL keyword + * @param false|string $notfound Optional string to return if keyword not found + * @return mixed|string */ function yourls_get_keyword_clicks( $keyword, $notfound = false ) { return yourls_get_keyword_info( $keyword, 'clicks', $notfound ); @@ -517,6 +589,9 @@ function yourls_get_keyword_clicks( $keyword, $notfound = false ) { /** * Return IP that added a keyword. Optional $notfound = string default message if nothing found * + * @param string $keyword Short URL keyword + * @param false|string $notfound Optional string to return if keyword not found + * @return mixed|string */ function yourls_get_keyword_IP( $keyword, $notfound = false ) { return yourls_get_keyword_info( $keyword, 'ip', $notfound ); @@ -525,6 +600,9 @@ function yourls_get_keyword_IP( $keyword, $notfound = false ) { /** * Return timestamp associated with a keyword. Optional $notfound = string default message if nothing found * + * @param string $keyword Short URL keyword + * @param false|string $notfound Optional string to return if keyword not found + * @return mixed|string */ function yourls_get_keyword_timestamp( $keyword, $notfound = false ) { return yourls_get_keyword_info( $keyword, 'timestamp', $notfound ); @@ -543,18 +621,17 @@ function yourls_get_keyword_stats( $shorturl ) { $table_url = YOURLS_DB_TABLE_URL; $shorturl = yourls_sanitize_keyword( $shorturl ); - $res = yourls_get_db()->fetchObject("SELECT * FROM `$table_url` WHERE `keyword` = :keyword", array('keyword' => $shorturl)); - $return = array(); + $res = yourls_get_db('read-get_keyword_stats')->fetchObject("SELECT * FROM `$table_url` WHERE `keyword` = :keyword", array('keyword' => $shorturl)); if( !$res ) { // non existent link $return = array( - 'statusCode' => 404, + 'statusCode' => '404', 'message' => 'Error: short URL not found', ); } else { $return = array( - 'statusCode' => 200, + 'statusCode' => '200', 'message' => 'success', 'link' => array( 'shorturl' => yourls_link($res->keyword), @@ -587,5 +664,5 @@ function yourls_get_longurl_keywords( $longurl, $order = 'ASC' ) { $sql .= " ORDER BY `keyword` ".$order; } - return yourls_apply_filter( 'get_longurl_keywords', yourls_get_db()->fetchCol($sql, array('url'=>$longurl)), $longurl ); + return yourls_apply_filter( 'get_longurl_keywords', yourls_get_db('read-get_longurl_keywords')->fetchCol($sql, array('url'=>$longurl)), $longurl ); } diff --git a/includes/functions-upgrade.php b/includes/functions-upgrade.php index 2de8e0e24..bff246eaf 100644 --- a/includes/functions-upgrade.php +++ b/includes/functions-upgrade.php @@ -5,10 +5,16 @@ * * Note to devs : prefer update function names using the SQL version, eg yourls_update_to_506(), * rather than using the YOURLS version number, eg yourls_update_to_18(). This is to allow having - * multiple SQL update during the dev cycle of the same Y0URLS version + * multiple SQL update during the dev cycle of the same YOURLS version * + * @param string|int $step + * @param string $oldver + * @param string $newver + * @param string|int $oldsql + * @param string|int $newsql + * @return void */ -function yourls_upgrade( $step, $oldver, $newver, $oldsql, $newsql ) { +function yourls_upgrade($step, $oldver, $newver, $oldsql, $newsql ) { /** * Sanitize input. Two notes : @@ -26,28 +32,28 @@ function yourls_upgrade( $step, $oldver, $newver, $oldsql, $newsql ) { yourls_maintenance_mode(true); // special case for 1.3: the upgrade is a multi step procedure - if( $oldsql == 100 ) { - yourls_upgrade_to_14( $step ); - } + if( $oldsql == 100 ) { + yourls_upgrade_to_14( $step ); + } - // other upgrades which are done in a single pass - switch( $step ) { + // other upgrades which are done in a single pass + switch( $step ) { - case 1: - case 2: - if( $oldsql < 210 ) - yourls_upgrade_to_141(); + case 1: + case 2: + if( $oldsql < 210 ) + yourls_upgrade_to_141(); - if( $oldsql < 220 ) - yourls_upgrade_to_143(); + if( $oldsql < 220 ) + yourls_upgrade_to_143(); - if( $oldsql < 250 ) - yourls_upgrade_to_15(); + if( $oldsql < 250 ) + yourls_upgrade_to_15(); - if( $oldsql < 482 ) - yourls_upgrade_482(); // that was somewhere 1.5 and 1.5.1 ... + if( $oldsql < 482 ) + yourls_upgrade_482(); // that was somewhere 1.5 and 1.5.1 ... - if( $oldsql < 506 ) { + if( $oldsql < 506 ) { /** * 505 was the botched update with the wrong collation, see #2766 * 506 is the updated collation. @@ -55,45 +61,74 @@ function yourls_upgrade( $step, $oldver, $newver, $oldsql, $newsql ) { * people on 505 to update to 506 * people before 505 to update to the FIXED complete upgrade */ - if( $oldsql == 505 ) { + if( $oldsql == 505 ) { yourls_upgrade_505_to_506(); } else { yourls_upgrade_to_506(); } } - yourls_redirect_javascript( yourls_admin_url( "upgrade.php?step=3" ) ); + if( $oldsql < 507 ) { + yourls_upgrade_to_507(); + } + + yourls_redirect_javascript( yourls_admin_url( "upgrade.php?step=3" ) ); - break; + break; - case 3: - // Update options to reflect latest version - yourls_update_option( 'version', YOURLS_VERSION ); - yourls_update_option( 'db_version', YOURLS_DB_VERSION ); + case 3: + // Update options to reflect latest version + yourls_update_option( 'version', YOURLS_VERSION ); + yourls_update_option( 'db_version', YOURLS_DB_VERSION ); yourls_maintenance_mode(false); - break; - } + break; + } } /************************** 1.6 -> 1.8 **************************/ +/** + * Add sort index for fast URL lookups. + * DB version 507. + */ +function yourls_upgrade_to_507() { + echo "

Adding index for url column. Please wait...

"; + + $table = YOURLS_DB_TABLE_URL; + + $query = sprintf("ALTER TABLE `%s` ADD INDEX `url_idx` (`url`(50));", $table); + + try { + yourls_get_db('write-upgrade_to_507')->perform($query); + } catch (\Exception $e) { + echo "

Unable to update the DB.

"; + echo "

Could not index urls. You will have to fix things manually :(. The error was +

";
+        echo $e->getMessage();
+        echo "\n
"; + die(); + } + + echo "

OK!

"; +} + /** * Update to 506, just the fix for people who had updated to master on 1.7.10 * */ function yourls_upgrade_505_to_506() { echo "

Updating DB. Please wait...

"; - // Fix collation which was wrongly set at first to utf8mb4_unicode_ci - $query = sprintf('ALTER TABLE `%s` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;', YOURLS_DB_TABLE_URL); + // Fix collation which was wrongly set at first to utf8mb4_unicode_ci + $query = sprintf('ALTER TABLE `%s` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;', YOURLS_DB_TABLE_URL); try { - yourls_get_db()->perform($query); + yourls_get_db('write-upgrade_505_to_506')->perform($query); } catch (\Exception $e) { echo "

Unable to update the DB.

"; echo "

Could not change collation. You will have to fix things manually :(. The error was

";
         echo $e->getMessage();
-        echo "/n
"; + echo "\n"; die(); } @@ -105,7 +140,7 @@ function yourls_upgrade_505_to_506() { * */ function yourls_upgrade_to_506() { - $ydb = yourls_get_db(); + $ydb = yourls_get_db('write-upgrade_to_506'); $error_msg = []; echo "

Updating DB. Please wait...

"; @@ -149,11 +184,11 @@ function yourls_upgrade_to_506() { * */ function yourls_upgrade_482() { - // Change URL title charset to UTF8 - $table_url = YOURLS_DB_TABLE_URL; - $sql = "ALTER TABLE `$table_url` CHANGE `title` `title` TEXT CHARACTER SET utf8;"; - yourls_get_db()->perform( $sql ); - echo "

Updating table structure. Please wait...

"; + // Change URL title charset to UTF8 + $table_url = YOURLS_DB_TABLE_URL; + $sql = "ALTER TABLE `$table_url` CHANGE `title` `title` TEXT CHARACTER SET utf8;"; + yourls_get_db('write-upgrade_482')->perform( $sql ); + echo "

Updating table structure. Please wait...

"; } /************************** 1.4.3 -> 1.5 **************************/ @@ -163,20 +198,20 @@ function yourls_upgrade_482() { * */ function yourls_upgrade_to_15( ) { - // Create empty 'active_plugins' entry in the option if needed - if( yourls_get_option( 'active_plugins' ) === false ) - yourls_add_option( 'active_plugins', array() ); - echo "

Enabling the plugin API. Please wait...

"; - - // Alter URL table to store titles - $table_url = YOURLS_DB_TABLE_URL; - $sql = "ALTER TABLE `$table_url` ADD `title` TEXT AFTER `url`;"; - yourls_get_db()->perform( $sql ); - echo "

Updating table structure. Please wait...

"; - - // Update .htaccess - yourls_create_htaccess(); - echo "

Updating .htaccess file. Please wait...

"; + // Create empty 'active_plugins' entry in the option if needed + if( yourls_get_option( 'active_plugins' ) === false ) + yourls_add_option( 'active_plugins', array() ); + echo "

Enabling the plugin API. Please wait...

"; + + // Alter URL table to store titles + $table_url = YOURLS_DB_TABLE_URL; + $sql = "ALTER TABLE `$table_url` ADD `title` TEXT AFTER `url`;"; + yourls_get_db('write-upgrade_to_15')->perform( $sql ); + echo "

Updating table structure. Please wait...

"; + + // Update .htaccess + yourls_create_htaccess(); + echo "

Updating .htaccess file. Please wait...

"; } /************************** 1.4.1 -> 1.4.3 **************************/ @@ -186,16 +221,16 @@ function yourls_upgrade_to_15( ) { * */ function yourls_upgrade_to_143( ) { - // Check if we have 'keyword' (borked install) or 'shorturl' (ok install) - $ydb = yourls_get_db(); - $table_log = YOURLS_DB_TABLE_LOG; - $sql = "SHOW COLUMNS FROM `$table_log`"; - $cols = $ydb->fetchObjects( $sql ); - if ( $cols[2]->Field == 'keyword' ) { - $sql = "ALTER TABLE `$table_log` CHANGE `keyword` `shorturl` VARCHAR( 200 ) BINARY;"; - $ydb->query( $sql ); - } - echo "

Structure of existing tables updated. Please wait...

"; + // Check if we have 'keyword' (borked install) or 'shorturl' (ok install) + $ydb = yourls_get_db('write-upgrade_to_143'); + $table_log = YOURLS_DB_TABLE_LOG; + $sql = "SHOW COLUMNS FROM `$table_log`"; + $cols = $ydb->fetchObjects( $sql ); + if ( $cols[2]->Field == 'keyword' ) { + $sql = "ALTER TABLE `$table_log` CHANGE `keyword` `shorturl` VARCHAR( 200 ) BINARY;"; + $ydb->query( $sql ); + } + echo "

Structure of existing tables updated. Please wait...

"; } /************************** 1.4 -> 1.4.1 **************************/ @@ -205,13 +240,13 @@ function yourls_upgrade_to_143( ) { * */ function yourls_upgrade_to_141( ) { - // Kill old cookies from 1.3 and prior - setcookie('yourls_username', null, time() - 3600 ); - setcookie('yourls_password', null, time() - 3600 ); - // alter table URL - yourls_alter_url_table_to_141(); - // recreate the htaccess file if needed - yourls_create_htaccess(); + // Kill old cookies from 1.3 and prior + setcookie('yourls_username', '', time() - 3600 ); + setcookie('yourls_password', '', time() - 3600 ); + // alter table URL + yourls_alter_url_table_to_141(); + // recreate the htaccess file if needed + yourls_create_htaccess(); } /** @@ -219,10 +254,10 @@ function yourls_upgrade_to_141( ) { * */ function yourls_alter_url_table_to_141() { - $table_url = YOURLS_DB_TABLE_URL; - $alter = "ALTER TABLE `$table_url` CHANGE `keyword` `keyword` VARCHAR( 200 ) BINARY, CHANGE `url` `url` TEXT BINARY "; - yourls_get_db()->perform( $alter ); - echo "

Structure of existing tables updated. Please wait...

"; + $table_url = YOURLS_DB_TABLE_URL; + $alter = "ALTER TABLE `$table_url` CHANGE `keyword` `keyword` VARCHAR( 200 ) BINARY, CHANGE `url` `url` TEXT BINARY "; + yourls_get_db('write-alter_url_table_to_141')->perform( $alter ); + echo "

Structure of existing tables updated. Please wait...

"; } @@ -234,35 +269,35 @@ function yourls_alter_url_table_to_141() { */ function yourls_upgrade_to_14( $step ) { - switch( $step ) { - case 1: - // create table log & table options - // update table url structure - // update .htaccess - yourls_create_tables_for_14(); // no value returned, assuming it went OK - yourls_alter_url_table_to_14(); // no value returned, assuming it went OK - $clean = yourls_clean_htaccess_for_14(); // returns bool - $create = yourls_create_htaccess(); // returns bool - if ( !$create ) - echo "

Please create your .htaccess file (I could not do it for you). Please refer to http://yourls.org/htaccess."; - yourls_redirect_javascript( yourls_admin_url( "upgrade.php?step=2&oldver=1.3&newver=1.4&oldsql=100&newsql=200" ), $create ); - break; - - case 2: - // convert each link in table url - yourls_update_table_to_14(); - break; - - case 3: - // update table url structure part 2: recreate indexes - yourls_alter_url_table_to_14_part_two(); - // update version & db_version & next_id in the option table - // attempt to drop YOURLS_DB_TABLE_NEXTDEC - yourls_update_options_to_14(); - // Now upgrade to 1.4.1 - yourls_redirect_javascript( yourls_admin_url( "upgrade.php?step=1&oldver=1.4&newver=1.4.1&oldsql=200&newsql=210" ) ); - break; - } + switch( $step ) { + case 1: + // create table log & table options + // update table url structure + // update .htaccess + yourls_create_tables_for_14(); // no value returned, assuming it went OK + yourls_alter_url_table_to_14(); // no value returned, assuming it went OK + $clean = yourls_clean_htaccess_for_14(); // returns bool + $create = yourls_create_htaccess(); // returns bool + if ( !$create ) + echo "

Please create your .htaccess file (I could not do it for you). Please refer to http://yourls.org/htaccess."; + yourls_redirect_javascript( yourls_admin_url( "upgrade.php?step=2&oldver=1.3&newver=1.4&oldsql=100&newsql=200" ), $create ); + break; + + case 2: + // convert each link in table url + yourls_update_table_to_14(); + break; + + case 3: + // update table url structure part 2: recreate indexes + yourls_alter_url_table_to_14_part_two(); + // update version & db_version & next_id in the option table + // attempt to drop YOURLS_DB_TABLE_NEXTDEC + yourls_update_options_to_14(); + // Now upgrade to 1.4.1 + yourls_redirect_javascript( yourls_admin_url( "upgrade.php?step=1&oldver=1.4&newver=1.4.1&oldsql=200&newsql=210" ) ); + break; + } } /** @@ -270,17 +305,17 @@ function yourls_upgrade_to_14( $step ) { * */ function yourls_update_options_to_14() { - yourls_update_option( 'version', '1.4' ); - yourls_update_option( 'db_version', '200' ); - - if( defined('YOURLS_DB_TABLE_NEXTDEC') ) { - $table = YOURLS_DB_TABLE_NEXTDEC; - $next_id = yourls_get_db()->fetchValue("SELECT `next_id` FROM `$table`"); - yourls_update_option( 'next_id', $next_id ); - yourls_get_db()->perform( "DROP TABLE `$table`" ); - } else { - yourls_update_option( 'next_id', 1 ); // In case someone mistakenly deleted the next_id constant or table too early - } + yourls_update_option( 'version', '1.4' ); + yourls_update_option( 'db_version', '200' ); + + if( defined('YOURLS_DB_TABLE_NEXTDEC') ) { + $table = YOURLS_DB_TABLE_NEXTDEC; + $next_id = yourls_get_db('read-update_options_to_14')->fetchValue("SELECT `next_id` FROM `$table`"); + yourls_update_option( 'next_id', $next_id ); + yourls_get_db('write-update_options_to_14')->perform( "DROP TABLE `$table`" ); + } else { + yourls_update_option( 'next_id', 1 ); // In case someone mistakenly deleted the next_id constant or table too early + } } /** @@ -288,37 +323,37 @@ function yourls_update_options_to_14() { * */ function yourls_create_tables_for_14() { - $ydb = yourls_get_db(); - - $queries = array(); - - $queries[YOURLS_DB_TABLE_OPTIONS] = - 'CREATE TABLE IF NOT EXISTS `'.YOURLS_DB_TABLE_OPTIONS.'` ('. - '`option_id` int(11) unsigned NOT NULL auto_increment,'. - '`option_name` varchar(64) NOT NULL default "",'. - '`option_value` longtext NOT NULL,'. - 'PRIMARY KEY (`option_id`,`option_name`),'. - 'KEY `option_name` (`option_name`)'. - ');'; - - $queries[YOURLS_DB_TABLE_LOG] = - 'CREATE TABLE IF NOT EXISTS `'.YOURLS_DB_TABLE_LOG.'` ('. - '`click_id` int(11) NOT NULL auto_increment,'. - '`click_time` datetime NOT NULL,'. - '`shorturl` varchar(200) NOT NULL,'. - '`referrer` varchar(200) NOT NULL,'. - '`user_agent` varchar(255) NOT NULL,'. - '`ip_address` varchar(41) NOT NULL,'. - '`country_code` char(2) NOT NULL,'. - 'PRIMARY KEY (`click_id`),'. - 'KEY `shorturl` (`shorturl`)'. - ');'; - - foreach( $queries as $query ) { - $ydb->perform( $query ); // There's no result to be returned to check if table was created (except making another query to check table existence, which we'll avoid) - } - - echo "

New tables created. Please wait...

"; + $ydb = yourls_get_db('write-create_tables_for_14'); + + $queries = array(); + + $queries[YOURLS_DB_TABLE_OPTIONS] = + 'CREATE TABLE IF NOT EXISTS `'.YOURLS_DB_TABLE_OPTIONS.'` ('. + '`option_id` int(11) unsigned NOT NULL auto_increment,'. + '`option_name` varchar(64) NOT NULL default "",'. + '`option_value` longtext NOT NULL,'. + 'PRIMARY KEY (`option_id`,`option_name`),'. + 'KEY `option_name` (`option_name`)'. + ');'; + + $queries[YOURLS_DB_TABLE_LOG] = + 'CREATE TABLE IF NOT EXISTS `'.YOURLS_DB_TABLE_LOG.'` ('. + '`click_id` int(11) NOT NULL auto_increment,'. + '`click_time` datetime NOT NULL,'. + '`shorturl` varchar(200) NOT NULL,'. + '`referrer` varchar(200) NOT NULL,'. + '`user_agent` varchar(255) NOT NULL,'. + '`ip_address` varchar(41) NOT NULL,'. + '`country_code` char(2) NOT NULL,'. + 'PRIMARY KEY (`click_id`),'. + 'KEY `shorturl` (`shorturl`)'. + ');'; + + foreach( $queries as $query ) { + $ydb->perform( $query ); // There's no result to be returned to check if table was created (except making another query to check table existence, which we'll avoid) + } + + echo "

New tables created. Please wait...

"; } @@ -327,20 +362,20 @@ function yourls_create_tables_for_14() { * */ function yourls_alter_url_table_to_14() { - $ydb = yourls_get_db(); - $table = YOURLS_DB_TABLE_URL; + $ydb = yourls_get_db('write-alter_url_table_to_14'); + $table = YOURLS_DB_TABLE_URL; - $alters = array(); - $results = array(); - $alters[] = "ALTER TABLE `$table` CHANGE `id` `keyword` VARCHAR( 200 ) NOT NULL"; - $alters[] = "ALTER TABLE `$table` CHANGE `url` `url` TEXT NOT NULL"; - $alters[] = "ALTER TABLE `$table` DROP PRIMARY KEY"; + $alters = array(); + $results = array(); + $alters[] = "ALTER TABLE `$table` CHANGE `id` `keyword` VARCHAR( 200 ) NOT NULL"; + $alters[] = "ALTER TABLE `$table` CHANGE `url` `url` TEXT NOT NULL"; + $alters[] = "ALTER TABLE `$table` DROP PRIMARY KEY"; - foreach ( $alters as $query ) { - $ydb->perform( $query ); - } + foreach ( $alters as $query ) { + $ydb->perform( $query ); + } - echo "

Structure of existing tables updated. Please wait...

"; + echo "

Structure of existing tables updated. Please wait...

"; } /** @@ -348,19 +383,19 @@ function yourls_alter_url_table_to_14() { * */ function yourls_alter_url_table_to_14_part_two() { - $ydb = yourls_get_db(); - $table = YOURLS_DB_TABLE_URL; + $ydb = yourls_get_db('write-alter_url_table_to_14_part_two'); + $table = YOURLS_DB_TABLE_URL; - $alters = array(); - $alters[] = "ALTER TABLE `$table` ADD PRIMARY KEY ( `keyword` )"; - $alters[] = "ALTER TABLE `$table` ADD INDEX ( `ip` )"; - $alters[] = "ALTER TABLE `$table` ADD INDEX ( `timestamp` )"; + $alters = array(); + $alters[] = "ALTER TABLE `$table` ADD PRIMARY KEY ( `keyword` )"; + $alters[] = "ALTER TABLE `$table` ADD INDEX ( `ip` )"; + $alters[] = "ALTER TABLE `$table` ADD INDEX ( `timestamp` )"; - foreach ( $alters as $query ) { - $ydb->perform( $query ); - } + foreach ( $alters as $query ) { + $ydb->perform( $query ); + } - echo "

New table index created

"; + echo "

New table index created

"; } /** @@ -368,52 +403,52 @@ function yourls_alter_url_table_to_14_part_two() { * */ function yourls_update_table_to_14() { - $ydb = yourls_get_db(); - $table = YOURLS_DB_TABLE_URL; - - // Modify each link to reflect new structure - $chunk = 45; - $from = isset($_GET['from']) ? intval( $_GET['from'] ) : 0 ; - $total = yourls_get_db_stats(); - $total = $total['total_links']; - - $sql = "SELECT `keyword`,`url` FROM `$table` WHERE 1=1 ORDER BY `url` ASC LIMIT $from, $chunk ;"; - - $rows = $ydb->fetchObjects($sql); - - $count = 0; - $queries = 0; - foreach( $rows as $row ) { - $keyword = $row->keyword; - $url = $row->url; - $newkeyword = yourls_int2string( $keyword ); - if( true === $ydb->perform("UPDATE `$table` SET `keyword` = '$newkeyword' WHERE `url` = '$url';") ) { - $queries++; - } else { - echo "

Huho... Could not update rown with url='$url', from keyword '$keyword' to keyword '$newkeyword'

"; // Find what went wrong :/ - } - $count++; - } - - // All done for this chunk of queries, did it all go as expected? - $success = true; - if( $count != $queries ) { - $success = false; - $num = $count - $queries; - echo "

$num error(s) occured while updating the URL table :(

"; - } - - if ( $count == $chunk ) { - // there are probably other rows to convert - $from = $from + $chunk; - $remain = $total - $from; - echo "

Converted $chunk database rows ($remain remaining). Continuing... Please do not close this window until it's finished!

"; - yourls_redirect_javascript( yourls_admin_url( "upgrade.php?step=2&oldver=1.3&newver=1.4&oldsql=100&newsql=200&from=$from" ), $success ); - } else { - // All done - echo '

All rows converted! Please wait...

'; - yourls_redirect_javascript( yourls_admin_url( "upgrade.php?step=3&oldver=1.3&newver=1.4&oldsql=100&newsql=200" ), $success ); - } + $ydb = yourls_get_db('write-update_table_to_14'); + $table = YOURLS_DB_TABLE_URL; + + // Modify each link to reflect new structure + $chunk = 45; + $from = isset($_GET['from']) ? intval( $_GET['from'] ) : 0 ; + $total = yourls_get_db_stats(); + $total = $total['total_links']; + + $sql = "SELECT `keyword`,`url` FROM `$table` WHERE 1=1 ORDER BY `url` ASC LIMIT $from, $chunk ;"; + + $rows = $ydb->fetchObjects($sql); + + $count = 0; + $queries = 0; + foreach( $rows as $row ) { + $keyword = $row->keyword; + $url = $row->url; + $newkeyword = yourls_int2string( $keyword ); + if( true === $ydb->perform("UPDATE `$table` SET `keyword` = '$newkeyword' WHERE `url` = '$url';") ) { + $queries++; + } else { + echo "

Huho... Could not update rown with url='$url', from keyword '$keyword' to keyword '$newkeyword'

"; // Find what went wrong :/ + } + $count++; + } + + // All done for this chunk of queries, did it all go as expected? + $success = true; + if( $count != $queries ) { + $success = false; + $num = $count - $queries; + echo "

$num error(s) occurred while updating the URL table :(

"; + } + + if ( $count == $chunk ) { + // there are probably other rows to convert + $from = $from + $chunk; + $remain = $total - $from; + echo "

Converted $chunk database rows ($remain remaining). Continuing... Please do not close this window until it's finished!

"; + yourls_redirect_javascript( yourls_admin_url( "upgrade.php?step=2&oldver=1.3&newver=1.4&oldsql=100&newsql=200&from=$from" ), $success ); + } else { + // All done + echo '

All rows converted! Please wait...

'; + yourls_redirect_javascript( yourls_admin_url( "upgrade.php?step=3&oldver=1.3&newver=1.4&oldsql=100&newsql=200" ), $success ); + } } @@ -422,27 +457,26 @@ function yourls_update_table_to_14() { * */ function yourls_clean_htaccess_for_14() { - $filename = YOURLS_ABSPATH.'/.htaccess'; - - $result = false; - if( is_writeable( $filename ) ) { - $contents = implode( '', file( $filename ) ); - // remove "ShortURL" block - $contents = preg_replace( '/# BEGIN ShortURL.*# END ShortURL/s', '', $contents ); - // comment out deprecated RewriteRule - $find = 'RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization},L]'; - $replace = "# You can safely remove this 5 lines block -- it's no longer used in YOURLS\n". - "# $find"; - $contents = str_replace( $find, $replace, $contents ); - - // Write cleaned file - $f = fopen( $filename, 'w' ); - fwrite( $f, $contents ); - fclose( $f ); - - $result = true; - } - - return $result; -} + $filename = YOURLS_ABSPATH.'/.htaccess'; + + $result = false; + if( is_writeable( $filename ) ) { + $contents = implode( '', file( $filename ) ); + // remove "ShortURL" block + $contents = preg_replace( '/# BEGIN ShortURL.*# END ShortURL/s', '', $contents ); + // comment out deprecated RewriteRule + $find = 'RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization},L]'; + $replace = "# You can safely remove this 5 lines block -- it's no longer used in YOURLS\n". + "# $find"; + $contents = str_replace( $find, $replace, $contents ); + + // Write cleaned file + $f = fopen( $filename, 'w' ); + fwrite( $f, $contents ); + fclose( $f ); + + $result = true; + } + return $result; +} diff --git a/includes/functions.php b/includes/functions.php index 06f75f863..3884e74bd 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -6,7 +6,8 @@ /** * Make an optimized regexp pattern from a string of characters - * @param $string + * + * @param string $string * @return string */ function yourls_make_regexp_pattern( $string ) { @@ -16,26 +17,27 @@ function yourls_make_regexp_pattern( $string ) { } /** - * Function: Get client IP Address. Returns a DB safe string. + * Get client IP Address. Returns a DB safe string. + * * @return string */ function yourls_get_IP() { - $ip = ''; - - // Precedence: if set, X-Forwarded-For > HTTP_X_FORWARDED_FOR > HTTP_CLIENT_IP > HTTP_VIA > REMOTE_ADDR - $headers = [ 'X-Forwarded-For', 'HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'HTTP_VIA', 'REMOTE_ADDR' ]; - foreach( $headers as $header ) { - if ( !empty( $_SERVER[ $header ] ) ) { - $ip = $_SERVER[ $header ]; - break; - } - } - - // headers can contain multiple IPs (X-Forwarded-For = client, proxy1, proxy2). Take first one. - if ( strpos( $ip, ',' ) !== false ) - $ip = substr( $ip, 0, strpos( $ip, ',' ) ); - - return (string)yourls_apply_filter( 'get_IP', yourls_sanitize_ip( $ip ) ); + $ip = ''; + + // Precedence: if set, X-Forwarded-For > HTTP_X_FORWARDED_FOR > HTTP_CLIENT_IP > HTTP_VIA > REMOTE_ADDR + $headers = [ 'X-Forwarded-For', 'HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'HTTP_VIA', 'REMOTE_ADDR' ]; + foreach( $headers as $header ) { + if ( !empty( $_SERVER[ $header ] ) ) { + $ip = $_SERVER[ $header ]; + break; + } + } + + // headers can contain multiple IPs (X-Forwarded-For = client, proxy1, proxy2). Take first one. + if ( strpos( $ip, ',' ) !== false ) + $ip = substr( $ip, 0, strpos( $ip, ',' ) ); + + return (string)yourls_apply_filter( 'get_IP', yourls_sanitize_ip( $ip ) ); } /** @@ -45,115 +47,154 @@ function yourls_get_IP() { * @return int id of next link */ function yourls_get_next_decimal() { - return (int)yourls_apply_filter( 'get_next_decimal', (int)yourls_get_option( 'next_id' ) ); + return (int)yourls_apply_filter( 'get_next_decimal', (int)yourls_get_option( 'next_id' ) ); } /** * Update id for next link with no custom keyword * * Note: this function relies upon yourls_update_option(), which will return either true or false - * depending if there has been an actual MySQL query updating the DB. - * In other words, this function may return false yet this would not mean it has functionnaly failed - * In other words I'm not sure we really need this function to return something :face_with_eyes_looking_up: + * depending upon if there has been an actual MySQL query updating the DB. + * In other words, this function may return false yet this would not mean it has functionally failed + * In other words I'm not sure if we really need this function to return something :face_with_eyes_looking_up: * See issue 2621 for more on this. * * @since 1.0 - * @param integer $int id for next link - * @return bool true or false depending on if there has been an actual MySQL query. See note above. + * @param integer $int id for next link + * @return bool true or false depending on if there has been an actual MySQL query. See note above. */ -function yourls_update_next_decimal( $int = '' ) { - $int = ( $int == '' ) ? yourls_get_next_decimal() + 1 : (int)$int ; - $update = yourls_update_option( 'next_id', $int ); - yourls_do_action( 'update_next_decimal', $int, $update ); - return $update; +function yourls_update_next_decimal( $int = 0 ) { + $int = ( $int == 0 ) ? yourls_get_next_decimal() + 1 : (int)$int ; + $update = yourls_update_option( 'next_id', $int ); + yourls_do_action( 'update_next_decimal', $int, $update ); + return $update; } /** * Return XML output. + * * @param array $array * @return string */ function yourls_xml_encode( $array ) { - return (\Spatie\ArrayToXml\ArrayToXml::convert($array)); + return (\Spatie\ArrayToXml\ArrayToXml::convert($array, '', true, 'UTF-8')); } /** * Update click count on a short URL. Return 0/1 for error/success. + * * @param string $keyword - * @param bool $clicks - * @return mixed|string + * @param false|int $clicks + * @return int 0 or 1 for error/success */ function yourls_update_clicks( $keyword, $clicks = false ) { - // Allow plugins to short-circuit the whole function - $pre = yourls_apply_filter( 'shunt_update_clicks', false, $keyword, $clicks ); - if ( false !== $pre ) - return $pre; - - $keyword = yourls_sanitize_keyword( $keyword ); - $table = YOURLS_DB_TABLE_URL; - if ( $clicks !== false && is_int( $clicks ) && $clicks >= 0 ) - $update = yourls_get_db()->fetchAffected( "UPDATE `$table` SET `clicks` = :clicks WHERE `keyword` = :keyword", [ 'clicks' => $clicks, 'keyword' => $keyword ] ); - else - $update = yourls_get_db()->fetchAffected( "UPDATE `$table` SET `clicks` = clicks + 1 WHERE `keyword` = :keyword", [ 'keyword' => $keyword ] ); - - yourls_do_action( 'update_clicks', $keyword, $update, $clicks ); - return $update; + // Allow plugins to short-circuit the whole function + $pre = yourls_apply_filter( 'shunt_update_clicks', false, $keyword, $clicks ); + if ( false !== $pre ) { + return $pre; + } + + $keyword = yourls_sanitize_keyword( $keyword ); + $table = YOURLS_DB_TABLE_URL; + if ( $clicks !== false && is_int( $clicks ) && $clicks >= 0 ) { + $update = "UPDATE `$table` SET `clicks` = :clicks WHERE `keyword` = :keyword"; + $values = [ 'clicks' => $clicks, 'keyword' => $keyword ]; + $update_type = 'set'; + } else { + $update = "UPDATE `$table` SET `clicks` = clicks + 1 WHERE `keyword` = :keyword"; + $values = [ 'keyword' => $keyword ]; + $update_type = 'increment'; + } + + $ydb = yourls_get_db('write-update_clicks'); + + // Try and update click count. An error probably means a concurrency problem : just skip the update + try { + $result = $ydb->fetchAffected($update, $values); + } catch (Exception $e) { + $result = 0; + } + + if ( $result ) { + if ( $ydb->has_infos($keyword) ) { + if ( $update_type === 'increment' ) { + $infos = $ydb->get_infos($keyword); + if ( isset( $infos['clicks'] ) ) { + $infos['clicks']++; + $ydb->set_infos($keyword, $infos); + } else { + $ydb->delete_infos($keyword); // We don't know why it's missing, so just purge the cache. + } + } elseif ( $update_type === 'set' ) { + $ydb->update_infos_if_exists($keyword, ['clicks' => $clicks]); + } + } + } + + yourls_do_action( 'update_clicks', $keyword, $result, $clicks ); + + return $result; } + /** * Return array of stats. (string)$filter is 'bottom', 'last', 'rand' or 'top'. (int)$limit is the number of links to return * + * @param string $filter 'bottom', 'last', 'rand' or 'top' + * @param int $limit Number of links to return + * @param int $start Offset to start from + * @return array Array of links */ -function yourls_get_stats( $filter = 'top', $limit = 10, $start = 0 ) { - switch( $filter ) { - case 'bottom': - $sort_by = '`clicks`'; - $sort_order = 'asc'; - break; - case 'last': - $sort_by = '`timestamp`'; - $sort_order = 'desc'; - break; - case 'rand': - case 'random': - $sort_by = 'RAND()'; - $sort_order = ''; - break; - case 'top': - default: - $sort_by = '`clicks`'; - $sort_order = 'desc'; - break; - } - - // Fetch links - $limit = intval( $limit ); - $start = intval( $start ); - if ( $limit > 0 ) { - - $table_url = YOURLS_DB_TABLE_URL; - $results = yourls_get_db()->fetchObjects( "SELECT * FROM `$table_url` WHERE 1=1 ORDER BY $sort_by $sort_order LIMIT $start, $limit;" ); - - $return = []; - $i = 1; - - foreach ( (array)$results as $res ) { - $return['links']['link_'.$i++] = [ - 'shorturl' => yourls_link($res->keyword), - 'url' => $res->url, - 'title' => $res->title, - 'timestamp'=> $res->timestamp, - 'ip' => $res->ip, - 'clicks' => $res->clicks, +function yourls_get_stats($filter = 'top', $limit = 10, $start = 0) { + switch( $filter ) { + case 'bottom': + $sort_by = '`clicks`'; + $sort_order = 'asc'; + break; + case 'last': + $sort_by = '`timestamp`'; + $sort_order = 'desc'; + break; + case 'rand': + case 'random': + $sort_by = 'RAND()'; + $sort_order = ''; + break; + case 'top': + default: + $sort_by = '`clicks`'; + $sort_order = 'desc'; + break; + } + + // Fetch links + $limit = intval( $limit ); + $start = intval( $start ); + if ( $limit > 0 ) { + + $table_url = YOURLS_DB_TABLE_URL; + $results = yourls_get_db('read-get_stats')->fetchObjects( "SELECT * FROM `$table_url` WHERE 1=1 ORDER BY $sort_by $sort_order LIMIT $start, $limit;" ); + + $return = []; + $i = 1; + + foreach ( (array)$results as $res ) { + $return['links']['link_'.$i++] = [ + 'shorturl' => yourls_link($res->keyword), + 'url' => $res->url, + 'title' => $res->title, + 'timestamp'=> $res->timestamp, + 'ip' => $res->ip, + 'clicks' => $res->clicks, ]; - } - } + } + } - $return['stats'] = yourls_get_db_stats(); + $return['stats'] = yourls_get_db_stats(); - $return['statusCode'] = 200; + $return['statusCode'] = '200'; - return yourls_apply_filter( 'get_stats', $return, $filter, $limit, $start ); + return yourls_apply_filter( 'get_stats', $return, $filter, $limit, $start ); } /** @@ -163,21 +204,22 @@ function yourls_get_stats( $filter = 'top', $limit = 10, $start = 0 ) { * $where['sql'] will concatenate SQL clauses: $where['sql'] = ' AND something = :value AND otherthing < :othervalue'; * $where['binds'] will hold the (name => value) placeholder pairs: $where['binds'] = array('value' => $value, 'othervalue' => $value2) * - * @param $where array See comment above + * @param array $where See comment above * @return array */ function yourls_get_db_stats( $where = [ 'sql' => '', 'binds' => [] ] ) { - $table_url = YOURLS_DB_TABLE_URL; + $table_url = YOURLS_DB_TABLE_URL; - $totals = yourls_get_db()->fetchObject( "SELECT COUNT(keyword) as count, SUM(clicks) as sum FROM `$table_url` WHERE 1=1 " . $where['sql'] , $where['binds'] ); - $return = [ 'total_links' => $totals->count, 'total_clicks' => $totals->sum ]; + $totals = yourls_get_db('read-get_db_stats')->fetchObject( "SELECT COUNT(keyword) as count, SUM(clicks) as sum FROM `$table_url` WHERE 1=1 " . $where['sql'] , $where['binds'] ); + $return = [ 'total_links' => $totals->count, 'total_clicks' => $totals->sum ]; - return yourls_apply_filter( 'get_db_stats', $return, $where ); + return yourls_apply_filter( 'get_db_stats', $return, $where ); } /** * Returns a sanitized a user agent string. Given what I found on http://www.user-agents.org/ it should be OK. * + * @return string */ function yourls_get_user_agent() { $ua = '-'; @@ -208,63 +250,86 @@ function yourls_get_referrer() { * is achieved with PHP's header(). If headers have been sent already and we're not in a command line * client, redirection occurs with Javascript. * + * Note: yourls_redirect() does not exit automatically, and should almost always be followed by a call to exit() + * to prevent the script from continuing. + * * @since 1.4 * @param string $location URL to redirect to * @param int $code HTTP status code to send * @return int 1 for header redirection, 2 for js redirection, 3 otherwise (CLI) */ function yourls_redirect( $location, $code = 301 ) { - yourls_do_action( 'pre_redirect', $location, $code ); - $location = yourls_apply_filter( 'redirect_location', $location, $code ); - $code = yourls_apply_filter( 'redirect_code', $code, $location ); - - // Redirect, either properly if possible, or via Javascript otherwise - if( !headers_sent() ) { - yourls_status_header( $code ); - header( "Location: $location" ); + yourls_do_action( 'pre_redirect', $location, $code ); + $location = yourls_apply_filter( 'redirect_location', $location, $code ); + $code = yourls_apply_filter( 'redirect_code', $code, $location ); + + // Redirect, either properly if possible, or via Javascript otherwise + if( !headers_sent() ) { + yourls_status_header( $code ); + header( "Location: $location" ); return 1; - } + } - // Headers sent : redirect with JS if not in CLI - if( php_sapi_name() !== 'cli') { + // Headers sent : redirect with JS if not in CLI + if( php_sapi_name() !== 'cli') { yourls_redirect_javascript( $location ); return 2; - } + } - // We're in CLI - return 3; + // We're in CLI + return 3; } /** * Redirect to an existing short URL * * Redirect client to an existing short URL (no check performed) and execute misc tasks: update - * clicks for short URL, update logs, and send a nocache header to prevent bots indexing short - * URLS (see #2202) + * clicks for short URL, update logs, and send an X-Robots-Tag header to control indexing of a page. * * @since 1.7.3 * @param string $url * @param string $keyword + * @return void */ function yourls_redirect_shorturl($url, $keyword) { yourls_do_action( 'redirect_shorturl', $url, $keyword ); - // Update click count in main table + // Attempt to update click count in main table yourls_update_clicks( $keyword ); // Update detailed log for stats yourls_log_redirect( $keyword ); - // Tell (Google)bots not to index this short URL, see #2202 - if ( !headers_sent() ) { - header( "X-Robots-Tag: noindex", true ); - } + // Send an X-Robots-Tag header + yourls_robots_tag_header(); yourls_redirect( $url, 301 ); } /** - * Send headers to explicitely tell browser not to cache content or redirection + * Send an X-Robots-Tag header. See #3486 + * + * @since 1.9.2 + * @return void + */ +function yourls_robots_tag_header() { + // Allow plugins to short-circuit the whole function + $pre = yourls_apply_filter( 'shunt_robots_tag_header', false ); + if ( false !== $pre ) { + return $pre; + } + + // By default, we're sending a 'noindex' header + $tag = yourls_apply_filter( 'robots_tag_header', 'noindex' ); + $replace = yourls_apply_filter( 'robots_tag_header_replace', true ); + if ( !headers_sent() ) { + header( "X-Robots-Tag: $tag", $replace ); + } +} + + +/** + * Send headers to explicitly tell browser not to cache content or redirection * * @since 1.7.10 * @return void @@ -310,12 +375,12 @@ function yourls_no_frame_header() { */ function yourls_content_type_header( $type ) { yourls_do_action( 'content_type_header', $type ); - if( !headers_sent() ) { - $charset = yourls_apply_filter( 'content_type_header_charset', 'utf-8' ); - header( "Content-Type: $type; charset=$charset" ); - return true; - } - return false; + if( !headers_sent() ) { + $charset = yourls_apply_filter( 'content_type_header_charset', 'utf-8' ); + header( "Content-Type: $type; charset=$charset" ); + return true; + } + return false; } /** @@ -326,19 +391,19 @@ function yourls_content_type_header( $type ) { * @return bool whether header was sent */ function yourls_status_header( $code = 200 ) { - yourls_do_action( 'status_header', $code ); + yourls_do_action( 'status_header', $code ); - if( headers_sent() ) - return false; + if( headers_sent() ) + return false; - $protocol = $_SERVER['SERVER_PROTOCOL']; - if ( 'HTTP/1.1' != $protocol && 'HTTP/1.0' != $protocol ) - $protocol = 'HTTP/1.0'; + $protocol = $_SERVER['SERVER_PROTOCOL']; + if ( 'HTTP/1.1' != $protocol && 'HTTP/1.0' != $protocol ) + $protocol = 'HTTP/1.0'; - $code = intval( $code ); - $desc = yourls_get_HTTP_status( $code ); + $code = intval( $code ); + $desc = yourls_get_HTTP_status( $code ); - @header ("$protocol $code $desc"); // This causes problems on IIS and some FastCGI setups + @header ("$protocol $code $desc"); // This causes problems on IIS and some FastCGI setups return true; } @@ -349,6 +414,7 @@ function yourls_status_header( $code = 200 ) { * * @param string $location * @param bool $dontwait + * @return void */ function yourls_redirect_javascript( $location, $dontwait = true ) { yourls_do_action( 'pre_redirect_javascript', $location, $dontwait ); @@ -356,10 +422,10 @@ function yourls_redirect_javascript( $location, $dontwait = true ) { if ( $dontwait ) { $message = yourls_s( 'if you are not redirected after 10 seconds, please click here', $location ); echo << - window.location="$location"; - - ($message) + + ($message) REDIR; } else { @@ -370,70 +436,71 @@ function yourls_redirect_javascript( $location, $dontwait = true ) { /** * Return an HTTP status code + * * @param int $code * @return string */ function yourls_get_HTTP_status( $code ) { - $code = intval( $code ); - $headers_desc = [ - 100 => 'Continue', - 101 => 'Switching Protocols', - 102 => 'Processing', - - 200 => 'OK', - 201 => 'Created', - 202 => 'Accepted', - 203 => 'Non-Authoritative Information', - 204 => 'No Content', - 205 => 'Reset Content', - 206 => 'Partial Content', - 207 => 'Multi-Status', - 226 => 'IM Used', - - 300 => 'Multiple Choices', - 301 => 'Moved Permanently', - 302 => 'Found', - 303 => 'See Other', - 304 => 'Not Modified', - 305 => 'Use Proxy', - 306 => 'Reserved', - 307 => 'Temporary Redirect', - - 400 => 'Bad Request', - 401 => 'Unauthorized', - 402 => 'Payment Required', - 403 => 'Forbidden', - 404 => 'Not Found', - 405 => 'Method Not Allowed', - 406 => 'Not Acceptable', - 407 => 'Proxy Authentication Required', - 408 => 'Request Timeout', - 409 => 'Conflict', - 410 => 'Gone', - 411 => 'Length Required', - 412 => 'Precondition Failed', - 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Long', - 415 => 'Unsupported Media Type', - 416 => 'Requested Range Not Satisfiable', - 417 => 'Expectation Failed', - 422 => 'Unprocessable Entity', - 423 => 'Locked', - 424 => 'Failed Dependency', - 426 => 'Upgrade Required', - - 500 => 'Internal Server Error', - 501 => 'Not Implemented', - 502 => 'Bad Gateway', - 503 => 'Service Unavailable', - 504 => 'Gateway Timeout', - 505 => 'HTTP Version Not Supported', - 506 => 'Variant Also Negotiates', - 507 => 'Insufficient Storage', - 510 => 'Not Extended' + $code = intval( $code ); + $headers_desc = [ + 100 => 'Continue', + 101 => 'Switching Protocols', + 102 => 'Processing', + + 200 => 'OK', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + 207 => 'Multi-Status', + 226 => 'IM Used', + + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 303 => 'See Other', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 306 => 'Reserved', + 307 => 'Temporary Redirect', + + 400 => 'Bad Request', + 401 => 'Unauthorized', + 402 => 'Payment Required', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Timeout', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Long', + 415 => 'Unsupported Media Type', + 416 => 'Requested Range Not Satisfiable', + 417 => 'Expectation Failed', + 422 => 'Unprocessable Entity', + 423 => 'Locked', + 424 => 'Failed Dependency', + 426 => 'Upgrade Required', + + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version Not Supported', + 506 => 'Variant Also Negotiates', + 507 => 'Insufficient Storage', + 510 => 'Not Extended' ]; - return isset( $headers_desc[ $code ] ) ? $headers_desc[ $code ] : ''; + return $headers_desc[$code] ?? ''; } /** @@ -447,15 +514,17 @@ function yourls_get_HTTP_status( $code ) { * @return mixed Result of the INSERT query (1 on success) */ function yourls_log_redirect( $keyword ) { - // Allow plugins to short-circuit the whole function - $pre = yourls_apply_filter( 'shunt_log_redirect', false, $keyword ); - if ( false !== $pre ) - return $pre; + // Allow plugins to short-circuit the whole function + $pre = yourls_apply_filter( 'shunt_log_redirect', false, $keyword ); + if ( false !== $pre ) { + return $pre; + } - if ( !yourls_do_log_redirect() ) - return true; + if (!yourls_do_log_redirect()) { + return true; + } - $table = YOURLS_DB_TABLE_LOG; + $table = YOURLS_DB_TABLE_LOG; $ip = yourls_get_IP(); $binds = [ 'now' => date( 'Y-m-d H:i:s' ), @@ -466,19 +535,28 @@ function yourls_log_redirect( $keyword ) { 'location' => yourls_geo_ip_to_countrycode($ip), ]; - return yourls_get_db()->fetchAffected("INSERT INTO `$table` (click_time, shorturl, referrer, user_agent, ip_address, country_code) VALUES (:now, :keyword, :referrer, :ua, :ip, :location)", $binds ); + // Try and log. An error probably means a concurrency problem : just skip the logging + try { + $result = yourls_get_db('write-log_redirect')->fetchAffected("INSERT INTO `$table` (click_time, shorturl, referrer, user_agent, ip_address, country_code) VALUES (:now, :keyword, :referrer, :ua, :ip, :location)", $binds ); + } catch (Exception $e) { + $result = 0; + } + + return $result; } /** * Check if we want to not log redirects (for stats) * + * @return bool */ function yourls_do_log_redirect() { - return ( !defined( 'YOURLS_NOSTATS' ) || YOURLS_NOSTATS != true ); + return ( !defined( 'YOURLS_NOSTATS' ) || YOURLS_NOSTATS != true ); } /** * Check if an upgrade is needed + * * @return bool */ function yourls_upgrade_is_needed() { @@ -498,6 +576,7 @@ function yourls_upgrade_is_needed() { /** * Get current version & db version as stored in the options DB. Prior to 1.4 there's no option table. + * * @return array */ function yourls_get_current_version_from_sql() { @@ -518,6 +597,7 @@ function yourls_get_current_version_from_sql() { /** * Determine if the current page is private * + * @return bool */ function yourls_is_private() { $private = defined( 'YOURLS_PRIVATE' ) && YOURLS_PRIVATE; @@ -542,6 +622,7 @@ function yourls_is_private() { /** * Allow several short URLs for the same long URL ? + * * @return bool */ function yourls_allow_duplicate_longurls() { @@ -555,59 +636,60 @@ function yourls_allow_duplicate_longurls() { /** * Check if an IP shortens URL too fast to prevent DB flood. Return true, or die. + * * @param string $ip * @return bool|mixed|string */ function yourls_check_IP_flood( $ip = '' ) { - // Allow plugins to short-circuit the whole function - $pre = yourls_apply_filter( 'shunt_check_IP_flood', false, $ip ); - if ( false !== $pre ) - return $pre; - - yourls_do_action( 'pre_check_ip_flood', $ip ); // at this point $ip can be '', check it if your plugin hooks in here - - // Raise white flag if installing or if no flood delay defined - if( - ( defined('YOURLS_FLOOD_DELAY_SECONDS') && YOURLS_FLOOD_DELAY_SECONDS === 0 ) || - !defined('YOURLS_FLOOD_DELAY_SECONDS') || - yourls_is_installing() - ) - return true; - - // Don't throttle logged in users - if( yourls_is_private() ) { - if( yourls_is_valid_user() === true ) - return true; - } - - // Don't throttle whitelist IPs - if( defined( 'YOURLS_FLOOD_IP_WHITELIST' ) && YOURLS_FLOOD_IP_WHITELIST ) { - $whitelist_ips = explode( ',', YOURLS_FLOOD_IP_WHITELIST ); - foreach( (array)$whitelist_ips as $whitelist_ip ) { - $whitelist_ip = trim( $whitelist_ip ); - if ( $whitelist_ip == $ip ) - return true; - } - } - - $ip = ( $ip ? yourls_sanitize_ip( $ip ) : yourls_get_IP() ); - - yourls_do_action( 'check_ip_flood', $ip ); - - $table = YOURLS_DB_TABLE_URL; - $lasttime = yourls_get_db()->fetchValue( "SELECT `timestamp` FROM $table WHERE `ip` = :ip ORDER BY `timestamp` DESC LIMIT 1", [ 'ip' => $ip ] ); - if( $lasttime ) { - $now = date( 'U' ); - $then = date( 'U', strtotime( $lasttime ) ); - if( ( $now - $then ) <= YOURLS_FLOOD_DELAY_SECONDS ) { - // Flood! - yourls_do_action( 'ip_flood', $ip, $now - $then ); - yourls_die( yourls__( 'Too many URLs added too fast. Slow down please.' ), yourls__( 'Too Many Requests' ), 429 ); - } - } - - return true; + // Allow plugins to short-circuit the whole function + $pre = yourls_apply_filter( 'shunt_check_IP_flood', false, $ip ); + if ( false !== $pre ) + return $pre; + + yourls_do_action( 'pre_check_ip_flood', $ip ); // at this point $ip can be '', check it if your plugin hooks in here + + // Raise white flag if installing or if no flood delay defined + if( + ( defined('YOURLS_FLOOD_DELAY_SECONDS') && YOURLS_FLOOD_DELAY_SECONDS === 0 ) || + !defined('YOURLS_FLOOD_DELAY_SECONDS') || + yourls_is_installing() + ) + return true; + + // Don't throttle logged in users + if( yourls_is_private() ) { + if( yourls_is_valid_user() === true ) + return true; + } + + // Don't throttle whitelist IPs + if( defined( 'YOURLS_FLOOD_IP_WHITELIST' ) && YOURLS_FLOOD_IP_WHITELIST ) { + $whitelist_ips = explode( ',', YOURLS_FLOOD_IP_WHITELIST ); + foreach( (array)$whitelist_ips as $whitelist_ip ) { + $whitelist_ip = trim( $whitelist_ip ); + if ( $whitelist_ip == $ip ) + return true; + } + } + + $ip = ( $ip ? yourls_sanitize_ip( $ip ) : yourls_get_IP() ); + + yourls_do_action( 'check_ip_flood', $ip ); + + $table = YOURLS_DB_TABLE_URL; + $lasttime = yourls_get_db('read-check_ip_flood')->fetchValue( "SELECT `timestamp` FROM $table WHERE `ip` = :ip ORDER BY `timestamp` DESC LIMIT 1", [ 'ip' => $ip ] ); + if( $lasttime ) { + $now = date( 'U' ); + $then = date( 'U', strtotime( $lasttime ) ); + if( ( $now - $then ) <= YOURLS_FLOOD_DELAY_SECONDS ) { + // Flood! + yourls_do_action( 'ip_flood', $ip, $now - $then ); + yourls_die( yourls__( 'Too many URLs added too fast. Slow down please.' ), yourls__( 'Too Many Requests' ), 429 ); + } + } + + return true; } /** @@ -617,7 +699,7 @@ function yourls_check_IP_flood( $ip = '' ) { * @return bool */ function yourls_is_installing() { - return (bool)yourls_apply_filter( 'is_installing', defined( 'YOURLS_INSTALLING' ) && YOURLS_INSTALLING ); + return (bool)yourls_apply_filter( 'is_installing', defined( 'YOURLS_INSTALLING' ) && YOURLS_INSTALLING ); } /** @@ -640,7 +722,7 @@ function yourls_is_upgrading() { * @return bool */ function yourls_is_installed() { - return (bool)yourls_apply_filter( 'is_installed', yourls_get_db()->is_installed() ); + return (bool)yourls_apply_filter( 'is_installed', yourls_get_db('read-is_installed')->is_installed() ); } /** @@ -651,7 +733,7 @@ function yourls_is_installed() { * @return void */ function yourls_set_installed( $bool ) { - yourls_get_db()->set_installed( $bool ); + yourls_get_db('read-set_installed')->set_installed( $bool ); } /** @@ -711,6 +793,7 @@ function yourls_rnd_string ( $length = 5, $type = 0, $charlist = '' ) { /** * Check if we're in API mode. + * * @return bool */ function yourls_is_API() { @@ -719,6 +802,7 @@ function yourls_is_API() { /** * Check if we're in Ajax mode. + * * @return bool */ function yourls_is_Ajax() { @@ -727,6 +811,7 @@ function yourls_is_Ajax() { /** * Check if we're in GO mode (yourls-go.php). + * * @return bool */ function yourls_is_GO() { @@ -736,14 +821,16 @@ function yourls_is_GO() { /** * Check if we're displaying stats infos (yourls-infos.php). Returns bool * + * @return bool */ function yourls_is_infos() { return (bool)yourls_apply_filter( 'is_infos', defined( 'YOURLS_INFOS' ) && YOURLS_INFOS ); } /** - * Check if we're in the admin area. Returns bool + * Check if we're in the admin area. Returns bool. Does not relate with user rights. * + * @return bool */ function yourls_is_admin() { return (bool)yourls_apply_filter( 'is_admin', defined( 'YOURLS_ADMIN' ) && YOURLS_ADMIN ); @@ -752,13 +839,15 @@ function yourls_is_admin() { /** * Check if the server seems to be running on Windows. Not exactly sure how reliable this is. * + * @return bool */ function yourls_is_windows() { - return defined( 'DIRECTORY_SEPARATOR' ) && DIRECTORY_SEPARATOR == '\\'; + return defined( 'DIRECTORY_SEPARATOR' ) && DIRECTORY_SEPARATOR == '\\'; } /** * Check if SSL is required. + * * @return bool */ function yourls_needs_ssl() { @@ -767,6 +856,7 @@ function yourls_needs_ssl() { /** * Check if SSL is used. Stolen from WP. + * * @return bool */ function yourls_is_ssl() { @@ -844,14 +934,19 @@ function yourls_get_remote_title( $url ) { // // or and all possible variations: see https://gist.github.com/ozh/7951236 if ( preg_match( '/]*charset\s*=["\' ]*([a-zA-Z0-9\-_]+)/is', $content, $found ) ) { - $charset = $found[ 1 ]; + if ( yourls_is_valid_charset( $found[ 1 ] ) ) { + $charset = $found[ 1 ]; + } unset( $found ); } - else { + if ( empty( $charset ) ) { // No charset found in HTML. Get charset as (and if) defined by the server response $_charset = current( $response->headers->getValues( 'content-type' ) ); if ( preg_match( '/charset=(\S+)/', $_charset, $found ) ) { - $charset = trim( $found[ 1 ], ';' ); + $_charset = trim( $found[ 1 ], ';' ); + if ( yourls_is_valid_charset( $_charset ) ) { + $charset = $_charset; + } unset( $found ); } } @@ -876,27 +971,43 @@ function yourls_get_remote_title( $url ) { return (string)yourls_apply_filter( 'get_remote_title', $title, $url ); } +/** + * Is supported charset encoding for conversion. + * + * @return bool + */ +function yourls_is_valid_charset( $charset ) { + if ( ! function_exists( 'mb_list_encodings' ) ) { + return false; // Okay to return false if mb_list_encodings() is not available since we won't be able to convert the charset. + } + $charset = strtolower( $charset ); + $charsets = array_map( 'strtolower', mb_list_encodings() ); + + return in_array( $charset, $charsets ); +} + /** * Quick UA check for mobile devices. + * * @return bool */ function yourls_is_mobile_device() { - // Strings searched - $mobiles = [ - 'android', 'blackberry', 'blazer', - 'compal', 'elaine', 'fennec', 'hiptop', - 'iemobile', 'iphone', 'ipod', 'ipad', - 'iris', 'kindle', 'opera mobi', 'opera mini', - 'palm', 'phone', 'pocket', 'psp', 'symbian', - 'treo', 'wap', 'windows ce', 'windows phone' + // Strings searched + $mobiles = [ + 'android', 'blackberry', 'blazer', + 'compal', 'elaine', 'fennec', 'hiptop', + 'iemobile', 'iphone', 'ipod', 'ipad', + 'iris', 'kindle', 'opera mobi', 'opera mini', + 'palm', 'phone', 'pocket', 'psp', 'symbian', + 'treo', 'wap', 'windows ce', 'windows phone' ]; - // Current user-agent - $current = strtolower( $_SERVER['HTTP_USER_AGENT'] ); + // Current user-agent + $current = strtolower( $_SERVER['HTTP_USER_AGENT'] ); - // Check and return - $is_mobile = ( str_replace( $mobiles, '', $current ) != $current ); - return (bool)yourls_apply_filter( 'is_mobile_device', $is_mobile ); + // Check and return + $is_mobile = ( str_replace( $mobiles, '', $current ) != $current ); + return (bool)yourls_apply_filter( 'is_mobile_device', $is_mobile ); } /** @@ -911,7 +1022,7 @@ function yourls_is_mobile_device() { * @param string $uri Optional, page requested (default to $_SERVER['REQUEST_URI'] eg '/yourls/abcd' ) * @return string request relative to YOURLS base (eg 'abdc') */ -function yourls_get_request($yourls_site = false, $uri = false) { +function yourls_get_request($yourls_site = '', $uri = '') { // Allow plugins to short-circuit the whole function $pre = yourls_apply_filter( 'shunt_get_request', false ); if ( false !== $pre ) { @@ -921,10 +1032,10 @@ function yourls_get_request($yourls_site = false, $uri = false) { yourls_do_action( 'pre_get_request', $yourls_site, $uri ); // Default values - if ( false === $yourls_site ) { + if ( '' === $yourls_site ) { $yourls_site = yourls_get_yourls_site(); } - if ( false === $uri ) { + if ( '' === $uri ) { $uri = $_SERVER[ 'REQUEST_URI' ]; } @@ -962,6 +1073,11 @@ function yourls_get_request($yourls_site = false, $uri = false) { /** * Fix $_SERVER['REQUEST_URI'] variable for various setups. Stolen from WP. * + * We also strip $_COOKIE from $_REQUEST to allow our lazy using $_REQUEST without 3rd party cookie interfering. + * See #3383 for explanation. + * + * @since 1.5.1 + * @return void */ function yourls_fix_request_uri() { @@ -971,6 +1087,9 @@ function yourls_fix_request_uri() { ]; $_SERVER = array_merge( $default_server_values, $_SERVER ); + // Make $_REQUEST with only $_GET and $_POST, not $_COOKIE. See #3383. + $_REQUEST = array_merge( $_GET, $_POST ); + // Fix for IIS when running with PHP ISAPI if ( empty( $_SERVER[ 'REQUEST_URI' ] ) || ( php_sapi_name() != 'cgi-fcgi' && preg_match( '/^Microsoft-IIS\//', $_SERVER[ 'SERVER_SOFTWARE' ] ) ) ) { @@ -1009,49 +1128,35 @@ function yourls_fix_request_uri() { /** * Check for maintenance mode. If yes, die. See yourls_maintenance_mode(). Stolen from WP. * + * @return void */ function yourls_check_maintenance_mode() { + $dot_file = YOURLS_ABSPATH . '/.maintenance' ; - $file = YOURLS_ABSPATH . '/.maintenance' ; - if ( !file_exists( $file ) || yourls_is_upgrading() || yourls_is_installing() ) - return; - - global $maintenance_start; - - include_once( $file ); - // If the $maintenance_start timestamp is older than 10 minutes, don't die. - if ( ( time() - $maintenance_start ) >= 600 ) - return; - - // Use any /user/maintenance.php file - if( file_exists( YOURLS_USERDIR.'/maintenance.php' ) ) { - include_once( YOURLS_USERDIR.'/maintenance.php' ); - die(); - } + if ( !file_exists( $dot_file ) || yourls_is_upgrading() || yourls_is_installing() ) { + return; + } - // https://www.youtube.com/watch?v=Xw-m4jEY-Ns - $title = yourls__( 'Service temporarily unavailable' ); - $message = yourls__( 'Our service is currently undergoing scheduled maintenance.' ) . "

\n

" . - yourls__( 'Things should not last very long, thank you for your patience and please excuse the inconvenience' ); - yourls_die( $message, $title , 503 ); + global $maintenance_start; + yourls_include_file_sandbox( $dot_file ); + // If the $maintenance_start timestamp is older than 10 minutes, don't die. + if ( ( time() - $maintenance_start ) >= 600 ) { + return; + } -} + // Use any /user/maintenance.php file + $file = YOURLS_USERDIR . '/maintenance.php'; + if(file_exists($file)) { + if(yourls_include_file_sandbox( $file ) == true) { + die(); + } + } -/** - * Return current admin page, or null if not an admin page - * - * @return mixed string if admin page, null if not an admin page - * @since 1.6 - */ -function yourls_current_admin_page() { - if( yourls_is_admin() ) { - $current = substr( yourls_get_request(), 6 ); - if( $current === false ) - $current = 'index.php'; // if current page is http://sho.rt/admin/ instead of http://sho.rt/admin/index.php - - return $current; - } - return null; + // Or use the default messages + $title = yourls__('Service temporarily unavailable'); + $message = yourls__('Our service is currently undergoing scheduled maintenance.') . "

\n

" . + yourls__('Things should not last very long, thank you for your patience and please excuse the inconvenience'); + yourls_die( $message, $title, 503 ); } /** @@ -1093,15 +1198,15 @@ function yourls_is_allowed_protocol( $url, $protocols = [] ) { * @return string Protocol, with slash slash if applicable. Empty string if no protocol */ function yourls_get_protocol( $url ) { - /* - http://en.wikipedia.org/wiki/URI_scheme#Generic_syntax - The scheme name consists of a sequence of characters beginning with a letter and followed by any - combination of letters, digits, plus ("+"), period ("."), or hyphen ("-"). Although schemes are - case-insensitive, the canonical form is lowercase and documents that specify schemes must do so - with lowercase letters. It is followed by a colon (":"). - */ + /* + http://en.wikipedia.org/wiki/URI_scheme#Generic_syntax + The scheme name consists of a sequence of characters beginning with a letter and followed by any + combination of letters, digits, plus ("+"), period ("."), or hyphen ("-"). Although schemes are + case-insensitive, the canonical form is lowercase and documents that specify schemes must do so + with lowercase letters. It is followed by a colon (":"). + */ preg_match( '!^[a-zA-Z][a-zA-Z0-9+.-]+:(//)?!', $url, $matches ); - return (string)yourls_apply_filter( 'get_protocol', isset( $matches[0] ) ? $matches[0] : '', $url ); + return (string)yourls_apply_filter( 'get_protocol', isset( $matches[0] ) ? $matches[0] : '', $url ); } /** @@ -1131,7 +1236,7 @@ function yourls_get_relative_url( $url, $strict = true ) { } /** - * Marks a function as deprecated and informs when it has been used. Stolen from WP. + * Marks a function as deprecated and informs that it has been used. Stolen from WP. * * There is a hook deprecated_function that will be called that can be used * to get the backtrace up to what file and function called the deprecated @@ -1142,39 +1247,23 @@ function yourls_get_relative_url( $url, $strict = true ) { * This function is to be used in every function that is deprecated. * * @since 1.6 - * @uses yourls_do_action() Calls 'deprecated_function' and passes the function name, what to use instead, - * and the version the function was deprecated in. - * @uses yourls_apply_filter() Calls 'deprecated_function_trigger_error' and expects boolean value of true to do - * trigger or false to not trigger error. * * @param string $function The function that was called * @param string $version The version of WordPress that deprecated the function * @param string $replacement Optional. The function that should have been called + * @return void */ function yourls_deprecated_function( $function, $version, $replacement = null ) { - yourls_do_action( 'deprecated_function', $function, $replacement, $version ); + yourls_do_action( 'deprecated_function', $function, $replacement, $version ); - // Allow plugin to filter the output error trigger - if ( yourls_get_debug_mode() && yourls_apply_filter( 'deprecated_function_trigger_error', true ) ) { - if ( ! is_null( $replacement ) ) - trigger_error( sprintf( yourls__('%1$s is deprecated since version %2$s! Use %3$s instead.'), $function, $version, $replacement ) ); - else - trigger_error( sprintf( yourls__('%1$s is deprecated since version %2$s with no alternative available.'), $function, $version ) ); - } -} - -/** - * Return the value if not an empty string - * - * Used with array_filter(), to remove empty keys but not keys with value 0 or false - * - * @since 1.6 - * @param mixed $val Value to test against '' - * @return bool True if not an empty string - */ -function yourls_return_if_not_empty_string( $val ) { - return ( $val !== '' ); + // Allow plugin to filter the output error trigger + if ( yourls_get_debug_mode() && yourls_apply_filter( 'deprecated_function_trigger_error', true ) ) { + if ( ! is_null( $replacement ) ) + trigger_error( sprintf( yourls__('%1$s is deprecated since version %2$s! Use %3$s instead.'), $function, $version, $replacement ) ); + else + trigger_error( sprintf( yourls__('%1$s is deprecated since version %2$s with no alternative available.'), $function, $version ) ); + } } /** @@ -1219,14 +1308,14 @@ function yourls_get_protocol_slashes_and_rest( $url, $array = [ 'protocol', 'sla } /** - * Set URL scheme (to HTTP or HTTPS) + * Set URL scheme (HTTP or HTTPS) to a URL * * @since 1.7.1 * @param string $url URL * @param string $scheme scheme, either 'http' or 'https' * @return string URL with chosen scheme */ -function yourls_set_url_scheme( $url, $scheme = false ) { +function yourls_set_url_scheme( $url, $scheme = '' ) { if ( in_array( $scheme, [ 'http', 'https' ] ) ) { $url = preg_replace( '!^[a-zA-Z0-9+.-]+://!', $scheme.'://', $url ); } @@ -1236,12 +1325,36 @@ function yourls_set_url_scheme( $url, $scheme = false ) { /** * Tell if there is a new YOURLS version * - * This function checks, if needed, if there's a new version of YOURLS and, if applicable, display + * This function checks, if needed, if there's a new version of YOURLS and, if applicable, displays * an update notice. * * @since 1.7.3 + * @return void */ function yourls_tell_if_new_version() { yourls_debug_log( 'Check for new version: '.( yourls_maybe_check_core_version() ? 'yes' : 'no' ) ); - yourls_new_core_version_notice(); + yourls_new_core_version_notice(YOURLS_VERSION); +} + +/** + * File include sandbox + * + * Attempt to include a PHP file, fail with an error message if the file isn't valid PHP code. + * This function does not check first if the file exists : depending on use case, you may check first. + * + * @since 1.9.2 + * @param string $file filename (full path) + * @return string|bool string if error, true if success + */ +function yourls_include_file_sandbox($file) { + try { + if (is_readable( $file )) { + require_once $file; + yourls_debug_log("loaded $file"); + return true; + } + } catch ( \Throwable $e ) { + yourls_debug_log("could not load $file"); + return sprintf("%s (%s : %s)", $e->getMessage() , $e->getFile() , $e->getLine() ); + } } diff --git a/includes/geo/COPYRIGHT.txt b/includes/geo/COPYRIGHT.txt new file mode 100644 index 000000000..51e7fe646 --- /dev/null +++ b/includes/geo/COPYRIGHT.txt @@ -0,0 +1 @@ +Database and Contents Copyright (c) 2026 MaxMind, Inc. diff --git a/includes/geo/GeoLite2-Country.mmdb b/includes/geo/GeoLite2-Country.mmdb index fc0081c00..6ddca9358 100644 Binary files a/includes/geo/GeoLite2-Country.mmdb and b/includes/geo/GeoLite2-Country.mmdb differ diff --git a/includes/geo/LICENSE.txt b/includes/geo/LICENSE.txt new file mode 100644 index 000000000..ee7434dc9 --- /dev/null +++ b/includes/geo/LICENSE.txt @@ -0,0 +1,3 @@ +Use of this MaxMind product is governed by MaxMind's GeoLite2 End User License Agreement, which can be viewed at https://www.maxmind.com/en/geolite2/eula. + +This database incorporates GeoNames [https://www.geonames.org] geographical data, which is made available under the Creative Commons Attribution 4.0 License. To view a copy of this license, visit https://creativecommons.org/licenses/by/4.0/. diff --git a/includes/vendor/aura/sql/README.md b/includes/vendor/aura/sql/README.md index c7e707578..3dbdee976 100644 --- a/includes/vendor/aura/sql/README.md +++ b/includes/vendor/aura/sql/README.md @@ -54,8 +54,8 @@ Alternatively, [download a release][], or clone this repository, then map the ## Dependencies -This package requires PHP 5.6 or later; it has also been tested on PHP 7 and -HHVM. We recommend using the latest available version of PHP as a matter of +This package requires PHP 8.1 or later; it has also been tested on PHP 8.1-8.2. +We recommend using the latest available version of PHP as a matter of principle. Aura library packages may sometimes depend on external interfaces, but never on @@ -65,9 +65,9 @@ without compromising flexibility. For specifics, please examine the package ## Quality -[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/auraphp/Aura.Sql/badges/quality-score.png?b=3.x)](https://scrutinizer-ci.com/g/auraphp/Aura.Sql/) -[![Code Coverage](https://scrutinizer-ci.com/g/auraphp/Aura.Sql/badges/coverage.png?b=3.x)](https://scrutinizer-ci.com/g/auraphp/Aura.Sql/) -[![Build Status](https://travis-ci.org/auraphp/Aura.Sql.png?branch=3.x)](https://travis-ci.org/auraphp/Aura.Sql) +[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/auraphp/Aura.Sql/badges/quality-score.png?b=5.x)](https://scrutinizer-ci.com/g/auraphp/Aura.Sql/) +[![Code Coverage](https://scrutinizer-ci.com/g/auraphp/Aura.Sql/badges/coverage.png?b=5.x)](https://scrutinizer-ci.com/g/auraphp/Aura.Sql/) +[![Build Status](https://github.com/auraphp/Aura.Sql/actions/workflows/continuous-integration.yml/badge.svg?branch=5.x)](https://github.com/auraphp/Aura.Sql/actions/workflows/continuous-integration.yml) [![PDS Skeleton](https://img.shields.io/badge/pds-skeleton-blue.svg?style=flat-square)](https://github.com/php-pds/skeleton) This project adheres to [Semantic Versioning](http://semver.org/). diff --git a/includes/vendor/aura/sql/src/AbstractExtendedPdo.php b/includes/vendor/aura/sql/src/AbstractExtendedPdo.php index 483740bbe..3b73af32d 100644 --- a/includes/vendor/aura/sql/src/AbstractExtendedPdo.php +++ b/includes/vendor/aura/sql/src/AbstractExtendedPdo.php @@ -8,10 +8,10 @@ */ namespace Aura\Sql; -use Aura\Sql\Exception; use Aura\Sql\Parser\ParserInterface; use Aura\Sql\Profiler\ProfilerInterface; use BadMethodCallException; +use Generator; use PDO; use PDOStatement; @@ -29,10 +29,10 @@ abstract class AbstractExtendedPdo extends PDO implements ExtendedPdoInterface * * The internal PDO connection. * - * @var PDO + * @var PDO|null * */ - protected $pdo; + protected ?PDO $pdo = null; /** * @@ -41,7 +41,7 @@ abstract class AbstractExtendedPdo extends PDO implements ExtendedPdoInterface * @var ProfilerInterface * */ - protected $profiler; + protected ProfilerInterface $profiler; /** * @@ -50,7 +50,7 @@ abstract class AbstractExtendedPdo extends PDO implements ExtendedPdoInterface * @var ParserInterface * */ - protected $parser; + protected ParserInterface $parser; /** * @@ -59,7 +59,7 @@ abstract class AbstractExtendedPdo extends PDO implements ExtendedPdoInterface * @var string * */ - protected $quoteNamePrefix = '"'; + protected string $quoteNamePrefix = '"'; /** * @@ -68,7 +68,7 @@ abstract class AbstractExtendedPdo extends PDO implements ExtendedPdoInterface * @var string * */ - protected $quoteNameSuffix = '"'; + protected string $quoteNameSuffix = '"'; /** * @@ -77,7 +77,7 @@ abstract class AbstractExtendedPdo extends PDO implements ExtendedPdoInterface * @var string * */ - protected $quoteNameEscapeFind = '"'; + protected string $quoteNameEscapeFind = '"'; /** * @@ -86,7 +86,7 @@ abstract class AbstractExtendedPdo extends PDO implements ExtendedPdoInterface * @var string * */ - protected $quoteNameEscapeRepl = '""'; + protected string $quoteNameEscapeRepl = '""'; /** * @@ -103,13 +103,13 @@ abstract class AbstractExtendedPdo extends PDO implements ExtendedPdoInterface * @throws BadMethodCallException when the method does not exist. * */ - public function __call($name, array $arguments) + public function __call(string $name, array $arguments) { - $this->connect(); + $this->lazyConnect(); if (! method_exists($this->pdo, $name)) { $class = get_class($this); - $message = "Class '{$class}' does not have a method '{$name}'"; + $message = "Class '$class' does not have a method '$name'"; throw new BadMethodCallException($message); } @@ -125,9 +125,9 @@ public function __call($name, array $arguments) * @see http://php.net/manual/en/pdo.begintransaction.php * */ - public function beginTransaction() + public function beginTransaction(): bool { - $this->connect(); + $this->lazyConnect(); $this->profiler->start(__FUNCTION__); $result = $this->pdo->beginTransaction(); $this->profiler->finish(); @@ -143,9 +143,9 @@ public function beginTransaction() * @see http://php.net/manual/en/pdo.commit.php * */ - public function commit() + public function commit(): bool { - $this->connect(); + $this->lazyConnect(); $this->profiler->start(__FUNCTION__); $result = $this->pdo->commit(); $this->profiler->finish(); @@ -156,30 +156,28 @@ public function commit() * * Connects to the database. * - * @return null - * + * @return void */ - abstract public function connect(); + abstract public function lazyConnect(): void; /** * * Disconnects from the database. * - * @return null - * + * @return void */ - abstract public function disconnect(); + abstract public function disconnect(): void; /** * * Gets the most recent error code. * - * @return mixed + * @return string|null * */ - public function errorCode() + public function errorCode(): ?string { - $this->connect(); + $this->lazyConnect(); return $this->pdo->errorCode(); } @@ -190,9 +188,9 @@ public function errorCode() * @return array * */ - public function errorInfo() + public function errorInfo(): array { - $this->connect(); + $this->lazyConnect(); return $this->pdo->errorInfo(); } @@ -202,14 +200,14 @@ public function errorInfo() * * @param string $statement The SQL statement to prepare and execute. * - * @return int The number of affected rows. + * @return int|false The number of affected rows. * * @see http://php.net/manual/en/pdo.exec.php * */ - public function exec($statement) + public function exec(string $statement): int|false { - $this->connect(); + $this->lazyConnect(); $this->profiler->start(__FUNCTION__); $affectedRows = $this->pdo->exec($statement); $this->profiler->finish($statement); @@ -227,7 +225,7 @@ public function exec($statement) * @return int * */ - public function fetchAffected($statement, array $values = []) + public function fetchAffected(string $statement, array $values = []): int { $sth = $this->perform($statement, $values); return $sth->rowCount(); @@ -245,7 +243,7 @@ public function fetchAffected($statement, array $values = []) * @return array * */ - public function fetchAll($statement, array $values = []) + public function fetchAll(string $statement, array $values = []): array { $sth = $this->perform($statement, $values); return $sth->fetchAll(self::FETCH_ASSOC); @@ -267,7 +265,7 @@ public function fetchAll($statement, array $values = []) * @return array * */ - public function fetchAssoc($statement, array $values = []) + public function fetchAssoc(string $statement, array $values = []): array { $sth = $this->perform($statement, $values); $data = []; @@ -288,7 +286,7 @@ public function fetchAssoc($statement, array $values = []) * @return array * */ - public function fetchCol($statement, array $values = []) + public function fetchCol(string $statement, array $values = []): array { $sth = $this->perform($statement, $values); return $sth->fetchAll(self::FETCH_COLUMN, 0); @@ -310,10 +308,10 @@ public function fetchCol($statement, array $values = []) * */ public function fetchGroup( - $statement, + string $statement, array $values = [], - $style = PDO::FETCH_COLUMN - ) { + int $style = PDO::FETCH_COLUMN + ): array { $sth = $this->perform($statement, $values); return $sth->fetchAll(self::FETCH_GROUP | $style); } @@ -342,11 +340,11 @@ public function fetchGroup( * */ public function fetchObject( - $statement, + string $statement, array $values = [], - $class = 'stdClass', + string $class = 'stdClass', array $args = [] - ) { + ): object|false { $sth = $this->perform($statement, $values); if (! empty($args)) { @@ -382,11 +380,11 @@ public function fetchObject( * */ public function fetchObjects( - $statement, + string $statement, array $values = [], - $class = 'stdClass', + string $class = 'stdClass', array $args = [] - ) { + ): array { $sth = $this->perform($statement, $values); if (! empty($args)) { @@ -404,10 +402,10 @@ public function fetchObjects( * * @param array $values Values to bind to the query. * - * @return array + * @return array|false * */ - public function fetchOne($statement, array $values = []) + public function fetchOne(string $statement, array $values = []): array|false { $sth = $this->perform($statement, $values); return $sth->fetch(self::FETCH_ASSOC); @@ -425,7 +423,7 @@ public function fetchOne($statement, array $values = []) * @return array * */ - public function fetchPairs($statement, array $values = []) + public function fetchPairs(string $statement, array $values = []): array { $sth = $this->perform($statement, $values); return $sth->fetchAll(self::FETCH_KEY_PAIR); @@ -442,7 +440,7 @@ public function fetchPairs($statement, array $values = []) * @return mixed * */ - public function fetchValue($statement, array $values = []) + public function fetchValue(string $statement, array $values = []): mixed { $sth = $this->perform($statement, $values); return $sth->fetchColumn(0); @@ -455,7 +453,7 @@ public function fetchValue($statement, array $values = []) * @return ParserInterface * */ - public function getParser() + public function getParser(): ParserInterface { return $this->parser; } @@ -467,7 +465,7 @@ public function getParser() * @return \PDO * */ - public function getPdo() + public function getPdo(): PDO { return $this->pdo; } @@ -479,7 +477,7 @@ public function getPdo() * @return ProfilerInterface * */ - public function getProfiler() + public function getProfiler(): ProfilerInterface { return $this->profiler; } @@ -493,9 +491,9 @@ public function getProfiler() * @see http://php.net/manual/en/pdo.intransaction.php * */ - public function inTransaction() + public function inTransaction(): bool { - $this->connect(); + $this->lazyConnect(); $this->profiler->start(__FUNCTION__); $result = $this->pdo->inTransaction(); $this->profiler->finish(); @@ -509,7 +507,7 @@ public function inTransaction() * @return bool * */ - public function isConnected() + public function isConnected(): bool { return (bool) $this->pdo; } @@ -518,17 +516,16 @@ public function isConnected() * * Returns the last inserted autoincrement sequence value. * - * @param string $name The name of the sequence to check; typically needed + * @param string|null $name The name of the sequence to check; typically needed * only for PostgreSQL, where it takes the form of `__seq`. * - * @return string + * @return string|false * * @see http://php.net/manual/en/pdo.lastinsertid.php - * */ - public function lastInsertId($name = null) + public function lastInsertId(?string $name = null): string|false { - $this->connect(); + $this->lazyConnect(); $this->profiler->start(__FUNCTION__); $result = $this->pdo->lastInsertId($name); $this->profiler->finish(); @@ -547,12 +544,13 @@ public function lastInsertId($name = null) * * @return PDOStatement * + * @throws \Aura\Sql\Exception\CannotBindValue * @see quote() * */ - public function perform($statement, array $values = []) + public function perform(string $statement, array $values = []): PDOStatement { - $this->connect(); + $this->lazyConnect(); $sth = $this->prepareWithValues($statement, $values); $this->profiler->start(__FUNCTION__); $sth->execute(); @@ -564,20 +562,20 @@ public function perform($statement, array $values = []) * * Prepares an SQL statement for execution. * - * @param string $statement The SQL statement to prepare for execution. + * @param string $query The SQL statement to prepare for execution. * * @param array $options Set these attributes on the returned * PDOStatement. * - * @return PDOStatement + * @return PDOStatement|false * * @see http://php.net/manual/en/pdo.prepare.php * */ - public function prepare($statement, $options = []) + public function prepare(string $query, array $options = []): PDOStatement|false { - $this->connect(); - $sth = $this->pdo->prepare($statement, $options); + $this->lazyConnect(); + $sth = $this->pdo->prepare($query, $options); return $sth; } @@ -600,10 +598,11 @@ public function prepare($statement, $options = []) * * @return PDOStatement * + * @throws \Aura\Sql\Exception\CannotBindValue * @see http://php.net/manual/en/pdo.prepare.php * */ - public function prepareWithValues($statement, array $values = []) + public function prepareWithValues(string $statement, array $values = []): PDOStatement { // if there are no values to bind ... if (empty($values)) { @@ -611,11 +610,11 @@ public function prepareWithValues($statement, array $values = []) return $this->prepare($statement); } - $this->connect(); + $this->lazyConnect(); // rebuild the statement and values $parser = clone $this->parser; - list ($statement, $values) = $parser->rebuild($statement, $values); + list($statement, $values) = $parser->rebuild($statement, $values); // prepare the statement $sth = $this->pdo->prepare($statement); @@ -633,20 +632,22 @@ public function prepareWithValues($statement, array $values = []) * * Queries the database and returns a PDOStatement. * - * @param string $statement The SQL statement to prepare and execute. + * @param string $query The SQL statement to prepare and execute. * - * @param mixed ...$fetch Optional fetch-related parameters. + * @param int|null $fetchMode * - * @return PDOStatement + * @param mixed ...$fetch_mode_args Optional fetch-related parameters. + * + * @return PDOStatement|false * * @see http://php.net/manual/en/pdo.query.php * */ - public function query($statement, ...$fetch) + public function query(string $query, ?int $fetchMode = null, mixed ...$fetch_mode_args): PDOStatement|false { - $this->connect(); + $this->lazyConnect(); $this->profiler->start(__FUNCTION__); - $sth = $this->pdo->query($statement, ...$fetch); + $sth = $this->pdo->query($query, $fetchMode, ...$fetch_mode_args); $this->profiler->finish($sth->queryString); return $sth; } @@ -658,18 +659,20 @@ public function query($statement, ...$fetch) * This differs from `PDO::quote()` in that it will convert an array into * a string of comma-separated quoted values. * - * @param mixed $value The value to quote. + * @param string|int|array|float|null $value The value to quote. * * @param int $type A data type hint for the database driver. * - * @return string The quoted value. + * @return string|false The quoted value or false if the driver does not support quoting in this way. * * @see http://php.net/manual/en/pdo.quote.php * */ - public function quote($value, $type = self::PARAM_STR) + public function quote(string|int|array|float|null $value, int $type = self::PARAM_STR): string|false { - $this->connect(); + $this->lazyConnect(); + + $value = $value ?? ""; // non-array quoting if (! is_array($value)) { @@ -692,9 +695,9 @@ public function quote($value, $type = self::PARAM_STR) * @return string The multi-part identifier name, quoted. * */ - public function quoteName($name) + public function quoteName(string $name): string { - if (strpos($name, '.') === false) { + if (! str_contains($name, '.')) { return $this->quoteSingleName($name); } @@ -716,7 +719,7 @@ public function quoteName($name) * @return string The quoted identifier name. * */ - public function quoteSingleName($name) + public function quoteSingleName(string $name): string { $name = str_replace( $this->quoteNameEscapeFind, @@ -737,9 +740,9 @@ public function quoteSingleName($name) * @see http://php.net/manual/en/pdo.rollback.php * */ - public function rollBack() + public function rollBack(): bool { - $this->connect(); + $this->lazyConnect(); $this->profiler->start(__FUNCTION__); $result = $this->pdo->rollBack(); $this->profiler->finish(); @@ -753,7 +756,7 @@ public function rollBack() * @param ParserInterface $parser The Parser instance. * */ - public function setParser(ParserInterface $parser) + public function setParser(ParserInterface $parser): void { $this->parser = $parser; } @@ -765,7 +768,7 @@ public function setParser(ParserInterface $parser) * @param ProfilerInterface $profiler The Profiler instance. * */ - public function setProfiler(ProfilerInterface $profiler) + public function setProfiler(ProfilerInterface $profiler): void { $this->profiler = $profiler; } @@ -781,7 +784,7 @@ public function setProfiler(ProfilerInterface $profiler) * @return \Generator * */ - public function yieldAll($statement, array $values = []) + public function yieldAll(string $statement, array $values = []): Generator { $sth = $this->perform($statement, $values); while ($row = $sth->fetch(self::FETCH_ASSOC)) { @@ -800,7 +803,7 @@ public function yieldAll($statement, array $values = []) * @return \Generator * */ - public function yieldAssoc($statement, array $values = []) + public function yieldAssoc(string $statement, array $values = []): Generator { $sth = $this->perform($statement, $values); while ($row = $sth->fetch(self::FETCH_ASSOC)) { @@ -820,7 +823,7 @@ public function yieldAssoc($statement, array $values = []) * @return \Generator * */ - public function yieldCol($statement, array $values = []) + public function yieldCol(string $statement, array $values = []): Generator { $sth = $this->perform($statement, $values); while ($row = $sth->fetch(self::FETCH_NUM)) { @@ -851,11 +854,11 @@ public function yieldCol($statement, array $values = []) * */ public function yieldObjects( - $statement, + string $statement, array $values = [], - $class = 'stdClass', + string $class = 'stdClass', array $args = [] - ) { + ): Generator { $sth = $this->perform($statement, $values); if (empty($args)) { @@ -881,7 +884,7 @@ public function yieldObjects( * @return \Generator * */ - public function yieldPairs($statement, array $values = []) + public function yieldPairs(string $statement, array $values = []): Generator { $sth = $this->perform($statement, $values); while ($row = $sth->fetch(self::FETCH_NUM)) { @@ -899,13 +902,13 @@ public function yieldPairs($statement, array $values = []) * * @param mixed $val The value to bind to the statement. * - * @return boolean + * @return bool * * @throws Exception\CannotBindValue when the value to be bound is not * bindable (e.g., array, object, or resource). * */ - protected function bindValue(PDOStatement $sth, $key, $val) + protected function bindValue(PDOStatement $sth, mixed $key, mixed $val): bool { if (is_int($val)) { return $sth->bindValue($key, $val, self::PARAM_INT); @@ -938,11 +941,11 @@ protected function bindValue(PDOStatement $sth, $key, $val) * @return ParserInterface * */ - protected function newParser($driver) + protected function newParser(string $driver): ParserInterface { $class = 'Aura\Sql\Parser\\' . ucfirst($driver) . 'Parser'; if (! class_exists($class)) { - $class = 'Aura\Sql\Parser\SqliteParser'; + $class = 'Aura\Sql\Parser\SqliteParser'; } return new $class(); } @@ -953,10 +956,10 @@ protected function newParser($driver) * * @param string $driver The PDO driver name. * - * @return null + * @return void * */ - protected function setQuoteName($driver) + protected function setQuoteName(string $driver): void { switch ($driver) { case 'mysql': @@ -985,11 +988,11 @@ protected function setQuoteName($driver) * Retrieve a database connection attribute * * @param int $attribute - * @return mixed + * @return bool|int|string|array|null */ - public function getAttribute($attribute) + public function getAttribute(int $attribute): bool|int|string|array|null { - $this->connect(); + $this->lazyConnect(); return $this->pdo->getAttribute($attribute); } @@ -1001,9 +1004,9 @@ public function getAttribute($attribute) * @param mixed $value * @return bool */ - public function setAttribute($attribute, $value) + public function setAttribute(int $attribute, mixed $value): bool { - $this->connect(); + $this->lazyConnect(); return $this->pdo->setAttribute($attribute, $value); } } diff --git a/includes/vendor/aura/sql/src/ConnectionLocator.php b/includes/vendor/aura/sql/src/ConnectionLocator.php index 80a8fbe0c..66cb1fa60 100644 --- a/includes/vendor/aura/sql/src/ConnectionLocator.php +++ b/includes/vendor/aura/sql/src/ConnectionLocator.php @@ -33,7 +33,7 @@ class ConnectionLocator implements ConnectionLocatorInterface * @var array * */ - protected $read = []; + protected array $read = []; /** * @@ -42,13 +42,13 @@ class ConnectionLocator implements ConnectionLocatorInterface * @var array * */ - protected $write = []; + protected array $write = []; /** * * Constructor. * - * @param callable $default A callable to create a default connection. + * @param callable|null $default A callable to create a default connection. * * @param array $read An array of callables to create read connections. * @@ -56,7 +56,7 @@ class ConnectionLocator implements ConnectionLocatorInterface * */ public function __construct( - $default = null, + ?callable $default = null, array $read = [], array $write = [] ) { @@ -77,10 +77,9 @@ public function __construct( * * @param callable $callable The factory for the connection. * - * @return null - * + * @return void */ - public function setDefault(callable $callable) + public function setDefault(callable $callable): void { $this->default = $callable; } @@ -91,9 +90,14 @@ public function setDefault(callable $callable) * * @return ExtendedPdoInterface * + * @throws Exception\ConnectionNotFound */ - public function getDefault() + public function getDefault(): ExtendedPdoInterface { + if (! $this->default) { + throw new Exception\ConnectionNotFound("default"); + } + if (! $this->default instanceof ExtendedPdo) { $this->default = call_user_func($this->default); } @@ -109,10 +113,9 @@ public function getDefault() * * @param callable $callable The factory for the connection. * - * @return null - * + * @return void */ - public function setRead($name, callable $callable) + public function setRead(string $name, callable $callable): void { $this->read[$name] = $callable; } @@ -127,8 +130,9 @@ public function setRead($name, callable $callable) * * @return ExtendedPdoInterface * + * @throws \Aura\Sql\Exception\ConnectionNotFound */ - public function getRead($name = '') + public function getRead(string $name = ''): ExtendedPdoInterface { return $this->getConnection('read', $name); } @@ -141,10 +145,9 @@ public function getRead($name = '') * * @param callable $callable The factory for the connection. * - * @return null - * + * @return void */ - public function setWrite($name, callable $callable) + public function setWrite(string $name, callable $callable): void { $this->write[$name] = $callable; } @@ -159,8 +162,9 @@ public function setWrite($name, callable $callable) * * @return ExtendedPdoInterface * + * @throws \Aura\Sql\Exception\ConnectionNotFound */ - public function getWrite($name = '') + public function getWrite(string $name = ''): ExtendedPdoInterface { return $this->getConnection('write', $name); } @@ -178,7 +182,7 @@ public function getWrite($name = '') * @throws Exception\ConnectionNotFound * */ - protected function getConnection($type, $name) + protected function getConnection(string $type, string $name): ExtendedPdoInterface { $conn = &$this->{$type}; @@ -191,7 +195,7 @@ protected function getConnection($type, $name) } if (! isset($conn[$name])) { - throw new Exception\ConnectionNotFound("{$type}:{$name}"); + throw new Exception\ConnectionNotFound("$type:$name"); } if (! $conn[$name] instanceof ExtendedPdo) { diff --git a/includes/vendor/aura/sql/src/ConnectionLocatorInterface.php b/includes/vendor/aura/sql/src/ConnectionLocatorInterface.php index 5daf99c24..e30beb6f0 100644 --- a/includes/vendor/aura/sql/src/ConnectionLocatorInterface.php +++ b/includes/vendor/aura/sql/src/ConnectionLocatorInterface.php @@ -23,10 +23,9 @@ interface ConnectionLocatorInterface * * @param callable $callable The registry entry. * - * @return null - * + * @return void */ - public function setDefault(callable $callable); + public function setDefault(callable $callable): void; /** * @@ -35,7 +34,7 @@ public function setDefault(callable $callable); * @return ExtendedPdoInterface * */ - public function getDefault(); + public function getDefault(): ExtendedPdoInterface; /** * @@ -45,10 +44,9 @@ public function getDefault(); * * @param callable $callable The registry entry. * - * @return null - * + * @return void */ - public function setRead($name, callable $callable); + public function setRead(string $name, callable $callable): void; /** * @@ -61,7 +59,7 @@ public function setRead($name, callable $callable); * @return ExtendedPdoInterface * */ - public function getRead($name = ''); + public function getRead(string $name = ''): ExtendedPdoInterface; /** * @@ -71,10 +69,9 @@ public function getRead($name = ''); * * @param callable $callable The registry entry. * - * @return null - * + * @return void */ - public function setWrite($name, callable $callable); + public function setWrite(string $name, callable $callable): void; /** * @@ -87,5 +84,5 @@ public function setWrite($name, callable $callable); * @return ExtendedPdoInterface * */ - public function getWrite($name = ''); + public function getWrite(string $name = ''): ExtendedPdoInterface; } diff --git a/includes/vendor/aura/sql/src/DecoratedPdo.php b/includes/vendor/aura/sql/src/DecoratedPdo.php index 8916b86ae..7dd2fc82d 100644 --- a/includes/vendor/aura/sql/src/DecoratedPdo.php +++ b/includes/vendor/aura/sql/src/DecoratedPdo.php @@ -30,31 +30,42 @@ class DecoratedPdo extends AbstractExtendedPdo * * @param PDO $pdo An existing PDO instance to decorate. * - * @param ProfilerInterface $profiler Tracks and logs query profiles. + * @param ProfilerInterface|null $profiler Tracks and logs query profiles. * */ - public function __construct(PDO $pdo, ProfilerInterface $profiler = null) + public function __construct(PDO $pdo, ?ProfilerInterface $profiler = null) { $this->pdo = $pdo; - if ($profiler === null) { - $profiler = new Profiler(); - } - $this->setProfiler($profiler); + $this->setProfiler($profiler ?? new Profiler()); $driver = $pdo->getAttribute(PDO::ATTR_DRIVER_NAME); $this->setParser($this->newParser($driver)); $this->setQuoteName($driver); } + public static function connect( + string $dsn, + ?string $username = null, + ?string $password = null, + ?array $options = null, + ?ProfilerInterface $profiler = null + ): static { + if (version_compare(PHP_VERSION, '8.4.0', '>=')) { + return new static(\PDO::connect($dsn, $username, $password, $options)); + } else { + return new static(new PDO($dsn, $username, $password, $options), $profiler); + } + } + /** * * Connects to the database. * - * @return null + * @return void * */ - public function connect() + public function lazyConnect(): void { // already connected } @@ -63,10 +74,11 @@ public function connect() * * Disconnects from the database; disallowed with decorated PDO connections. * - * @return null + * @return void * + * @throws Exception\CannotDisconnect */ - public function disconnect() + public function disconnect(): void { $message = "Cannot disconnect a DecoratedPdo instance."; throw new Exception\CannotDisconnect($message); diff --git a/includes/vendor/aura/sql/src/ExtendedPdo.php b/includes/vendor/aura/sql/src/ExtendedPdo.php index 18820e68d..700889e67 100644 --- a/includes/vendor/aura/sql/src/ExtendedPdo.php +++ b/includes/vendor/aura/sql/src/ExtendedPdo.php @@ -21,6 +21,9 @@ */ class ExtendedPdo extends AbstractExtendedPdo { + public const CONNECT_IMMEDIATELY = 'auraSqlImmediate'; + public const DRIVER_SPECIFIC = 'auraSqlDriverSpecific'; + /** * * Constructor arguments for instantiating the PDO connection. @@ -28,7 +31,15 @@ class ExtendedPdo extends AbstractExtendedPdo * @var array * */ - protected $args = []; + protected array $args = []; + + /** + * + * Flag for how to construct the PDO object + * + * @var bool + */ + protected bool $driverSpecific = false; /** * @@ -39,32 +50,37 @@ class ExtendedPdo extends AbstractExtendedPdo * * @param string $dsn The data source name for the connection. * - * @param string $username The username for the connection. + * @param string|null $username The username for the connection. * - * @param string $password The password for the connection. + * @param string|null $password The password for the connection. * * @param array $options Driver-specific options for the connection. * * @param array $queries Queries to execute after the connection. * - * @param ProfilerInterface $profiler Tracks and logs query profiles. + * @param \Aura\Sql\Profiler\ProfilerInterface|null $profiler Tracks and logs query profiles. * * @see http://php.net/manual/en/pdo.construct.php - * */ public function __construct( - $dsn, - $username = null, - $password = null, + string $dsn, + ?string $username = null, + ?string $password = null, array $options = [], array $queries = [], - ProfilerInterface $profiler = null + ?ProfilerInterface $profiler = null ) { // if no error mode is specified, use exceptions if (! isset($options[PDO::ATTR_ERRMODE])) { $options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION; } + // check option for driver specific construct and set flag for lazy loading later + if (isset($options[static::DRIVER_SPECIFIC])) { + $this->driverSpecific = (bool)$options[static::DRIVER_SPECIFIC]; + unset($options[static::DRIVER_SPECIFIC]); + } + // retain the arguments for later $this->args = [ $dsn, @@ -75,28 +91,46 @@ public function __construct( ]; // retain a profiler, instantiating a default one if needed - if ($profiler === null) { - $profiler = new Profiler(); - } - $this->setProfiler($profiler); + $this->setProfiler($profiler ?? new Profiler()); // retain a query parser - $parts = explode(':', $dsn); + $parts = explode(":", $dsn); $parser = $this->newParser($parts[0]); $this->setParser($parser); // set quotes for identifier names $this->setQuoteName($parts[0]); + + // create a connection immediately + if (isset($options[static::CONNECT_IMMEDIATELY])) { + $connectImmediately = (bool)$options[static::CONNECT_IMMEDIATELY]; + unset($options[static::CONNECT_IMMEDIATELY]); + if ($connectImmediately) { + $this->lazyConnect(); + } + } + } + + public static function connect( + string $dsn, + ?string $username = null, + ?string $password = null, + ?array $options = null, + array $queries = [], + ?ProfilerInterface $profiler = null + ): static { + $options ??= []; + $options[static::DRIVER_SPECIFIC] = true; + return new static($dsn, $username, $password, $options, $queries, $profiler); } /** * * Connects to the database. * - * @return null - * + * @return void */ - public function connect() + public function lazyConnect(): void { if ($this->pdo) { return; @@ -105,6 +139,11 @@ public function connect() // connect $this->profiler->start(__FUNCTION__); list($dsn, $username, $password, $options, $queries) = $this->args; + if ($this->driverSpecific && version_compare(PHP_VERSION, '8.4.0', '>=')) { + $this->pdo = PDO::connect($dsn, $username, $password, $options); + } else { + $this->pdo = new PDO($dsn, $username, $password, $options); + } $this->pdo = new PDO($dsn, $username, $password, $options); $this->profiler->finish(); @@ -118,10 +157,10 @@ public function connect() * * Disconnects from the database. * - * @return null + * @return void * */ - public function disconnect() + public function disconnect(): void { $this->profiler->start(__FUNCTION__); $this->pdo = null; @@ -135,7 +174,7 @@ public function disconnect() * @return array * */ - public function __debugInfo() + public function __debugInfo(): array { return [ 'args' => [ @@ -144,7 +183,7 @@ public function __debugInfo() '****', $this->args[3], $this->args[4], - ] + ], ]; } @@ -155,9 +194,9 @@ public function __debugInfo() * @return \PDO * */ - public function getPdo() + public function getPdo(): PDO { - $this->connect(); + $this->lazyConnect(); return $this->pdo; } } diff --git a/includes/vendor/aura/sql/src/ExtendedPdoInterface.php b/includes/vendor/aura/sql/src/ExtendedPdoInterface.php index 323c3f659..0aaa3f433 100644 --- a/includes/vendor/aura/sql/src/ExtendedPdoInterface.php +++ b/includes/vendor/aura/sql/src/ExtendedPdoInterface.php @@ -10,7 +10,9 @@ use Aura\Sql\Parser\ParserInterface; use Aura\Sql\Profiler\ProfilerInterface; +use Generator; use PDO; +use PDOStatement; /** * @@ -26,14 +28,14 @@ interface ExtendedPdoInterface extends PdoInterface * Connects to the database. * */ - public function connect(); + public function lazyConnect(): void; /** * * Disconnects from the database. * */ - public function disconnect(); + public function disconnect(): void; /** * @@ -46,7 +48,7 @@ public function disconnect(); * @return int * */ - public function fetchAffected($statement, array $values = []); + public function fetchAffected(string $statement, array $values = []): int; /** * @@ -60,7 +62,7 @@ public function fetchAffected($statement, array $values = []); * @return array * */ - public function fetchAll($statement, array $values = []); + public function fetchAll(string $statement, array $values = []): array; /** * @@ -78,7 +80,7 @@ public function fetchAll($statement, array $values = []); * @return array * */ - public function fetchAssoc($statement, array $values = []); + public function fetchAssoc(string $statement, array $values = []): array; /** * @@ -91,7 +93,7 @@ public function fetchAssoc($statement, array $values = []); * @return array * */ - public function fetchCol($statement, array $values = []); + public function fetchCol(string $statement, array $values = []): array; /** * @@ -109,10 +111,10 @@ public function fetchCol($statement, array $values = []); * */ public function fetchGroup( - $statement, + string $statement, array $values = [], - $style = PDO::FETCH_COLUMN - ); + int $style = PDO::FETCH_COLUMN + ): array; /** * @@ -133,15 +135,15 @@ public function fetchGroup( * * @param array $args Arguments to pass to the object constructor. * - * @return object + * @return object|false * */ public function fetchObject( - $statement, + string $statement, array $values = [], - $class = 'stdClass', + string $class = 'stdClass', array $args = [] - ); + ): object|false; /** * @@ -168,11 +170,11 @@ public function fetchObject( * */ public function fetchObjects( - $statement, + string $statement, array $values = [], - $class = 'stdClass', + string $class = 'stdClass', array $args = [] - ); + ): array; /** * @@ -182,10 +184,10 @@ public function fetchObjects( * * @param array $values Values to bind to the query. * - * @return array + * @return array|false * */ - public function fetchOne($statement, array $values = []); + public function fetchOne(string $statement, array $values = []): array|false; /** * @@ -199,7 +201,7 @@ public function fetchOne($statement, array $values = []); * @return array * */ - public function fetchPairs($statement, array $values = []); + public function fetchPairs(string $statement, array $values = []): array; /** * @@ -212,7 +214,7 @@ public function fetchPairs($statement, array $values = []); * @return mixed * */ - public function fetchValue($statement, array $values = []); + public function fetchValue(string $statement, array $values = []): mixed; /** * @@ -221,7 +223,7 @@ public function fetchValue($statement, array $values = []); * @return ParserInterface * */ - public function getParser(); + public function getParser(): ParserInterface; /** * @@ -230,7 +232,7 @@ public function getParser(); * @return \PDO * */ - public function getPdo(); + public function getPdo(): PDO; /** * @@ -239,7 +241,7 @@ public function getPdo(); * @return ProfilerInterface * */ - public function getProfiler(); + public function getProfiler(): ProfilerInterface; /** * @@ -250,7 +252,7 @@ public function getProfiler(); * @return string The multi-part identifier name, quoted. * */ - public function quoteName($name); + public function quoteName(string $name): string; /** * @@ -261,7 +263,7 @@ public function quoteName($name); * @return string The quoted identifier name. * */ - public function quoteSingleName($name); + public function quoteSingleName(string $name): string; /** * @@ -270,7 +272,7 @@ public function quoteSingleName($name); * @return bool * */ - public function isConnected(); + public function isConnected(): bool; /** * @@ -279,7 +281,7 @@ public function isConnected(); * @param ParserInterface $parser The Parser instance. * */ - public function setParser(ParserInterface $parser); + public function setParser(ParserInterface $parser): void; /** * @@ -288,7 +290,7 @@ public function setParser(ParserInterface $parser); * @param ProfilerInterface $profiler The Profiler instance. * */ - public function setProfiler(ProfilerInterface $profiler); + public function setProfiler(ProfilerInterface $profiler): void; /** * @@ -301,7 +303,7 @@ public function setProfiler(ProfilerInterface $profiler); * @return \Generator * */ - public function yieldAll($statement, array $values = []); + public function yieldAll(string $statement, array $values = []): Generator; /** * @@ -314,7 +316,7 @@ public function yieldAll($statement, array $values = []); * @return \Generator * */ - public function yieldAssoc($statement, array $values = []); + public function yieldAssoc(string $statement, array $values = []): Generator; /** * @@ -327,7 +329,7 @@ public function yieldAssoc($statement, array $values = []); * @return \Generator * */ - public function yieldCol($statement, array $values = []); + public function yieldCol(string $statement, array $values = []): Generator; /** * @@ -352,11 +354,11 @@ public function yieldCol($statement, array $values = []); * */ public function yieldObjects( - $statement, + string $statement, array $values = [], - $class = 'stdClass', + string $class = 'stdClass', array $args = [] - ); + ): Generator; /** * @@ -370,7 +372,7 @@ public function yieldObjects( * @return \Generator * */ - public function yieldPairs($statement, array $values = []); + public function yieldPairs(string $statement, array $values = []): Generator; /** * @@ -384,7 +386,7 @@ public function yieldPairs($statement, array $values = []); * @return \PDOStatement * */ - public function perform($statement, array $values = []); + public function perform(string $statement, array $values = []): PDOStatement; /** * @@ -408,5 +410,5 @@ public function perform($statement, array $values = []); * @see http://php.net/manual/en/pdo.prepare.php * */ - public function prepareWithValues($statement, array $values = []); + public function prepareWithValues(string $statement, array $values = []): PDOStatement; } diff --git a/includes/vendor/aura/sql/src/Parser/AbstractParser.php b/includes/vendor/aura/sql/src/Parser/AbstractParser.php index d69b3d90d..007244de4 100644 --- a/includes/vendor/aura/sql/src/Parser/AbstractParser.php +++ b/includes/vendor/aura/sql/src/Parser/AbstractParser.php @@ -29,7 +29,7 @@ abstract class AbstractParser implements ParserInterface * @var array * */ - protected $split = [ + protected array $split = [ // single-quoted string "'(?:[^'\\\\]|\\\\'?)*'", // double-quoted string @@ -43,7 +43,7 @@ abstract class AbstractParser implements ParserInterface * @var string * */ - protected $skip = '/^(\'|\"|\:[^a-zA-Z_])/um'; + protected string $skip = '/^(\'|\"|\:[^a-zA-Z_])/um'; /** * @@ -52,7 +52,7 @@ abstract class AbstractParser implements ParserInterface * @var int * */ - protected $num = 0; + protected int $num = 0; /** * @@ -61,7 +61,7 @@ abstract class AbstractParser implements ParserInterface * @var array * */ - protected $count = [ + protected array $count = [ '__' => null, ]; @@ -72,7 +72,7 @@ abstract class AbstractParser implements ParserInterface * @var array * */ - protected $values = []; + protected array $values = []; /** * @@ -81,7 +81,7 @@ abstract class AbstractParser implements ParserInterface * @var array * */ - protected $final_values = []; + protected array $final_values = []; /** * @@ -95,7 +95,7 @@ abstract class AbstractParser implements ParserInterface * element 1 is the rebuilt array of values. * */ - public function rebuild($statement, array $values = []) + public function rebuild(string $statement, array $values = []): array { // match standard PDO execute() behavior of zero-indexed arrays if (array_key_exists(0, $values)) { @@ -116,7 +116,7 @@ public function rebuild($statement, array $values = []) * @return string The rebuilt statement. * */ - protected function rebuildStatement($statement) + protected function rebuildStatement(string $statement): string { $parts = $this->getParts($statement); return $this->rebuildParts($parts); @@ -131,7 +131,7 @@ protected function rebuildStatement($statement) * @return string The rebuilt statement. * */ - protected function rebuildParts(array $parts) + protected function rebuildParts(array $parts): string { $statement = ''; foreach ($parts as $part) { @@ -149,7 +149,7 @@ protected function rebuildParts(array $parts) * @return string The rebuilt statement. * */ - protected function rebuildPart($part) + protected function rebuildPart(string $part): string { if (preg_match($this->skip, $part)) { return $part; @@ -176,13 +176,13 @@ protected function rebuildPart($part) * @return string The prepared subparts. * */ - protected function prepareValuePlaceholders(array $subs) + protected function prepareValuePlaceholders(array $subs): string { $str = ''; foreach ($subs as $i => $sub) { $char = substr($sub, 0, 1); if ($char == '?') { - $str .= $this->prepareNumberedPlaceholder($sub); + $str .= $this->prepareNumberedPlaceholder(); } elseif ($char == ':') { $str .= $this->prepareNamedPlaceholder($sub); } else { @@ -196,13 +196,11 @@ protected function prepareValuePlaceholders(array $subs) * * Bind or quote a numbered placeholder in a query subpart. * - * @param string $sub The query subpart. - * * @return string The prepared query subpart. * * @throws MissingParameter */ - protected function prepareNumberedPlaceholder($sub) + protected function prepareNumberedPlaceholder() { $this->num ++; if (array_key_exists($this->num, $this->values) === false) { @@ -232,7 +230,7 @@ protected function prepareNumberedPlaceholder($sub) * @return string The prepared query subpart. * */ - protected function prepareNamedPlaceholder($sub) + protected function prepareNamedPlaceholder(string $sub): string { $orig = substr($sub, 1); if (array_key_exists($orig, $this->values) === false) { @@ -262,7 +260,7 @@ protected function prepareNamedPlaceholder($sub) * @return string * */ - protected function getPlaceholderName($orig) + protected function getPlaceholderName(string $orig): string { if (! isset($this->count[$orig])) { $this->count[$orig] = 0; @@ -285,7 +283,7 @@ protected function getPlaceholderName($orig) * @return string * */ - protected function expandNamedPlaceholder($prefix, array $values) + protected function expandNamedPlaceholder(string $prefix, array $values): string { $i = 0; $expanded = []; @@ -307,7 +305,7 @@ protected function expandNamedPlaceholder($prefix, array $values) * @return array * */ - protected function getParts($statement) + protected function getParts(string $statement): array { $split = implode('|', $this->split); return preg_split( diff --git a/includes/vendor/aura/sql/src/Parser/MysqlParser.php b/includes/vendor/aura/sql/src/Parser/MysqlParser.php index f516f551e..7066abac7 100644 --- a/includes/vendor/aura/sql/src/Parser/MysqlParser.php +++ b/includes/vendor/aura/sql/src/Parser/MysqlParser.php @@ -24,7 +24,7 @@ class MysqlParser extends AbstractParser * @var array * */ - protected $split = [ + protected array $split = [ // single-quoted string "'(?:[^'\\\\]|\\\\'?)*'", // double-quoted string @@ -40,5 +40,5 @@ class MysqlParser extends AbstractParser * @var string * */ - protected $skip = '/^(\'|\"|\`)/um'; + protected string $skip = '/^(\'|\"|\`)/um'; } diff --git a/includes/vendor/aura/sql/src/Parser/NullParser.php b/includes/vendor/aura/sql/src/Parser/NullParser.php index 09af509ab..a6534a390 100644 --- a/includes/vendor/aura/sql/src/Parser/NullParser.php +++ b/includes/vendor/aura/sql/src/Parser/NullParser.php @@ -22,15 +22,15 @@ class NullParser implements ParserInterface * * Leaves the query and parameters alone. * - * @param string $statement The query statement string. + * @param string $string The query statement string. * - * @param array $values Bind these values into the query. + * @param array $parameters Bind these values into the query. * * @return array * */ - public function rebuild($statement, array $values = []) + public function rebuild(string $string, array $parameters = []): array { - return [$statement, $values]; + return [$string, $parameters]; } } diff --git a/includes/vendor/aura/sql/src/Parser/ParserInterface.php b/includes/vendor/aura/sql/src/Parser/ParserInterface.php index dc1380792..b90dd922b 100644 --- a/includes/vendor/aura/sql/src/Parser/ParserInterface.php +++ b/includes/vendor/aura/sql/src/Parser/ParserInterface.php @@ -30,5 +30,5 @@ interface ParserInterface * element 1 is the rebuilt array of values. * */ - public function rebuild($string, array $parameters = []); + public function rebuild(string $string, array $parameters = []): array; } diff --git a/includes/vendor/aura/sql/src/Parser/PgsqlParser.php b/includes/vendor/aura/sql/src/Parser/PgsqlParser.php index ead10f732..261cf5da5 100644 --- a/includes/vendor/aura/sql/src/Parser/PgsqlParser.php +++ b/includes/vendor/aura/sql/src/Parser/PgsqlParser.php @@ -24,7 +24,7 @@ class PgsqlParser extends AbstractParser * @var array * */ - protected $split = [ + protected array $split = [ // single-quoted string "'(?:[^'\\\\]|\\\\'?)*'", // double-quoted string @@ -42,5 +42,5 @@ class PgsqlParser extends AbstractParser * @var string * */ - protected $skip = '/^(\'|\"|\$|\:[^a-zA-Z_])/um'; + protected string $skip = '/^(\'|\"|\$|\:[^a-zA-Z_])/um'; } diff --git a/includes/vendor/aura/sql/src/Parser/SqliteParser.php b/includes/vendor/aura/sql/src/Parser/SqliteParser.php index 61bf9bf7a..2806d749b 100644 --- a/includes/vendor/aura/sql/src/Parser/SqliteParser.php +++ b/includes/vendor/aura/sql/src/Parser/SqliteParser.php @@ -17,4 +17,20 @@ */ class SqliteParser extends AbstractParser { + /** + * {@inheritDoc} + */ + protected array $split = [ + // single-quoted string + "'(?:[^'\\\\]|\\\\'?)*'", + // double-quoted string + '"(?:[^"\\\\]|\\\\"?)*"', + // backticked column names + '`(?:[^`\\\\]|\\\\`?)*`', + ]; + + /** + * {@inheritDoc} + */ + protected string $skip = '/^(\'|"|`|\:[^a-zA-Z_])/um'; } diff --git a/includes/vendor/aura/sql/src/PdoInterface.php b/includes/vendor/aura/sql/src/PdoInterface.php index 23754c0a5..7f2954576 100644 --- a/includes/vendor/aura/sql/src/PdoInterface.php +++ b/includes/vendor/aura/sql/src/PdoInterface.php @@ -9,6 +9,7 @@ namespace Aura\Sql; use PDO; +use PDOStatement; /** * @@ -28,7 +29,7 @@ interface PdoInterface * @see http://php.net/manual/en/pdo.begintransaction.php * */ - public function beginTransaction(); + public function beginTransaction(): bool; /** * @@ -39,16 +40,38 @@ public function beginTransaction(); * @see http://php.net/manual/en/pdo.commit.php * */ - public function commit(); + public function commit(): bool; /** * - * Gets the most recent error code. + * Introduced in 6.x due to PHP 8.4 change. This is a BC break for Aura.Sql. + * + * @param string $dsn The Data Source Name, or DSN, contains the information required to connect to the database. + * + * @param string | null $username The user name for the DSN string. This parameter is optional for some PDO drivers. + * + * @param string | null $password The password for the DSN string. This parameter is optional for some PDO drivers. * - * @return mixed + * @param array | null $options A key=>value array of driver-specific connection options. * + * @return \PDO Returns an instance of a generic PDO instance. + * + * @see https://www.php.net/manual/en/pdo.connect.php */ - public function errorCode(); + public static function connect( + string $dsn, + ?string $username = null, + #[\SensitiveParameter] ?string $password = null, + ?array $options = null + ): static; + + /** + * + * Gets the most recent error code. + * + * @return string|null + */ + public function errorCode(): ?string; /** * @@ -57,7 +80,7 @@ public function errorCode(); * @return array * */ - public function errorInfo(); + public function errorInfo(): array; /** * @@ -65,23 +88,32 @@ public function errorInfo(); * * @param string $statement The SQL statement to execute. * - * @return int The number of rows affected. + * @return int|false The number of rows affected. * * @see http://php.net/manual/en/pdo.exec.php * */ - public function exec($statement); + public function exec(string $statement): int|false; /** * * Gets a PDO attribute value. * - * @param mixed $attribute The PDO::ATTR_* constant. + * @param int $attribute The PDO::ATTR_* constant. * - * @return mixed The value for the attribute. + * @return bool|int|string|array|null The value for the attribute. * */ - public function getAttribute($attribute); + public function getAttribute(int $attribute): bool|int|string|array|null; + + /** + * + * Returns all currently available PDO drivers. + * + * @return array + * + */ + public static function getAvailableDrivers(): array; /** * @@ -92,67 +124,68 @@ public function getAttribute($attribute); * @see http://php.net/manual/en/pdo.intransaction.php * */ - public function inTransaction(); + public function inTransaction(): bool; /** * * Returns the last inserted autoincrement sequence value. * - * @param string $name The name of the sequence to check; typically needed + * @param string|null $name The name of the sequence to check; typically needed * only for PostgreSQL, where it takes the form of `
__seq`. * - * @return string + * @return string|false * * @see http://php.net/manual/en/pdo.lastinsertid.php * */ - public function lastInsertId($name = null); + public function lastInsertId(?string $name = null): string|false; /** * * Prepares an SQL statement for execution. * - * @param string $statement The SQL statement to prepare for execution. + * @param string $query The SQL statement to prepare for execution. * * @param array $options Set these attributes on the returned * PDOStatement. * - * @return \PDOStatement + * @return \PDOStatement|false * * @see http://php.net/manual/en/pdo.prepare.php - * */ - public function prepare($statement, $options = null); + public function prepare(string $query, array $options = []): PDOStatement|false; /** * * Queries the database and returns a PDOStatement. * - * @param string $statement The SQL statement to prepare and execute. + * @param string $query The SQL statement to prepare and execute. + * + * @param int|null $fetchMode * - * @param mixed ...$fetch Optional fetch-related parameters. + * @param mixed ...$fetch_mode_args Optional fetch-related parameters. * - * @return \PDOStatement + * @return \PDOStatement|false * * @see http://php.net/manual/en/pdo.query.php * */ - public function query($statement, ...$fetch); + public function query(string $query, ?int $fetchMode = null, ...$fetch_mode_args): PDOStatement|false; /** * * Quotes a value for use in an SQL statement. * - * @param mixed $value The value to quote. + * @param string|int|array|float|null $value The value to quote. * - * @param int $parameter_type A data type hint for the database driver. + * @param int $type A data type hint for the database driver. * - * @return string The quoted value. + * @return string|false The quoted value. * * @see http://php.net/manual/en/pdo.quote.php * */ - public function quote($value, $parameter_type = PDO::PARAM_STR); + public function quote(string|int|array|float|null $value, int $type = PDO::PARAM_STR): string|false; /** * @@ -163,27 +196,18 @@ public function quote($value, $parameter_type = PDO::PARAM_STR); * @see http://php.net/manual/en/pdo.rollback.php * */ - public function rollBack(); + public function rollBack(): bool; /** * * Sets a PDO attribute value. * - * @param mixed $attribute The PDO::ATTR_* constant. + * @param int $attribute The PDO::ATTR_* constant. * * @param mixed $value The value for the attribute. * * @return bool * */ - public function setAttribute($attribute, $value); - - /** - * - * Returns all currently available PDO drivers. - * - * @return array - * - */ - public static function getAvailableDrivers(); + public function setAttribute(int $attribute, mixed $value): bool; } diff --git a/includes/vendor/aura/sql/src/Profiler/MemoryLogger.php b/includes/vendor/aura/sql/src/Profiler/MemoryLogger.php index c94e564f8..78184eed5 100644 --- a/includes/vendor/aura/sql/src/Profiler/MemoryLogger.php +++ b/includes/vendor/aura/sql/src/Profiler/MemoryLogger.php @@ -26,7 +26,7 @@ class MemoryLogger extends AbstractLogger * @var array * */ - protected $messages = []; + protected array $messages = []; /** * @@ -38,10 +38,9 @@ class MemoryLogger extends AbstractLogger * * @param array $context Data to interpolate into the message. * - * @return null - * + * @return void */ - public function log($level, $message, array $context = []) + public function log($level, $message, array $context = []): void { $replace = []; foreach ($context as $key => $val) { @@ -57,7 +56,7 @@ public function log($level, $message, array $context = []) * @return array * */ - public function getMessages() + public function getMessages(): array { return $this->messages; } diff --git a/includes/vendor/aura/sql/src/Profiler/Profiler.php b/includes/vendor/aura/sql/src/Profiler/Profiler.php index 6f341bc81..42d591b6b 100644 --- a/includes/vendor/aura/sql/src/Profiler/Profiler.php +++ b/includes/vendor/aura/sql/src/Profiler/Profiler.php @@ -28,7 +28,7 @@ class Profiler implements ProfilerInterface * @var array * */ - protected $context = []; + protected array $context = []; /** * @@ -37,7 +37,7 @@ class Profiler implements ProfilerInterface * @var LoggerInterface * */ - protected $logger; + protected LoggerInterface $logger; /** * @@ -48,7 +48,7 @@ class Profiler implements ProfilerInterface * @see setActive() * */ - protected $active = false; + protected bool $active = false; /** * @@ -59,7 +59,7 @@ class Profiler implements ProfilerInterface * @see setLogLevel() * */ - protected $logLevel = LogLevel::DEBUG; + protected string $logLevel = LogLevel::DEBUG; /** * @@ -70,21 +70,17 @@ class Profiler implements ProfilerInterface * @see setLogFormat() * */ - protected $logFormat = "{function} ({duration} seconds): {statement} {backtrace}"; + protected string $logFormat = "{function} ({duration} seconds): {statement} {backtrace}"; /** * * Constructor. * - * @param LoggerInterface $logger Record profiles through this interface. - * + * @param \Psr\Log\LoggerInterface|null $logger Record profiles through this interface. */ - public function __construct(LoggerInterface $logger = null) + public function __construct(?LoggerInterface $logger = null) { - if ($logger === null) { - $logger = new MemoryLogger(); - } - $this->logger = $logger; + $this->logger = $logger ?? new MemoryLogger(); } /** @@ -94,9 +90,9 @@ public function __construct(LoggerInterface $logger = null) * @param bool $active * */ - public function setActive($active) + public function setActive(bool $active) { - $this->active = (bool) $active; + $this->active = $active; } /** @@ -106,7 +102,7 @@ public function setActive($active) * @return bool * */ - public function isActive() + public function isActive(): bool { return $this->active; } @@ -118,7 +114,7 @@ public function isActive() * @return \Psr\Log\LoggerInterface * */ - public function getLogger() + public function getLogger(): LoggerInterface { return $this->logger; } @@ -130,7 +126,7 @@ public function getLogger() * @return string * */ - public function getLogLevel() + public function getLogLevel(): string { return $this->logLevel; } @@ -141,10 +137,9 @@ public function getLogLevel() * * @param string $logLevel A PSR LogLevel constant. * - * @return null - * + * @return void */ - public function setLogLevel($logLevel) + public function setLogLevel(string $logLevel): void { $this->logLevel = $logLevel; } @@ -156,7 +151,7 @@ public function setLogLevel($logLevel) * @return string * */ - public function getLogFormat() + public function getLogFormat(): string { return $this->logFormat; } @@ -167,10 +162,9 @@ public function getLogFormat() * * @param string $logFormat * - * @return null - * + * @return void */ - public function setLogFormat($logFormat) + public function setLogFormat(string $logFormat): void { $this->logFormat = $logFormat; } @@ -181,10 +175,9 @@ public function setLogFormat($logFormat) * * @param string $function The function starting the profile entry. * - * @return null - * + * @return void */ - public function start($function) + public function start(string $function): void { if (! $this->active) { return; @@ -200,14 +193,13 @@ public function start($function) * * Finishes and logs a profile entry. * - * @param string $statement The statement being profiled, if any. + * @param string|null $statement The statement being profiled, if any. * * @param array $values The values bound to the statement, if any. * - * @return null - * + * @return void */ - public function finish($statement = null, array $values = []) + public function finish(?string $statement = null, array $values = []): void { if (! $this->active) { return; diff --git a/includes/vendor/aura/sql/src/Profiler/ProfilerInterface.php b/includes/vendor/aura/sql/src/Profiler/ProfilerInterface.php index 14d114b42..ae1f6a89d 100644 --- a/includes/vendor/aura/sql/src/Profiler/ProfilerInterface.php +++ b/includes/vendor/aura/sql/src/Profiler/ProfilerInterface.php @@ -24,7 +24,7 @@ interface ProfilerInterface * @param bool $active * */ - public function setActive($active); + public function setActive(bool $active); /** * @@ -33,7 +33,7 @@ public function setActive($active); * @return bool * */ - public function isActive(); + public function isActive(): bool; /** * @@ -42,7 +42,7 @@ public function isActive(); * @return \Psr\Log\LoggerInterface * */ - public function getLogger(); + public function getLogger(): \Psr\Log\LoggerInterface; /** * @@ -51,7 +51,7 @@ public function getLogger(); * @return string * */ - public function getLogLevel(); + public function getLogLevel(): string; /** * @@ -59,10 +59,9 @@ public function getLogLevel(); * * @param string $logLevel A PSR LogLevel constant. * - * @return null - * + * @return void */ - public function setLogLevel($logLevel); + public function setLogLevel(string $logLevel): void; /** * @@ -71,7 +70,7 @@ public function setLogLevel($logLevel); * @return string * */ - public function getLogFormat(); + public function getLogFormat(): string; /** * @@ -79,10 +78,9 @@ public function getLogFormat(); * * @param string $logFormat * - * @return null - * + * @return void */ - public function setLogFormat($logFormat); + public function setLogFormat(string $logFormat): void; /** * @@ -90,21 +88,19 @@ public function setLogFormat($logFormat); * * @param string $function The function starting the profile entry. * - * @return null - * + * @return void */ - public function start($function); + public function start(string $function): void; /** * * Finishes and logs a profile entry. * - * @param string $statement The statement being profiled, if any. + * @param string|null $statement The statement being profiled, if any. * * @param array $values The values bound to the statement, if any. * - * @return null - * + * @return void */ - public function finish($statement = null, array $values = []); + public function finish(?string $statement = null, array $values = []): void; } diff --git a/includes/vendor/autoload.php b/includes/vendor/autoload.php index 4a65e6f8a..744c47e29 100644 --- a/includes/vendor/autoload.php +++ b/includes/vendor/autoload.php @@ -2,6 +2,21 @@ // autoload.php @generated by Composer +if (PHP_VERSION_ID < 50600) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL; + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, $err); + } elseif (!headers_sent()) { + echo $err; + } + } + throw new RuntimeException($err); +} + require_once __DIR__ . '/composer/autoload_real.php'; -return ComposerAutoloaderInit2d6d15a8f6cc4bfbfd4a2943a6c4df59::getLoader(); +return ComposerAutoloaderInit1d5e2036274043d1e0e9e3243991653e::getLoader(); diff --git a/includes/vendor/build-script/yourls-build.sh b/includes/vendor/build-script/yourls-build.sh index 678541e6d..3fd4b9716 100755 --- a/includes/vendor/build-script/yourls-build.sh +++ b/includes/vendor/build-script/yourls-build.sh @@ -38,6 +38,7 @@ PRESERVE_IN_LIB=( 'Psr' 'README.md' 'readme.md' + 'certificates' ) # Nothing to edit past this line ! diff --git a/includes/vendor/composer/ClassLoader.php b/includes/vendor/composer/ClassLoader.php index 4d989a212..7824d8f7e 100644 --- a/includes/vendor/composer/ClassLoader.php +++ b/includes/vendor/composer/ClassLoader.php @@ -42,30 +42,76 @@ */ class ClassLoader { + /** @var \Closure(string):void */ + private static $includeFile; + + /** @var string|null */ private $vendorDir; // PSR-4 + /** + * @var array> + */ private $prefixLengthsPsr4 = array(); + /** + * @var array> + */ private $prefixDirsPsr4 = array(); + /** + * @var list + */ private $fallbackDirsPsr4 = array(); // PSR-0 + /** + * List of PSR-0 prefixes + * + * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) + * + * @var array>> + */ private $prefixesPsr0 = array(); + /** + * @var list + */ private $fallbackDirsPsr0 = array(); + /** @var bool */ private $useIncludePath = false; + + /** + * @var array + */ private $classMap = array(); + + /** @var bool */ private $classMapAuthoritative = false; + + /** + * @var array + */ private $missingClasses = array(); + + /** @var string|null */ private $apcuPrefix; + /** + * @var array + */ private static $registeredLoaders = array(); + /** + * @param string|null $vendorDir + */ public function __construct($vendorDir = null) { $this->vendorDir = $vendorDir; + self::initializeIncludeClosure(); } + /** + * @return array> + */ public function getPrefixes() { if (!empty($this->prefixesPsr0)) { @@ -75,28 +121,42 @@ public function getPrefixes() return array(); } + /** + * @return array> + */ public function getPrefixesPsr4() { return $this->prefixDirsPsr4; } + /** + * @return list + */ public function getFallbackDirs() { return $this->fallbackDirsPsr0; } + /** + * @return list + */ public function getFallbackDirsPsr4() { return $this->fallbackDirsPsr4; } + /** + * @return array Array of classname => path + */ public function getClassMap() { return $this->classMap; } /** - * @param array $classMap Class to filename map + * @param array $classMap Class to filename map + * + * @return void */ public function addClassMap(array $classMap) { @@ -111,22 +171,25 @@ public function addClassMap(array $classMap) * Registers a set of PSR-0 directories for a given prefix, either * appending or prepending to the ones previously set for this prefix. * - * @param string $prefix The prefix - * @param array|string $paths The PSR-0 root directories - * @param bool $prepend Whether to prepend the directories + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + * + * @return void */ public function add($prefix, $paths, $prepend = false) { + $paths = (array) $paths; if (!$prefix) { if ($prepend) { $this->fallbackDirsPsr0 = array_merge( - (array) $paths, + $paths, $this->fallbackDirsPsr0 ); } else { $this->fallbackDirsPsr0 = array_merge( $this->fallbackDirsPsr0, - (array) $paths + $paths ); } @@ -135,19 +198,19 @@ public function add($prefix, $paths, $prepend = false) $first = $prefix[0]; if (!isset($this->prefixesPsr0[$first][$prefix])) { - $this->prefixesPsr0[$first][$prefix] = (array) $paths; + $this->prefixesPsr0[$first][$prefix] = $paths; return; } if ($prepend) { $this->prefixesPsr0[$first][$prefix] = array_merge( - (array) $paths, + $paths, $this->prefixesPsr0[$first][$prefix] ); } else { $this->prefixesPsr0[$first][$prefix] = array_merge( $this->prefixesPsr0[$first][$prefix], - (array) $paths + $paths ); } } @@ -156,25 +219,28 @@ public function add($prefix, $paths, $prepend = false) * Registers a set of PSR-4 directories for a given namespace, either * appending or prepending to the ones previously set for this namespace. * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param array|string $paths The PSR-4 base directories - * @param bool $prepend Whether to prepend the directories + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories * * @throws \InvalidArgumentException + * + * @return void */ public function addPsr4($prefix, $paths, $prepend = false) { + $paths = (array) $paths; if (!$prefix) { // Register directories for the root namespace. if ($prepend) { $this->fallbackDirsPsr4 = array_merge( - (array) $paths, + $paths, $this->fallbackDirsPsr4 ); } else { $this->fallbackDirsPsr4 = array_merge( $this->fallbackDirsPsr4, - (array) $paths + $paths ); } } elseif (!isset($this->prefixDirsPsr4[$prefix])) { @@ -184,18 +250,18 @@ public function addPsr4($prefix, $paths, $prepend = false) throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); } $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - $this->prefixDirsPsr4[$prefix] = (array) $paths; + $this->prefixDirsPsr4[$prefix] = $paths; } elseif ($prepend) { // Prepend directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( - (array) $paths, + $paths, $this->prefixDirsPsr4[$prefix] ); } else { // Append directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( $this->prefixDirsPsr4[$prefix], - (array) $paths + $paths ); } } @@ -204,8 +270,10 @@ public function addPsr4($prefix, $paths, $prepend = false) * Registers a set of PSR-0 directories for a given prefix, * replacing any others previously set for this prefix. * - * @param string $prefix The prefix - * @param array|string $paths The PSR-0 base directories + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 base directories + * + * @return void */ public function set($prefix, $paths) { @@ -220,10 +288,12 @@ public function set($prefix, $paths) * Registers a set of PSR-4 directories for a given namespace, * replacing any others previously set for this namespace. * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param array|string $paths The PSR-4 base directories + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories * * @throws \InvalidArgumentException + * + * @return void */ public function setPsr4($prefix, $paths) { @@ -243,6 +313,8 @@ public function setPsr4($prefix, $paths) * Turns on searching the include path for class files. * * @param bool $useIncludePath + * + * @return void */ public function setUseIncludePath($useIncludePath) { @@ -265,6 +337,8 @@ public function getUseIncludePath() * that have not been registered with the class map. * * @param bool $classMapAuthoritative + * + * @return void */ public function setClassMapAuthoritative($classMapAuthoritative) { @@ -285,6 +359,8 @@ public function isClassMapAuthoritative() * APCu prefix to use to cache found/not-found classes, if the extension is enabled. * * @param string|null $apcuPrefix + * + * @return void */ public function setApcuPrefix($apcuPrefix) { @@ -305,14 +381,18 @@ public function getApcuPrefix() * Registers this instance as an autoloader. * * @param bool $prepend Whether to prepend the autoloader or not + * + * @return void */ public function register($prepend = false) { spl_autoload_register(array($this, 'loadClass'), true, $prepend); if (null === $this->vendorDir) { - //no-op - } elseif ($prepend) { + return; + } + + if ($prepend) { self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; } else { unset(self::$registeredLoaders[$this->vendorDir]); @@ -322,6 +402,8 @@ public function register($prepend = false) /** * Unregisters this instance as an autoloader. + * + * @return void */ public function unregister() { @@ -336,15 +418,18 @@ public function unregister() * Loads the given class or interface. * * @param string $class The name of the class - * @return bool|null True if loaded, null otherwise + * @return true|null True if loaded, null otherwise */ public function loadClass($class) { if ($file = $this->findFile($class)) { - includeFile($file); + $includeFile = self::$includeFile; + $includeFile($file); return true; } + + return null; } /** @@ -390,15 +475,20 @@ public function findFile($class) } /** - * Returns the currently registered loaders indexed by their corresponding vendor directories. + * Returns the currently registered loaders keyed by their corresponding vendor directories. * - * @return self[] + * @return array */ public static function getRegisteredLoaders() { return self::$registeredLoaders; } + /** + * @param string $class + * @param string $ext + * @return string|false + */ private function findFileWithExtension($class, $ext) { // PSR-4 lookup @@ -464,14 +554,26 @@ private function findFileWithExtension($class, $ext) return false; } -} -/** - * Scope isolated include. - * - * Prevents access to $this/self from included files. - */ -function includeFile($file) -{ - include $file; + /** + * @return void + */ + private static function initializeIncludeClosure() + { + if (self::$includeFile !== null) { + return; + } + + /** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + */ + self::$includeFile = \Closure::bind(static function($file) { + include $file; + }, null, null); + } } diff --git a/includes/vendor/composer/InstalledVersions.php b/includes/vendor/composer/InstalledVersions.php index 7c38a3d18..2052022fd 100644 --- a/includes/vendor/composer/InstalledVersions.php +++ b/includes/vendor/composer/InstalledVersions.php @@ -1,428 +1,396 @@ + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ namespace Composer; use Composer\Autoload\ClassLoader; use Composer\Semver\VersionParser; - - - - - +/** + * This class is copied in every Composer installed project and available to all + * + * See also https://getcomposer.org/doc/07-runtime.md#installed-versions + * + * To require its presence, you can require `composer-runtime-api ^2.0` + * + * @final + */ class InstalledVersions { -private static $installed = array ( - 'root' => - array ( - 'pretty_version' => 'dev-master', - 'version' => 'dev-master', - 'aliases' => - array ( - ), - 'reference' => 'a3dd5e500abdd264c01f4c8ff026108f093f9769', - 'name' => 'yourls/yourls', - ), - 'versions' => - array ( - 'aura/sql' => - array ( - 'pretty_version' => '3.0.0', - 'version' => '3.0.0.0', - 'aliases' => - array ( - ), - 'reference' => '2be02d5dfd9fdee6df199de1a19572aa490bb744', - ), - 'composer/ca-bundle' => - array ( - 'pretty_version' => '1.2.9', - 'version' => '1.2.9.0', - 'aliases' => - array ( - ), - 'reference' => '78a0e288fdcebf92aa2318a8d3656168da6ac1a5', - ), - 'geoip2/geoip2' => - array ( - 'pretty_version' => 'v2.10.0', - 'version' => '2.10.0.0', - 'aliases' => - array ( - ), - 'reference' => '419557cd21d9fe039721a83490701a58c8ce784a', - ), - 'jakeasmith/http_build_url' => - array ( - 'pretty_version' => '1.0.1', - 'version' => '1.0.1.0', - 'aliases' => - array ( - ), - 'reference' => '93c273e77cb1edead0cf8bcf8cd2003428e74e37', - ), - 'maxmind-db/reader' => - array ( - 'pretty_version' => 'v1.9.0', - 'version' => '1.9.0.0', - 'aliases' => - array ( - ), - 'reference' => '9ee9ba9ee287b119e9f5a8e8dbfea0b49647cec4', - ), - 'maxmind/web-service-common' => - array ( - 'pretty_version' => 'v0.8.1', - 'version' => '0.8.1.0', - 'aliases' => - array ( - ), - 'reference' => '32f274051c543fc865e5a84d3a2c703913641ea8', - ), - 'ozh/bookmarkletgen' => - array ( - 'pretty_version' => '1.2', - 'version' => '1.2.0.0', - 'aliases' => - array ( - ), - 'reference' => '3319b53c493a1474a03d1cc4e087617652284c20', - ), - 'ozh/phpass' => - array ( - 'pretty_version' => '1.3.0', - 'version' => '1.3.0.0', - 'aliases' => - array ( - ), - 'reference' => '44149d1ee06ccbda397f08f69d32c59802e4ce43', - ), - 'pomo/pomo' => - array ( - 'pretty_version' => 'v1.4.1', - 'version' => '1.4.1.0', - 'aliases' => - array ( - ), - 'reference' => '1594bd1f90c89a45ffc3da2ee6d5d582bfac7542', - ), - 'psr/log' => - array ( - 'pretty_version' => '1.1.3', - 'version' => '1.1.3.0', - 'aliases' => - array ( - ), - 'reference' => '0f73288fd15629204f9d42b7055f72dacbe811fc', - ), - 'rmccue/requests' => - array ( - 'pretty_version' => 'v1.7.0', - 'version' => '1.7.0.0', - 'aliases' => - array ( - ), - 'reference' => '87932f52ffad70504d93f04f15690cf16a089546', - ), - 'spatie/array-to-xml' => - array ( - 'pretty_version' => '2.15.0', - 'version' => '2.15.0.0', - 'aliases' => - array ( - ), - 'reference' => '1795afad4e5a1f4b7af2e0e09802550eaa00a6f8', - ), - 'symfony/polyfill-intl-idn' => - array ( - 'pretty_version' => 'v1.22.0', - 'version' => '1.22.0.0', - 'aliases' => - array ( - ), - 'reference' => '0eb8293dbbcd6ef6bf81404c9ce7d95bcdf34f44', - ), - 'symfony/polyfill-intl-normalizer' => - array ( - 'pretty_version' => 'v1.22.0', - 'version' => '1.22.0.0', - 'aliases' => - array ( - ), - 'reference' => '6e971c891537eb617a00bb07a43d182a6915faba', - ), - 'symfony/polyfill-mbstring' => - array ( - 'pretty_version' => 'v1.15.0', - 'version' => '1.15.0.0', - 'aliases' => - array ( - ), - 'reference' => '81ffd3a9c6d707be22e3012b827de1c9775fc5ac', - ), - 'symfony/polyfill-php72' => - array ( - 'pretty_version' => 'v1.22.0', - 'version' => '1.22.0.0', - 'aliases' => - array ( - ), - 'reference' => 'cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9', - ), - 'yourls/yourls' => - array ( - 'pretty_version' => 'dev-master', - 'version' => 'dev-master', - 'aliases' => - array ( - ), - 'reference' => 'a3dd5e500abdd264c01f4c8ff026108f093f9769', - ), - ), -); -private static $canGetVendors; -private static $installedByVendor = array(); - - - - - - - -public static function getInstalledPackages() -{ -$packages = array(); -foreach (self::getInstalled() as $installed) { -$packages[] = array_keys($installed['versions']); -} - - -if (1 === \count($packages)) { -return $packages[0]; -} - -return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); -} - - - - - - - - - -public static function isInstalled($packageName) -{ -foreach (self::getInstalled() as $installed) { -if (isset($installed['versions'][$packageName])) { -return true; -} -} - -return false; -} - - - - - - - - - - - - - - -public static function satisfies(VersionParser $parser, $packageName, $constraint) -{ -$constraint = $parser->parseConstraints($constraint); -$provided = $parser->parseConstraints(self::getVersionRanges($packageName)); - -return $provided->matches($constraint); -} - - - - - - - - - - -public static function getVersionRanges($packageName) -{ -foreach (self::getInstalled() as $installed) { -if (!isset($installed['versions'][$packageName])) { -continue; -} - -$ranges = array(); -if (isset($installed['versions'][$packageName]['pretty_version'])) { -$ranges[] = $installed['versions'][$packageName]['pretty_version']; -} -if (array_key_exists('aliases', $installed['versions'][$packageName])) { -$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); -} -if (array_key_exists('replaced', $installed['versions'][$packageName])) { -$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); -} -if (array_key_exists('provided', $installed['versions'][$packageName])) { -$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); -} - -return implode(' || ', $ranges); -} - -throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); -} - - - - - -public static function getVersion($packageName) -{ -foreach (self::getInstalled() as $installed) { -if (!isset($installed['versions'][$packageName])) { -continue; -} - -if (!isset($installed['versions'][$packageName]['version'])) { -return null; -} - -return $installed['versions'][$packageName]['version']; -} - -throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); -} - - - - - -public static function getPrettyVersion($packageName) -{ -foreach (self::getInstalled() as $installed) { -if (!isset($installed['versions'][$packageName])) { -continue; -} - -if (!isset($installed['versions'][$packageName]['pretty_version'])) { -return null; -} - -return $installed['versions'][$packageName]['pretty_version']; -} - -throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); -} - - - - - -public static function getReference($packageName) -{ -foreach (self::getInstalled() as $installed) { -if (!isset($installed['versions'][$packageName])) { -continue; -} - -if (!isset($installed['versions'][$packageName]['reference'])) { -return null; -} - -return $installed['versions'][$packageName]['reference']; -} - -throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); -} - - - - - -public static function getRootPackage() -{ -$installed = self::getInstalled(); - -return $installed[0]['root']; -} - - - - - - - -public static function getRawData() -{ -return self::$installed; -} - - - - - - - - - - - - - - - - - - - -public static function reload($data) -{ -self::$installed = $data; -self::$installedByVendor = array(); -} - - - - -private static function getInstalled() -{ -if (null === self::$canGetVendors) { -self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); -} - -$installed = array(); - -if (self::$canGetVendors) { - -foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { -if (isset(self::$installedByVendor[$vendorDir])) { -$installed[] = self::$installedByVendor[$vendorDir]; -} elseif (is_file($vendorDir.'/composer/installed.php')) { -$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; -} -} -} - -$installed[] = self::$installed; - -return $installed; -} + /** + * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to + * @internal + */ + private static $selfDir = null; + + /** + * @var mixed[]|null + * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null + */ + private static $installed; + + /** + * @var bool + */ + private static $installedIsLocalDir; + + /** + * @var bool|null + */ + private static $canGetVendors; + + /** + * @var array[] + * @psalm-var array}> + */ + private static $installedByVendor = array(); + + /** + * Returns a list of all package names which are present, either by being installed, replaced or provided + * + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackages() + { + $packages = array(); + foreach (self::getInstalled() as $installed) { + $packages[] = array_keys($installed['versions']); + } + + if (1 === \count($packages)) { + return $packages[0]; + } + + return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); + } + + /** + * Returns a list of all package names with a specific type e.g. 'library' + * + * @param string $type + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackagesByType($type) + { + $packagesByType = array(); + + foreach (self::getInstalled() as $installed) { + foreach ($installed['versions'] as $name => $package) { + if (isset($package['type']) && $package['type'] === $type) { + $packagesByType[] = $name; + } + } + } + + return $packagesByType; + } + + /** + * Checks whether the given package is installed + * + * This also returns true if the package name is provided or replaced by another package + * + * @param string $packageName + * @param bool $includeDevRequirements + * @return bool + */ + public static function isInstalled($packageName, $includeDevRequirements = true) + { + foreach (self::getInstalled() as $installed) { + if (isset($installed['versions'][$packageName])) { + return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; + } + } + + return false; + } + + /** + * Checks whether the given package satisfies a version constraint + * + * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: + * + * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') + * + * @param VersionParser $parser Install composer/semver to have access to this class and functionality + * @param string $packageName + * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * @return bool + */ + public static function satisfies(VersionParser $parser, $packageName, $constraint) + { + $constraint = $parser->parseConstraints((string) $constraint); + $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + + return $provided->matches($constraint); + } + + /** + * Returns a version constraint representing all the range(s) which are installed for a given package + * + * It is easier to use this via isInstalled() with the $constraint argument if you need to check + * whether a given version of a package is installed, and not just whether it exists + * + * @param string $packageName + * @return string Version constraint usable with composer/semver + */ + public static function getVersionRanges($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + $ranges = array(); + if (isset($installed['versions'][$packageName]['pretty_version'])) { + $ranges[] = $installed['versions'][$packageName]['pretty_version']; + } + if (array_key_exists('aliases', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); + } + if (array_key_exists('replaced', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); + } + if (array_key_exists('provided', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); + } + + return implode(' || ', $ranges); + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['version'])) { + return null; + } + + return $installed['versions'][$packageName]['version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getPrettyVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['pretty_version'])) { + return null; + } + + return $installed['versions'][$packageName]['pretty_version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference + */ + public static function getReference($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['reference'])) { + return null; + } + + return $installed['versions'][$packageName]['reference']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. + */ + public static function getInstallPath($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @return array + * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} + */ + public static function getRootPackage() + { + $installed = self::getInstalled(); + + return $installed[0]['root']; + } + + /** + * Returns the raw installed.php data for custom implementations + * + * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. + * @return array[] + * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} + */ + public static function getRawData() + { + @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = include __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + + return self::$installed; + } + + /** + * Returns the raw data of all installed.php which are currently loaded for custom implementations + * + * @return array[] + * @psalm-return list}> + */ + public static function getAllRawData() + { + return self::getInstalled(); + } + + /** + * Lets you reload the static array from another file + * + * This is only useful for complex integrations in which a project needs to use + * this class but then also needs to execute another project's autoloader in process, + * and wants to ensure both projects have access to their version of installed.php. + * + * A typical case would be PHPUnit, where it would need to make sure it reads all + * the data it needs from this class, then call reload() with + * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure + * the project in which it runs can then also use this class safely, without + * interference between PHPUnit's dependencies and the project's dependencies. + * + * @param array[] $data A vendor/composer/installed.php data set + * @return void + * + * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data + */ + public static function reload($data) + { + self::$installed = $data; + self::$installedByVendor = array(); + + // when using reload, we disable the duplicate protection to ensure that self::$installed data is + // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not, + // so we have to assume it does not, and that may result in duplicate data being returned when listing + // all installed packages for example + self::$installedIsLocalDir = false; + } + + /** + * @return string + */ + private static function getSelfDir() + { + if (self::$selfDir === null) { + self::$selfDir = strtr(__DIR__, '\\', '/'); + } + + return self::$selfDir; + } + + /** + * @return array[] + * @psalm-return list}> + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + } + + $installed = array(); + $copiedLocalDir = false; + + if (self::$canGetVendors) { + $selfDir = self::getSelfDir(); + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + $vendorDir = strtr($vendorDir, '\\', '/'); + if (isset(self::$installedByVendor[$vendorDir])) { + $installed[] = self::$installedByVendor[$vendorDir]; + } elseif (is_file($vendorDir.'/composer/installed.php')) { + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require $vendorDir.'/composer/installed.php'; + self::$installedByVendor[$vendorDir] = $required; + $installed[] = $required; + if (self::$installed === null && $vendorDir.'/composer' === $selfDir) { + self::$installed = $required; + self::$installedIsLocalDir = true; + } + } + if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) { + $copiedLocalDir = true; + } + } + } + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require __DIR__ . '/installed.php'; + self::$installed = $required; + } else { + self::$installed = array(); + } + } + + if (self::$installed !== array() && !$copiedLocalDir) { + $installed[] = self::$installed; + } + + return $installed; + } } diff --git a/includes/vendor/composer/autoload_classmap.php b/includes/vendor/composer/autoload_classmap.php index c70bb40ae..b501e4f26 100644 --- a/includes/vendor/composer/autoload_classmap.php +++ b/includes/vendor/composer/autoload_classmap.php @@ -2,10 +2,11 @@ // autoload_classmap.php @generated by Composer -$vendorDir = dirname(dirname(__FILE__)); +$vendorDir = dirname(__DIR__); $baseDir = dirname(dirname($vendorDir)); return array( 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', 'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php', + 'Requests' => $vendorDir . '/rmccue/requests/library/Requests.php', ); diff --git a/includes/vendor/composer/autoload_files.php b/includes/vendor/composer/autoload_files.php index e98b54613..8493be270 100644 --- a/includes/vendor/composer/autoload_files.php +++ b/includes/vendor/composer/autoload_files.php @@ -2,13 +2,13 @@ // autoload_files.php @generated by Composer -$vendorDir = dirname(dirname(__FILE__)); +$vendorDir = dirname(__DIR__); $baseDir = dirname(dirname($vendorDir)); return array( 'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php', - '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php', 'b45b351e6b6f7487d819961fef2fda77' => $vendorDir . '/jakeasmith/http_build_url/src/http_build_url.php', + '941748b3c8cae4466c827dfb5ca9602a' => $vendorDir . '/rmccue/requests/library/Deprecated.php', 'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php', '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', ); diff --git a/includes/vendor/composer/autoload_namespaces.php b/includes/vendor/composer/autoload_namespaces.php index 0f842b4a5..52e8e79f8 100644 --- a/includes/vendor/composer/autoload_namespaces.php +++ b/includes/vendor/composer/autoload_namespaces.php @@ -2,11 +2,9 @@ // autoload_namespaces.php @generated by Composer -$vendorDir = dirname(dirname(__FILE__)); +$vendorDir = dirname(__DIR__); $baseDir = dirname(dirname($vendorDir)); return array( - 'Requests' => array($vendorDir . '/rmccue/requests/library'), - 'Ozh\\Phpass\\' => array($vendorDir . '/ozh/phpass/src'), 'Ozh\\Bookmarkletgen\\' => array($vendorDir . '/ozh/bookmarkletgen/src'), ); diff --git a/includes/vendor/composer/autoload_psr4.php b/includes/vendor/composer/autoload_psr4.php index 684c28d28..5f3334d2e 100644 --- a/includes/vendor/composer/autoload_psr4.php +++ b/includes/vendor/composer/autoload_psr4.php @@ -2,17 +2,17 @@ // autoload_psr4.php @generated by Composer -$vendorDir = dirname(dirname(__FILE__)); +$vendorDir = dirname(__DIR__); $baseDir = dirname(dirname($vendorDir)); return array( 'YOURLS\\' => array($baseDir . '/includes'), - 'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'), + 'WpOrg\\Requests\\' => array($vendorDir . '/rmccue/requests/src'), 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'), 'Symfony\\Polyfill\\Intl\\Normalizer\\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'), 'Symfony\\Polyfill\\Intl\\Idn\\' => array($vendorDir . '/symfony/polyfill-intl-idn'), 'Spatie\\ArrayToXml\\' => array($vendorDir . '/spatie/array-to-xml/src'), - 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'), + 'Psr\\Log\\' => array($vendorDir . '/psr/log/src'), 'POMO\\' => array($vendorDir . '/pomo/pomo/src'), 'MaxMind\\WebService\\' => array($vendorDir . '/maxmind/web-service-common/src/WebService'), 'MaxMind\\Exception\\' => array($vendorDir . '/maxmind/web-service-common/src/Exception'), diff --git a/includes/vendor/composer/autoload_real.php b/includes/vendor/composer/autoload_real.php index 50a2b3a27..3b4aa4644 100644 --- a/includes/vendor/composer/autoload_real.php +++ b/includes/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit2d6d15a8f6cc4bfbfd4a2943a6c4df59 +class ComposerAutoloaderInit1d5e2036274043d1e0e9e3243991653e { private static $loader; @@ -22,54 +22,27 @@ public static function getLoader() return self::$loader; } - require __DIR__ . '/platform_check.php'; + spl_autoload_register(array('ComposerAutoloaderInit1d5e2036274043d1e0e9e3243991653e', 'loadClassLoader'), true, true); + self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); + spl_autoload_unregister(array('ComposerAutoloaderInit1d5e2036274043d1e0e9e3243991653e', 'loadClassLoader')); - spl_autoload_register(array('ComposerAutoloaderInit2d6d15a8f6cc4bfbfd4a2943a6c4df59', 'loadClassLoader'), true, true); - self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); - spl_autoload_unregister(array('ComposerAutoloaderInit2d6d15a8f6cc4bfbfd4a2943a6c4df59', 'loadClassLoader')); + require __DIR__ . '/autoload_static.php'; + call_user_func(\Composer\Autoload\ComposerStaticInit1d5e2036274043d1e0e9e3243991653e::getInitializer($loader)); - $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); - if ($useStaticLoader) { - require __DIR__ . '/autoload_static.php'; - - call_user_func(\Composer\Autoload\ComposerStaticInit2d6d15a8f6cc4bfbfd4a2943a6c4df59::getInitializer($loader)); - } else { - $map = require __DIR__ . '/autoload_namespaces.php'; - foreach ($map as $namespace => $path) { - $loader->set($namespace, $path); - } + $loader->register(true); - $map = require __DIR__ . '/autoload_psr4.php'; - foreach ($map as $namespace => $path) { - $loader->setPsr4($namespace, $path); - } + $filesToLoad = \Composer\Autoload\ComposerStaticInit1d5e2036274043d1e0e9e3243991653e::$files; + $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; - $classMap = require __DIR__ . '/autoload_classmap.php'; - if ($classMap) { - $loader->addClassMap($classMap); + require $file; } - } - - $loader->register(true); - - if ($useStaticLoader) { - $includeFiles = Composer\Autoload\ComposerStaticInit2d6d15a8f6cc4bfbfd4a2943a6c4df59::$files; - } else { - $includeFiles = require __DIR__ . '/autoload_files.php'; - } - foreach ($includeFiles as $fileIdentifier => $file) { - composerRequire2d6d15a8f6cc4bfbfd4a2943a6c4df59($fileIdentifier, $file); + }, null, null); + foreach ($filesToLoad as $fileIdentifier => $file) { + $requireFile($fileIdentifier, $file); } return $loader; } } - -function composerRequire2d6d15a8f6cc4bfbfd4a2943a6c4df59($fileIdentifier, $file) -{ - if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { - require $file; - - $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; - } -} diff --git a/includes/vendor/composer/autoload_static.php b/includes/vendor/composer/autoload_static.php index ad6f2d09c..db0fa2a53 100644 --- a/includes/vendor/composer/autoload_static.php +++ b/includes/vendor/composer/autoload_static.php @@ -4,12 +4,12 @@ namespace Composer\Autoload; -class ComposerStaticInit2d6d15a8f6cc4bfbfd4a2943a6c4df59 +class ComposerStaticInit1d5e2036274043d1e0e9e3243991653e { public static $files = array ( 'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php', - '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php', 'b45b351e6b6f7487d819961fef2fda77' => __DIR__ . '/..' . '/jakeasmith/http_build_url/src/http_build_url.php', + '941748b3c8cae4466c827dfb5ca9602a' => __DIR__ . '/..' . '/rmccue/requests/library/Deprecated.php', 'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php', '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', ); @@ -19,9 +19,12 @@ class ComposerStaticInit2d6d15a8f6cc4bfbfd4a2943a6c4df59 array ( 'YOURLS\\' => 7, ), + 'W' => + array ( + 'WpOrg\\Requests\\' => 15, + ), 'S' => array ( - 'Symfony\\Polyfill\\Php72\\' => 23, 'Symfony\\Polyfill\\Mbstring\\' => 26, 'Symfony\\Polyfill\\Intl\\Normalizer\\' => 33, 'Symfony\\Polyfill\\Intl\\Idn\\' => 26, @@ -57,9 +60,9 @@ class ComposerStaticInit2d6d15a8f6cc4bfbfd4a2943a6c4df59 array ( 0 => __DIR__ . '/../../..' . '/includes', ), - 'Symfony\\Polyfill\\Php72\\' => + 'WpOrg\\Requests\\' => array ( - 0 => __DIR__ . '/..' . '/symfony/polyfill-php72', + 0 => __DIR__ . '/..' . '/rmccue/requests/src', ), 'Symfony\\Polyfill\\Mbstring\\' => array ( @@ -79,7 +82,7 @@ class ComposerStaticInit2d6d15a8f6cc4bfbfd4a2943a6c4df59 ), 'Psr\\Log\\' => array ( - 0 => __DIR__ . '/..' . '/psr/log/Psr/Log', + 0 => __DIR__ . '/..' . '/psr/log/src', ), 'POMO\\' => array ( @@ -112,19 +115,8 @@ class ComposerStaticInit2d6d15a8f6cc4bfbfd4a2943a6c4df59 ); public static $prefixesPsr0 = array ( - 'R' => - array ( - 'Requests' => - array ( - 0 => __DIR__ . '/..' . '/rmccue/requests/library', - ), - ), 'O' => array ( - 'Ozh\\Phpass\\' => - array ( - 0 => __DIR__ . '/..' . '/ozh/phpass/src', - ), 'Ozh\\Bookmarkletgen\\' => array ( 0 => __DIR__ . '/..' . '/ozh/bookmarkletgen/src', @@ -135,15 +127,16 @@ class ComposerStaticInit2d6d15a8f6cc4bfbfd4a2943a6c4df59 public static $classMap = array ( 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php', + 'Requests' => __DIR__ . '/..' . '/rmccue/requests/library/Requests.php', ); public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInit2d6d15a8f6cc4bfbfd4a2943a6c4df59::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInit2d6d15a8f6cc4bfbfd4a2943a6c4df59::$prefixDirsPsr4; - $loader->prefixesPsr0 = ComposerStaticInit2d6d15a8f6cc4bfbfd4a2943a6c4df59::$prefixesPsr0; - $loader->classMap = ComposerStaticInit2d6d15a8f6cc4bfbfd4a2943a6c4df59::$classMap; + $loader->prefixLengthsPsr4 = ComposerStaticInit1d5e2036274043d1e0e9e3243991653e::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit1d5e2036274043d1e0e9e3243991653e::$prefixDirsPsr4; + $loader->prefixesPsr0 = ComposerStaticInit1d5e2036274043d1e0e9e3243991653e::$prefixesPsr0; + $loader->classMap = ComposerStaticInit1d5e2036274043d1e0e9e3243991653e::$classMap; }, null, ClassLoader::class); } diff --git a/includes/vendor/composer/ca-bundle/composer.json b/includes/vendor/composer/ca-bundle/composer.json index 5213e9763..c2ce2bb8e 100644 --- a/includes/vendor/composer/ca-bundle/composer.json +++ b/includes/vendor/composer/ca-bundle/composer.json @@ -24,13 +24,13 @@ "require": { "ext-openssl": "*", "ext-pcre": "*", - "php": "^5.3.2 || ^7.0 || ^8.0" + "php": "^7.2 || ^8.0" }, "require-dev": { - "symfony/phpunit-bridge": "^4.2 || ^5", - "phpstan/phpstan": "^0.12.55", - "psr/log": "^1.0", - "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" + "phpunit/phpunit": "^8 || ^9", + "phpstan/phpstan": "^1.10", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" }, "autoload": { "psr-4": { @@ -48,7 +48,7 @@ } }, "scripts": { - "test": "SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT=1 vendor/bin/simple-phpunit", - "phpstan": "vendor/bin/phpstan analyse" + "test": "@php phpunit", + "phpstan": "@php phpstan analyse" } } diff --git a/includes/vendor/composer/ca-bundle/phpstan.neon.dist b/includes/vendor/composer/ca-bundle/phpstan.neon.dist deleted file mode 100644 index 1cd333bd1..000000000 --- a/includes/vendor/composer/ca-bundle/phpstan.neon.dist +++ /dev/null @@ -1,5 +0,0 @@ -parameters: - level: 8 - paths: - - src - - tests diff --git a/includes/vendor/composer/ca-bundle/res/cacert.pem b/includes/vendor/composer/ca-bundle/res/cacert.pem index 3a08fd8db..e8cc6c1c0 100644 --- a/includes/vendor/composer/ca-bundle/res/cacert.pem +++ b/includes/vendor/composer/ca-bundle/res/cacert.pem @@ -1,7 +1,9 @@ ## ## Bundle of CA Root Certificates ## -## Certificate data from Mozilla as of: Tue Dec 8 04:12:05 2020 GMT +## Certificate data from Mozilla as of: Tue Dec 31 04:12:05 2024 GMT +## +## Find updated versions here: https://curl.se/docs/caextract.html ## ## This is a bundle of X.509 certificates of public Certificate Authorities ## (CA). These were automatically extracted from Mozilla's root certificates @@ -13,8 +15,8 @@ ## an Apache+mod_ssl webserver for SSL client authentication. ## Just configure this file as the SSLCACertificateFile. ## -## Conversion done with mk-ca-bundle.pl version 1.28. -## SHA256: d820b8696d8ffe42064a1384a56a8981cdc7e7e198036bbb5fa04a6c282dd9a2 +## Conversion done with mk-ca-bundle.pl version 1.29. +## SHA256: c99d6d3f8d3d4e47719ba2b648992f5b58b150128d3aca3c05c566d8dc98e116 ## @@ -39,28 +41,6 @@ hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== -----END CERTIFICATE----- -GlobalSign Root CA - R2 -======================= ------BEGIN CERTIFICATE----- -MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv -YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh -bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT -aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln -bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6 -ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp -s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN -S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL -TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C -ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E -FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i -YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN -BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp -9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu -01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7 -9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 -TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== ------END CERTIFICATE----- - Entrust.net Premium 2048 Secure Server CA ========================================= -----BEGIN CERTIFICATE----- @@ -132,87 +112,6 @@ W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 -----END CERTIFICATE----- -GeoTrust Global CA -================== ------BEGIN CERTIFICATE----- -MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK -Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw -MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j -LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo -BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet -8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc -T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU -vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD -AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk -DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q -zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4 -d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2 -mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p -XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm -Mw== ------END CERTIFICATE----- - -GeoTrust Universal CA -===================== ------BEGIN CERTIFICATE----- -MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN -R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1 -MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu -Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP -ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t -JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e -RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs -7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d -8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V -qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga -Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB -Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu -KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08 -ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0 -XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB -hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc -aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2 -qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL -oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK -xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF -KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2 -DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK -xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU -p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI -P/rmMuGNG2+k5o7Y+SlIis5z/iw= ------END CERTIFICATE----- - -GeoTrust Universal CA 2 -======================= ------BEGIN CERTIFICATE----- -MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN -R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0 -MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg -SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA -A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0 -DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17 -j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q -JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a -QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2 -WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP -20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn -ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC -SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG -8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2 -+/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E -BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z -dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ -4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+ -mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq -A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg -Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP -pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d -FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp -gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm -X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS ------END CERTIFICATE----- - Comodo AAA Services root ======================== -----BEGIN CERTIFICATE----- @@ -237,38 +136,6 @@ Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z 12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== -----END CERTIFICATE----- -QuoVadis Root CA -================ ------BEGIN CERTIFICATE----- -MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE -ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 -eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz -MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp -cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD -EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk -J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL -F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL -YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen -AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w -PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y -ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7 -MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj -YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs -ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh -Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW -Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu -BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw -FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6 -tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo -fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul -LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x -gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi -5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi -5nrQNiOKSnQ2+Q== ------END CERTIFICATE----- - QuoVadis Root CA 2 ================== -----BEGIN CERTIFICATE----- @@ -335,47 +202,6 @@ vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto= -----END CERTIFICATE----- -Security Communication Root CA -============================== ------BEGIN CERTIFICATE----- -MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP -U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw -HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP -U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw -8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM -DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX -5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd -DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2 -JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw -DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g -0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a -mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ -s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ -6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi -FL39vmwLAw== ------END CERTIFICATE----- - -Sonera Class 2 Root CA -====================== ------BEGIN CERTIFICATE----- -MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG -U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw -NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh -IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3 -/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT -dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG -f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P -tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH -nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT -XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt -0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI -cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph -Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx -EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH -llpwrN9M ------END CERTIFICATE----- - XRamp Global CA Root ==================== -----BEGIN CERTIFICATE----- @@ -514,26 +340,6 @@ mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K -----END CERTIFICATE----- -DST Root CA X3 -============== ------BEGIN CERTIFICATE----- -MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK -ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X -DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1 -cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT -rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9 -UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy -xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d -utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T -AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ -MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug -dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE -GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw -RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS -fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ ------END CERTIFICATE----- - SwissSign Gold CA - G2 ====================== -----BEGIN CERTIFICATE----- @@ -596,78 +402,6 @@ DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u -----END CERTIFICATE----- -GeoTrust Primary Certification Authority -======================================== ------BEGIN CERTIFICATE----- -MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG -EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD -ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx -CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ -cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN -b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9 -nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge -RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt -tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD -AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI -hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K -Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN -NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa -Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG -1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= ------END CERTIFICATE----- - -thawte Primary Root CA -====================== ------BEGIN CERTIFICATE----- -MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE -BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 -aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv -cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3 -MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg -SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv -KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT -FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs -oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ -1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc -q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K -aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p -afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD -VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF -AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE -uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX -xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89 -jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH -z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA== ------END CERTIFICATE----- - -VeriSign Class 3 Public Primary Certification Authority - G5 -============================================================ ------BEGIN CERTIFICATE----- -MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE -BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO -ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk -IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB -yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln -biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh -dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt -YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw -ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz -j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD -Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/ -Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r -fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/ -BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv -Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy -aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG -SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+ -X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE -KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC -Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE -ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq ------END CERTIFICATE----- - SecureTrust CA ============== -----BEGIN CERTIFICATE----- @@ -736,29 +470,6 @@ IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN +8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ== -----END CERTIFICATE----- -Network Solutions Certificate Authority -======================================= ------BEGIN CERTIFICATE----- -MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG -EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr -IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx -MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu -MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx -jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT -aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT -crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc -/Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB -AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP -BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv -bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA -A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q -4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/ -GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv -wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD -ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey ------END CERTIFICATE----- - COMODO ECC Certification Authority ================================== -----BEGIN CERTIFICATE----- @@ -798,28 +509,6 @@ PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== -----END CERTIFICATE----- -Cybertrust Global Root -====================== ------BEGIN CERTIFICATE----- -MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li -ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4 -MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD -ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA -+Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW -0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL -AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin -89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT -8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP -BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2 -MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G -A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO -lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi -5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2 -hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T -X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW -WL1WMRJOEcgh4LMRkWXbtKaIOM5V ------END CERTIFICATE----- - ePKI Root Certification Authority ================================= -----BEGIN CERTIFICATE----- @@ -871,136 +560,6 @@ vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD -----END CERTIFICATE----- -GeoTrust Primary Certification Authority - G3 -============================================= ------BEGIN CERTIFICATE----- -MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE -BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0 -IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy -eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz -NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo -YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT -LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j -K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE -c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C -IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu -dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC -MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr -2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9 -cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE -Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD -AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s -t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt ------END CERTIFICATE----- - -thawte Primary Root CA - G2 -=========================== ------BEGIN CERTIFICATE----- -MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC -VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu -IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg -Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV -MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG -b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt -IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS -LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5 -8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU -mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN -G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K -rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== ------END CERTIFICATE----- - -thawte Primary Root CA - G3 -=========================== ------BEGIN CERTIFICATE----- -MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE -BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 -aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv -cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w -ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh -d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD -VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG -A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At -P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC -+BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY -7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW -vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E -BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ -KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK -A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu -t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC -8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm -er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A= ------END CERTIFICATE----- - -GeoTrust Primary Certification Authority - G2 -============================================= ------BEGIN CERTIFICATE----- -MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC -VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu -Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD -ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1 -OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg -MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl -b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG -BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc -KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD -VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+ -EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m -ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2 -npaqBA+K ------END CERTIFICATE----- - -VeriSign Universal Root Certification Authority -=============================================== ------BEGIN CERTIFICATE----- -MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE -BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO -ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk -IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u -IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV -UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv -cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl -IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj -1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP -MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72 -9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I -AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR -tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G -CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O -a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud -DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3 -Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx -Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx -P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P -wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4 -mJO37M2CYfE45k+XmCpajQ== ------END CERTIFICATE----- - -VeriSign Class 3 Public Primary Certification Authority - G4 -============================================================ ------BEGIN CERTIFICATE----- -MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC -VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3 -b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz -ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL -MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU -cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo -b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5 -IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8 -Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz -rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB -/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw -HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u -Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD -A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx -AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== ------END CERTIFICATE----- - NetLock Arany (Class Gold) Főtanúsítvány ======================================== -----BEGIN CERTIFICATE----- @@ -1025,47 +584,6 @@ NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= -----END CERTIFICATE----- -Hongkong Post Root CA 1 -======================= ------BEGIN CERTIFICATE----- -MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT -DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx -NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n -IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1 -ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr -auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh -qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY -V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV -HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i -h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio -l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei -IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps -T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT -c4afU9hDDl3WY4JxHYB0yvbiAmvZWg== ------END CERTIFICATE----- - -SecureSign RootCA11 -=================== ------BEGIN CERTIFICATE----- -MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi -SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS -b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw -KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1 -cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL -TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO -wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq -g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP -O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA -bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX -t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh -OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r -bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ -Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01 -y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061 -lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I= ------END CERTIFICATE----- - Microsec e-Szigno Root CA 2009 ============================== -----BEGIN CERTIFICATE----- @@ -1111,39 +629,6 @@ YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r kpeDMdmztcpHWD9f -----END CERTIFICATE----- -Autoridad de Certificacion Firmaprofesional CIF A62634068 -========================================================= ------BEGIN CERTIFICATE----- -MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA -BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 -MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw -QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB -NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD -Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P -B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY -7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH -ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI -plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX -MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX -LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK -bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU -vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud -EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH -DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp -cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA -bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx -ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx -51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk -R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP -T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f -Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl -osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR -crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR -saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD -KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi -6Et8Vcad+qMUu2WFbm5PEn4KPJ2V ------END CERTIFICATE----- - Izenpe.com ========== -----BEGIN CERTIFICATE----- @@ -1176,82 +661,6 @@ Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== -----END CERTIFICATE----- -Chambers of Commerce Root - 2008 -================================ ------BEGIN CERTIFICATE----- -MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD -MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv -bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu -QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy -Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl -ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF -EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl -cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC -AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA -XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj -h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/ -ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk -NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g -D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331 -lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ -0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj -ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2 -EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI -G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ -BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh -bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh -bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC -CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH -AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1 -wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH -3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU -RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6 -M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1 -YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF -9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK -zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG -nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg -OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ ------END CERTIFICATE----- - -Global Chambersign Root - 2008 -============================== ------BEGIN CERTIFICATE----- -MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD -MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv -bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu -QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx -NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg -Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ -QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD -aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf -VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf -XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0 -ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB -/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA -TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M -H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe -Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF -HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh -wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB -AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT -BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE -BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm -aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm -aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp -1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0 -dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG -/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6 -ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s -dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg -9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH -foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du -qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr -P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq -c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z -09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B ------END CERTIFICATE----- - Go Daddy Root Certificate Authority - G2 ======================================== -----BEGIN CERTIFICATE----- @@ -1468,60 +877,6 @@ tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29 mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 -----END CERTIFICATE----- -EC-ACC -====== ------BEGIN CERTIFICATE----- -MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE -BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w -ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD -VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE -CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT -BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7 -MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt -SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl -Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh -cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK -w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT -ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4 -HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a -E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw -0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E -BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD -VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0 -Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l -dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ -lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa -Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe -l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2 -E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D -5EI= ------END CERTIFICATE----- - -Hellenic Academic and Research Institutions RootCA 2011 -======================================================= ------BEGIN CERTIFICATE----- -MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT -O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y -aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z -IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT -AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z -IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo -IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI -1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa -71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u -8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH -3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/ -MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8 -MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu -b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt -XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 -TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD -/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N -7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4 ------END CERTIFICATE----- - Actalis Authentication Root CA ============================== -----BEGIN CERTIFICATE----- @@ -1553,27 +908,6 @@ OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9 vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== -----END CERTIFICATE----- -Trustis FPS Root CA -=================== ------BEGIN CERTIFICATE----- -MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG -EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290 -IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV -BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ -KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ -RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk -H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa -cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt -o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA -AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd -BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c -GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC -yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P -8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV -l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl -iB6XzCGcKQENZetX2fNXlrtIzYE= ------END CERTIFICATE----- - Buypass Class 2 Root CA ======================= -----BEGIN CERTIFICATE----- @@ -1834,40 +1168,6 @@ Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= -----END CERTIFICATE----- -E-Tugra Certification Authority -=============================== ------BEGIN CERTIFICATE----- -MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAlRSMQ8w -DQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamls -ZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN -ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMw -NTEyMDk0OFoXDTIzMDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmEx -QDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxl -cmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQD -DB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A -MIICCgKCAgEA4vU/kwVRHoViVF56C/UYB4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vd -hQd2h8y/L5VMzH2nPbxHD5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5K -CKpbknSFQ9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEoq1+g -ElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3Dk14opz8n8Y4e0ypQ -BaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcHfC425lAcP9tDJMW/hkd5s3kc91r0 -E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsutdEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gz -rt48Ue7LE3wBf4QOXVGUnhMMti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAq -jqFGOjGY5RH8zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn -rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUXU8u3Zg5mTPj5 -dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6Jyr+zE7S6E5UMA8GA1UdEwEB -/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEG -MA0GCSqGSIb3DQEBCwUAA4ICAQAFNzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAK -kEh47U6YA5n+KGCRHTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jO -XKqYGwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c77NCR807 -VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3+GbHeJAAFS6LrVE1Uweo -a2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WKvJUawSg5TB9D0pH0clmKuVb8P7Sd2nCc -dlqMQ1DujjByTd//SffGqWfZbawCEeI6FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEV -KV0jq9BgoRJP3vQXzTLlyb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gT -Dx4JnW2PAJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpDy4Q0 -8ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8dNL/+I5c30jn6PQ0G -C7TbO6Orb1wdtn7os4I07QZcJA== ------END CERTIFICATE----- - T-TeleSec GlobalRoot Class 2 ============================ -----BEGIN CERTIFICATE----- @@ -2189,20 +1489,6 @@ HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu 9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= -----END CERTIFICATE----- -GlobalSign ECC Root CA - R4 -=========================== ------BEGIN CERTIFICATE----- -MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEkMCIGA1UECxMb -R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD -EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb -R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD -EwpHbG9iYWxTaWduMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprl -OQcJFspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAwDgYDVR0P -AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61FuOJAf/sKbvu+M8k8o4TV -MAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGXkPoUVy0D7O48027KqGx2vKLeuwIgJ6iF -JzWbVsaj8kfSt24bAgAXqmemFZHe+pTsewv4n4Q= ------END CERTIFICATE----- - GlobalSign ECC Root CA - R5 =========================== -----BEGIN CERTIFICATE----- @@ -2218,66 +1504,6 @@ uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7 yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3 -----END CERTIFICATE----- -Staat der Nederlanden Root CA - G3 -================================== ------BEGIN CERTIFICATE----- -MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE -CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g -Um9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloXDTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMC -TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l -ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4y -olQPcPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WWIkYFsO2t -x1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqXxz8ecAgwoNzFs21v0IJy -EavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFyKJLZWyNtZrVtB0LrpjPOktvA9mxjeM3K -Tj215VKb8b475lRgsGYeCasH/lSJEULR9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUur -mkVLoR9BvUhTFXFkC4az5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU5 -1nus6+N86U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7Ngzp -07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHPbMk7ccHViLVlvMDo -FxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXtBznaqB16nzaeErAMZRKQFWDZJkBE -41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTtXUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMB -AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleu -yjWcLhL75LpdINyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD -U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwpLiniyMMB8jPq -KqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8Ipf3YF3qKS9Ysr1YvY2WTxB1 -v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixpgZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA -8KCWAg8zxXHzniN9lLf9OtMJgwYh/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b -8KKaa8MFSu1BYBQw0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0r -mj1AfsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq4BZ+Extq -1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR1VmiiXTTn74eS9fGbbeI -JG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/QFH1T/U67cjF68IeHRaVesd+QnGTbksV -tzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM94B7IWcnMFk= ------END CERTIFICATE----- - -Staat der Nederlanden EV Root CA -================================ ------BEGIN CERTIFICATE----- -MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJOTDEeMBwGA1UE -CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFhdCBkZXIgTmVkZXJsYW5kZW4g -RVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0yMjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5M -MR4wHAYDVQQKDBVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRl -cmxhbmRlbiBFViBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkk -SzrSM4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nCUiY4iKTW -O0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3dZ//BYY1jTw+bbRcwJu+r -0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46prfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8 -Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13lpJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gV -XJrm0w912fxBmJc+qiXbj5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr -08C+eKxCKFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS/ZbV -0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0XcgOPvZuM5l5Tnrmd -74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH1vI4gnPah1vlPNOePqc7nvQDs/nx -fRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrPpx9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNC -MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwa -ivsnuL8wbqg7MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI -eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u2dfOWBfoqSmu -c0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHSv4ilf0X8rLiltTMMgsT7B/Zq -5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTCwPTxGfARKbalGAKb12NMcIxHowNDXLldRqAN -b/9Zjr7dn3LDWyvfjFvO5QxGbJKyCqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tN -f1zuacpzEPuKqf2evTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi -5Dp6Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIaGl6I6lD4 -WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeLeG9QgkRQP2YGiqtDhFZK -DyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGy -eUN51q1veieQA6TqJIc/2b3Z6fJfUEkc7uzXLg== ------END CERTIFICATE----- - IdenTrust Commercial Root CA 1 ============================== -----BEGIN CERTIFICATE----- @@ -2729,87 +1955,6 @@ F8Io2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV09tL7ECQ aaApJUqlyyvdimYHFngVV3Eb7PVHhPOeMTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== -----END CERTIFICATE----- -TrustCor RootCert CA-1 -====================== ------BEGIN CERTIFICATE----- -MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYDVQQGEwJQQTEP -MA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3Ig -U3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3Jp -dHkxHzAdBgNVBAMMFlRydXN0Q29yIFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkx -MjMxMTcyMzE2WjCBpDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFu -YW1hIENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUGA1UECwwe -VHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZUcnVzdENvciBSb290Q2Vy -dCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv463leLCJhJrMxnHQFgKq1mq -jQCj/IDHUHuO1CAmujIS2CNUSSUQIpidRtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4 -pQa81QBeCQryJ3pS/C3Vseq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0 -JEsq1pme9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CVEY4h -gLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorWhnAbJN7+KIor0Gqw -/Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/DeOxCbeKyKsZn3MzUOcwHwYDVR0j -BBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AYYwDQYJKoZIhvcNAQELBQADggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5 -mDo4Nvu7Zp5I/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf -ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZyonnMlo2HD6C -qFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djtsL1Ac59v2Z3kf9YKVmgenFK+P -3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdNzl/HHk484IkzlQsPpTLWPFp5LBk= ------END CERTIFICATE----- - -TrustCor RootCert CA-2 -====================== ------BEGIN CERTIFICATE----- -MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNVBAYTAlBBMQ8w -DQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQwIgYDVQQKDBtUcnVzdENvciBT -eXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRydXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0 -eTEfMB0GA1UEAwwWVHJ1c3RDb3IgUm9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEy -MzExNzI2MzlaMIGkMQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5h -bWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U -cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29yIFJvb3RDZXJ0 -IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnIG7CKqJiJJWQdsg4foDSq8Gb -ZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9Nk -RvRUqdw6VC0xK5mC8tkq1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1 -oYxOdqHp2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nKDOOb -XUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hapeaz6LMvYHL1cEksr1 -/p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF3wP+TfSvPd9cW436cOGlfifHhi5q -jxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQP -eSghYA2FFn3XVDjxklb9tTNMg9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+Ctg -rKAmrhQhJ8Z3mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh -8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAdBgNVHQ4EFgQU -2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6UnrybPZx9mCAZ5YwwYrIwDwYD -VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/h -Osh80QA9z+LqBrWyOrsGS2h60COXdKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnp -kpfbsEZC89NiqpX+MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv -2wnL/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RXCI/hOWB3 -S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYaZH9bDTMJBzN7Bj8RpFxw -PIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dv -DDqPys/cA8GiCcjl/YBeyGBCARsaU1q7N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYU -RpFHmygk71dSTlxCnKr3Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANE -xdqtvArBAs8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp5KeX -RKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu1uwJ ------END CERTIFICATE----- - -TrustCor ECA-1 -============== ------BEGIN CERTIFICATE----- -MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYDVQQGEwJQQTEP -MA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3Ig -U3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3Jp -dHkxFzAVBgNVBAMMDlRydXN0Q29yIEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3Mjgw -N1owgZwxCzAJBgNVBAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5 -MSQwIgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRydXN0Q29y -IENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3IgRUNBLTEwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb3w9U73NjKYKtR8aja+3+XzP4Q1HpGjOR -MRegdMTUpwHmspI+ap3tDvl0mEDTPwOABoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23 -xFUfJ3zSCNV2HykVh0A53ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmc -p0yJF4OuowReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/wZ0+ -fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZFZtS6mFjBAgMBAAGj -YzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAfBgNVHSMEGDAWgBREnkj1zG1I1KBL -f/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF -AAOCAQEABT41XBVwm8nHc2FvcivUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u -/ukZMjgDfxT2AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F -hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50soIipX1TH0Xs -J5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BIWJZpTdwHjFGTot+fDz2LYLSC -jaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1WitJ/X5g== ------END CERTIFICATE----- - SSL.com Root Certification Authority RSA ======================================== -----BEGIN CERTIFICATE----- @@ -2954,96 +2099,6 @@ AwMDaAAwZQIwJsdpW9zV57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtk AjEA2zQgMgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 -----END CERTIFICATE----- -GTS Root R1 -=========== ------BEGIN CERTIFICATE----- -MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQG -EwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJv -b3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAG -A1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx -9vaMf/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7wCl7r -aKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjwTcLCeoiKu7rPWRnW -r4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0PfyblqAj+lug8aJRT7oM6iCsVlgmy4HqM -LnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly -4cpk9+aCEI3oncKKiPo4Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr -06zqkUspzBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 -wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70paDPvOmbsB4om -3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrNVjzRlwW5y0vtOUucxD/SVRNu -JLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEM -BQADggIBADiWCu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1 -d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6ZXPYfcX3v73sv -fuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZRgyFmxhE+885H7pwoHyXa/6xm -ld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9b -gsiG1eGZbYwE8na6SfZu6W0eX6DvJ4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq -4BjFbkerQUIpm/ZgDdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWEr -tXvM+SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyyF62ARPBo -pY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9SQ98POyDGCBDTtWTurQ0 -sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdwsE3PYJ/HQcu51OyLemGhmW/HGY0dVHLql -CFF1pkgl ------END CERTIFICATE----- - -GTS Root R2 -=========== ------BEGIN CERTIFICATE----- -MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQG -EwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJv -b3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAG -A1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTuk -k3LvCvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY6Dlo -7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAuMC6C/Pq8tBcKSOWI -m8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7kRXuJVfeKH2JShBKzwkCX44ofR5Gm -dFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbu -ak7MkogwTZq9TwtImoS1mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscsz -cTJGr61K8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW -Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKaG73Vululycsl -aVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCqgc7dGtxRcw1PcOnlthYhGXmy -5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEM -BQADggIBALZp8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT -vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiTz9D2PGcDFWEJ -+YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiApJiS4wGWAqoC7o87xdFtCjMw -c3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvbpxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3Da -WsYDQvTtN6LwG1BUSw7YhN4ZKJmBR64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5r -n/WkhLx3+WuXrD5RRaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56Gtmwfu -Nmsk0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC5AwiWVIQ -7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiFizoHCBy69Y9Vmhh1fuXs -gWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLnyOd/xCxgXS/Dr55FBcOEArf9LAhST4Ld -o/DUhgkC ------END CERTIFICATE----- - -GTS Root R3 -=========== ------BEGIN CERTIFICATE----- -MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJV -UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg -UjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE -ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcq -hkjOPQIBBgUrgQQAIgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUU -Rout736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL24Cej -QjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTB8Sa6oC2uhYHP -0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFukfCPAlaUs3L6JbyO5o91lAFJekazInXJ0 -glMLfalAvWhgxeG4VDvBNhcl2MG9AjEAnjWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOa -KaqW04MjyaR7YbPMAuhd ------END CERTIFICATE----- - -GTS Root R4 -=========== ------BEGIN CERTIFICATE----- -MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJV -UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg -UjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE -ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcq -hkjOPQIBBgUrgQQAIgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa -6zzuhXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvRHYqj -QjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSATNbrdP9JNqPV -2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0CMRw3J5QdCHojXohw0+WbhXRIjVhLfoI -N+4Zba3bssx9BzT1YBkstTTZbyACMANxsbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11x -zPKwTdb+mciUqXWi4w== ------END CERTIFICATE----- - UCA Global G2 Root ================== -----BEGIN CERTIFICATE----- @@ -3243,40 +2298,6 @@ hcErulWuBurQB7Lcq9CClnXO0lD+mefPL5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB dBb9HxEGmpv0 -----END CERTIFICATE----- -Entrust Root Certification Authority - G4 -========================================= ------BEGIN CERTIFICATE----- -MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAwgb4xCzAJBgNV -BAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3Qu -bmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1 -dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1 -dGhvcml0eSAtIEc0MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYT -AlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 -L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhv -cml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhv -cml0eSAtIEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3D -umSXbcr3DbVZwbPLqGgZ2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV -3imz/f3ET+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j5pds -8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAMC1rlLAHGVK/XqsEQ -e9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73TDtTUXm6Hnmo9RR3RXRv06QqsYJn7 -ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNXwbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5X -xNMhIWNlUpEbsZmOeX7m640A2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV -7rtNOzK+mndmnqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 -dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwlN4y6mACXi0mW -Hv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNjc0kCAwEAAaNCMEAwDwYDVR0T -AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9n -MA0GCSqGSIb3DQEBCwUAA4ICAQAS5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4Q -jbRaZIxowLByQzTSGwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht -7LGrhFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/B7NTeLUK -YvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uIAeV8KEsD+UmDfLJ/fOPt -jqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbwH5Lk6rWS02FREAutp9lfx1/cH6NcjKF+ -m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKW -RGhXxNUzzxkvFMSUHHuk2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjA -JOgc47OlIQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk5F6G -+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuYn/PIjhs4ViFqUZPT -kcpG2om3PVODLAgfi49T3f+sHw== ------END CERTIFICATE----- - Microsoft ECC Root Certificate Authority 2017 ============================================= -----BEGIN CERTIFICATE----- @@ -3433,3 +2454,1158 @@ HQ8BAf8EBQMDBwYAMB0GA1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNn ADBkAjA3AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsCMGcl CrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVuSw== -----END CERTIFICATE----- + +NAVER Global Root Certification Authority +========================================= +-----BEGIN CERTIFICATE----- +MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEMBQAwaTELMAkG +A1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRGT1JNIENvcnAuMTIwMAYDVQQD +DClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4 +NDJaFw0zNzA4MTgyMzU5NTlaMGkxCzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVT +UyBQTEFURk9STSBDb3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVAiQqrDZBb +UGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH38dq6SZeWYp34+hInDEW ++j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lEHoSTGEq0n+USZGnQJoViAbbJAh2+g1G7 +XNr4rRVqmfeSVPc0W+m/6imBEtRTkZazkVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2 +aacp+yPOiNgSnABIqKYPszuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4 +Yb8ObtoqvC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHfnZ3z +VHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaGYQ5fG8Ir4ozVu53B +A0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo0es+nPxdGoMuK8u180SdOqcXYZai +cdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3aCJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejy +YhbLgGvtPe31HzClrkvJE+2KAQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNV +HQ4EFgQU0p+I36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB +Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoNqo0hV4/GPnrK +21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatjcu3cvuzHV+YwIHHW1xDBE1UB +jCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm+LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bx +hYTeodoS76TiEJd6eN4MUZeoIUCLhr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTg +E34h5prCy8VCZLQelHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTH +D8z7p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8piKCk5XQ +A76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLRLBT/DShycpWbXgnbiUSY +qqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oG +I/hGoiLtk/bdmuYqh7GYVPEi92tF4+KOdh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmg +kpzNNIaRkPpkUZ3+/uul9XXeifdy +-----END CERTIFICATE----- + +AC RAIZ FNMT-RCM SERVIDORES SEGUROS +=================================== +-----BEGIN CERTIFICATE----- +MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQswCQYDVQQGEwJF +UzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgwFgYDVQRhDA9WQVRFUy1RMjgy +NjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1SQ00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4 +MTIyMDA5MzczM1oXDTQzMTIyMDA5MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQt +UkNNMQ4wDAYDVQQLDAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNB +QyBSQUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuBBAAiA2IA +BPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LHsbI6GA60XYyzZl2hNPk2 +LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oKUm8BA06Oi6NCMEAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqG +SM49BAMDA2kAMGYCMQCuSuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoD +zBOQn5ICMQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJyv+c= +-----END CERTIFICATE----- + +GlobalSign Root R46 +=================== +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUAMEYxCzAJBgNV +BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJv +b3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAX +BgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08Es +CVeJOaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQGvGIFAha/ +r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud316HCkD7rRlr+/fKYIje +2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo0q3v84RLHIf8E6M6cqJaESvWJ3En7YEt +bWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSEy132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvj +K8Cd+RTyG/FWaha/LIWFzXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD4 +12lPFzYE+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCNI/on +ccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzsx2sZy/N78CsHpdls +eVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqaByFrgY/bxFn63iLABJzjqls2k+g9 +vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEM +BQADggIBAHx47PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg +JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti2kM3S+LGteWy +gxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIkpnnpHs6i58FZFZ8d4kuaPp92 +CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRFFRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZm +OUdkLG5NrmJ7v2B0GbhWrJKsFjLtrWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qq +JZ4d16GLuc1CLgSkZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwye +qiv5u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP4vkYxboz +nxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6N3ec592kD3ZDZopD8p/7 +DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3vouXsXgxT7PntgMTzlSdriVZzH81Xwj3 +QEUxeCp6 +-----END CERTIFICATE----- + +GlobalSign Root E46 +=================== +-----BEGIN CERTIFICATE----- +MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYxCzAJBgNVBAYT +AkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJvb3Qg +RTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNV +BAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkB +jtjqR+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGddyXqBPCCj +QjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQxCpCPtsad0kRL +gLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZk +vLtoURMMA/cVi4RguYv/Uo7njLwcAjA8+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+ +CAezNIm8BZ/3Hobui3A= +-----END CERTIFICATE----- + +GLOBALTRUST 2020 +================ +-----BEGIN CERTIFICATE----- +MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkGA1UEBhMCQVQx +IzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVT +VCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYxMDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAh +BgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAy +MDIwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWi +D59bRatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9ZYybNpyrO +VPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3QWPKzv9pj2gOlTblzLmM +CcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPwyJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCm +fecqQjuCgGOlYx8ZzHyyZqjC0203b+J+BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKA +A1GqtH6qRNdDYfOiaxaJSaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9OR +JitHHmkHr96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj04KlG +DfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9MedKZssCz3AwyIDMvU +clOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIwq7ejMZdnrY8XD2zHc+0klGvIg5rQ +mjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1Ud +IwQYMBaAFNwuH9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA +VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJCXtzoRlgHNQIw +4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd6IwPS3BD0IL/qMy/pJTAvoe9 +iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf+I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS +8cE54+X1+NZK3TTN+2/BT+MAi1bikvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2 +HcqtbepBEX4tdJP7wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxS +vTOBTI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6CMUO+1918 +oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn4rnvyOL2NSl6dPrFf4IF +YqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+IaFvowdlxfv1k7/9nR4hYJS8+hge9+6jl +gqispdNpQ80xiEmEU5LAsTkbOYMBMMTyqfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== +-----END CERTIFICATE----- + +ANF Secure Server Root CA +========================= +-----BEGIN CERTIFICATE----- +MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNVBAUTCUc2MzI4 +NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lv +bjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNVBAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3Qg +Q0EwHhcNMTkwOTA0MTAwMDM4WhcNMzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEw +MQswCQYDVQQGEwJFUzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQw +EgYDVQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9vdCBDQTCC +AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCjcqQZAZ2cC4Ffc0m6p6zz +BE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9qyGFOtibBTI3/TO80sh9l2Ll49a2pcbnv +T1gdpd50IJeh7WhM3pIXS7yr/2WanvtH2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcv +B2VSAKduyK9o7PQUlrZXH1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXse +zx76W0OLzc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyRp1RM +VwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQzW7i1o0TJrH93PB0j +7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/SiOL9V8BY9KHcyi1Swr1+KuCLH5z +JTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJnLNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe +8TZBAQIvfXOn3kLMTOmJDVb3n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVO +Hj1tyRRM4y5Bu8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj +o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAOBgNVHQ8BAf8E +BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEATh65isagmD9uw2nAalxJ +UqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzx +j6ptBZNscsdW699QIyjlRRA96Gejrw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDt +dD+4E5UGUcjohybKpFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM +5gf0vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjqOknkJjCb +5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ/zo1PqVUSlJZS2Db7v54 +EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ92zg/LFis6ELhDtjTO0wugumDLmsx2d1H +hk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI+PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGy +g77FGr8H6lnco4g175x2MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3 +r5+qPeoott7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw= +-----END CERTIFICATE----- + +Certum EC-384 CA +================ +-----BEGIN CERTIFICATE----- +MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQswCQYDVQQGEwJQ +TDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2 +MDcyNDU0WhcNNDMwMzI2MDcyNDU0WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERh +dGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx +GTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATEKI6rGFtq +vm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7TmFy8as10CW4kjPMIRBSqn +iBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68KjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFI0GZnQkdjrzife81r1HfS+8EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNo +ADBlAjADVS2m5hjEfO/JUG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0 +QoSZ/6vnnvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= +-----END CERTIFICATE----- + +Certum Trusted Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6MQswCQYDVQQG +EwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0g +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0Ew +HhcNMTgwMzE2MTIxMDEzWhcNNDMwMzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMY +QXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZn0EGze2jusDbCSzBfN8p +fktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/qp1x4EaTByIVcJdPTsuclzxFUl6s1wB52 +HO8AU5853BSlLCIls3Jy/I2z5T4IHhQqNwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2 +fJmItdUDmj0VDT06qKhF8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGt +g/BKEiJ3HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGamqi4 +NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi7VdNIuJGmj8PkTQk +fVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSFytKAQd8FqKPVhJBPC/PgP5sZ0jeJ +P/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0PqafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSY +njYJdmZm/Bo/6khUHL4wvYBQv3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHK +HRzQ+8S1h9E6Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1 +vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQADggIBAEii1QAL +LtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4WxmB82M+w85bj/UvXgF2Ez8s +ALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvozMrnadyHncI013nR03e4qllY/p0m+jiGPp2K +h2RX5Rc64vmNueMzeMGQ2Ljdt4NR5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8 +CYyqOhNf6DR5UMEQGfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA +4kZf5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq0Uc9Nneo +WWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7DP78v3DSk+yshzWePS/Tj +6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTMqJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmT +OPQD8rv7gmsHINFSH5pkAnuYZttcTVoP0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZck +bxJF0WddCajJFdr60qZfE2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb +-----END CERTIFICATE----- + +TunTrust Root CA +================ +-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQELBQAwYTELMAkG +A1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUgQ2VydGlmaWNhdGlvbiBFbGVj +dHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJvb3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQw +NDI2MDg1NzU2WjBhMQswCQYDVQQGEwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBD +ZXJ0aWZpY2F0aW9uIEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZn56eY+hz +2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd2JQDoOw05TDENX37Jk0b +bjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgFVwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7 +NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZGoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAd +gjH8KcwAWJeRTIAAHDOFli/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViW +VSHbhlnUr8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2eY8f +Tpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIbMlEsPvLfe/ZdeikZ +juXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISgjwBUFfyRbVinljvrS5YnzWuioYas +DXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwS +VXAkPcvCFDVDXSdOvsC9qnyW5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI +04Y+oXNZtPdEITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0 +90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+zxiD2BkewhpMl +0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYuQEkHDVneixCwSQXi/5E/S7fd +Ao74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRY +YdZ2vyJ/0Adqp2RT8JeNnYA/u8EH22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJp +adbGNjHh/PqAulxPxOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65x +xBzndFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5Xc0yGYuP +jCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7bnV2UqL1g52KAdoGDDIzM +MEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQCvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9z +ZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZHu/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3r +AZ3r2OvEhJn7wAzMMujjd9qDRIueVSjAi1jTkD5OGwDxFa2DK5o= +-----END CERTIFICATE----- + +HARICA TLS RSA Root CA 2021 +=========================== +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQG +EwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u +cyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0EgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUz +OFoXDTQ1MDIxMzEwNTUzN1owbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRl +bWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNB +IFJvb3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569lmwVnlskN +JLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE4VGC/6zStGndLuwRo0Xu +a2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uva9of08WRiFukiZLRgeaMOVig1mlDqa2Y +Ulhu2wr7a89o+uOkXjpFc5gH6l8Cct4MpbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K +5FrZx40d/JiZ+yykgmvwKh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEv +dmn8kN3bLW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcYAuUR +0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqBAGMUuTNe3QvboEUH +GjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYqE613TBoYm5EPWNgGVMWX+Ko/IIqm +haZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHrW2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQ +CPxrvrNQKlr9qEgYRtaQQJKQCoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8G +A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAUX15QvWiWkKQU +EapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3f5Z2EMVGpdAgS1D0NTsY9FVq +QRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxajaH6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxD +QpSbIPDRzbLrLFPCU3hKTwSUQZqPJzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcR +j88YxeMn/ibvBZ3PzzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5 +vZStjBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0/L5H9MG0 +qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pTBGIBnfHAT+7hOtSLIBD6 +Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79aPib8qXPMThcFarmlwDB31qlpzmq6YR/ +PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YWxw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnn +kf3/W9b3raYvAwtt41dU63ZTGI0RmLo= +-----END CERTIFICATE----- + +HARICA TLS ECC Root CA 2021 +=========================== +-----BEGIN CERTIFICATE----- +MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQswCQYDVQQGEwJH +UjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBD +QTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoX +DTQ1MDIxMzExMDEwOVowbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWlj +IGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJv +b3QgQ0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7KKrxcm1l +AEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9YSTHMmE5gEYd103KUkE+b +ECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW +0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAi +rcJRQO9gcS3ujwLEXQNwSaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/Qw +CZ61IygNnxS2PFOiTAZpffpskcYqSUXm7LcT4Tps +-----END CERTIFICATE----- + +Autoridad de Certificacion Firmaprofesional CIF A62634068 +========================================================= +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCRVMxQjBA +BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 +MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIw +QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB +NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD +Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P +B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY +7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH +ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI +plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX +MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX +LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK +bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU +vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1Ud +DgQWBBRlzeurNR4APn7VdMActHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4w +gZswgZgGBFUdIAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j +b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABCAG8AbgBhAG4A +bwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAwADEANzAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9miWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL +4QjbEwj4KKE1soCzC1HA01aajTNFSa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDb +LIpgD7dvlAceHabJhfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1il +I45PVf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZEEAEeiGaP +cjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV1aUsIC+nmCjuRfzxuIgA +LI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2tCsvMo2ebKHTEm9caPARYpoKdrcd7b/+A +lun4jWq9GJAd/0kakFI3ky88Al2CdgtR5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH +9IBk9W6VULgRfhVwOEqwf9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpf +NIbnYrX9ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNKGbqE +ZycPvEJdvSRUDewdcAZfpLz6IHxV +-----END CERTIFICATE----- + +vTrus ECC Root CA +================= +-----BEGIN CERTIFICATE----- +MIICDzCCAZWgAwIBAgIUbmq8WapTvpg5Z6LSa6Q75m0c1towCgYIKoZIzj0EAwMwRzELMAkGA1UE +BhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBS +b290IENBMB4XDTE4MDczMTA3MjY0NFoXDTQzMDczMTA3MjY0NFowRzELMAkGA1UEBhMCQ04xHDAa +BgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBSb290IENBMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEZVBKrox5lkqqHAjDo6LN/llWQXf9JpRCux3NCNtzslt188+c +ToL0v/hhJoVs1oVbcnDS/dtitN9Ti72xRFhiQgnH+n9bEOf+QP3A2MMrMudwpremIFUde4BdS49n +TPEQo0IwQDAdBgNVHQ4EFgQUmDnNvtiyjPeyq+GtJK97fKHbH88wDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIwV53dVvHH4+m4SVBrm2nDb+zDfSXkV5UT +QJtS0zvzQBm8JsctBp61ezaf9SXUY2sAAjEA6dPGnlaaKsyh2j/IZivTWJwghfqrkYpwcBE4YGQL +YgmRWAD5Tfs0aNoJrSEGGJTO +-----END CERTIFICATE----- + +vTrus Root CA +============= +-----BEGIN CERTIFICATE----- +MIIFVjCCAz6gAwIBAgIUQ+NxE9izWRRdt86M/TX9b7wFjUUwDQYJKoZIhvcNAQELBQAwQzELMAkG +A1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xFjAUBgNVBAMTDXZUcnVzIFJv +b3QgQ0EwHhcNMTgwNzMxMDcyNDA1WhcNNDMwNzMxMDcyNDA1WjBDMQswCQYDVQQGEwJDTjEcMBoG +A1UEChMTaVRydXNDaGluYSBDby4sTHRkLjEWMBQGA1UEAxMNdlRydXMgUm9vdCBDQTCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAL1VfGHTuB0EYgWgrmy3cLRB6ksDXhA/kFocizuwZots +SKYcIrrVQJLuM7IjWcmOvFjai57QGfIvWcaMY1q6n6MLsLOaXLoRuBLpDLvPbmyAhykUAyyNJJrI +ZIO1aqwTLDPxn9wsYTwaP3BVm60AUn/PBLn+NvqcwBauYv6WTEN+VRS+GrPSbcKvdmaVayqwlHeF +XgQPYh1jdfdr58tbmnDsPmcF8P4HCIDPKNsFxhQnL4Z98Cfe/+Z+M0jnCx5Y0ScrUw5XSmXX+6KA +YPxMvDVTAWqXcoKv8R1w6Jz1717CbMdHflqUhSZNO7rrTOiwCcJlwp2dCZtOtZcFrPUGoPc2BX70 +kLJrxLT5ZOrpGgrIDajtJ8nU57O5q4IikCc9Kuh8kO+8T/3iCiSn3mUkpF3qwHYw03dQ+A0Em5Q2 +AXPKBlim0zvc+gRGE1WKyURHuFE5Gi7oNOJ5y1lKCn+8pu8fA2dqWSslYpPZUxlmPCdiKYZNpGvu +/9ROutW04o5IWgAZCfEF2c6Rsffr6TlP9m8EQ5pV9T4FFL2/s1m02I4zhKOQUqqzApVg+QxMaPnu +1RcN+HFXtSXkKe5lXa/R7jwXC1pDxaWG6iSe4gUH3DRCEpHWOXSuTEGC2/KmSNGzm/MzqvOmwMVO +9fSddmPmAsYiS8GVP1BkLFTltvA8Kc9XAgMBAAGjQjBAMB0GA1UdDgQWBBRUYnBj8XWEQ1iO0RYg +scasGrz2iTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOC +AgEAKbqSSaet8PFww+SX8J+pJdVrnjT+5hpk9jprUrIQeBqfTNqK2uwcN1LgQkv7bHbKJAs5EhWd +nxEt/Hlk3ODg9d3gV8mlsnZwUKT+twpw1aA08XXXTUm6EdGz2OyC/+sOxL9kLX1jbhd47F18iMjr +jld22VkE+rxSH0Ws8HqA7Oxvdq6R2xCOBNyS36D25q5J08FsEhvMKar5CKXiNxTKsbhm7xqC5PD4 +8acWabfbqWE8n/Uxy+QARsIvdLGx14HuqCaVvIivTDUHKgLKeBRtRytAVunLKmChZwOgzoy8sHJn +xDHO2zTlJQNgJXtxmOTAGytfdELSS8VZCAeHvsXDf+eW2eHcKJfWjwXj9ZtOyh1QRwVTsMo554Wg +icEFOwE30z9J4nfrI8iIZjs9OXYhRvHsXyO466JmdXTBQPfYaJqT4i2pLr0cox7IdMakLXogqzu4 +sEb9b91fUlV1YvCXoHzXOP0l382gmxDPi7g4Xl7FtKYCNqEeXxzP4padKar9mK5S4fNBUvupLnKW +nyfjqnN9+BojZns7q2WwMgFLFT49ok8MKzWixtlnEjUwzXYuFrOZnk1PTi07NEPhmg4NpGaXutIc +SkwsKouLgU9xGqndXHt7CMUADTdA43x7VF8vhV929vensBxXVsFy6K2ir40zSbofitzmdHxghm+H +l3s= +-----END CERTIFICATE----- + +ISRG Root X2 +============ +-----BEGIN CERTIFICATE----- +MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQswCQYDVQQGEwJV +UzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElT +UkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVT +MSkwJwYDVQQKEyBJbnRlcm5ldCBTZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNS +RyBSb290IFgyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0H +ttwW+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9ItgKbppb +d9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZIzj0EAwMDaAAwZQIwe3lORlCEwkSHRhtF +cP9Ymd70/aTSVaYgLXTWNLxBo1BfASdWtL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5 +U6VR5CmD1/iQMVtCnwr1/q4AaOeMSQ+2b1tbFfLn +-----END CERTIFICATE----- + +HiPKI Root CA - G1 +================== +-----BEGIN CERTIFICATE----- +MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQG +EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xGzAZBgNVBAMMEkhpUEtJ +IFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRaFw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYT +AlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kg +Um9vdCBDQSAtIEcxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0 +o9QwqNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twvVcg3Px+k +wJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6lZgRZq2XNdZ1AYDgr/SE +YYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnzQs7ZngyzsHeXZJzA9KMuH5UHsBffMNsA +GJZMoYFL3QRtU6M9/Aes1MU3guvklQgZKILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfd +hSi8MEyr48KxRURHH+CKFgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj +1jOXTyFjHluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDry+K4 +9a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ/W3c1pzAtH2lsN0/ +Vm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgMa/aOEmem8rJY5AIJEzypuxC00jBF +8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQD +AgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi +7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqcSE5XCV0vrPSl +tJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6FzaZsT0pPBWGTMpWmWSBUdGSquE +wx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9TcXzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07Q +JNBAsNB1CI69aO4I1258EHBGG3zgiLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv +5wiZqAxeJoBF1PhoL5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+Gpz +jLrFNe85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wrkkVbbiVg +hUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+vhV4nYWBSipX3tUZQ9rb +yltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQUYDksswBVLuT1sw5XxJFBAJw/6KXf6vb/ +yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ== +-----END CERTIFICATE----- + +GlobalSign ECC Root CA - R4 +=========================== +-----BEGIN CERTIFICATE----- +MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYDVQQLExtHbG9i +YWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds +b2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgwMTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9i +YWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds +b2JhbFNpZ24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkW +ymOxuYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNVHQ8BAf8E +BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/+wpu+74zyTyjhNUwCgYI +KoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147bmF0774BxL4YSFlhgjICICadVGNA3jdg +UM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm +-----END CERTIFICATE----- + +GTS Root R1 +=========== +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQGEwJV +UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg +UjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE +ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM +f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7wCl7raKb0 +xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjwTcLCeoiKu7rPWRnWr4+w +B7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0PfyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXW +nOunVmSPlk9orj2XwoSPwLxAwAtcvfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk +9+aCEI3oncKKiPo4Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zq +kUspzBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92wO1A +K/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70paDPvOmbsB4om3xPX +V2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDW +cfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQAD +ggIBAJ+qQibbC5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe +QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuyh6f88/qBVRRi +ClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM47HLwEXWdyzRSjeZ2axfG34ar +J45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8JZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYci +NuaCp+0KueIHoI17eko8cdLiA6EfMgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5me +LMFrUKTX5hgUvYU/Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJF +fbdT6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ0E6yove+ +7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm2tIMPNuzjsmhDYAPexZ3 +FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bbbP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3 +gm3c +-----END CERTIFICATE----- + +GTS Root R2 +=========== +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQGEwJV +UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg +UjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE +ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv +CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY6Dlo7JUl +e3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAuMC6C/Pq8tBcKSOWIm8Wb +a96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS ++LFjKBC4swm4VndAoiaYecb+3yXuPuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7M +kogwTZq9TwtImoS1mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJG +r61K8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RWIr9q +S34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKaG73VululycslaVNV +J1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCqgc7dGtxRcw1PcOnlthYhGXmy5okL +dWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQAD +ggIBAB/Kzt3HvqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8 +0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyCB19m3H0Q/gxh +swWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2uNmSRXbBoGOqKYcl3qJfEycel +/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMgyALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVn +jWQye+mew4K6Ki3pHrTgSAai/GevHyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y5 +9PYjJbigapordwj6xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M +7YNRTOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924SgJPFI/2R8 +0L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV7LXTWtiBmelDGDfrs7vR +WGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjW +HYbL +-----END CERTIFICATE----- + +GTS Root R3 +=========== +-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJVUzEi +MCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMw +HhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZ +R29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjO +PQIBBgUrgQQAIgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout +736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL24CejQjBA +MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTB8Sa6oC2uhYHP0/Eq +Er24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azT +L818+FsuVbu/3ZL3pAzcMeGiAjEA/JdmZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV +11RZt+cRLInUue4X +-----END CERTIFICATE----- + +GTS Root R4 +=========== +-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJVUzEi +MCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQw +HhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZ +R29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjO +PQIBBgUrgQQAIgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu +hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvRHYqjQjBA +MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSATNbrdP9JNqPV2Py1 +PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/C +r8deVl5c1RxYIigL9zC2L7F8AjEA8GE8p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh +4rsUecrNIdSUtUlD +-----END CERTIFICATE----- + +Telia Root CA v2 +================ +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQxCzAJBgNVBAYT +AkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2 +MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQK +DBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZI +hvcNAQEBBQADggIPADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ7 +6zBqAMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9vVYiQJ3q +9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9lRdU2HhE8Qx3FZLgmEKn +pNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTODn3WhUidhOPFZPY5Q4L15POdslv5e2QJl +tI5c0BE0312/UqeBAMN/mUWZFdUXyApT7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW +5olWK8jjfN7j/4nlNW4o6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNr +RBH0pUPCTEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6WT0E +BXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63RDolUK5X6wK0dmBR4 +M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZIpEYslOqodmJHixBTB0hXbOKSTbau +BcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGjYzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7W +xy+G2CQ5MB0GA1UdDgQWBBRyrOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ +8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi0f6X+J8wfBj5 +tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMMA8iZGok1GTzTyVR8qPAs5m4H +eW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBSSRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+C +y748fdHif64W1lZYudogsYMVoe+KTTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygC +QMez2P2ccGrGKMOF6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15 +h2Er3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMtTy3EHD70 +sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pTVmBds9hCG1xLEooc6+t9 +xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAWysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQ +raVplI/owd8k+BsHMYeB2F326CjYSlKArBPuUBQemMc= +-----END CERTIFICATE----- + +D-TRUST BR Root CA 1 2020 +========================= +-----BEGIN CERTIFICATE----- +MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE +RTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEJSIFJvb3QgQ0EgMSAy +MDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNV +BAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7 +dPYSzuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0QVK5buXu +QqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/VbNafAkl1bK6CKBrqx9t +MA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu +bmV0L2NybC9kLXRydXN0X2JyX3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj +dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP +PUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD +AwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFWwKrY7RjEsK70Pvom +AjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHVdWNbFJWcHwHP2NVypw87 +-----END CERTIFICATE----- + +D-TRUST EV Root CA 1 2020 +========================= +-----BEGIN CERTIFICATE----- +MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE +RTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEVWIFJvb3QgQ0EgMSAy +MDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNV +BAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8 +ZRCC/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rDwpdhQntJ +raOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3OqQo5FD4pPfsazK2/umL +MA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu +bmV0L2NybC9kLXRydXN0X2V2X3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj +dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP +PUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD +AwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CAy/m0sRtW9XLS/BnR +AjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJbgfM0agPnIjhQW+0ZT0MW +-----END CERTIFICATE----- + +DigiCert TLS ECC P384 Root G5 +============================= +-----BEGIN CERTIFICATE----- +MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURpZ2lDZXJ0IFRMUyBFQ0MgUDM4 +NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQg +Um9vdCBHNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1Tzvd +lHJS7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp0zVozptj +n4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICISB4CIfBFqMA4GA1UdDwEB +/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQCJao1H5+z8blUD2Wds +Jk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQLgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIx +AJSdYsiJvRmEFOml+wG4DXZDjC5Ty3zfDBeWUA== +-----END CERTIFICATE----- + +DigiCert TLS RSA4096 Root G5 +============================ +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBNMQswCQYDVQQG +EwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0 +MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcNNDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2 +IFJvb3QgRzUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS8 +7IE+ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG02C+JFvuU +AT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgpwgscONyfMXdcvyej/Ces +tyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZMpG2T6T867jp8nVid9E6P/DsjyG244gXa +zOvswzH016cpVIDPRFtMbzCe88zdH5RDnU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnV +DdXifBBiqmvwPXbzP6PosMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9q +TXeXAaDxZre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cdLvvy +z6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvXKyY//SovcfXWJL5/ +MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNeXoVPzthwiHvOAbWWl9fNff2C+MIk +wcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPLtgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4E +FgQUUTMc7TZArxfTJc1paPKvTiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8w +DQYJKoZIhvcNAQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw +GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7HPNtQOa27PShN +lnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLFO4uJ+DQtpBflF+aZfTCIITfN +MBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQREtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/ +u4cnYiWB39yhL/btp/96j1EuMPikAdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9G +OUrYU9DzLjtxpdRv/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh +47a+p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilwMUc/dNAU +FvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WFqUITVuwhd4GTWgzqltlJ +yqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCKovfepEWFJqgejF0pW8hL2JpqA15w8oVP +bEtoL8pU9ozaMv7Da4M/OMZ+ +-----END CERTIFICATE----- + +Certainly Root R1 +================= +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAwPTELMAkGA1UE +BhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2VydGFpbmx5IFJvb3QgUjEwHhcN +MjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2Vy +dGFpbmx5MRowGAYDVQQDExFDZXJ0YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBANA21B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O +5MQTvqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbedaFySpvXl +8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b01C7jcvk2xusVtyWMOvwl +DbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGI +XsXwClTNSaa/ApzSRKft43jvRl5tcdF5cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkN +KPl6I7ENPT2a/Z2B7yyQwHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQ +AjeZjOVJ6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA2Cnb +rlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyHWyf5QBGenDPBt+U1 +VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMReiFPCyEQtkA6qyI6BJyLm4SGcprS +p6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBTgqj8ljZ9EXME66C6ud0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAsz +HQNTVfSVcOQrPbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d +8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi1wrykXprOQ4v +MMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrdrRT90+7iIgXr0PK3aBLXWopB +GsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9ditaY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+ +gjwN/KUD+nsa2UUeYNrEjvn8K8l7lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgH +JBu6haEaBQmAupVjyTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7 +fpYnKx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLyyCwzk5Iw +x06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5nwXARPbv0+Em34yaXOp/S +X3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6OV+KmalBWQewLK8= +-----END CERTIFICATE----- + +Certainly Root E1 +================= +-----BEGIN CERTIFICATE----- +MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQswCQYDVQQGEwJV +UzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlubHkgUm9vdCBFMTAeFw0yMTA0 +MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJBgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlu +bHkxGjAYBgNVBAMTEUNlcnRhaW5seSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4 +fxzf7flHh4axpMCK+IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9 +YBk2QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4hevIIgcwCgYIKoZIzj0E +AwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozmut6Dacpps6kFtZaSF4fC0urQe87YQVt8 +rgIwRt7qy12a7DLCZRawTDBcMPPaTnOGBtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR +-----END CERTIFICATE----- + +Security Communication ECC RootCA1 +================================== +-----BEGIN CERTIFICATE----- +MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYTAkpQMSUwIwYD +VQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYDVQQDEyJTZWN1cml0eSBDb21t +dW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYxNjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTEL +MAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNV +BAMTIlNlY3VyaXR5IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+CnnfdldB9sELLo +5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpKULGjQjBAMB0GA1UdDgQW +BBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAK +BggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3L +snNdo4gIxwwCMQDAqy0Obe0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70e +N9k= +-----END CERTIFICATE----- + +BJCA Global Root CA1 +==================== +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIQVW9l47TZkGobCdFsPsBsIDANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQG +EwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJVFkxHTAbBgNVBAMMFEJK +Q0EgR2xvYmFsIFJvb3QgQ0ExMB4XDTE5MTIxOTAzMTYxN1oXDTQ0MTIxMjAzMTYxN1owVDELMAkG +A1UEBhMCQ04xJjAkBgNVBAoMHUJFSUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQD +DBRCSkNBIEdsb2JhbCBSb290IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPFm +CL3ZxRVhy4QEQaVpN3cdwbB7+sN3SJATcmTRuHyQNZ0YeYjjlwE8R4HyDqKYDZ4/N+AZspDyRhyS +sTphzvq3Rp4Dhtczbu33RYx2N95ulpH3134rhxfVizXuhJFyV9xgw8O558dnJCNPYwpj9mZ9S1Wn +P3hkSWkSl+BMDdMJoDIwOvqfwPKcxRIqLhy1BDPapDgRat7GGPZHOiJBhyL8xIkoVNiMpTAK+BcW +yqw3/XmnkRd4OJmtWO2y3syJfQOcs4ll5+M7sSKGjwZteAf9kRJ/sGsciQ35uMt0WwfCyPQ10WRj +eulumijWML3mG90Vr4TqnMfK9Q7q8l0ph49pczm+LiRvRSGsxdRpJQaDrXpIhRMsDQa4bHlW/KNn +MoH1V6XKV0Jp6VwkYe/iMBhORJhVb3rCk9gZtt58R4oRTklH2yiUAguUSiz5EtBP6DF+bHq/pj+b +OT0CFqMYs2esWz8sgytnOYFcuX6U1WTdno9uruh8W7TXakdI136z1C2OVnZOz2nxbkRs1CTqjSSh +GL+9V/6pmTW12xB3uD1IutbB5/EjPtffhZ0nPNRAvQoMvfXnjSXWgXSHRtQpdaJCbPdzied9v3pK +H9MiyRVVz99vfFXQpIsHETdfg6YmV6YBW37+WGgHqel62bno/1Afq8K0wM7o6v0PvY1NuLxxAgMB +AAGjQjBAMB0GA1UdDgQWBBTF7+3M2I0hxkjk49cULqcWk+WYATAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAUoKsITQfI/Ki2Pm4rzc2IInRNwPWaZ+4 +YRC6ojGYWUfo0Q0lHhVBDOAqVdVXUsv45Mdpox1NcQJeXyFFYEhcCY5JEMEE3KliawLwQ8hOnThJ +dMkycFRtwUf8jrQ2ntScvd0g1lPJGKm1Vrl2i5VnZu69mP6u775u+2D2/VnGKhs/I0qUJDAnyIm8 +60Qkmss9vk/Ves6OF8tiwdneHg56/0OGNFK8YT88X7vZdrRTvJez/opMEi4r89fO4aL/3Xtw+zuh +TaRjAv04l5U/BXCga99igUOLtFkNSoxUnMW7gZ/NfaXvCyUeOiDbHPwfmGcCCtRzRBPbUYQaVQNW +4AB+dAb/OMRyHdOoP2gxXdMJxy6MW2Pg6Nwe0uxhHvLe5e/2mXZgLR6UcnHGCyoyx5JO1UbXHfmp +GQrI+pXObSOYqgs4rZpWDW+N8TEAiMEXnM0ZNjX+VVOg4DwzX5Ze4jLp3zO7Bkqp2IRzznfSxqxx +4VyjHQy7Ct9f4qNx2No3WqB4K/TUfet27fJhcKVlmtOJNBir+3I+17Q9eVzYH6Eze9mCUAyTF6ps +3MKCuwJXNq+YJyo5UOGwifUll35HaBC07HPKs5fRJNz2YqAo07WjuGS3iGJCz51TzZm+ZGiPTx4S +SPfSKcOYKMryMguTjClPPGAyzQWWYezyr/6zcCwupvI= +-----END CERTIFICATE----- + +BJCA Global Root CA2 +==================== +-----BEGIN CERTIFICATE----- +MIICJTCCAaugAwIBAgIQLBcIfWQqwP6FGFkGz7RK6zAKBggqhkjOPQQDAzBUMQswCQYDVQQGEwJD +TjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJVFkxHTAbBgNVBAMMFEJKQ0Eg +R2xvYmFsIFJvb3QgQ0EyMB4XDTE5MTIxOTAzMTgyMVoXDTQ0MTIxMjAzMTgyMVowVDELMAkGA1UE +BhMCQ04xJjAkBgNVBAoMHUJFSUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRC +SkNBIEdsb2JhbCBSb290IENBMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABJ3LgJGNU2e1uVCxA/jl +SR9BIgmwUVJY1is0j8USRhTFiy8shP8sbqjV8QnjAyEUxEM9fMEsxEtqSs3ph+B99iK++kpRuDCK +/eHeGBIK9ke35xe/J4rUQUyWPGCWwf0VHKNCMEAwHQYDVR0OBBYEFNJKsVF/BvDRgh9Obl+rg/xI +1LCRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUCMBq8 +W9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8g +UXOQwKhbYdDFUDn9hf7B43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w== +-----END CERTIFICATE----- + +Sectigo Public Server Authentication Root E46 +============================================= +-----BEGIN CERTIFICATE----- +MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQswCQYDVQQGEwJH +QjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBTZXJ2 +ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5 +WjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0 +aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUr +gQQAIgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccCWvkEN/U0 +NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+6xnOQ6OjQjBAMB0GA1Ud +DgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAKBggqhkjOPQQDAwNnADBkAjAn7qRaqCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RH +lAFWovgzJQxC36oCMB3q4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21U +SAGKcw== +-----END CERTIFICATE----- + +Sectigo Public Server Authentication Root R46 +============================================= +-----BEGIN CERTIFICATE----- +MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBfMQswCQYDVQQG +EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT +ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1 +OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T +ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3 +DQEBAQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDaef0rty2k +1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnzSDBh+oF8HqcIStw+Kxwf +GExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xfiOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMP +FF1bFOdLvt30yNoDN9HWOaEhUTCDsG3XME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vu +ZDCQOc2TZYEhMbUjUDM3IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5Qaz +Yw6A3OASVYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgESJ/A +wSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu+Zd4KKTIRJLpfSYF +plhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt8uaZFURww3y8nDnAtOFr94MlI1fZ +EoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+LHaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW +6aWWrL3DkJiy4Pmi1KZHQ3xtzwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWI +IUkwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c +mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQYKlJfp/imTYp +E0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52gDY9hAaLMyZlbcp+nv4fjFg4 +exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZAFv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M +0ejf5lG5Nkc/kLnHvALcWxxPDkjBJYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI +84HxZmduTILA7rpXDhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9m +pFuiTdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5dHn5Hrwd +Vw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65LvKRRFHQV80MNNVIIb/b +E/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmm +J1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAYQqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL +-----END CERTIFICATE----- + +SSL.com TLS RSA Root CA 2022 +============================ +-----BEGIN CERTIFICATE----- +MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQG +EwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBSU0Eg +Um9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloXDTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMC +VVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJv +b3QgQ0EgMjAyMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u +9nTPL3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OYt6/wNr/y +7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0insS657Lb85/bRi3pZ7Qcac +oOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3PnxEX4MN8/HdIGkWCVDi1FW24IBydm5M +R7d1VVm0U3TZlMZBrViKMWYPHqIbKUBOL9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDG +D6C1vBdOSHtRwvzpXGk3R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEW +TO6Af77wdr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS+YCk +8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYSd66UNHsef8JmAOSq +g+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoGAtUjHBPW6dvbxrB6y3snm/vg1UYk +7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2fgTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1Ud +EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsu +N+7jhHonLs0ZNbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt +hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsMQtfhWsSWTVTN +j8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvfR4iyrT7gJ4eLSYwfqUdYe5by +iB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJDPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjU +o3KUQyxi4U5cMj29TH0ZR6LDSeeWP4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqo +ENjwuSfr98t67wVylrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7Egkaib +MOlqbLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2wAgDHbICi +vRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3qr5nsLFR+jM4uElZI7xc7 +P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sjiMho6/4UIyYOf8kpIEFR3N+2ivEC+5BB0 +9+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA= +-----END CERTIFICATE----- + +SSL.com TLS ECC Root CA 2022 +============================ +-----BEGIN CERTIFICATE----- +MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV +UzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBFQ0MgUm9v +dCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMx +GDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3Qg +Q0EgMjAyMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWy +JGYmacCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFNSeR7T5v1 +5wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSJjy+j6CugFFR7 +81a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NWuCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGG +MAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w +7deedWo1dlJF4AIxAMeNb0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5 +Zn6g6g== +-----END CERTIFICATE----- + +Atos TrustedRoot Root CA ECC TLS 2021 +===================================== +-----BEGIN CERTIFICATE----- +MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4wLAYDVQQDDCVB +dG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQswCQYD +VQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3Mg +VHJ1c3RlZFJvb3QgUm9vdCBDQSBFQ0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYT +AkRFMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6K +DP/XtXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4AjJn8ZQS +b+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2KCXWfeBmmnoJsmo7jjPX +NtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMDaAAwZQIwW5kp85wxtolrbNa9d+F851F+ +uDrNozZffPc8dz7kUK2o59JZDCaOMDtuCCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGY +a3cpetskz2VAv9LcjBHo9H1/IISpQuQo +-----END CERTIFICATE----- + +Atos TrustedRoot Root CA RSA TLS 2021 +===================================== +-----BEGIN CERTIFICATE----- +MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBMMS4wLAYDVQQD +DCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQsw +CQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0 +b3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNV +BAYTAkRFMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BB +l01Z4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYvYe+W/CBG +vevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZkmGbzSoXfduP9LVq6hdK +ZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDsGY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt +0xU6kGpn8bRrZtkh68rZYnxGEFzedUlnnkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVK +PNe0OwANwI8f4UDErmwh3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMY +sluMWuPD0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzygeBY +Br3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8ANSbhqRAvNncTFd+ +rrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezBc6eUWsuSZIKmAMFwoW4sKeFYV+xa +fJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lIpw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUdEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0G +CSqGSIb3DQEBDAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS +4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPso0UvFJ/1TCpl +Q3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJqM7F78PRreBrAwA0JrRUITWX +AdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuywxfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9G +slA9hGCZcbUztVdF5kJHdWoOsAgMrr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2Vkt +afcxBPTy+av5EzH4AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9q +TFsR0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuYo7Ey7Nmj +1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5dDTedk+SKlOxJTnbPP/l +PqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcEoji2jbDwN/zIIX8/syQbPYtuzE2wFg2W +HYMfRsCbvUOZ58SWLs5fyQ== +-----END CERTIFICATE----- + +TrustAsia Global Root CA G3 +=========================== +-----BEGIN CERTIFICATE----- +MIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEMBQAwWjELMAkG +A1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMM +G1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAeFw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEw +MTlaMFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMu +MSQwIgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNST1QY4Sxz +lZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqKAtCWHwDNBSHvBm3dIZwZ +Q0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/V +P68czH5GX6zfZBCK70bwkPAPLfSIC7Epqq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1Ag +dB4SQXMeJNnKziyhWTXAyB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm +9WAPzJMshH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gXzhqc +D0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAvkV34PmVACxmZySYg +WmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msTf9FkPz2ccEblooV7WIQn3MSAPmea +mseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jAuPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCF +TIcQcf+eQxuulXUtgQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj +7zjKsK5Xf/IhMBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E +BAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4wM8zAQLpw6o1 +D/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2XFNFV1pF1AWZLy4jVe5jaN/T +G3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNj +duMNhXJEIlU/HHzp/LgV6FL6qj6jITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstl +cHboCoWASzY9M/eVVHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys ++TIxxHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1onAX1daBli +2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d7XB4tmBZrOFdRWOPyN9y +aFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2NtjjgKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsAS +ZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV+Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFR +JQJ6+N1rZdVtTTDIZbpoFGWsJwt0ivKH +-----END CERTIFICATE----- + +TrustAsia Global Root CA G4 +=========================== +-----BEGIN CERTIFICATE----- +MIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMwWjELMAkGA1UE +BhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMMG1Ry +dXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0yMTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJa +MFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQw +IgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AATxs8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbwLxYI+hW8 +m7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJijYzBhMA8GA1UdEwEB/wQF +MAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mDpm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/ +pDHel4NZg6ZvccveMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AA +bbd+NvBNEU/zy4k6LHiRUKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xk +dUfFVZDj/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA== +-----END CERTIFICATE----- + +CommScope Public Trust ECC Root-01 +================================== +-----BEGIN CERTIFICATE----- +MIICHTCCAaOgAwIBAgIUQ3CCd89NXTTxyq4yLzf39H91oJ4wCgYIKoZIzj0EAwMwTjELMAkGA1UE +BhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBUcnVz +dCBFQ0MgUm9vdC0wMTAeFw0yMTA0MjgxNzM1NDNaFw00NjA0MjgxNzM1NDJaME4xCzAJBgNVBAYT +AlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3Qg +RUNDIFJvb3QtMDEwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARLNumuV16ocNfQj3Rid8NeeqrltqLx +eP0CflfdkXmcbLlSiFS8LwS+uM32ENEp7LXQoMPwiXAZu1FlxUOcw5tjnSCDPgYLpkJEhRGnSjot +6dZoL0hOUysHP029uax3OVejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBSOB2LAUN3GGQYARnQE9/OufXVNMDAKBggqhkjOPQQDAwNoADBlAjEAnDPfQeMjqEI2 +Jpc1XHvr20v4qotzVRVcrHgpD7oh2MSg2NED3W3ROT3Ek2DS43KyAjB8xX6I01D1HiXo+k515liW +pDVfG2XqYZpwI7UNo5uSUm9poIyNStDuiw7LR47QjRE= +-----END CERTIFICATE----- + +CommScope Public Trust ECC Root-02 +================================== +-----BEGIN CERTIFICATE----- +MIICHDCCAaOgAwIBAgIUKP2ZYEFHpgE6yhR7H+/5aAiDXX0wCgYIKoZIzj0EAwMwTjELMAkGA1UE +BhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBUcnVz +dCBFQ0MgUm9vdC0wMjAeFw0yMTA0MjgxNzQ0NTRaFw00NjA0MjgxNzQ0NTNaME4xCzAJBgNVBAYT +AlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3Qg +RUNDIFJvb3QtMDIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAR4MIHoYx7l63FRD/cHB8o5mXxO1Q/M +MDALj2aTPs+9xYa9+bG3tD60B8jzljHz7aRP+KNOjSkVWLjVb3/ubCK1sK9IRQq9qEmUv4RDsNuE +SgMjGWdqb8FuvAY5N9GIIvejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBTmGHX/72DehKT1RsfeSlXjMjZ59TAKBggqhkjOPQQDAwNnADBkAjAmc0l6tqvmSfR9 +Uj/UQQSugEODZXW5hYA4O9Zv5JOGq4/nich/m35rChJVYaoR4HkCMHfoMXGsPHED1oQmHhS48zs7 +3u1Z/GtMMH9ZzkXpc2AVmkzw5l4lIhVtwodZ0LKOag== +-----END CERTIFICATE----- + +CommScope Public Trust RSA Root-01 +================================== +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIUPgNJgXUWdDGOTKvVxZAplsU5EN0wDQYJKoZIhvcNAQELBQAwTjELMAkG +A1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBU +cnVzdCBSU0EgUm9vdC0wMTAeFw0yMTA0MjgxNjQ1NTRaFw00NjA0MjgxNjQ1NTNaME4xCzAJBgNV +BAYTAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1 +c3QgUlNBIFJvb3QtMDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwSGWjDR1C45Ft +nYSkYZYSwu3D2iM0GXb26v1VWvZVAVMP8syMl0+5UMuzAURWlv2bKOx7dAvnQmtVzslhsuitQDy6 +uUEKBU8bJoWPQ7VAtYXR1HHcg0Hz9kXHgKKEUJdGzqAMxGBWBB0HW0alDrJLpA6lfO741GIDuZNq +ihS4cPgugkY4Iw50x2tBt9Apo52AsH53k2NC+zSDO3OjWiE260f6GBfZumbCk6SP/F2krfxQapWs +vCQz0b2If4b19bJzKo98rwjyGpg/qYFlP8GMicWWMJoKz/TUyDTtnS+8jTiGU+6Xn6myY5QXjQ/c +Zip8UlF1y5mO6D1cv547KI2DAg+pn3LiLCuz3GaXAEDQpFSOm117RTYm1nJD68/A6g3czhLmfTif +BSeolz7pUcZsBSjBAg/pGG3svZwG1KdJ9FQFa2ww8esD1eo9anbCyxooSU1/ZOD6K9pzg4H/kQO9 +lLvkuI6cMmPNn7togbGEW682v3fuHX/3SZtS7NJ3Wn2RnU3COS3kuoL4b/JOHg9O5j9ZpSPcPYeo +KFgo0fEbNttPxP/hjFtyjMcmAyejOQoBqsCyMWCDIqFPEgkBEa801M/XrmLTBQe0MXXgDW1XT2mH ++VepuhX2yFJtocucH+X8eKg1mp9BFM6ltM6UCBwJrVbl2rZJmkrqYxhTnCwuwwIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUN12mmnQywsL5x6YVEFm4 +5P3luG0wDQYJKoZIhvcNAQELBQADggIBAK+nz97/4L1CjU3lIpbfaOp9TSp90K09FlxD533Ahuh6 +NWPxzIHIxgvoLlI1pKZJkGNRrDSsBTtXAOnTYtPZKdVUvhwQkZyybf5Z/Xn36lbQnmhUQo8mUuJM +3y+Xpi/SB5io82BdS5pYV4jvguX6r2yBS5KPQJqTRlnLX3gWsWc+QgvfKNmwrZggvkN80V4aCRck +jXtdlemrwWCrWxhkgPut4AZ9HcpZuPN4KWfGVh2vtrV0KnahP/t1MJ+UXjulYPPLXAziDslg+Mkf +Foom3ecnf+slpoq9uC02EJqxWE2aaE9gVOX2RhOOiKy8IUISrcZKiX2bwdgt6ZYD9KJ0DLwAHb/W +NyVntHKLr4W96ioDj8z7PEQkguIBpQtZtjSNMgsSDesnwv1B10A8ckYpwIzqug/xBpMu95yo9GA+ +o/E4Xo4TwbM6l4c/ksp4qRyv0LAbJh6+cOx69TOY6lz/KwsETkPdY34Op054A5U+1C0wlREQKC6/ +oAI+/15Z0wUOlV9TRe9rh9VIzRamloPh37MG88EU26fsHItdkJANclHnYfkUyq+Dj7+vsQpZXdxc +1+SWrVtgHdqul7I52Qb1dgAT+GhMIbA1xNxVssnBQVocicCMb3SgazNNtQEo/a2tiRc7ppqEvOuM +6sRxJKi6KfkIsidWNTJf6jn7MZrVGczw +-----END CERTIFICATE----- + +CommScope Public Trust RSA Root-02 +================================== +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIUVBa/O345lXGN0aoApYYNK496BU4wDQYJKoZIhvcNAQELBQAwTjELMAkG +A1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBU +cnVzdCBSU0EgUm9vdC0wMjAeFw0yMTA0MjgxNzE2NDNaFw00NjA0MjgxNzE2NDJaME4xCzAJBgNV +BAYTAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1 +c3QgUlNBIFJvb3QtMDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDh+g77aAASyE3V +rCLENQE7xVTlWXZjpX/rwcRqmL0yjReA61260WI9JSMZNRTpf4mnG2I81lDnNJUDMrG0kyI9p+Kx +7eZ7Ti6Hmw0zdQreqjXnfuU2mKKuJZ6VszKWpCtYHu8//mI0SFHRtI1CrWDaSWqVcN3SAOLMV2MC +e5bdSZdbkk6V0/nLKR8YSvgBKtJjCW4k6YnS5cciTNxzhkcAqg2Ijq6FfUrpuzNPDlJwnZXjfG2W +Wy09X6GDRl224yW4fKcZgBzqZUPckXk2LHR88mcGyYnJ27/aaL8j7dxrrSiDeS/sOKUNNwFnJ5rp +M9kzXzehxfCrPfp4sOcsn/Y+n2Dg70jpkEUeBVF4GiwSLFworA2iI540jwXmojPOEXcT1A6kHkIf +hs1w/tkuFT0du7jyU1fbzMZ0KZwYszZ1OC4PVKH4kh+Jlk+71O6d6Ts2QrUKOyrUZHk2EOH5kQMr +eyBUzQ0ZGshBMjTRsJnhkB4BQDa1t/qp5Xd1pCKBXbCL5CcSD1SIxtuFdOa3wNemKfrb3vOTlycE +VS8KbzfFPROvCgCpLIscgSjX74Yxqa7ybrjKaixUR9gqiC6vwQcQeKwRoi9C8DfF8rhW3Q5iLc4t +Vn5V8qdE9isy9COoR+jUKgF4z2rDN6ieZdIs5fq6M8EGRPbmz6UNp2YINIos8wIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUR9DnsSL/nSz12Vdgs7Gx +cJXvYXowDQYJKoZIhvcNAQELBQADggIBAIZpsU0v6Z9PIpNojuQhmaPORVMbc0RTAIFhzTHjCLqB +KCh6krm2qMhDnscTJk3C2OVVnJJdUNjCK9v+5qiXz1I6JMNlZFxHMaNlNRPDk7n3+VGXu6TwYofF +1gbTl4MgqX67tiHCpQ2EAOHyJxCDut0DgdXdaMNmEMjRdrSzbymeAPnCKfWxkxlSaRosTKCL4BWa +MS/TiJVZbuXEs1DIFAhKm4sTg7GkcrI7djNB3NyqpgdvHSQSn8h2vS/ZjvQs7rfSOBAkNlEv41xd +gSGn2rtO/+YHqP65DSdsu3BaVXoT6fEqSWnHX4dXTEN5bTpl6TBcQe7rd6VzEojov32u5cSoHw2O +HG1QAk8mGEPej1WFsQs3BWDJVTkSBKEqz3EWnzZRSb9wO55nnPt7eck5HHisd5FUmrh1CoFSl+Nm +YWvtPjgelmFV4ZFUjO2MJB+ByRCac5krFk5yAD9UG/iNuovnFNa2RU9g7Jauwy8CTl2dlklyALKr +dVwPaFsdZcJfMw8eD/A7hvWwTruc9+olBdytoptLFwG+Qt81IR2tq670v64fG9PiO/yzcnMcmyiQ +iRM9HcEARwmWmjgb3bHPDcK0RPOWlc4yOo80nOAXx17Org3bhzjlP1v9mxnhMUF6cKojawHhRUzN +lM47ni3niAIi9G7oyOzWPPO5std3eqx7 +-----END CERTIFICATE----- + +Telekom Security TLS ECC Root 2020 +================================== +-----BEGIN CERTIFICATE----- +MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQswCQYDVQQGEwJE +RTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJUZWxl +a29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIwMB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIz +NTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkg +R21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqG +SM49AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/OtdKPD/M1 +2kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDPf8iAC8GXs7s1J8nCG6NC +MEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6fMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMAoGCCqGSM49BAMDA2cAMGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZ +Mo7k+5Dck2TOrbRBR2Diz6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdU +ga/sf+Rn27iQ7t0l +-----END CERTIFICATE----- + +Telekom Security TLS RSA Root 2023 +================================== +-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBjMQswCQYDVQQG +EwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJU +ZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAyMDIzMB4XDTIzMDMyODEyMTY0NVoXDTQ4MDMy +NzIzNTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJp +dHkgR21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgUlNBIFJvb3QgMjAyMzCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAO01oYGA88tKaVvC+1GDrib94W7zgRJ9cUD/h3VC +KSHtgVIs3xLBGYSJwb3FKNXVS2xE1kzbB5ZKVXrKNoIENqil/Cf2SfHVcp6R+SPWcHu79ZvB7JPP +GeplfohwoHP89v+1VmLhc2o0mD6CuKyVU/QBoCcHcqMAU6DksquDOFczJZSfvkgdmOGjup5czQRx +UX11eKvzWarE4GC+j4NSuHUaQTXtvPM6Y+mpFEXX5lLRbtLevOP1Czvm4MS9Q2QTps70mDdsipWo +l8hHD/BeEIvnHRz+sTugBTNoBUGCwQMrAcjnj02r6LX2zWtEtefdi+zqJbQAIldNsLGyMcEWzv/9 +FIS3R/qy8XDe24tsNlikfLMR0cN3f1+2JeANxdKz+bi4d9s3cXFH42AYTyS2dTd4uaNir73Jco4v +zLuu2+QVUhkHM/tqty1LkCiCc/4YizWN26cEar7qwU02OxY2kTLvtkCJkUPg8qKrBC7m8kwOFjQg +rIfBLX7JZkcXFBGk8/ehJImr2BrIoVyxo/eMbcgByU/J7MT8rFEz0ciD0cmfHdRHNCk+y7AO+oML +KFjlKdw/fKifybYKu6boRhYPluV75Gp6SG12mAWl3G0eQh5C2hrgUve1g8Aae3g1LDj1H/1Joy7S +WWO/gLCMk3PLNaaZlSJhZQNg+y+TS/qanIA7AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAdBgNV +HQ4EFgQUtqeXgj10hZv3PJ+TmpV5dVKMbUcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS2 +p5eCPXSFm/c8n5OalXl1UoxtRzANBgkqhkiG9w0BAQwFAAOCAgEAqMxhpr51nhVQpGv7qHBFfLp+ +sVr8WyP6Cnf4mHGCDG3gXkaqk/QeoMPhk9tLrbKmXauw1GLLXrtm9S3ul0A8Yute1hTWjOKWi0Fp +kzXmuZlrYrShF2Y0pmtjxrlO8iLpWA1WQdH6DErwM807u20hOq6OcrXDSvvpfeWxm4bu4uB9tPcy +/SKE8YXJN3nptT+/XOR0so8RYgDdGGah2XsjX/GO1WfoVNpbOms2b/mBsTNHM3dA+VKq3dSDz4V4 +mZqTuXNnQkYRIer+CqkbGmVps4+uFrb2S1ayLfmlyOw7YqPta9BO1UAJpB+Y1zqlklkg5LB9zVtz +aL1txKITDmcZuI1CfmwMmm6gJC3VRRvcxAIU/oVbZZfKTpBQCHpCNfnqwmbU+AGuHrS+w6jv/naa +oqYfRvaE7fzbzsQCzndILIyy7MMAo+wsVRjBfhnu4S/yrYObnqsZ38aKL4x35bcF7DvB7L6Gs4a8 +wPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+ljX273CXE2whJdV/LItM3z7gLfEdxquVeE +HVlNjM7IDiPCtyaaEBRx/pOyiriA8A4QntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0 +o82bNSQ3+pCTE4FCxpgmdTdmQRCsu/WU48IxK63nI1bMNSWSs1A= +-----END CERTIFICATE----- + +FIRMAPROFESIONAL CA ROOT-A WEB +============================== +-----BEGIN CERTIFICATE----- +MIICejCCAgCgAwIBAgIQMZch7a+JQn81QYehZ1ZMbTAKBggqhkjOPQQDAzBuMQswCQYDVQQGEwJF +UzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25hbCBTQTEYMBYGA1UEYQwPVkFURVMtQTYyNjM0MDY4 +MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFMIENBIFJPT1QtQSBXRUIwHhcNMjIwNDA2MDkwMTM2 +WhcNNDcwMzMxMDkwMTM2WjBuMQswCQYDVQQGEwJFUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25h +bCBTQTEYMBYGA1UEYQwPVkFURVMtQTYyNjM0MDY4MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFM +IENBIFJPT1QtQSBXRUIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARHU+osEaR3xyrq89Zfe9MEkVz6 +iMYiuYMQYneEMy3pA4jU4DP37XcsSmDq5G+tbbT4TIqk5B/K6k84Si6CcyvHZpsKjECcfIr28jlg +st7L7Ljkb+qbXbdTkBgyVcUgt5SjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUk+FD +Y1w8ndYn81LsF7Kpryz3dvgwHQYDVR0OBBYEFJPhQ2NcPJ3WJ/NS7Beyqa8s93b4MA4GA1UdDwEB +/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjAdfKR7w4l1M+E7qUW/Runpod3JIha3RxEL2Jq68cgL +cFBTApFwhVmpHqTm6iMxoAACMQD94vizrxa5HnPEluPBMBnYfubDl94cT7iJLzPrSA8Z94dGXSaQ +pYXFuXqUPoeovQA= +-----END CERTIFICATE----- + +TWCA CYBER Root CA +================== +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIQQAE0jMIAAAAAAAAAATzyxjANBgkqhkiG9w0BAQwFADBQMQswCQYDVQQG +EwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NB +IENZQkVSIFJvb3QgQ0EwHhcNMjIxMTIyMDY1NDI5WhcNNDcxMTIyMTU1OTU5WjBQMQswCQYDVQQG +EwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NB +IENZQkVSIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDG+Moe2Qkgfh1s +Ts6P40czRJzHyWmqOlt47nDSkvgEs1JSHWdyKKHfi12VCv7qze33Kc7wb3+szT3vsxxFavcokPFh +V8UMxKNQXd7UtcsZyoC5dc4pztKFIuwCY8xEMCDa6pFbVuYdHNWdZsc/34bKS1PE2Y2yHer43CdT +o0fhYcx9tbD47nORxc5zb87uEB8aBs/pJ2DFTxnk684iJkXXYJndzk834H/nY62wuFm40AZoNWDT +Nq5xQwTxaWV4fPMf88oon1oglWa0zbfuj3ikRRjpJi+NmykosaS3Om251Bw4ckVYsV7r8Cibt4LK +/c/WMw+f+5eesRycnupfXtuq3VTpMCEobY5583WSjCb+3MX2w7DfRFlDo7YDKPYIMKoNM+HvnKkH +IuNZW0CP2oi3aQiotyMuRAlZN1vH4xfyIutuOVLF3lSnmMlLIJXcRolftBL5hSmO68gnFSDAS9TM +fAxsNAwmmyYxpjyn9tnQS6Jk/zuZQXLB4HCX8SS7K8R0IrGsayIyJNN4KsDAoS/xUgXJP+92ZuJF +2A09rZXIx4kmyA+upwMu+8Ff+iDhcK2wZSA3M2Cw1a/XDBzCkHDXShi8fgGwsOsVHkQGzaRP6AzR +wyAQ4VRlnrZR0Bp2a0JaWHY06rc3Ga4udfmW5cFZ95RXKSWNOkyrTZpB0F8mAwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSdhWEUfMFib5do5E83 +QOGt4A1WNzAdBgNVHQ4EFgQUnYVhFHzBYm+XaORPN0DhreANVjcwDQYJKoZIhvcNAQEMBQADggIB +AGSPesRiDrWIzLjHhg6hShbNcAu3p4ULs3a2D6f/CIsLJc+o1IN1KriWiLb73y0ttGlTITVX1olN +c79pj3CjYcya2x6a4CD4bLubIp1dhDGaLIrdaqHXKGnK/nZVekZn68xDiBaiA9a5F/gZbG0jAn/x +X9AKKSM70aoK7akXJlQKTcKlTfjF/biBzysseKNnTKkHmvPfXvt89YnNdJdhEGoHK4Fa0o635yDR +IG4kqIQnoVesqlVYL9zZyvpoBJ7tRCT5dEA7IzOrg1oYJkK2bVS1FmAwbLGg+LhBoF1JSdJlBTrq +/p1hvIbZv97Tujqxf36SNI7JAG7cmL3c7IAFrQI932XtCwP39xaEBDG6k5TY8hL4iuO/Qq+n1M0R +FxbIQh0UqEL20kCGoE8jypZFVmAGzbdVAaYBlGX+bgUJurSkquLvWL69J1bY73NxW0Qz8ppy6rBe +Pm6pUlvscG21h483XjyMnM7k8M4MZ0HMzvaAq07MTFb1wWFZk7Q+ptq4NxKfKjLji7gh7MMrZQzv +It6IKTtM1/r+t+FHvpw+PoP7UV31aPcuIYXcv/Fa4nzXxeSDwWrruoBa3lwtcHb4yOWHh8qgnaHl +IhInD0Q9HWzq1MKLL295q39QpsQZp6F6t5b5wR9iWqJDB0BeJsas7a5wFsWqynKKTbDPAYsDP27X +-----END CERTIFICATE----- + +SecureSign Root CA12 +==================== +-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUZvnHwa/swlG07VOX5uaCwysckBYwDQYJKoZIhvcNAQELBQAwUTELMAkG +A1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRT +ZWN1cmVTaWduIFJvb3QgQ0ExMjAeFw0yMDA0MDgwNTM2NDZaFw00MDA0MDgwNTM2NDZaMFExCzAJ +BgNVBAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMU +U2VjdXJlU2lnbiBSb290IENBMTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6OcE3 +emhFKxS06+QT61d1I02PJC0W6K6OyX2kVzsqdiUzg2zqMoqUm048luT9Ub+ZyZN+v/mtp7JIKwcc +J/VMvHASd6SFVLX9kHrko+RRWAPNEHl57muTH2SOa2SroxPjcf59q5zdJ1M3s6oYwlkm7Fsf0uZl +fO+TvdhYXAvA42VvPMfKWeP+bl+sg779XSVOKik71gurFzJ4pOE+lEa+Ym6b3kaosRbnhW70CEBF +EaCeVESE99g2zvVQR9wsMJvuwPWW0v4JhscGWa5Pro4RmHvzC1KqYiaqId+OJTN5lxZJjfU+1Uef +NzFJM3IFTQy2VYzxV4+Kh9GtxRESOaCtAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMB0GA1UdDgQWBBRXNPN0zwRL1SXm8UC2LEzZLemgrTANBgkqhkiG9w0BAQsFAAOC +AQEAPrvbFxbS8hQBICw4g0utvsqFepq2m2um4fylOqyttCg6r9cBg0krY6LdmmQOmFxv3Y67ilQi +LUoT865AQ9tPkbeGGuwAtEGBpE/6aouIs3YIcipJQMPTw4WJmBClnW8Zt7vPemVV2zfrPIpyMpce +mik+rY3moxtt9XUa5rBouVui7mlHJzWhhpmA8zNL4WukJsPvdFlseqJkth5Ew1DgDzk9qTPxpfPS +vWKErI4cqc1avTc7bgoitPQV55FYxTpE05Uo2cBl6XLK0A+9H7MV2anjpEcJnuDLN/v9vZfVvhga +aaI5gdka9at/yOPiZwud9AzqVN/Ssq+xIvEg37xEHA== +-----END CERTIFICATE----- + +SecureSign Root CA14 +==================== +-----BEGIN CERTIFICATE----- +MIIFcjCCA1qgAwIBAgIUZNtaDCBO6Ncpd8hQJ6JaJ90t8sswDQYJKoZIhvcNAQEMBQAwUTELMAkG +A1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRT +ZWN1cmVTaWduIFJvb3QgQ0ExNDAeFw0yMDA0MDgwNzA2MTlaFw00NTA0MDgwNzA2MTlaMFExCzAJ +BgNVBAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMU +U2VjdXJlU2lnbiBSb290IENBMTQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDF0nqh +1oq/FjHQmNE6lPxauG4iwWL3pwon71D2LrGeaBLwbCRjOfHw3xDG3rdSINVSW0KZnvOgvlIfX8xn +bacuUKLBl422+JX1sLrcneC+y9/3OPJH9aaakpUqYllQC6KxNedlsmGy6pJxaeQp8E+BgQQ8sqVb +1MWoWWd7VRxJq3qdwudzTe/NCcLEVxLbAQ4jeQkHO6Lo/IrPj8BGJJw4J+CDnRugv3gVEOuGTgpa +/d/aLIJ+7sr2KeH6caH3iGicnPCNvg9JkdjqOvn90Ghx2+m1K06Ckm9mH+Dw3EzsytHqunQG+bOE +kJTRX45zGRBdAuVwpcAQ0BB8b8VYSbSwbprafZX1zNoCr7gsfXmPvkPx+SgojQlD+Ajda8iLLCSx +jVIHvXiby8posqTdDEx5YMaZ0ZPxMBoH064iwurO8YQJzOAUbn8/ftKChazcqRZOhaBgy/ac18iz +ju3Gm5h1DVXoX+WViwKkrkMpKBGk5hIwAUt1ax5mnXkvpXYvHUC0bcl9eQjs0Wq2XSqypWa9a4X0 +dFbD9ed1Uigspf9mR6XU/v6eVL9lfgHWMI+lNpyiUBzuOIABSMbHdPTGrMNASRZhdCyvjG817XsY +AFs2PJxQDcqSMxDxJklt33UkN4Ii1+iW/RVLApY+B3KVfqs9TC7XyvDf4Fg/LS8EmjijAQIDAQAB +o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUBpOjCl4oaTeq +YR3r6/wtbyPk86AwDQYJKoZIhvcNAQEMBQADggIBAJaAcgkGfpzMkwQWu6A6jZJOtxEaCnFxEM0E +rX+lRVAQZk5KQaID2RFPeje5S+LGjzJmdSX7684/AykmjbgWHfYfM25I5uj4V7Ibed87hwriZLoA +ymzvftAj63iP/2SbNDefNWWipAA9EiOWWF3KY4fGoweITedpdopTzfFP7ELyk+OZpDc8h7hi2/Ds +Hzc/N19DzFGdtfCXwreFamgLRB7lUe6TzktuhsHSDCRZNhqfLJGP4xjblJUK7ZGqDpncllPjYYPG +FrojutzdfhrGe0K22VoF3Jpf1d+42kd92jjbrDnVHmtsKheMYc2xbXIBw8MgAGJoFjHVdqqGuw6q +nsb58Nn4DSEC5MUoFlkRudlpcyqSeLiSV5sI8jrlL5WwWLdrIBRtFO8KvH7YVdiI2i/6GaX7i+B/ +OfVyK4XELKzvGUWSTLNhB9xNH27SgRNcmvMSZ4PPmz+Ln52kuaiWA3rF7iDeM9ovnhp6dB7h7sxa +OgTdsxoEqBRjrLdHEoOabPXm6RUVkRqEGQ6UROcSjiVbgGcZ3GOTEAtlLor6CZpO2oYofaphNdgO +pygau1LgePhsumywbrmHXumZNTfxPWQrqaA0k89jL9WB365jJ6UeTo3cKXhZ+PmhIIynJkBugnLN +eLLIjzwec+fBH7/PzqUqm9tEZDKgu39cJRNItX+S +-----END CERTIFICATE----- + +SecureSign Root CA15 +==================== +-----BEGIN CERTIFICATE----- +MIICIzCCAamgAwIBAgIUFhXHw9hJp75pDIqI7fBw+d23PocwCgYIKoZIzj0EAwMwUTELMAkGA1UE +BhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRTZWN1 +cmVTaWduIFJvb3QgQ0ExNTAeFw0yMDA0MDgwODMyNTZaFw00NTA0MDgwODMyNTZaMFExCzAJBgNV +BAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2Vj +dXJlU2lnbiBSb290IENBMTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQLUHSNZDKZmbPSYAi4Io5G +dCx4wCtELW1fHcmuS1Iggz24FG1Th2CeX2yF2wYUleDHKP+dX+Sq8bOLbe1PL0vJSpSRZHX+AezB +2Ot6lHhWGENfa4HL9rzatAy2KZMIaY+jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBTrQciu/NWeUUj1vYv0hyCTQSvT9DAKBggqhkjOPQQDAwNoADBlAjEA2S6J +fl5OpBEHvVnCB96rMjhTKkZEBhd6zlHp4P9mLQlO4E/0BdGF9jVg3PVys0Z9AjBEmEYagoUeYWmJ +SwdLZrWeqrqgHkHZAXQ6bkU6iYAZezKYVWOr62Nuk22rGwlgMU4= +-----END CERTIFICATE----- diff --git a/includes/vendor/composer/ca-bundle/src/CaBundle.php b/includes/vendor/composer/ca-bundle/src/CaBundle.php index 0109ba037..2d6b48c56 100644 --- a/includes/vendor/composer/ca-bundle/src/CaBundle.php +++ b/includes/vendor/composer/ca-bundle/src/CaBundle.php @@ -24,8 +24,6 @@ class CaBundle private static $caPath; /** @var array */ private static $caFileValidity = array(); - /** @var bool|null */ - private static $useOpensslParse; /** * Returns the system CA bundle path, or a path to the bundled one @@ -64,7 +62,7 @@ class CaBundle * @param LoggerInterface $logger optional logger for information about which CA files were loaded * @return string path to a CA bundle file or directory */ - public static function getSystemCaRootBundlePath(LoggerInterface $logger = null) + public static function getSystemCaRootBundlePath(?LoggerInterface $logger = null) { if (self::$caPath !== null) { return self::$caPath; @@ -86,21 +84,19 @@ public static function getSystemCaRootBundlePath(LoggerInterface $logger = null) '/etc/pki/tls/certs/ca-bundle.crt', // Fedora, RHEL, CentOS (ca-certificates package) '/etc/ssl/certs/ca-certificates.crt', // Debian, Ubuntu, Gentoo, Arch Linux (ca-certificates package) '/etc/ssl/ca-bundle.pem', // SUSE, openSUSE (ca-certificates package) - '/usr/local/share/certs/ca-root-nss.crt', // FreeBSD (ca_root_nss_package) '/usr/ssl/certs/ca-bundle.crt', // Cygwin '/opt/local/share/curl/curl-ca-bundle.crt', // OS X macports, curl-ca-bundle package '/usr/local/share/curl/curl-ca-bundle.crt', // Default cURL CA bunde path (without --with-ca-bundle option) '/usr/share/ssl/certs/ca-bundle.crt', // Really old RedHat? '/etc/ssl/cert.pem', // OpenBSD - '/usr/local/etc/ssl/cert.pem', // FreeBSD 10.x '/usr/local/etc/openssl/cert.pem', // OS X homebrew, openssl package '/usr/local/etc/openssl@1.1/cert.pem', // OS X homebrew, openssl@1.1 package + '/opt/homebrew/etc/openssl@3/cert.pem', // macOS silicon homebrew, openssl@3 package + '/opt/homebrew/etc/openssl@1.1/cert.pem', // macOS silicon homebrew, openssl@1.1 package + '/etc/pki/tls/certs', + '/etc/ssl/certs', // FreeBSD ); - foreach($otherLocations as $location) { - $otherLocations[] = dirname($location); - } - $caBundlePaths = array_merge($caBundlePaths, $otherLocations); foreach ($caBundlePaths as $caBundle) { @@ -108,7 +104,7 @@ public static function getSystemCaRootBundlePath(LoggerInterface $logger = null) return self::$caPath = $caBundle; } - if ($caBundle && self::caDirUsable($caBundle)) { + if ($caBundle && self::caDirUsable($caBundle, $logger)) { return self::$caPath = $caBundle; } } @@ -158,7 +154,7 @@ public static function getBundledCaBundlePath() * * @return bool */ - public static function validateCaFile($filename, LoggerInterface $logger = null) + public static function validateCaFile($filename, ?LoggerInterface $logger = null) { static $warned = false; @@ -168,19 +164,7 @@ public static function validateCaFile($filename, LoggerInterface $logger = null) $contents = file_get_contents($filename); - // assume the CA is valid if php is vulnerable to - // https://www.sektioneins.de/advisories/advisory-012013-php-openssl_x509_parse-memory-corruption-vulnerability.html - if (!static::isOpensslParseSafe()) { - if (!$warned && $logger) { - $logger->warning(sprintf( - 'Your version of PHP, %s, is affected by CVE-2013-6420 and cannot safely perform certificate validation, we strongly suggest you upgrade.', - PHP_VERSION - )); - $warned = true; - } - - $isValid = !empty($contents); - } elseif (is_string($contents) && strlen($contents) > 0) { + if (is_string($contents) && strlen($contents) > 0) { $contents = preg_replace("/^(\\-+(?:BEGIN|END))\\s+TRUSTED\\s+(CERTIFICATE\\-+)\$/m", '$1 $2', $contents); if (null === $contents) { // regex extraction failed @@ -209,100 +193,7 @@ public static function validateCaFile($filename, LoggerInterface $logger = null) */ public static function isOpensslParseSafe() { - if (null !== self::$useOpensslParse) { - return self::$useOpensslParse; - } - - if (PHP_VERSION_ID >= 50600) { - return self::$useOpensslParse = true; - } - - // Vulnerable: - // PHP 5.3.0 - PHP 5.3.27 - // PHP 5.4.0 - PHP 5.4.22 - // PHP 5.5.0 - PHP 5.5.6 - if ( - (PHP_VERSION_ID < 50400 && PHP_VERSION_ID >= 50328) - || (PHP_VERSION_ID < 50500 && PHP_VERSION_ID >= 50423) - || PHP_VERSION_ID >= 50507 - ) { - // This version of PHP has the fix for CVE-2013-6420 applied. - return self::$useOpensslParse = true; - } - - if (defined('PHP_WINDOWS_VERSION_BUILD')) { - // Windows is probably insecure in this case. - return self::$useOpensslParse = false; - } - - $compareDistroVersionPrefix = function ($prefix, $fixedVersion) { - $regex = '{^'.preg_quote($prefix).'([0-9]+)$}'; - - if (preg_match($regex, PHP_VERSION, $m)) { - return ((int) $m[1]) >= $fixedVersion; - } - - return false; - }; - - // Hard coded list of PHP distributions with the fix backported. - if ( - $compareDistroVersionPrefix('5.3.3-7+squeeze', 18) // Debian 6 (Squeeze) - || $compareDistroVersionPrefix('5.4.4-14+deb7u', 7) // Debian 7 (Wheezy) - || $compareDistroVersionPrefix('5.3.10-1ubuntu3.', 9) // Ubuntu 12.04 (Precise) - ) { - return self::$useOpensslParse = true; - } - - // Symfony Process component is missing so we assume it is unsafe at this point - if (!class_exists('Symfony\Component\Process\PhpProcess')) { - return self::$useOpensslParse = false; - } - - // This is where things get crazy, because distros backport security - // fixes the chances are on NIX systems the fix has been applied but - // it's not possible to verify that from the PHP version. - // - // To verify exec a new PHP process and run the issue testcase with - // known safe input that replicates the bug. - - // Based on testcase in https://github.com/php/php-src/commit/c1224573c773b6845e83505f717fbf820fc18415 - // changes in https://github.com/php/php-src/commit/76a7fd893b7d6101300cc656058704a73254d593 - $cert = 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVwRENDQTR5Z0F3SUJBZ0lKQUp6dThyNnU2ZUJjTUEwR0NTcUdTSWIzRFFFQkJRVUFNSUhETVFzd0NRWUQKVlFRR0V3SkVSVEVjTUJvR0ExVUVDQXdUVG05eVpISm9aV2x1TFZkbGMzUm1ZV3hsYmpFUU1BNEdBMVVFQnd3SApTOE9Ed3Jac2JqRVVNQklHQTFVRUNnd0xVMlZyZEdsdmJrVnBibk14SHpBZEJnTlZCQXNNRmsxaGJHbGphVzkxCmN5QkRaWEowSUZObFkzUnBiMjR4SVRBZkJnTlZCQU1NR0cxaGJHbGphVzkxY3k1elpXdDBhVzl1WldsdWN5NWsKWlRFcU1DZ0dDU3FHU0liM0RRRUpBUlliYzNSbFptRnVMbVZ6YzJWeVFITmxhM1JwYjI1bGFXNXpMbVJsTUhVWQpaREU1TnpBd01UQXhNREF3TURBd1dnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBCkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEKQUFBQUFBQVhEVEUwTVRFeU9ERXhNemt6TlZvd2djTXhDekFKQmdOVkJBWVRBa1JGTVJ3d0dnWURWUVFJREJOTwpiM0prY21obGFXNHRWMlZ6ZEdaaGJHVnVNUkF3RGdZRFZRUUhEQWRMdzRQQ3RteHVNUlF3RWdZRFZRUUtEQXRUClpXdDBhVzl1UldsdWN6RWZNQjBHQTFVRUN3d1dUV0ZzYVdOcGIzVnpJRU5sY25RZ1UyVmpkR2x2YmpFaE1COEcKQTFVRUF3d1liV0ZzYVdOcGIzVnpMbk5sYTNScGIyNWxhVzV6TG1SbE1Tb3dLQVlKS29aSWh2Y05BUWtCRmh0egpkR1ZtWVc0dVpYTnpaWEpBYzJWcmRHbHZibVZwYm5NdVpHVXdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCCkR3QXdnZ0VLQW9JQkFRRERBZjNobDdKWTBYY0ZuaXlFSnBTU0RxbjBPcUJyNlFQNjV1c0pQUnQvOFBhRG9xQnUKd0VZVC9OYSs2ZnNnUGpDMHVLOURaZ1dnMnRIV1dvYW5TYmxBTW96NVBINlorUzRTSFJaN2UyZERJalBqZGhqaAowbUxnMlVNTzV5cDBWNzk3R2dzOWxOdDZKUmZIODFNTjJvYlhXczROdHp0TE11RDZlZ3FwcjhkRGJyMzRhT3M4CnBrZHVpNVVhd1Raa3N5NXBMUEhxNWNNaEZHbTA2djY1Q0xvMFYyUGQ5K0tBb2tQclBjTjVLTEtlYno3bUxwazYKU01lRVhPS1A0aWRFcXh5UTdPN2ZCdUhNZWRzUWh1K3ByWTNzaTNCVXlLZlF0UDVDWm5YMmJwMHdLSHhYMTJEWAoxbmZGSXQ5RGJHdkhUY3lPdU4rblpMUEJtM3ZXeG50eUlJdlZBZ01CQUFHalFqQkFNQWtHQTFVZEV3UUNNQUF3CkVRWUpZSVpJQVliNFFnRUJCQVFEQWdlQU1Bc0dBMVVkRHdRRUF3SUZvREFUQmdOVkhTVUVEREFLQmdnckJnRUYKQlFjREFqQU5CZ2txaGtpRzl3MEJBUVVGQUFPQ0FRRUFHMGZaWVlDVGJkajFYWWMrMVNub2FQUit2SThDOENhRAo4KzBVWWhkbnlVNGdnYTBCQWNEclk5ZTk0ZUVBdTZacXljRjZGakxxWFhkQWJvcHBXb2NyNlQ2R0QxeDMzQ2tsClZBcnpHL0t4UW9oR0QySmVxa2hJTWxEb214SE83a2EzOStPYThpMnZXTFZ5alU4QVp2V01BcnVIYTRFRU55RzcKbFcyQWFnYUZLRkNyOVRuWFRmcmR4R1ZFYnY3S1ZRNmJkaGc1cDVTanBXSDErTXEwM3VSM1pYUEJZZHlWODMxOQpvMGxWajFLRkkyRENML2xpV2lzSlJvb2YrMWNSMzVDdGQwd1lCY3BCNlRac2xNY09QbDc2ZHdLd0pnZUpvMlFnClpzZm1jMnZDMS9xT2xOdU5xLzBUenprVkd2OEVUVDNDZ2FVK1VYZTRYT1Z2a2NjZWJKbjJkZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K'; - $script = <<<'EOT' - -error_reporting(-1); -$info = openssl_x509_parse(base64_decode('%s')); -var_dump(PHP_VERSION, $info['issuer']['emailAddress'], $info['validFrom_time_t']); - -EOT; - $script = '<'."?php\n".sprintf($script, $cert); - - try { - $process = new PhpProcess($script); - $process->mustRun(); - } catch (\Exception $e) { - // In the case of any exceptions just accept it is not possible to - // determine the safety of openssl_x509_parse and bail out. - return self::$useOpensslParse = false; - } - - $output = preg_split('{\r?\n}', trim($process->getOutput())); - $errorOutput = trim($process->getErrorOutput()); - - if ( - is_array($output) - && count($output) === 3 - && $output[0] === sprintf('string(%d) "%s"', strlen(PHP_VERSION), PHP_VERSION) - && $output[1] === 'string(27) "stefan.esser@sektioneins.de"' - && $output[2] === 'int(-1)' - && preg_match('{openssl_x509_parse\(\): illegal (?:ASN1 data type for|length in) timestamp in - on line \d+}', $errorOutput) - ) { - // This PHP has the fix backported probably by a distro security team. - return self::$useOpensslParse = true; - } - - return self::$useOpensslParse = false; + return true; } /** @@ -313,7 +204,6 @@ public static function reset() { self::$caFileValidity = array(); self::$caPath = null; - self::$useOpensslParse = null; } /** @@ -335,19 +225,97 @@ private static function getEnvVariable($name) /** * @param string|false $certFile + * @param LoggerInterface|null $logger * @return bool */ - private static function caFileUsable($certFile, LoggerInterface $logger = null) + private static function caFileUsable($certFile, ?LoggerInterface $logger = null) { - return $certFile && @is_file($certFile) && @is_readable($certFile) && static::validateCaFile($certFile, $logger); + return $certFile + && self::isFile($certFile, $logger) + && self::isReadable($certFile, $logger) + && self::validateCaFile($certFile, $logger); } /** * @param string|false $certDir + * @param LoggerInterface|null $logger + * @return bool + */ + private static function caDirUsable($certDir, ?LoggerInterface $logger = null) + { + return $certDir + && self::isDir($certDir, $logger) + && self::isReadable($certDir, $logger) + && self::glob($certDir . '/*', $logger); + } + + /** + * @param string $certFile + * @param LoggerInterface|null $logger + * @return bool + */ + private static function isFile($certFile, ?LoggerInterface $logger = null) + { + $isFile = @is_file($certFile); + if (!$isFile && $logger) { + $logger->debug(sprintf('Checked CA file %s does not exist or it is not a file.', $certFile)); + } + + return $isFile; + } + + /** + * @param string $certDir + * @param LoggerInterface|null $logger + * @return bool + */ + private static function isDir($certDir, ?LoggerInterface $logger = null) + { + $isDir = @is_dir($certDir); + if (!$isDir && $logger) { + $logger->debug(sprintf('Checked directory %s does not exist or it is not a directory.', $certDir)); + } + + return $isDir; + } + + /** + * @param string $certFileOrDir + * @param LoggerInterface|null $logger * @return bool */ - private static function caDirUsable($certDir) + private static function isReadable($certFileOrDir, ?LoggerInterface $logger = null) { - return $certDir && @is_dir($certDir) && @is_readable($certDir) && glob($certDir . '/*'); + $isReadable = @is_readable($certFileOrDir); + if (!$isReadable && $logger) { + $logger->debug(sprintf('Checked file or directory %s is not readable.', $certFileOrDir)); + } + + return $isReadable; + } + + /** + * @param string $pattern + * @param LoggerInterface|null $logger + * @return bool + */ + private static function glob($pattern, ?LoggerInterface $logger = null) + { + $certs = glob($pattern); + if ($certs === false) { + if ($logger) { + $logger->debug(sprintf("An error occurred while trying to find certificates for pattern: %s", $pattern)); + } + return false; + } + + if (count($certs) === 0) { + if ($logger) { + $logger->debug(sprintf("No CA files found for pattern: %s", $pattern)); + } + return false; + } + + return true; } } diff --git a/includes/vendor/composer/installed.json b/includes/vendor/composer/installed.json index e0b7a2405..a4139f0f5 100644 --- a/includes/vendor/composer/installed.json +++ b/includes/vendor/composer/installed.json @@ -2,28 +2,29 @@ "packages": [ { "name": "aura/sql", - "version": "3.0.0", - "version_normalized": "3.0.0.0", + "version": "6.0.0", + "version_normalized": "6.0.0.0", "source": { "type": "git", "url": "https://github.com/auraphp/Aura.Sql.git", - "reference": "2be02d5dfd9fdee6df199de1a19572aa490bb744" + "reference": "8e2bb362e8953198df3682c9122e8b9edab5ff20" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/auraphp/Aura.Sql/zipball/2be02d5dfd9fdee6df199de1a19572aa490bb744", - "reference": "2be02d5dfd9fdee6df199de1a19572aa490bb744", + "url": "https://api.github.com/repos/auraphp/Aura.Sql/zipball/8e2bb362e8953198df3682c9122e8b9edab5ff20", + "reference": "8e2bb362e8953198df3682c9122e8b9edab5ff20", "shasum": "" }, "require": { - "php": ">=5.6.0", - "psr/log": "^1.0" + "ext-pdo": "*", + "php": "^8.4", + "psr/log": "^1.0 || ^2.0 || ^3.0" }, "require-dev": { "pds/skeleton": "~1.0", - "phpunit/phpunit": "~5.0" + "phpunit/phpunit": "^9.5" }, - "time": "2018-06-11T12:57:42+00:00", + "time": "2025-01-22T06:43:21+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -56,37 +57,37 @@ ], "support": { "issues": "https://github.com/auraphp/Aura.Sql/issues", - "source": "https://github.com/auraphp/Aura.Sql/tree/3.x" + "source": "https://github.com/auraphp/Aura.Sql/tree/6.0.0" }, "install-path": "../aura/sql" }, { "name": "composer/ca-bundle", - "version": "1.2.9", - "version_normalized": "1.2.9.0", + "version": "1.5.5", + "version_normalized": "1.5.5.0", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5" + "reference": "08c50d5ec4c6ced7d0271d2862dec8c1033283e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/78a0e288fdcebf92aa2318a8d3656168da6ac1a5", - "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/08c50d5ec4c6ced7d0271d2862dec8c1033283e6", + "reference": "08c50d5ec4c6ced7d0271d2862dec8c1033283e6", "shasum": "" }, "require": { "ext-openssl": "*", "ext-pcre": "*", - "php": "^5.3.2 || ^7.0 || ^8.0" + "php": "^7.2 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^0.12.55", - "psr/log": "^1.0", - "symfony/phpunit-bridge": "^4.2 || ^5", - "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8 || ^9", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" }, - "time": "2021-01-12T12:10:35+00:00", + "time": "2025-01-08T16:17:16+00:00", "type": "library", "extra": { "branch-alias": { @@ -121,7 +122,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.2.9" + "source": "https://github.com/composer/ca-bundle/tree/1.5.5" }, "funding": [ { @@ -141,31 +142,32 @@ }, { "name": "geoip2/geoip2", - "version": "v2.10.0", - "version_normalized": "2.10.0.0", + "version": "v2.13.0", + "version_normalized": "2.13.0.0", "source": { "type": "git", "url": "https://github.com/maxmind/GeoIP2-php.git", - "reference": "419557cd21d9fe039721a83490701a58c8ce784a" + "reference": "6a41d8fbd6b90052bc34dff3b4252d0f88067b23" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maxmind/GeoIP2-php/zipball/419557cd21d9fe039721a83490701a58c8ce784a", - "reference": "419557cd21d9fe039721a83490701a58c8ce784a", + "url": "https://api.github.com/repos/maxmind/GeoIP2-php/zipball/6a41d8fbd6b90052bc34dff3b4252d0f88067b23", + "reference": "6a41d8fbd6b90052bc34dff3b4252d0f88067b23", "shasum": "" }, "require": { "ext-json": "*", - "maxmind-db/reader": "~1.5", - "maxmind/web-service-common": "~0.6", - "php": ">=5.6" + "maxmind-db/reader": "~1.8", + "maxmind/web-service-common": "~0.8", + "php": ">=7.2" }, "require-dev": { - "friendsofphp/php-cs-fixer": "2.*", - "phpunit/phpunit": "5.*", + "friendsofphp/php-cs-fixer": "3.*", + "phpstan/phpstan": "*", + "phpunit/phpunit": "^8.0 || ^9.0", "squizlabs/php_codesniffer": "3.*" }, - "time": "2019-12-12T18:48:39+00:00", + "time": "2022-08-05T20:32:58+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -193,6 +195,10 @@ "geolocation", "maxmind" ], + "support": { + "issues": "https://github.com/maxmind/GeoIP2-php/issues", + "source": "https://github.com/maxmind/GeoIP2-php/tree/v2.13.0" + }, "install-path": "../geoip2/geoip2" }, { @@ -229,33 +235,36 @@ } ], "description": "Provides functionality for http_build_url() to environments without pecl_http.", + "support": { + "issues": "https://github.com/jakeasmith/http_build_url/issues", + "source": "https://github.com/jakeasmith/http_build_url" + }, "install-path": "../jakeasmith/http_build_url" }, { "name": "maxmind-db/reader", - "version": "v1.9.0", - "version_normalized": "1.9.0.0", + "version": "v1.12.0", + "version_normalized": "1.12.0.0", "source": { "type": "git", "url": "https://github.com/maxmind/MaxMind-DB-Reader-php.git", - "reference": "9ee9ba9ee287b119e9f5a8e8dbfea0b49647cec4" + "reference": "5b2d7a721dedfaef9dc20822c5fe7d26f9f8eb90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/9ee9ba9ee287b119e9f5a8e8dbfea0b49647cec4", - "reference": "9ee9ba9ee287b119e9f5a8e8dbfea0b49647cec4", + "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/5b2d7a721dedfaef9dc20822c5fe7d26f9f8eb90", + "reference": "5b2d7a721dedfaef9dc20822c5fe7d26f9f8eb90", "shasum": "" }, "require": { "php": ">=7.2" }, "conflict": { - "ext-maxminddb": "<1.9.0,>=2.0.0" + "ext-maxminddb": "<1.11.1 || >=2.0.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "*", - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpcov": ">=6.0.0", + "friendsofphp/php-cs-fixer": "3.*", + "phpstan/phpstan": "*", "phpunit/phpunit": ">=8.0.0,<10.0.0", "squizlabs/php_codesniffer": "3.*" }, @@ -264,7 +273,7 @@ "ext-gmp": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder", "ext-maxminddb": "A C-based database decoder that provides significantly faster lookups" }, - "time": "2021-01-07T21:15:29+00:00", + "time": "2024-11-14T22:43:47+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -294,37 +303,38 @@ ], "support": { "issues": "https://github.com/maxmind/MaxMind-DB-Reader-php/issues", - "source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.9.0" + "source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.12.0" }, "install-path": "../maxmind-db/reader" }, { "name": "maxmind/web-service-common", - "version": "v0.8.1", - "version_normalized": "0.8.1.0", + "version": "v0.10.0", + "version_normalized": "0.10.0.0", "source": { "type": "git", "url": "https://github.com/maxmind/web-service-common-php.git", - "reference": "32f274051c543fc865e5a84d3a2c703913641ea8" + "reference": "d7c7c42fc31bff26e0ded73a6e187bcfb193f9c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maxmind/web-service-common-php/zipball/32f274051c543fc865e5a84d3a2c703913641ea8", - "reference": "32f274051c543fc865e5a84d3a2c703913641ea8", + "url": "https://api.github.com/repos/maxmind/web-service-common-php/zipball/d7c7c42fc31bff26e0ded73a6e187bcfb193f9c4", + "reference": "d7c7c42fc31bff26e0ded73a6e187bcfb193f9c4", "shasum": "" }, "require": { "composer/ca-bundle": "^1.0.3", "ext-curl": "*", "ext-json": "*", - "php": ">=7.2" + "php": ">=8.1" }, "require-dev": { - "friendsofphp/php-cs-fixer": "2.*", + "friendsofphp/php-cs-fixer": "3.*", + "phpstan/phpstan": "*", "phpunit/phpunit": "^8.0 || ^9.0", "squizlabs/php_codesniffer": "3.*" }, - "time": "2020-11-02T17:00:53+00:00", + "time": "2024-11-14T23:14:52+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -347,29 +357,29 @@ "homepage": "https://github.com/maxmind/web-service-common-php", "support": { "issues": "https://github.com/maxmind/web-service-common-php/issues", - "source": "https://github.com/maxmind/web-service-common-php/tree/v0.8.1" + "source": "https://github.com/maxmind/web-service-common-php/tree/v0.10.0" }, "install-path": "../maxmind/web-service-common" }, { "name": "ozh/bookmarkletgen", - "version": "1.2", - "version_normalized": "1.2.0.0", + "version": "1.2.2", + "version_normalized": "1.2.2.0", "source": { "type": "git", "url": "https://github.com/ozh/bookmarkletgen.git", - "reference": "3319b53c493a1474a03d1cc4e087617652284c20" + "reference": "65fffa64bb11f70470d398d7baf6d9bb84411cfc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ozh/bookmarkletgen/zipball/3319b53c493a1474a03d1cc4e087617652284c20", - "reference": "3319b53c493a1474a03d1cc4e087617652284c20", + "url": "https://api.github.com/repos/ozh/bookmarkletgen/zipball/65fffa64bb11f70470d398d7baf6d9bb84411cfc", + "reference": "65fffa64bb11f70470d398d7baf6d9bb84411cfc", "shasum": "" }, "require": { - "php": ">=5.3" + "php": ">=7.2" }, - "time": "2017-05-18T12:46:21+00:00", + "time": "2022-05-04T13:05:16+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -393,81 +403,35 @@ "bookmarklet", "javascript" ], - "install-path": "../ozh/bookmarkletgen" - }, - { - "name": "ozh/phpass", - "version": "1.3.0", - "version_normalized": "1.3.0.0", - "source": { - "type": "git", - "url": "https://github.com/ozh/phpass.git", - "reference": "44149d1ee06ccbda397f08f69d32c59802e4ce43" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ozh/phpass/zipball/44149d1ee06ccbda397f08f69d32c59802e4ce43", - "reference": "44149d1ee06ccbda397f08f69d32c59802e4ce43", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "phpunit/phpunit": ">=4.0" - }, - "time": "2020-03-29T10:39:31+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-0": { - "Ozh\\Phpass\\": "src/" - } + "support": { + "issues": "https://github.com/ozh/bookmarkletgen/issues", + "source": "https://github.com/ozh/bookmarkletgen/tree/1.2.2" }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Public Domain" - ], - "authors": [ - { - "name": "Solar Designer", - "email": "solar@openwall.com", - "homepage": "http://openwall.com/phpass/" - } - ], - "description": "Portable PHP password hashing framework", - "homepage": "http://github.com/ozh/phpass/", - "keywords": [ - "blowfish", - "crypt", - "password", - "security" - ], - "install-path": "../ozh/phpass" + "install-path": "../ozh/bookmarkletgen" }, { "name": "pomo/pomo", - "version": "v1.4.1", - "version_normalized": "1.4.1.0", + "version": "v1.5.0", + "version_normalized": "1.5.0.0", "source": { "type": "git", "url": "https://github.com/LeoColomb/pomo.git", - "reference": "1594bd1f90c89a45ffc3da2ee6d5d582bfac7542" + "reference": "b1e53a997850496369634d574fa6b508091fc353" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/LeoColomb/pomo/zipball/1594bd1f90c89a45ffc3da2ee6d5d582bfac7542", - "reference": "1594bd1f90c89a45ffc3da2ee6d5d582bfac7542", + "url": "https://api.github.com/repos/LeoColomb/pomo/zipball/b1e53a997850496369634d574fa6b508091fc353", + "reference": "b1e53a997850496369634d574fa6b508091fc353", "shasum": "" }, "require": { "php": ">=5.3.0" }, "require-dev": { - "phpunit/phpunit": ">=4.0", - "squizlabs/php_codesniffer": "^3.0 || ^2.9.1" + "phpunit/phpunit": "^4.0 || ^7.0", + "squizlabs/php_codesniffer": "^3.0" }, - "time": "2018-12-20T14:55:38+00:00", + "time": "2023-01-06T01:05:43+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -491,7 +455,7 @@ "role": "Maintainer" } ], - "description": "Gettext library to translate with I18n", + "description": "Gettext library to translate with i18n", "homepage": "https://github.com/LeoColomb/pomo", "keywords": [ "gettext", @@ -500,37 +464,51 @@ "localization", "translation" ], + "support": { + "issues": "https://github.com/LeoColomb/pomo/issues", + "source": "https://github.com/LeoColomb/pomo/tree/v1.5.0" + }, + "funding": [ + { + "url": "https://github.com/LeoColomb", + "type": "github" + }, + { + "url": "https://www.patreon.com/LeoColomb", + "type": "patreon" + } + ], "install-path": "../pomo/pomo" }, { "name": "psr/log", - "version": "1.1.3", - "version_normalized": "1.1.3.0", + "version": "3.0.2", + "version_normalized": "3.0.2.0", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", - "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=8.0.0" }, - "time": "2020-03-23T09:12:05+00:00", + "time": "2024-09-11T13:17:53+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "3.x-dev" } }, "installation-source": "dist", "autoload": { "psr-4": { - "Psr\\Log\\": "Psr/Log/" + "Psr\\Log\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -540,7 +518,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for logging libraries", @@ -551,38 +529,59 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/1.1.3" + "source": "https://github.com/php-fig/log/tree/3.0.2" }, "install-path": "../psr/log" }, { "name": "rmccue/requests", - "version": "v1.7.0", - "version_normalized": "1.7.0.0", + "version": "v2.0.15", + "version_normalized": "2.0.15.0", "source": { "type": "git", - "url": "https://github.com/rmccue/Requests.git", - "reference": "87932f52ffad70504d93f04f15690cf16a089546" + "url": "https://github.com/WordPress/Requests.git", + "reference": "877cd66169755899682f1595e057334b40d9d149" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rmccue/Requests/zipball/87932f52ffad70504d93f04f15690cf16a089546", - "reference": "87932f52ffad70504d93f04f15690cf16a089546", + "url": "https://api.github.com/repos/WordPress/Requests/zipball/877cd66169755899682f1595e057334b40d9d149", + "reference": "877cd66169755899682f1595e057334b40d9d149", "shasum": "" }, "require": { - "php": ">=5.2" + "ext-json": "*", + "php": ">=5.6" }, "require-dev": { - "requests/test-server": "dev-master" + "dealerdirect/phpcodesniffer-composer-installer": "^0.7", + "php-parallel-lint/php-console-highlighter": "^0.5.0", + "php-parallel-lint/php-parallel-lint": "^1.3.1", + "phpcompatibility/php-compatibility": "^9.0", + "requests/test-server": "dev-main", + "roave/security-advisories": "dev-latest", + "squizlabs/php_codesniffer": "^3.6", + "wp-coding-standards/wpcs": "^2.0", + "yoast/phpunit-polyfills": "^1.0.0" + }, + "suggest": { + "art4/requests-psr18-adapter": "For using Requests as a PSR-18 HTTP Client", + "ext-curl": "For improved performance", + "ext-openssl": "For secure transport support", + "ext-zlib": "For improved performance when decompressing encoded streams" }, - "time": "2016-10-13T00:11:37+00:00", + "time": "2025-01-21T10:13:31+00:00", "type": "library", "installation-source": "dist", "autoload": { - "psr-0": { - "Requests": "library/" - } + "files": [ + "library/Deprecated.php" + ], + "psr-4": { + "WpOrg\\Requests\\": "src/" + }, + "classmap": [ + "library/Requests.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -591,11 +590,23 @@ "authors": [ { "name": "Ryan McCue", - "homepage": "http://ryanmccue.info" + "homepage": "https://rmccue.io/" + }, + { + "name": "Alain Schlesser", + "homepage": "https://github.com/schlessera" + }, + { + "name": "Juliette Reinders Folmer", + "homepage": "https://github.com/jrfnl" + }, + { + "name": "Contributors", + "homepage": "https://github.com/WordPress/Requests/graphs/contributors" } ], "description": "A HTTP library written in PHP, for human beings.", - "homepage": "http://github.com/rmccue/Requests", + "homepage": "https://requests.ryanmccue.info/", "keywords": [ "curl", "fsockopen", @@ -605,34 +616,44 @@ "iri", "sockets" ], + "support": { + "docs": "https://requests.ryanmccue.info/", + "issues": "https://github.com/WordPress/Requests/issues", + "source": "https://github.com/WordPress/Requests" + }, "install-path": "../rmccue/requests" }, { "name": "spatie/array-to-xml", - "version": "2.15.0", - "version_normalized": "2.15.0.0", + "version": "3.4.4", + "version_normalized": "3.4.4.0", "source": { "type": "git", "url": "https://github.com/spatie/array-to-xml.git", - "reference": "1795afad4e5a1f4b7af2e0e09802550eaa00a6f8" + "reference": "88b2f3852a922dd73177a68938f8eb2ec70c7224" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/1795afad4e5a1f4b7af2e0e09802550eaa00a6f8", - "reference": "1795afad4e5a1f4b7af2e0e09802550eaa00a6f8", + "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/88b2f3852a922dd73177a68938f8eb2ec70c7224", + "reference": "88b2f3852a922dd73177a68938f8eb2ec70c7224", "shasum": "" }, "require": { "ext-dom": "*", - "php": "^7.2" + "php": "^8.0" }, "require-dev": { - "mockery/mockery": "^1.0", - "phpunit/phpunit": "^8.0", - "spatie/phpunit-snapshot-assertions": "^2.0" + "mockery/mockery": "^1.2", + "pestphp/pest": "^1.21", + "spatie/pest-plugin-snapshots": "^1.1" }, - "time": "2020-10-29T18:11:03+00:00", + "time": "2025-12-15T09:00:41+00:00", "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, "installation-source": "dist", "autoload": { "psr-4": { @@ -647,7 +668,7 @@ { "name": "Freek Van der Herten", "email": "freek@spatie.be", - "homepage": "https://murze.be", + "homepage": "https://freek.dev", "role": "Developer" } ], @@ -659,53 +680,58 @@ "xml" ], "support": { - "issues": "https://github.com/spatie/array-to-xml/issues", - "source": "https://github.com/spatie/array-to-xml/tree/2.15.0" + "source": "https://github.com/spatie/array-to-xml/tree/3.4.4" }, + "funding": [ + { + "url": "https://spatie.be/open-source/support-us", + "type": "custom" + }, + { + "url": "https://github.com/spatie", + "type": "github" + } + ], "install-path": "../spatie/array-to-xml" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.22.0", - "version_normalized": "1.22.0.0", + "version": "v1.31.0", + "version_normalized": "1.31.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "0eb8293dbbcd6ef6bf81404c9ce7d95bcdf34f44" + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/0eb8293dbbcd6ef6bf81404c9ce7d95bcdf34f44", - "reference": "0eb8293dbbcd6ef6bf81404c9ce7d95bcdf34f44", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773", + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773", "shasum": "" }, "require": { - "php": ">=7.1", - "symfony/polyfill-intl-normalizer": "^1.10", - "symfony/polyfill-php72": "^1.10" + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" }, "suggest": { "ext-intl": "For best performance" }, - "time": "2021-01-07T16:49:33+00:00", + "time": "2024-09-09T11:45:10+00:00", "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.22-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "installation-source": "dist", "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Idn\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -736,7 +762,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0" }, "funding": [ { @@ -756,44 +782,41 @@ }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.22.0", - "version_normalized": "1.22.0.0", + "version": "v1.31.0", + "version_normalized": "1.31.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "6e971c891537eb617a00bb07a43d182a6915faba" + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/6e971c891537eb617a00bb07a43d182a6915faba", - "reference": "6e971c891537eb617a00bb07a43d182a6915faba", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" }, - "time": "2021-01-07T17:09:11+00:00", + "time": "2024-09-09T11:45:10+00:00", "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.22-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "installation-source": "dist", "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -823,7 +846,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" }, "funding": [ { @@ -843,40 +866,44 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.15.0", - "version_normalized": "1.15.0.0", + "version": "v1.31.0", + "version_normalized": "1.31.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac" + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/81ffd3a9c6d707be22e3012b827de1c9775fc5ac", - "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" }, "suggest": { "ext-mbstring": "For best performance" }, - "time": "2020-03-09T19:04:49+00:00", + "time": "2024-09-09T11:45:10+00:00", "type": "library", "extra": { - "branch-alias": { - "dev-master": "1.15-dev" + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "installation-source": "dist", "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -901,70 +928,8 @@ "portable", "shim" ], - "install-path": "../symfony/polyfill-mbstring" - }, - { - "name": "symfony/polyfill-php72", - "version": "v1.22.0", - "version_normalized": "1.22.0.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", - "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "time": "2021-01-07T16:49:33+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.22-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php72\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" }, "funding": [ { @@ -980,7 +945,7 @@ "type": "tidelift" } ], - "install-path": "../symfony/polyfill-php72" + "install-path": "../symfony/polyfill-mbstring" } ], "dev": true, diff --git a/includes/vendor/composer/installed.php b/includes/vendor/composer/installed.php index a842c7828..c958cb698 100644 --- a/includes/vendor/composer/installed.php +++ b/includes/vendor/composer/installed.php @@ -1,168 +1,149 @@ - - array ( - 'pretty_version' => 'dev-master', - 'version' => 'dev-master', - 'aliases' => - array ( + array( + 'name' => 'yourls/yourls', + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'reference' => 'ddc41ad11a45c6896b8b189f316776924f584ca6', + 'type' => 'project', + 'install_path' => __DIR__ . '/../../../', + 'aliases' => array(), + 'dev' => true, + ), + 'versions' => array( + 'aura/sql' => array( + 'pretty_version' => '6.0.0', + 'version' => '6.0.0.0', + 'reference' => '8e2bb362e8953198df3682c9122e8b9edab5ff20', + 'type' => 'library', + 'install_path' => __DIR__ . '/../aura/sql', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'composer/ca-bundle' => array( + 'pretty_version' => '1.5.5', + 'version' => '1.5.5.0', + 'reference' => '08c50d5ec4c6ced7d0271d2862dec8c1033283e6', + 'type' => 'library', + 'install_path' => __DIR__ . '/./ca-bundle', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'geoip2/geoip2' => array( + 'pretty_version' => 'v2.13.0', + 'version' => '2.13.0.0', + 'reference' => '6a41d8fbd6b90052bc34dff3b4252d0f88067b23', + 'type' => 'library', + 'install_path' => __DIR__ . '/../geoip2/geoip2', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'jakeasmith/http_build_url' => array( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'reference' => '93c273e77cb1edead0cf8bcf8cd2003428e74e37', + 'type' => 'library', + 'install_path' => __DIR__ . '/../jakeasmith/http_build_url', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'maxmind-db/reader' => array( + 'pretty_version' => 'v1.12.0', + 'version' => '1.12.0.0', + 'reference' => '5b2d7a721dedfaef9dc20822c5fe7d26f9f8eb90', + 'type' => 'library', + 'install_path' => __DIR__ . '/../maxmind-db/reader', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'maxmind/web-service-common' => array( + 'pretty_version' => 'v0.10.0', + 'version' => '0.10.0.0', + 'reference' => 'd7c7c42fc31bff26e0ded73a6e187bcfb193f9c4', + 'type' => 'library', + 'install_path' => __DIR__ . '/../maxmind/web-service-common', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ozh/bookmarkletgen' => array( + 'pretty_version' => '1.2.2', + 'version' => '1.2.2.0', + 'reference' => '65fffa64bb11f70470d398d7baf6d9bb84411cfc', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ozh/bookmarkletgen', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'pomo/pomo' => array( + 'pretty_version' => 'v1.5.0', + 'version' => '1.5.0.0', + 'reference' => 'b1e53a997850496369634d574fa6b508091fc353', + 'type' => 'library', + 'install_path' => __DIR__ . '/../pomo/pomo', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/log' => array( + 'pretty_version' => '3.0.2', + 'version' => '3.0.2.0', + 'reference' => 'f16e1d5863e37f8d8c2a01719f5b34baa2b714d3', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/log', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'rmccue/requests' => array( + 'pretty_version' => 'v2.0.15', + 'version' => '2.0.15.0', + 'reference' => '877cd66169755899682f1595e057334b40d9d149', + 'type' => 'library', + 'install_path' => __DIR__ . '/../rmccue/requests', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'spatie/array-to-xml' => array( + 'pretty_version' => '3.4.4', + 'version' => '3.4.4.0', + 'reference' => '88b2f3852a922dd73177a68938f8eb2ec70c7224', + 'type' => 'library', + 'install_path' => __DIR__ . '/../spatie/array-to-xml', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-intl-idn' => array( + 'pretty_version' => 'v1.31.0', + 'version' => '1.31.0.0', + 'reference' => 'c36586dcf89a12315939e00ec9b4474adcb1d773', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-intl-normalizer' => array( + 'pretty_version' => 'v1.31.0', + 'version' => '1.31.0.0', + 'reference' => '3833d7255cc303546435cb650316bff708a1c75c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-mbstring' => array( + 'pretty_version' => 'v1.31.0', + 'version' => '1.31.0.0', + 'reference' => '85181ba99b2345b0ef10ce42ecac37612d9fd341', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'yourls/yourls' => array( + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'reference' => 'ddc41ad11a45c6896b8b189f316776924f584ca6', + 'type' => 'project', + 'install_path' => __DIR__ . '/../../../', + 'aliases' => array(), + 'dev_requirement' => false, + ), ), - 'reference' => 'a3dd5e500abdd264c01f4c8ff026108f093f9769', - 'name' => 'yourls/yourls', - ), - 'versions' => - array ( - 'aura/sql' => - array ( - 'pretty_version' => '3.0.0', - 'version' => '3.0.0.0', - 'aliases' => - array ( - ), - 'reference' => '2be02d5dfd9fdee6df199de1a19572aa490bb744', - ), - 'composer/ca-bundle' => - array ( - 'pretty_version' => '1.2.9', - 'version' => '1.2.9.0', - 'aliases' => - array ( - ), - 'reference' => '78a0e288fdcebf92aa2318a8d3656168da6ac1a5', - ), - 'geoip2/geoip2' => - array ( - 'pretty_version' => 'v2.10.0', - 'version' => '2.10.0.0', - 'aliases' => - array ( - ), - 'reference' => '419557cd21d9fe039721a83490701a58c8ce784a', - ), - 'jakeasmith/http_build_url' => - array ( - 'pretty_version' => '1.0.1', - 'version' => '1.0.1.0', - 'aliases' => - array ( - ), - 'reference' => '93c273e77cb1edead0cf8bcf8cd2003428e74e37', - ), - 'maxmind-db/reader' => - array ( - 'pretty_version' => 'v1.9.0', - 'version' => '1.9.0.0', - 'aliases' => - array ( - ), - 'reference' => '9ee9ba9ee287b119e9f5a8e8dbfea0b49647cec4', - ), - 'maxmind/web-service-common' => - array ( - 'pretty_version' => 'v0.8.1', - 'version' => '0.8.1.0', - 'aliases' => - array ( - ), - 'reference' => '32f274051c543fc865e5a84d3a2c703913641ea8', - ), - 'ozh/bookmarkletgen' => - array ( - 'pretty_version' => '1.2', - 'version' => '1.2.0.0', - 'aliases' => - array ( - ), - 'reference' => '3319b53c493a1474a03d1cc4e087617652284c20', - ), - 'ozh/phpass' => - array ( - 'pretty_version' => '1.3.0', - 'version' => '1.3.0.0', - 'aliases' => - array ( - ), - 'reference' => '44149d1ee06ccbda397f08f69d32c59802e4ce43', - ), - 'pomo/pomo' => - array ( - 'pretty_version' => 'v1.4.1', - 'version' => '1.4.1.0', - 'aliases' => - array ( - ), - 'reference' => '1594bd1f90c89a45ffc3da2ee6d5d582bfac7542', - ), - 'psr/log' => - array ( - 'pretty_version' => '1.1.3', - 'version' => '1.1.3.0', - 'aliases' => - array ( - ), - 'reference' => '0f73288fd15629204f9d42b7055f72dacbe811fc', - ), - 'rmccue/requests' => - array ( - 'pretty_version' => 'v1.7.0', - 'version' => '1.7.0.0', - 'aliases' => - array ( - ), - 'reference' => '87932f52ffad70504d93f04f15690cf16a089546', - ), - 'spatie/array-to-xml' => - array ( - 'pretty_version' => '2.15.0', - 'version' => '2.15.0.0', - 'aliases' => - array ( - ), - 'reference' => '1795afad4e5a1f4b7af2e0e09802550eaa00a6f8', - ), - 'symfony/polyfill-intl-idn' => - array ( - 'pretty_version' => 'v1.22.0', - 'version' => '1.22.0.0', - 'aliases' => - array ( - ), - 'reference' => '0eb8293dbbcd6ef6bf81404c9ce7d95bcdf34f44', - ), - 'symfony/polyfill-intl-normalizer' => - array ( - 'pretty_version' => 'v1.22.0', - 'version' => '1.22.0.0', - 'aliases' => - array ( - ), - 'reference' => '6e971c891537eb617a00bb07a43d182a6915faba', - ), - 'symfony/polyfill-mbstring' => - array ( - 'pretty_version' => 'v1.15.0', - 'version' => '1.15.0.0', - 'aliases' => - array ( - ), - 'reference' => '81ffd3a9c6d707be22e3012b827de1c9775fc5ac', - ), - 'symfony/polyfill-php72' => - array ( - 'pretty_version' => 'v1.22.0', - 'version' => '1.22.0.0', - 'aliases' => - array ( - ), - 'reference' => 'cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9', - ), - 'yourls/yourls' => - array ( - 'pretty_version' => 'dev-master', - 'version' => 'dev-master', - 'aliases' => - array ( - ), - 'reference' => 'a3dd5e500abdd264c01f4c8ff026108f093f9769', - ), - ), ); diff --git a/includes/vendor/composer/platform_check.php b/includes/vendor/composer/platform_check.php deleted file mode 100644 index 589e9e770..000000000 --- a/includes/vendor/composer/platform_check.php +++ /dev/null @@ -1,26 +0,0 @@ -= 70200)) { - $issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.0". You are running ' . PHP_VERSION . '.'; -} - -if ($issues) { - if (!headers_sent()) { - header('HTTP/1.1 500 Internal Server Error'); - } - if (!ini_get('display_errors')) { - if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { - fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); - } elseif (!headers_sent()) { - echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; - } - } - trigger_error( - 'Composer detected issues in your platform: ' . implode(' ', $issues), - E_USER_ERROR - ); -} diff --git a/includes/vendor/geoip2/geoip2/README.md b/includes/vendor/geoip2/geoip2/README.md index e4a74dc10..ea08e27c9 100644 --- a/includes/vendor/geoip2/geoip2/README.md +++ b/includes/vendor/geoip2/geoip2/README.md @@ -2,11 +2,9 @@ ## Description ## -This package provides an API for the GeoIP2 -[web services](https://dev.maxmind.com/geoip/geoip2/web-services) and -[databases](https://dev.maxmind.com/geoip/geoip2/downloadable). The API also -works with the free -[GeoLite2 databases](https://dev.maxmind.com/geoip/geoip2/geolite2/). +This package provides an API for the GeoIP2 and GeoLite2 +[web services](https://dev.maxmind.com/geoip/docs/web-services?lang=en) and +[databases](https://dev.maxmind.com/geoip/docs/databases?lang=en). ## Install via Composer ## @@ -26,7 +24,7 @@ You should now have the file `composer.phar` in your project directory. Run in your project root: -``` +```sh php composer.phar require geoip2/geoip2:~2.0 ``` @@ -260,18 +258,51 @@ print($record->network . "\n"); // '128.101.101.101/32' ``` +## Database Updates ## + +You can keep your databases up to date with our +[GeoIP Update program](https://github.com/maxmind/geoipupdate/releases). +[Learn more about GeoIP Update on our developer +portal.](https://dev.maxmind.com/geoip/updating-databases?lang=en) + +There is also a third-party tool for updating databases using PHP and +Composer. MaxMind does not offer support for this tool or maintain it. +[Learn more about the Geoip2 Update tool for PHP and Composer on its +GitHub page.](https://github.com/tronovav/geoip2-update) + ## Web Service Client ## ### Usage ### To use this API, you must create a new `\GeoIp2\WebService\Client` -object with your `$accountId` and `$licenseKey`, then you call the method -corresponding to a specific end point, passing it the IP address you want to -look up. +object with your `$accountId` and `$licenseKey`: + +```php +$client = new Client(42, 'abcdef123456'); +``` + +You may also call the constructor with additional arguments. The third argument +specifies the language preferences when using the `->name` method on the model +classes that this client creates. The fourth argument is additional options +such as `host` and `timeout`. + +For instance, to call the GeoLite2 web service instead of the GeoIP2 web +service: + +```php +$client = new Client(42, 'abcdef123456', ['en'], ['host' => 'geolite.info']); +``` + +After creating the client, you may now call the method corresponding to a +specific endpoint with the IP address to look up, e.g.: + +```php +$record = $client->city('128.101.101.101'); +``` -If the request succeeds, the method call will return a model class for the end -point you called. This model in turn contains multiple record classes, each of -which represents part of the data returned by the web service. +If the request succeeds, the method call will return a model class for the +endpoint you called. This model in turn contains multiple record classes, each +of which represents part of the data returned by the web service. If there is an error, a structured exception is thrown. @@ -286,7 +317,9 @@ use GeoIp2\WebService\Client; // This creates a Client object that can be reused across requests. // Replace "42" with your account ID and "license_key" with your license -// key. +// key. Set the "host" to "geolite.info" in the fourth argument options +// array to use the GeoLite2 web service instead of the GeoIP2 web +// service. $client = new Client(42, 'abcdef123456'); // Replace "city" with the method corresponding to the web service that @@ -336,7 +369,7 @@ Because of these factors, it is possible for any end point to return a record where some or all of the attributes are unpopulated. See the -[GeoIP2 Precision web service docs](https://dev.maxmind.com/geoip/geoip2/web-services) +[GeoIP2 web service docs](https://dev.maxmind.com/geoip/docs/web-services?lang=en) for details on what data each end point may return. The only piece of data which is always returned is the `ipAddress` @@ -386,7 +419,7 @@ to the client API, please see ## Requirements ## -This library requires PHP 5.6 or greater. +This library requires PHP 7.2 or greater. This library also relies on the [MaxMind DB Reader](https://github.com/maxmind/MaxMind-DB-Reader-php). @@ -404,6 +437,6 @@ The GeoIP2 PHP API uses [Semantic Versioning](https://semver.org/). ## Copyright and License ## -This software is Copyright (c) 2013-2019 by MaxMind, Inc. +This software is Copyright (c) 2013-2020 by MaxMind, Inc. This is free software, licensed under the Apache License, Version 2.0. diff --git a/includes/vendor/geoip2/geoip2/src/Database/Reader.php b/includes/vendor/geoip2/geoip2/src/Database/Reader.php index 813654753..4dabc5d15 100644 --- a/includes/vendor/geoip2/geoip2/src/Database/Reader.php +++ b/includes/vendor/geoip2/geoip2/src/Database/Reader.php @@ -1,8 +1,19 @@ + */ private $locales; /** @@ -48,8 +70,8 @@ class Reader implements ProviderInterface * is corrupt or invalid */ public function __construct( - $filename, - $locales = ['en'] + string $filename, + array $locales = ['en'] ) { $this->dbReader = new DbReader($filename); $this->dbType = $this->dbReader->metadata()->databaseType; @@ -65,12 +87,11 @@ public function __construct( * not in the database * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database * is corrupt or invalid - * - * @return \GeoIp2\Model\City */ - public function city($ipAddress) + public function city(string $ipAddress): City { - return $this->modelFor('City', 'City', $ipAddress); + // @phpstan-ignore-next-line + return $this->modelFor(City::class, 'City', $ipAddress); } /** @@ -82,12 +103,11 @@ public function city($ipAddress) * not in the database * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database * is corrupt or invalid - * - * @return \GeoIp2\Model\Country */ - public function country($ipAddress) + public function country(string $ipAddress): Country { - return $this->modelFor('Country', 'Country', $ipAddress); + // @phpstan-ignore-next-line + return $this->modelFor(Country::class, 'Country', $ipAddress); } /** @@ -99,13 +119,12 @@ public function country($ipAddress) * not in the database * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database * is corrupt or invalid - * - * @return \GeoIp2\Model\AnonymousIp */ - public function anonymousIp($ipAddress) + public function anonymousIp(string $ipAddress): AnonymousIp { + // @phpstan-ignore-next-line return $this->flatModelFor( - 'AnonymousIp', + AnonymousIp::class, 'GeoIP2-Anonymous-IP', $ipAddress ); @@ -120,13 +139,12 @@ public function anonymousIp($ipAddress) * not in the database * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database * is corrupt or invalid - * - * @return \GeoIp2\Model\Asn */ - public function asn($ipAddress) + public function asn(string $ipAddress): Asn { + // @phpstan-ignore-next-line return $this->flatModelFor( - 'Asn', + Asn::class, 'GeoLite2-ASN', $ipAddress ); @@ -141,13 +159,12 @@ public function asn($ipAddress) * not in the database * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database * is corrupt or invalid - * - * @return \GeoIp2\Model\ConnectionType */ - public function connectionType($ipAddress) + public function connectionType(string $ipAddress): ConnectionType { + // @phpstan-ignore-next-line return $this->flatModelFor( - 'ConnectionType', + ConnectionType::class, 'GeoIP2-Connection-Type', $ipAddress ); @@ -162,13 +179,12 @@ public function connectionType($ipAddress) * not in the database * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database * is corrupt or invalid - * - * @return \GeoIp2\Model\Domain */ - public function domain($ipAddress) + public function domain(string $ipAddress): Domain { + // @phpstan-ignore-next-line return $this->flatModelFor( - 'Domain', + Domain::class, 'GeoIP2-Domain', $ipAddress ); @@ -183,12 +199,11 @@ public function domain($ipAddress) * not in the database * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database * is corrupt or invalid - * - * @return \GeoIp2\Model\Enterprise */ - public function enterprise($ipAddress) + public function enterprise(string $ipAddress): Enterprise { - return $this->modelFor('Enterprise', 'Enterprise', $ipAddress); + // @phpstan-ignore-next-line + return $this->modelFor(Enterprise::class, 'Enterprise', $ipAddress); } /** @@ -200,50 +215,47 @@ public function enterprise($ipAddress) * not in the database * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database * is corrupt or invalid - * - * @return \GeoIp2\Model\Isp */ - public function isp($ipAddress) + public function isp(string $ipAddress): Isp { + // @phpstan-ignore-next-line return $this->flatModelFor( - 'Isp', + Isp::class, 'GeoIP2-ISP', $ipAddress ); } - private function modelFor($class, $type, $ipAddress) + private function modelFor(string $class, string $type, string $ipAddress): AbstractModel { - list($record, $prefixLen) = $this->getRecord($class, $type, $ipAddress); + [$record, $prefixLen] = $this->getRecord($class, $type, $ipAddress); $record['traits']['ip_address'] = $ipAddress; $record['traits']['prefix_len'] = $prefixLen; - $class = 'GeoIp2\\Model\\' . $class; - return new $class($record, $this->locales); } - private function flatModelFor($class, $type, $ipAddress) + private function flatModelFor(string $class, string $type, string $ipAddress): AbstractModel { - list($record, $prefixLen) = $this->getRecord($class, $type, $ipAddress); + [$record, $prefixLen] = $this->getRecord($class, $type, $ipAddress); $record['ip_address'] = $ipAddress; $record['prefix_len'] = $prefixLen; - $class = 'GeoIp2\\Model\\' . $class; return new $class($record); } - private function getRecord($class, $type, $ipAddress) + private function getRecord(string $class, string $type, string $ipAddress): array { if (strpos($this->dbType, $type) === false) { - $method = lcfirst($class); + $method = lcfirst((new \ReflectionClass($class))->getShortName()); + throw new \BadMethodCallException( "The $method method cannot be used to open a {$this->dbType} database" ); } - list($record, $prefixLen) = $this->dbReader->getWithPrefixLen($ipAddress); + [$record, $prefixLen] = $this->dbReader->getWithPrefixLen($ipAddress); if ($record === null) { throw new AddressNotFoundException( "The address $ipAddress is not in the database." @@ -272,7 +284,7 @@ private function getRecord($class, $type, $ipAddress) * * @return \MaxMind\Db\Reader\Metadata object for the database */ - public function metadata() + public function metadata(): DbReader\Metadata { return $this->dbReader->metadata(); } @@ -280,7 +292,7 @@ public function metadata() /** * Closes the GeoIP2 database and returns the resources to the system. */ - public function close() + public function close(): void { $this->dbReader->close(); } diff --git a/includes/vendor/geoip2/geoip2/src/Exception/AddressNotFoundException.php b/includes/vendor/geoip2/geoip2/src/Exception/AddressNotFoundException.php index d5483388b..628fb0672 100644 --- a/includes/vendor/geoip2/geoip2/src/Exception/AddressNotFoundException.php +++ b/includes/vendor/geoip2/geoip2/src/Exception/AddressNotFoundException.php @@ -1,5 +1,7 @@ uri = $uri; diff --git a/includes/vendor/geoip2/geoip2/src/Exception/InvalidRequestException.php b/includes/vendor/geoip2/geoip2/src/Exception/InvalidRequestException.php index 6464bcbb1..925b68df0 100644 --- a/includes/vendor/geoip2/geoip2/src/Exception/InvalidRequestException.php +++ b/includes/vendor/geoip2/geoip2/src/Exception/InvalidRequestException.php @@ -1,5 +1,7 @@ error = $error; diff --git a/includes/vendor/geoip2/geoip2/src/Exception/OutOfQueriesException.php b/includes/vendor/geoip2/geoip2/src/Exception/OutOfQueriesException.php index 87a6ade41..9734c8ce4 100644 --- a/includes/vendor/geoip2/geoip2/src/Exception/OutOfQueriesException.php +++ b/includes/vendor/geoip2/geoip2/src/Exception/OutOfQueriesException.php @@ -1,5 +1,7 @@ + */ protected $raw; /** * @ignore - * - * @param mixed $raw */ - public function __construct($raw) + public function __construct(array $raw) { $this->raw = $raw; } @@ -22,9 +25,9 @@ public function __construct($raw) /** * @ignore * - * @param mixed $field + * @return mixed */ - protected function get($field) + protected function get(string $field) { if (isset($this->raw[$field])) { return $this->raw[$field]; @@ -39,12 +42,12 @@ protected function get($field) /** * @ignore * - * @param mixed $attr + * @return mixed */ - public function __get($attr) + public function __get(string $attr) { if ($attr !== 'instance' && property_exists($this, $attr)) { - return $this->$attr; + return $this->{$attr}; } throw new \RuntimeException("Unknown attribute: $attr"); @@ -52,15 +55,13 @@ public function __get($attr) /** * @ignore - * - * @param mixed $attr */ - public function __isset($attr) + public function __isset(string $attr): bool { - return $attr !== 'instance' && isset($this->$attr); + return $attr !== 'instance' && isset($this->{$attr}); } - public function jsonSerialize() + public function jsonSerialize(): array { return $this->raw; } diff --git a/includes/vendor/geoip2/geoip2/src/Model/AnonymousIp.php b/includes/vendor/geoip2/geoip2/src/Model/AnonymousIp.php index a8f946ee8..5586bd00f 100644 --- a/includes/vendor/geoip2/geoip2/src/Model/AnonymousIp.php +++ b/includes/vendor/geoip2/geoip2/src/Model/AnonymousIp.php @@ -1,5 +1,7 @@ isAnonymousVpn = $this->get('is_anonymous_vpn'); $this->isHostingProvider = $this->get('is_hosting_provider'); $this->isPublicProxy = $this->get('is_public_proxy'); + $this->isResidentialProxy = $this->get('is_residential_proxy'); $this->isTorExitNode = $this->get('is_tor_exit_node'); $ipAddress = $this->get('ip_address'); $this->ipAddress = $ipAddress; diff --git a/includes/vendor/geoip2/geoip2/src/Model/Asn.php b/includes/vendor/geoip2/geoip2/src/Model/Asn.php index 8e7c802ee..f05177eb9 100644 --- a/includes/vendor/geoip2/geoip2/src/Model/Asn.php +++ b/includes/vendor/geoip2/geoip2/src/Model/Asn.php @@ -1,5 +1,7 @@ autonomousSystemNumber = $this->get('autonomous_system_number'); diff --git a/includes/vendor/geoip2/geoip2/src/Model/City.php b/includes/vendor/geoip2/geoip2/src/Model/City.php index 3e78c4f14..b2e81dccb 100644 --- a/includes/vendor/geoip2/geoip2/src/Model/City.php +++ b/includes/vendor/geoip2/geoip2/src/Model/City.php @@ -1,13 +1,15 @@ */ protected $subdivisions = []; /** * @ignore - * - * @param mixed $raw - * @param mixed $locales */ - public function __construct($raw, $locales = ['en']) + public function __construct(array $raw, array $locales = ['en']) { parent::__construct($raw, $locales); @@ -63,29 +73,28 @@ public function __construct($raw, $locales = ['en']) $this->createSubdivisions($raw, $locales); } - private function createSubdivisions($raw, $locales) + private function createSubdivisions(array $raw, array $locales): void { if (!isset($raw['subdivisions'])) { return; } foreach ($raw['subdivisions'] as $sub) { - array_push( - $this->subdivisions, + $this->subdivisions[] = new \GeoIp2\Record\Subdivision($sub, $locales) - ); + ; } } /** * @ignore * - * @param mixed $attr + * @return mixed */ - public function __get($attr) + public function __get(string $attr) { if ($attr === 'mostSpecificSubdivision') { - return $this->$attr(); + return $this->{$attr}(); } return parent::__get($attr); @@ -93,10 +102,8 @@ public function __get($attr) /** * @ignore - * - * @param mixed $attr */ - public function __isset($attr) + public function __isset(string $attr): bool { if ($attr === 'mostSpecificSubdivision') { // We always return a mostSpecificSubdivision, even if it is the @@ -107,7 +114,7 @@ public function __isset($attr) return parent::__isset($attr); } - private function mostSpecificSubdivision() + private function mostSpecificSubdivision(): \GeoIp2\Record\Subdivision { return empty($this->subdivisions) ? new \GeoIp2\Record\Subdivision([], $this->locales) : diff --git a/includes/vendor/geoip2/geoip2/src/Model/ConnectionType.php b/includes/vendor/geoip2/geoip2/src/Model/ConnectionType.php index 8091e26ce..36d4529a2 100644 --- a/includes/vendor/geoip2/geoip2/src/Model/ConnectionType.php +++ b/includes/vendor/geoip2/geoip2/src/Model/ConnectionType.php @@ -1,5 +1,7 @@ + */ protected $locales; + + /** + * @var \GeoIp2\Record\MaxMind + */ protected $maxmind; + + /** + * @var \GeoIp2\Record\Country + */ protected $registeredCountry; + + /** + * @var \GeoIp2\Record\RepresentedCountry + */ protected $representedCountry; + + /** + * @var \GeoIp2\Record\Traits + */ protected $traits; /** * @ignore - * - * @param mixed $raw - * @param mixed $locales */ - public function __construct($raw, $locales = ['en']) + public function __construct(array $raw, array $locales = ['en']) { parent::__construct($raw); diff --git a/includes/vendor/geoip2/geoip2/src/Model/Domain.php b/includes/vendor/geoip2/geoip2/src/Model/Domain.php index 5e2cf346d..067a5076e 100644 --- a/includes/vendor/geoip2/geoip2/src/Model/Domain.php +++ b/includes/vendor/geoip2/geoip2/src/Model/Domain.php @@ -1,5 +1,7 @@ autonomousSystemNumber = $this->get('autonomous_system_number'); $this->autonomousSystemOrganization = $this->get('autonomous_system_organization'); $this->isp = $this->get('isp'); + $this->mobileCountryCode = $this->get('mobile_country_code'); + $this->mobileNetworkCode = $this->get('mobile_network_code'); $this->organization = $this->get('organization'); $ipAddress = $this->get('ip_address'); diff --git a/includes/vendor/geoip2/geoip2/src/ProviderInterface.php b/includes/vendor/geoip2/geoip2/src/ProviderInterface.php index 44851b07e..7d1489126 100644 --- a/includes/vendor/geoip2/geoip2/src/ProviderInterface.php +++ b/includes/vendor/geoip2/geoip2/src/ProviderInterface.php @@ -1,5 +1,7 @@ + */ private $locales; /** * @ignore - * - * @param mixed $record - * @param mixed $locales */ - public function __construct($record, $locales = ['en']) + public function __construct(?array $record, array $locales = ['en']) { $this->locales = $locales; parent::__construct($record); @@ -21,9 +23,9 @@ public function __construct($record, $locales = ['en']) /** * @ignore * - * @param mixed $attr + * @return mixed */ - public function __get($attr) + public function __get(string $attr) { if ($attr === 'name') { return $this->name(); @@ -34,26 +36,25 @@ public function __get($attr) /** * @ignore - * - * @param mixed $attr */ - public function __isset($attr) + public function __isset(string $attr): bool { if ($attr === 'name') { - return $this->firstSetNameLocale() === null ? false : true; + return $this->firstSetNameLocale() !== null; } return parent::__isset($attr); } - private function name() + private function name(): ?string { $locale = $this->firstSetNameLocale(); + // @phpstan-ignore-next-line return $locale === null ? null : $this->names[$locale]; } - private function firstSetNameLocale() + private function firstSetNameLocale(): ?string { foreach ($this->locales as $locale) { if (isset($this->names[$locale])) { diff --git a/includes/vendor/geoip2/geoip2/src/Record/AbstractRecord.php b/includes/vendor/geoip2/geoip2/src/Record/AbstractRecord.php index dad2fd3f3..5ddb3c679 100644 --- a/includes/vendor/geoip2/geoip2/src/Record/AbstractRecord.php +++ b/includes/vendor/geoip2/geoip2/src/Record/AbstractRecord.php @@ -1,17 +1,20 @@ + */ private $record; /** * @ignore - * - * @param mixed $record */ - public function __construct($record) + public function __construct(?array $record) { $this->record = isset($record) ? $record : []; } @@ -19,42 +22,45 @@ public function __construct($record) /** * @ignore * - * @param mixed $attr + * @return mixed */ - public function __get($attr) + public function __get(string $attr) { // XXX - kind of ugly but greatly reduces boilerplate code $key = $this->attributeToKey($attr); if ($this->__isset($attr)) { return $this->record[$key]; - } elseif ($this->validAttribute($attr)) { + } + if ($this->validAttribute($attr)) { if (preg_match('/^is_/', $key)) { return false; } return null; } + throw new \RuntimeException("Unknown attribute: $attr"); } - public function __isset($attr) + public function __isset(string $attr): bool { - return $this->validAttribute($attr) && - isset($this->record[$this->attributeToKey($attr)]); + return $this->validAttribute($attr) + && isset($this->record[$this->attributeToKey($attr)]); } - private function attributeToKey($attr) + private function attributeToKey(string $attr): string { return strtolower(preg_replace('/([A-Z])/', '_\1', $attr)); } - private function validAttribute($attr) + private function validAttribute(string $attr): bool { + // @phpstan-ignore-next-line return \in_array($attr, $this->validAttributes, true); } - public function jsonSerialize() + public function jsonSerialize(): ?array { return $this->record; } diff --git a/includes/vendor/geoip2/geoip2/src/Record/City.php b/includes/vendor/geoip2/geoip2/src/Record/City.php index 7f495ad7c..f25dcb389 100644 --- a/includes/vendor/geoip2/geoip2/src/Record/City.php +++ b/includes/vendor/geoip2/geoip2/src/Record/City.php @@ -1,5 +1,7 @@ */ protected $validAttributes = ['confidence', 'geonameId', 'names']; } diff --git a/includes/vendor/geoip2/geoip2/src/Record/Continent.php b/includes/vendor/geoip2/geoip2/src/Record/Continent.php index c6b17056e..103e2e3d8 100644 --- a/includes/vendor/geoip2/geoip2/src/Record/Continent.php +++ b/includes/vendor/geoip2/geoip2/src/Record/Continent.php @@ -1,5 +1,7 @@ */ protected $validAttributes = [ 'code', diff --git a/includes/vendor/geoip2/geoip2/src/Record/Country.php b/includes/vendor/geoip2/geoip2/src/Record/Country.php index ff9ecc7cd..3009ebc62 100644 --- a/includes/vendor/geoip2/geoip2/src/Record/Country.php +++ b/includes/vendor/geoip2/geoip2/src/Record/Country.php @@ -1,5 +1,7 @@ */ protected $validAttributes = [ 'confidence', diff --git a/includes/vendor/geoip2/geoip2/src/Record/Location.php b/includes/vendor/geoip2/geoip2/src/Record/Location.php index b59b3ee70..cb6111c2c 100644 --- a/includes/vendor/geoip2/geoip2/src/Record/Location.php +++ b/includes/vendor/geoip2/geoip2/src/Record/Location.php @@ -1,5 +1,7 @@ */ protected $validAttributes = [ 'averageIncome', diff --git a/includes/vendor/geoip2/geoip2/src/Record/MaxMind.php b/includes/vendor/geoip2/geoip2/src/Record/MaxMind.php index 2e2cc0024..e972506e5 100644 --- a/includes/vendor/geoip2/geoip2/src/Record/MaxMind.php +++ b/includes/vendor/geoip2/geoip2/src/Record/MaxMind.php @@ -1,5 +1,7 @@ */ protected $validAttributes = ['queriesRemaining']; } diff --git a/includes/vendor/geoip2/geoip2/src/Record/Postal.php b/includes/vendor/geoip2/geoip2/src/Record/Postal.php index 69508c782..3e9c2377b 100644 --- a/includes/vendor/geoip2/geoip2/src/Record/Postal.php +++ b/includes/vendor/geoip2/geoip2/src/Record/Postal.php @@ -1,5 +1,7 @@ */ protected $validAttributes = ['code', 'confidence']; } diff --git a/includes/vendor/geoip2/geoip2/src/Record/RepresentedCountry.php b/includes/vendor/geoip2/geoip2/src/Record/RepresentedCountry.php index bc79ee157..727c034af 100644 --- a/includes/vendor/geoip2/geoip2/src/Record/RepresentedCountry.php +++ b/includes/vendor/geoip2/geoip2/src/Record/RepresentedCountry.php @@ -1,5 +1,7 @@ + */ protected $validAttributes = [ 'confidence', 'geonameId', diff --git a/includes/vendor/geoip2/geoip2/src/Record/Subdivision.php b/includes/vendor/geoip2/geoip2/src/Record/Subdivision.php index 74ae3e2ca..0e8354938 100644 --- a/includes/vendor/geoip2/geoip2/src/Record/Subdivision.php +++ b/includes/vendor/geoip2/geoip2/src/Record/Subdivision.php @@ -1,5 +1,7 @@ */ protected $validAttributes = [ 'confidence', diff --git a/includes/vendor/geoip2/geoip2/src/Record/Traits.php b/includes/vendor/geoip2/geoip2/src/Record/Traits.php index e6b798f41..8000d5042 100644 --- a/includes/vendor/geoip2/geoip2/src/Record/Traits.php +++ b/includes/vendor/geoip2/geoip2/src/Record/Traits.php @@ -1,5 +1,7 @@ The user type associated with the IP * address. This can be one of the following values:

*
    @@ -85,6 +97,7 @@ *
  • cafe *
  • cellular *
  • college + *
  • consumer_privacy_network *
  • content_delivery_network *
  • dialup *
  • government @@ -106,6 +119,8 @@ class Traits extends AbstractRecord { /** * @ignore + * + * @var array */ protected $validAttributes = [ 'autonomousSystemNumber', @@ -120,8 +135,11 @@ class Traits extends AbstractRecord 'isLegitimateProxy', 'isp', 'isPublicProxy', + 'isResidentialProxy', 'isSatelliteProvider', 'isTorExitNode', + 'mobileCountryCode', + 'mobileNetworkCode', 'network', 'organization', 'staticIpScore', @@ -129,9 +147,9 @@ class Traits extends AbstractRecord 'userType', ]; - public function __construct($record) + public function __construct(?array $record) { - if (!isset($record['network']) && isset($record['ip_address']) && isset($record['prefix_len'])) { + if (!isset($record['network']) && isset($record['ip_address'], $record['prefix_len'])) { $record['network'] = Util::cidr($record['ip_address'], $record['prefix_len']); } diff --git a/includes/vendor/geoip2/geoip2/src/Util.php b/includes/vendor/geoip2/geoip2/src/Util.php index c158fb551..e0a03be8c 100644 --- a/includes/vendor/geoip2/geoip2/src/Util.php +++ b/includes/vendor/geoip2/geoip2/src/Util.php @@ -1,5 +1,7 @@ + */ private $locales; + + /** + * @var WsClient + */ private $client; + + /** + * @var string + */ private static $basePath = '/geoip/v2.1'; - const VERSION = 'v2.10.0'; + public const VERSION = 'v2.13.0'; /** * Constructor. @@ -57,7 +73,10 @@ class Client implements ProviderInterface * @param array $locales list of locale codes to use in name property * from most preferred to least preferred * @param array $options array of options. Valid options include: - * * `host` - The host to use when querying the web service. + * * `host` - The host to use when querying the web + * service. To query the GeoLite2 web service + * instead of the GeoIP2 web service, set the + * host to `geolite.info`. * * `timeout` - Timeout in seconds. * * `connectTimeout` - Initial connection timeout in seconds. * * `proxy` - The HTTP proxy to use. May include a schema, port, @@ -65,15 +84,16 @@ class Client implements ProviderInterface * `http://username:password@127.0.0.1:10`. */ public function __construct( - $accountId, - $licenseKey, - $locales = ['en'], - $options = [] + int $accountId, + string $licenseKey, + array $locales = ['en'], + array $options = [] ) { $this->locales = $locales; // This is for backwards compatibility. Do not remove except for a // major version bump. + // @phpstan-ignore-next-line if (\is_string($options)) { $options = ['host' => $options]; } @@ -87,13 +107,13 @@ public function __construct( $this->client = new WsClient($accountId, $licenseKey, $options); } - private function userAgent() + private function userAgent(): string { return 'GeoIP2-API/' . self::VERSION; } /** - * This method calls the GeoIP2 Precision: City service. + * This method calls the City Plus service. * * @param string $ipAddress IPv4 or IPv6 address as a string. If no * address is provided, the address that the web service is called @@ -108,23 +128,22 @@ private function userAgent() * @throws \GeoIp2\Exception\InvalidRequestException} if your request was received by the web service but is * invalid for some other reason. This may indicate an issue * with this API. Please report the error to MaxMind. - * @throws \GeoIp2\Exception\HttpException if an unexpected HTTP error code or message was returned. - * This could indicate a problem with the connection between - * your server and the web service or that the web service - * returned an invalid document or 500 error code - * @throws \GeoIp2\Exception\GeoIp2Exception This serves as the parent - * class to the above exceptions. It will be thrown directly - * if a 200 status code is returned but the body is invalid. - * - * @return \GeoIp2\Model\City + * @throws \GeoIp2\Exception\HttpException if an unexpected HTTP error code or message was returned. + * This could indicate a problem with the connection between + * your server and the web service or that the web service + * returned an invalid document or 500 error code + * @throws \GeoIp2\Exception\GeoIp2Exception This serves as the parent + * class to the above exceptions. It will be thrown directly + * if a 200 status code is returned but the body is invalid. */ - public function city($ipAddress = 'me') + public function city(string $ipAddress = 'me'): City { - return $this->responseFor('city', 'City', $ipAddress); + // @phpstan-ignore-next-line + return $this->responseFor('city', City::class, $ipAddress); } /** - * This method calls the GeoIP2 Precision: Country service. + * This method calls the Country service. * * @param string $ipAddress IPv4 or IPv6 address as a string. If no * address is provided, the address that the web service is called @@ -138,24 +157,23 @@ public function city($ipAddress = 'me') * @throws \GeoIp2\Exception\InvalidRequestException} if your request was received by the web service but is * invalid for some other reason. This may indicate an * issue with this API. Please report the error to MaxMind. - * @throws \GeoIp2\Exception\HttpException if an unexpected HTTP error - * code or message was returned. This could indicate a problem - * with the connection between your server and the web service - * or that the web service returned an invalid document or 500 - * error code. - * @throws \GeoIp2\Exception\GeoIp2Exception This serves as the parent class to the above exceptions. It - * will be thrown directly if a 200 status code is returned but - * the body is invalid. - * - * @return \GeoIp2\Model\Country + * @throws \GeoIp2\Exception\HttpException if an unexpected HTTP error + * code or message was returned. This could indicate a problem + * with the connection between your server and the web service + * or that the web service returned an invalid document or 500 + * error code. + * @throws \GeoIp2\Exception\GeoIp2Exception This serves as the parent class to the above exceptions. It + * will be thrown directly if a 200 status code is returned but + * the body is invalid. */ - public function country($ipAddress = 'me') + public function country(string $ipAddress = 'me'): Country { - return $this->responseFor('country', 'Country', $ipAddress); + return $this->responseFor('country', Country::class, $ipAddress); } /** - * This method calls the GeoIP2 Precision: Insights service. + * This method calls the Insights service. Insights is only supported by + * the GeoIP2 web service. The GeoLite2 web service does not support it. * * @param string $ipAddress IPv4 or IPv6 address as a string. If no * address is provided, the address that the web service is called @@ -170,27 +188,27 @@ public function country($ipAddress = 'me') * @throws \GeoIp2\Exception\InvalidRequestException} if your request was received by the web service but is * invalid for some other reason. This may indicate an * issue with this API. Please report the error to MaxMind. - * @throws \GeoIp2\Exception\HttpException if an unexpected HTTP error code or message was returned. - * This could indicate a problem with the connection between - * your server and the web service or that the web service - * returned an invalid document or 500 error code - * @throws \GeoIp2\Exception\GeoIp2Exception This serves as the parent - * class to the above exceptions. It will be thrown directly - * if a 200 status code is returned but the body is invalid. - * - * @return \GeoIp2\Model\Insights + * @throws \GeoIp2\Exception\HttpException if an unexpected HTTP error code or message was returned. + * This could indicate a problem with the connection between + * your server and the web service or that the web service + * returned an invalid document or 500 error code + * @throws \GeoIp2\Exception\GeoIp2Exception This serves as the parent + * class to the above exceptions. It will be thrown directly + * if a 200 status code is returned but the body is invalid. */ - public function insights($ipAddress = 'me') + public function insights(string $ipAddress = 'me'): Insights { - return $this->responseFor('insights', 'Insights', $ipAddress); + // @phpstan-ignore-next-line + return $this->responseFor('insights', Insights::class, $ipAddress); } - private function responseFor($endpoint, $class, $ipAddress) + private function responseFor(string $endpoint, string $class, string $ipAddress): Country { $path = implode('/', [self::$basePath, $endpoint, $ipAddress]); try { - $body = $this->client->get('GeoIP2 ' . $class, $path); + $service = (new \ReflectionClass($class))->getShortName(); + $body = $this->client->get('GeoIP2 ' . $service, $path); } catch (\MaxMind\Exception\IpAddressNotFoundException $ex) { throw new AddressNotFoundException( $ex->getMessage(), @@ -232,8 +250,6 @@ private function responseFor($endpoint, $class, $ipAddress) ); } - $class = 'GeoIp2\\Model\\' . $class; - return new $class($body, $this->locales); } } diff --git a/includes/vendor/maxmind-db/reader/README.md b/includes/vendor/maxmind-db/reader/README.md index 30ae94930..afefc3fd1 100644 --- a/includes/vendor/maxmind-db/reader/README.md +++ b/includes/vendor/maxmind-db/reader/README.md @@ -112,9 +112,16 @@ you are using an autoloader, no changes to your code should be necessary. First install [libmaxminddb](https://github.com/maxmind/libmaxminddb) as described in its [README.md -file](https://github.com/maxmind/libmaxminddb/blob/master/README.md#installing-from-a-tarball). -After successfully installing libmaxmindb, run the following commands from the -top-level directory of this distribution: +file](https://github.com/maxmind/libmaxminddb/blob/main/README.md#installing-from-a-tarball). +After successfully installing libmaxmindb, you may install the extension +from [pecl](https://pecl.php.net/package/maxminddb): + +``` +pecl install maxminddb +``` + +Alternatively, you may install it from the source. To do so, run the following +commands from the top-level directory of this distribution: ``` cd ext @@ -125,7 +132,7 @@ make test sudo make install ``` -You then must load your extension. The recommend method is to add the +You then must load your extension. The recommended method is to add the following to your `php.ini` file: ``` @@ -173,6 +180,6 @@ The MaxMind DB Reader PHP API uses [Semantic Versioning](https://semver.org/). ## Copyright and License ## -This software is Copyright (c) 2014-2020 by MaxMind, Inc. +This software is Copyright (c) 2014-2024 by MaxMind, Inc. This is free software, licensed under the Apache License, Version 2.0. diff --git a/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader.php b/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader.php index ee444f8f1..12c6b0950 100644 --- a/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader.php +++ b/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader.php @@ -4,15 +4,10 @@ namespace MaxMind\Db; -use ArgumentCountError; -use BadMethodCallException; -use Exception; -use InvalidArgumentException; use MaxMind\Db\Reader\Decoder; use MaxMind\Db\Reader\InvalidDatabaseException; use MaxMind\Db\Reader\Metadata; use MaxMind\Db\Reader\Util; -use UnexpectedValueException; /** * Instances of this class provide a reader for the MaxMind DB format. IP @@ -24,14 +19,17 @@ class Reader * @var int */ private static $DATA_SECTION_SEPARATOR_SIZE = 16; + /** * @var string */ private static $METADATA_START_MARKER = "\xAB\xCD\xEFMaxMind.com"; + /** - * @var int + * @var int<0, max> */ private static $METADATA_START_MARKER_LENGTH = 14; + /** * @var int */ @@ -41,18 +39,22 @@ class Reader * @var Decoder */ private $decoder; + /** * @var resource */ private $fileHandle; + /** * @var int */ private $fileSize; + /** * @var int */ private $ipV4Start; + /** * @var Metadata */ @@ -62,25 +64,31 @@ class Reader * Constructs a Reader for the MaxMind DB format. The file passed to it must * be a valid MaxMind DB file such as a GeoIp2 database file. * - * @param string $database - * the MaxMind DB file to use + * @param string $database the MaxMind DB file to use * - * @throws InvalidArgumentException for invalid database path or unknown arguments + * @throws \InvalidArgumentException for invalid database path or unknown arguments * @throws InvalidDatabaseException - * if the database is invalid or there is an error reading - * from it + * if the database is invalid or there is an error reading + * from it */ public function __construct(string $database) { if (\func_num_args() !== 1) { - throw new ArgumentCountError( - sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args()) + throw new \ArgumentCountError( + \sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args()) + ); + } + + if (is_dir($database)) { + // This matches the error that the C extension throws. + throw new InvalidDatabaseException( + "Error opening database file ($database). Is this a valid MaxMind DB file?" ); } $fileHandle = @fopen($database, 'rb'); if ($fileHandle === false) { - throw new InvalidArgumentException( + throw new \InvalidArgumentException( "The file \"$database\" does not exist or is not readable." ); } @@ -88,7 +96,7 @@ public function __construct(string $database) $fileSize = @filesize($database); if ($fileSize === false) { - throw new UnexpectedValueException( + throw new \UnexpectedValueException( "Error determining the size of \"$database\"." ); } @@ -108,22 +116,21 @@ public function __construct(string $database) /** * Retrieves the record for the IP address. * - * @param string $ipAddress - * the IP address to look up + * @param string $ipAddress the IP address to look up * - * @throws BadMethodCallException if this method is called on a closed database - * @throws InvalidArgumentException if something other than a single IP address is passed to the method + * @throws \BadMethodCallException if this method is called on a closed database + * @throws \InvalidArgumentException if something other than a single IP address is passed to the method * @throws InvalidDatabaseException - * if the database is invalid or there is an error reading - * from it + * if the database is invalid or there is an error reading + * from it * * @return mixed the record for the IP address */ public function get(string $ipAddress) { if (\func_num_args() !== 1) { - throw new ArgumentCountError( - sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args()) + throw new \ArgumentCountError( + \sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args()) ); } [$record] = $this->getWithPrefixLen($ipAddress); @@ -134,28 +141,27 @@ public function get(string $ipAddress) /** * Retrieves the record for the IP address and its associated network prefix length. * - * @param string $ipAddress - * the IP address to look up + * @param string $ipAddress the IP address to look up * - * @throws BadMethodCallException if this method is called on a closed database - * @throws InvalidArgumentException if something other than a single IP address is passed to the method + * @throws \BadMethodCallException if this method is called on a closed database + * @throws \InvalidArgumentException if something other than a single IP address is passed to the method * @throws InvalidDatabaseException - * if the database is invalid or there is an error reading - * from it + * if the database is invalid or there is an error reading + * from it * - * @return array an array where the first element is the record and the - * second the network prefix length for the record + * @return array{0:mixed, 1:int} an array where the first element is the record and the + * second the network prefix length for the record */ public function getWithPrefixLen(string $ipAddress): array { if (\func_num_args() !== 1) { - throw new ArgumentCountError( - sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args()) + throw new \ArgumentCountError( + \sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args()) ); } if (!\is_resource($this->fileHandle)) { - throw new BadMethodCallException( + throw new \BadMethodCallException( 'Attempt to read from a closed MaxMind DB.' ); } @@ -168,16 +174,24 @@ public function getWithPrefixLen(string $ipAddress): array return [$this->resolveDataPointer($pointer), $prefixLen]; } + /** + * @return array{0:int, 1:int} + */ private function findAddressInTree(string $ipAddress): array { $packedAddr = @inet_pton($ipAddress); if ($packedAddr === false) { - throw new InvalidArgumentException( + throw new \InvalidArgumentException( "The value \"$ipAddress\" is not a valid IP address." ); } $rawAddress = unpack('C*', $packedAddr); + if ($rawAddress === false) { + throw new InvalidDatabaseException( + 'Could not unpack the unsigned char of the packed in_addr representation.' + ); + } $bitCount = \count($rawAddress) * 8; @@ -194,7 +208,7 @@ private function findAddressInTree(string $ipAddress): array $node = $this->ipV4Start; } } elseif ($metadata->ipVersion === 4 && $bitCount === 128) { - throw new InvalidArgumentException( + throw new \InvalidArgumentException( "Error looking up $ipAddress. You attempted to look up an" . ' IPv6 address in an IPv4-only database.' ); @@ -211,10 +225,12 @@ private function findAddressInTree(string $ipAddress): array if ($node === $nodeCount) { // Record is empty return [0, $i]; - } elseif ($node > $nodeCount) { + } + if ($node > $nodeCount) { // Record is a data pointer return [$node, $i]; } + throw new InvalidDatabaseException( 'Invalid or corrupt database. Maximum search depth reached without finding a leaf node' ); @@ -243,9 +259,16 @@ private function readNode(int $nodeNumber, int $index): int switch ($this->metadata->recordSize) { case 24: $bytes = Util::read($this->fileHandle, $baseOffset + $index * 3, 3); - [, $node] = unpack('N', "\x00" . $bytes); + $rc = unpack('N', "\x00" . $bytes); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack the unsigned long of the node.' + ); + } + [, $node] = $rc; return $node; + case 28: $bytes = Util::read($this->fileHandle, $baseOffset + 3 * $index, 4); if ($index === 0) { @@ -253,14 +276,28 @@ private function readNode(int $nodeNumber, int $index): int } else { $middle = 0x0F & \ord($bytes[0]); } - [, $node] = unpack('N', \chr($middle) . substr($bytes, $index, 3)); + $rc = unpack('N', \chr($middle) . substr($bytes, $index, 3)); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack the unsigned long of the node.' + ); + } + [, $node] = $rc; return $node; + case 32: $bytes = Util::read($this->fileHandle, $baseOffset + $index * 4, 4); - [, $node] = unpack('N', $bytes); + $rc = unpack('N', $bytes); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack the unsigned long of the node.' + ); + } + [, $node] = $rc; return $node; + default: throw new InvalidDatabaseException( 'Unknown record size: ' @@ -296,6 +333,11 @@ private function findMetadataStart(string $filename): int { $handle = $this->fileHandle; $fstat = fstat($handle); + if ($fstat === false) { + throw new InvalidDatabaseException( + "Error getting file information ($filename)." + ); + } $fileSize = $fstat['size']; $marker = self::$METADATA_START_MARKER; $markerLength = self::$METADATA_START_MARKER_LENGTH; @@ -312,6 +354,7 @@ private function findMetadataStart(string $filename): int return $offset + $markerLength; } } + throw new InvalidDatabaseException( "Error opening database file ($filename). " . 'Is this a valid MaxMind DB file?' @@ -319,23 +362,23 @@ private function findMetadataStart(string $filename): int } /** - * @throws InvalidArgumentException if arguments are passed to the method - * @throws BadMethodCallException if the database has been closed + * @throws \InvalidArgumentException if arguments are passed to the method + * @throws \BadMethodCallException if the database has been closed * * @return Metadata object for the database */ public function metadata(): Metadata { if (\func_num_args()) { - throw new ArgumentCountError( - sprintf('%s() expects exactly 0 parameters, %d given', __METHOD__, \func_num_args()) + throw new \ArgumentCountError( + \sprintf('%s() expects exactly 0 parameters, %d given', __METHOD__, \func_num_args()) ); } // Not technically required, but this makes it consistent with // C extension and it allows us to change our implementation later. if (!\is_resource($this->fileHandle)) { - throw new BadMethodCallException( + throw new \BadMethodCallException( 'Attempt to read from a closed MaxMind DB.' ); } @@ -346,19 +389,19 @@ public function metadata(): Metadata /** * Closes the MaxMind DB and returns resources to the system. * - * @throws Exception - * if an I/O error occurs + * @throws \Exception + * if an I/O error occurs */ public function close(): void { if (\func_num_args()) { - throw new ArgumentCountError( - sprintf('%s() expects exactly 0 parameters, %d given', __METHOD__, \func_num_args()) + throw new \ArgumentCountError( + \sprintf('%s() expects exactly 0 parameters, %d given', __METHOD__, \func_num_args()) ); } if (!\is_resource($this->fileHandle)) { - throw new BadMethodCallException( + throw new \BadMethodCallException( 'Attempt to close a closed MaxMind DB.' ); } diff --git a/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php b/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php index 9816befa6..1bb673167 100644 --- a/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php +++ b/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php @@ -5,14 +5,6 @@ namespace MaxMind\Db\Reader; // @codingStandardsIgnoreLine -use RuntimeException; - -/** - * @ignore - * - * We subtract 1 from the log to protect against precision loss. - */ -\define(__NAMESPACE__ . '\_MM_MAX_INT_BYTES', (log(PHP_INT_MAX, 2) - 1) / 8); class Decoder { @@ -20,20 +12,19 @@ class Decoder * @var resource */ private $fileStream; + /** * @var int */ private $pointerBase; - /** - * @var float - */ - private $pointerBaseByteSize; + /** * This is only used for unit testing. * * @var bool */ private $pointerTestHack; + /** * @var bool */ @@ -51,8 +42,8 @@ class Decoder private const _UINT64 = 9; private const _UINT128 = 10; private const _ARRAY = 11; - private const _CONTAINER = 12; - private const _END_MARKER = 13; + // 12 is the container type + // 13 is the end marker type private const _BOOLEAN = 14; private const _FLOAT = 15; @@ -67,12 +58,14 @@ public function __construct( $this->fileStream = $fileStream; $this->pointerBase = $pointerBase; - $this->pointerBaseByteSize = $pointerBase > 0 ? log($pointerBase, 2) / 8 : 0; $this->pointerTestHack = $pointerTestHack; $this->switchByteOrder = $this->isPlatformLittleEndian(); } + /** + * @return array + */ public function decode(int $offset): array { $ctrlByte = \ord(Util::read($this->fileStream, $offset, 1)); @@ -118,38 +111,51 @@ public function decode(int $offset): array return $this->decodeByType($type, $offset, $size); } + /** + * @param int<0, max> $size + * + * @return array{0:mixed, 1:int} + */ private function decodeByType(int $type, int $offset, int $size): array { switch ($type) { case self::_MAP: return $this->decodeMap($size, $offset); + case self::_ARRAY: return $this->decodeArray($size, $offset); + case self::_BOOLEAN: return [$this->decodeBoolean($size), $offset]; } $newOffset = $offset + $size; $bytes = Util::read($this->fileStream, $offset, $size); + switch ($type) { case self::_BYTES: case self::_UTF8_STRING: return [$bytes, $newOffset]; + case self::_DOUBLE: $this->verifySize(8, $size); return [$this->decodeDouble($bytes), $newOffset]; + case self::_FLOAT: $this->verifySize(4, $size); return [$this->decodeFloat($bytes), $newOffset]; + case self::_INT32: return [$this->decodeInt32($bytes, $size), $newOffset]; + case self::_UINT16: case self::_UINT32: case self::_UINT64: case self::_UINT128: return [$this->decodeUint($bytes, $size), $newOffset]; + default: throw new InvalidDatabaseException( 'Unknown or unexpected type: ' . $type @@ -166,6 +172,9 @@ private function verifySize(int $expected, int $actual): void } } + /** + * @return array{0:array, 1:int} + */ private function decodeArray(int $size, int $offset): array { $array = []; @@ -187,7 +196,13 @@ private function decodeDouble(string $bytes): float { // This assumes IEEE 754 doubles, but most (all?) modern platforms // use them. - [, $double] = unpack('E', $bytes); + $rc = unpack('E', $bytes); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack a double value from the given bytes.' + ); + } + [, $double] = $rc; return $double; } @@ -196,7 +211,13 @@ private function decodeFloat(string $bytes): float { // This assumes IEEE 754 floats, but most (all?) modern platforms // use them. - [, $float] = unpack('G', $bytes); + $rc = unpack('G', $bytes); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack a float value from the given bytes.' + ); + } + [, $float] = $rc; return $float; } @@ -206,24 +227,37 @@ private function decodeInt32(string $bytes, int $size): int switch ($size) { case 0: return 0; + case 1: case 2: case 3: - $bytes = str_pad($bytes, 4, "\x00", STR_PAD_LEFT); + $bytes = str_pad($bytes, 4, "\x00", \STR_PAD_LEFT); + break; + case 4: break; + default: throw new InvalidDatabaseException( "The MaxMind DB file's data section contains bad data (unknown data type or corrupt data)" ); } - [, $int] = unpack('l', $this->maybeSwitchByteOrder($bytes)); + $rc = unpack('l', $this->maybeSwitchByteOrder($bytes)); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack a 32bit integer value from the given bytes.' + ); + } + [, $int] = $rc; return $int; } + /** + * @return array{0:array, 1:int} + */ private function decodeMap(int $size, int $offset): array { $map = []; @@ -237,51 +271,76 @@ private function decodeMap(int $size, int $offset): array return [$map, $offset]; } + /** + * @return array{0:int, 1:int} + */ private function decodePointer(int $ctrlByte, int $offset): array { $pointerSize = (($ctrlByte >> 3) & 0x3) + 1; $buffer = Util::read($this->fileStream, $offset, $pointerSize); - $offset = $offset + $pointerSize; + $offset += $pointerSize; switch ($pointerSize) { case 1: $packed = \chr($ctrlByte & 0x7) . $buffer; - [, $pointer] = unpack('n', $packed); + $rc = unpack('n', $packed); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack an unsigned short value from the given bytes (pointerSize is 1).' + ); + } + [, $pointer] = $rc; $pointer += $this->pointerBase; + break; + case 2: $packed = "\x00" . \chr($ctrlByte & 0x7) . $buffer; - [, $pointer] = unpack('N', $packed); + $rc = unpack('N', $packed); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack an unsigned long value from the given bytes (pointerSize is 2).' + ); + } + [, $pointer] = $rc; $pointer += $this->pointerBase + 2048; + break; + case 3: $packed = \chr($ctrlByte & 0x7) . $buffer; // It is safe to use 'N' here, even on 32 bit machines as the // first bit is 0. - [, $pointer] = unpack('N', $packed); + $rc = unpack('N', $packed); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack an unsigned long value from the given bytes (pointerSize is 3).' + ); + } + [, $pointer] = $rc; $pointer += $this->pointerBase + 526336; + break; + case 4: // We cannot use unpack here as we might overflow on 32 bit // machines $pointerOffset = $this->decodeUint($buffer, $pointerSize); - $byteLength = $pointerSize + $this->pointerBaseByteSize; + $pointerBase = $this->pointerBase; - if ($byteLength <= _MM_MAX_INT_BYTES) { - $pointer = $pointerOffset + $this->pointerBase; - } elseif (\extension_loaded('gmp')) { - $pointer = gmp_strval(gmp_add($pointerOffset, $this->pointerBase)); - } elseif (\extension_loaded('bcmath')) { - $pointer = bcadd($pointerOffset, (string) $this->pointerBase); + if (\PHP_INT_MAX - $pointerBase >= $pointerOffset) { + $pointer = $pointerOffset + $pointerBase; } else { - throw new RuntimeException( - 'The gmp or bcmath extension must be installed to read this database.' + throw new \RuntimeException( + 'The database offset is too large to be represented on your platform.' ); } + break; + default: throw new InvalidDatabaseException( 'Unexpected pointer size ' . $pointerSize @@ -291,37 +350,54 @@ private function decodePointer(int $ctrlByte, int $offset): array return [$pointer, $offset]; } + // @phpstan-ignore-next-line private function decodeUint(string $bytes, int $byteLength) { if ($byteLength === 0) { return 0; } - $integer = 0; + // PHP integers are signed. PHP_INT_SIZE - 1 is the number of + // complete bytes that can be converted to an integer. However, + // we can convert another byte if the leading bit is zero. + $useRealInts = $byteLength <= \PHP_INT_SIZE - 1 + || ($byteLength === \PHP_INT_SIZE && (\ord($bytes[0]) & 0x80) === 0); + if ($useRealInts) { + $integer = 0; + for ($i = 0; $i < $byteLength; ++$i) { + $part = \ord($bytes[$i]); + $integer = ($integer << 8) + $part; + } + + return $integer; + } + + // We only use gmp or bcmath if the final value is too big + $integerAsString = '0'; for ($i = 0; $i < $byteLength; ++$i) { $part = \ord($bytes[$i]); - // We only use gmp or bcmath if the final value is too big - if ($byteLength <= _MM_MAX_INT_BYTES) { - $integer = ($integer << 8) + $part; - } elseif (\extension_loaded('gmp')) { - $integer = gmp_strval(gmp_add(gmp_mul((string) $integer, '256'), $part)); + if (\extension_loaded('gmp')) { + $integerAsString = gmp_strval(gmp_add(gmp_mul($integerAsString, '256'), $part)); } elseif (\extension_loaded('bcmath')) { - $integer = bcadd(bcmul((string) $integer, '256'), (string) $part); + $integerAsString = bcadd(bcmul($integerAsString, '256'), (string) $part); } else { - throw new RuntimeException( + throw new \RuntimeException( 'The gmp or bcmath extension must be installed to read this database.' ); } } - return $integer; + return $integerAsString; } + /** + * @return array{0:int, 1:int} + */ private function sizeFromCtrlByte(int $ctrlByte, int $offset): array { - $size = $ctrlByte & 0x1f; + $size = $ctrlByte & 0x1F; if ($size < 29) { return [$size, $offset]; @@ -333,10 +409,22 @@ private function sizeFromCtrlByte(int $ctrlByte, int $offset): array if ($size === 29) { $size = 29 + \ord($bytes); } elseif ($size === 30) { - [, $adjust] = unpack('n', $bytes); + $rc = unpack('n', $bytes); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack an unsigned short value from the given bytes.' + ); + } + [, $adjust] = $rc; $size = 285 + $adjust; } else { - [, $adjust] = unpack('N', "\x00" . $bytes); + $rc = unpack('N', "\x00" . $bytes); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack an unsigned long value from the given bytes.' + ); + } + [, $adjust] = $rc; $size = $adjust + 65821; } @@ -352,7 +440,13 @@ private function isPlatformLittleEndian(): bool { $testint = 0x00FF; $packed = pack('S', $testint); + $rc = unpack('v', $packed); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack an unsigned short value from the given bytes.' + ); + } - return $testint === current(unpack('v', $packed)); + return $testint === current($rc); } } diff --git a/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php b/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php index 532310703..b1da1ed24 100644 --- a/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php +++ b/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php @@ -4,11 +4,8 @@ namespace MaxMind\Db\Reader; -use Exception; - /** * This class should be thrown when unexpected data is found in the database. */ -class InvalidDatabaseException extends Exception -{ -} +// phpcs:disable +class InvalidDatabaseException extends \Exception {} diff --git a/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php b/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php index 873064b0a..9cade2221 100644 --- a/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php +++ b/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php @@ -4,8 +4,6 @@ namespace MaxMind\Db\Reader; -use ArgumentCountError; - /** * This class provides the metadata for the MaxMind DB file. */ @@ -18,6 +16,7 @@ class Metadata * @var int */ public $binaryFormatMajorVersion; + /** * This is an unsigned 16-bit integer indicating the minor version number * for the database's binary format. @@ -25,6 +24,7 @@ class Metadata * @var int */ public $binaryFormatMinorVersion; + /** * This is an unsigned 64-bit integer that contains the database build * timestamp as a Unix epoch value. @@ -32,6 +32,7 @@ class Metadata * @var int */ public $buildEpoch; + /** * This is a string that indicates the structure of each data record * associated with an IP address. The actual definition of these @@ -40,15 +41,17 @@ class Metadata * @var string */ public $databaseType; + /** * This key will always point to a map (associative array). The keys of * that map will be language codes, and the values will be a description * in that language as a UTF-8 string. May be undefined for some * databases. * - * @var array + * @var array */ public $description; + /** * This is an unsigned 16-bit integer which is always 4 or 6. It indicates * whether the database contains IPv4 or IPv6 address data. @@ -56,18 +59,21 @@ class Metadata * @var int */ public $ipVersion; + /** * An array of strings, each of which is a language code. A given record * may contain data items that have been localized to some or all of * these languages. This may be undefined. * - * @var array + * @var array */ public $languages; + /** * @var int */ public $nodeByteSize; + /** * This is an unsigned 32-bit integer indicating the number of nodes in * the search tree. @@ -75,6 +81,7 @@ class Metadata * @var int */ public $nodeCount; + /** * This is an unsigned 16-bit integer. It indicates the number of bits in a * record in the search tree. Note that each node consists of two records. @@ -82,16 +89,20 @@ class Metadata * @var int */ public $recordSize; + /** * @var int */ public $searchTreeSize; + /** + * @param array $metadata + */ public function __construct(array $metadata) { if (\func_num_args() !== 1) { - throw new ArgumentCountError( - sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args()) + throw new \ArgumentCountError( + \sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args()) ); } diff --git a/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php b/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php index 15e6bc4d4..c2c3212d9 100644 --- a/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php +++ b/includes/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php @@ -7,7 +7,8 @@ class Util { /** - * @param resource $stream + * @param resource $stream + * @param int<0, max> $numberOfBytes */ public static function read($stream, int $offset, int $numberOfBytes): string { @@ -24,6 +25,7 @@ public static function read($stream, int $offset, int $numberOfBytes): string return $value; } } + throw new InvalidDatabaseException( 'The MaxMind DB file contains bad data' ); diff --git a/includes/vendor/maxmind/web-service-common/README.md b/includes/vendor/maxmind/web-service-common/README.md index d987e4936..4344ec601 100644 --- a/includes/vendor/maxmind/web-service-common/README.md +++ b/includes/vendor/maxmind/web-service-common/README.md @@ -5,7 +5,7 @@ shared code between MaxMind's various web service client APIs. ## Requirements ## -The library requires PHP 7.2 or greater. +The library requires PHP 8.1 or greater. There are several other dependencies as defined in the `composer.json` file. @@ -16,10 +16,10 @@ style guidelines. Please include unit tests whenever possible. ## Versioning ## -This API uses [Semantic Versioning](http://semver.org/). +This API uses [Semantic Versioning](https://semver.org/). ## Copyright and License ## -This software is Copyright (c) 2015-2020 by MaxMind, Inc. +This software is Copyright (c) 2015-2024 by MaxMind, Inc. This is free software, licensed under the Apache License, Version 2.0. diff --git a/includes/vendor/maxmind/web-service-common/src/Exception/AuthenticationException.php b/includes/vendor/maxmind/web-service-common/src/Exception/AuthenticationException.php index 5b016ce51..9e045d2ec 100644 --- a/includes/vendor/maxmind/web-service-common/src/Exception/AuthenticationException.php +++ b/includes/vendor/maxmind/web-service-common/src/Exception/AuthenticationException.php @@ -7,6 +7,5 @@ /** * This class represents an error authenticating. */ -class AuthenticationException extends InvalidRequestException -{ -} +// phpcs:disable +class AuthenticationException extends InvalidRequestException {} diff --git a/includes/vendor/maxmind/web-service-common/src/Exception/HttpException.php b/includes/vendor/maxmind/web-service-common/src/Exception/HttpException.php index 318baa81f..904b8582d 100644 --- a/includes/vendor/maxmind/web-service-common/src/Exception/HttpException.php +++ b/includes/vendor/maxmind/web-service-common/src/Exception/HttpException.php @@ -11,6 +11,8 @@ class HttpException extends WebServiceException { /** * The URI queried. + * + * @var string */ private $uri; @@ -24,7 +26,7 @@ public function __construct( string $message, int $httpStatus, string $uri, - \Exception $previous = null + ?\Exception $previous = null ) { $this->uri = $uri; parent::__construct($message, $httpStatus, $previous); diff --git a/includes/vendor/maxmind/web-service-common/src/Exception/InsufficientFundsException.php b/includes/vendor/maxmind/web-service-common/src/Exception/InsufficientFundsException.php index 283145650..a29da89f3 100644 --- a/includes/vendor/maxmind/web-service-common/src/Exception/InsufficientFundsException.php +++ b/includes/vendor/maxmind/web-service-common/src/Exception/InsufficientFundsException.php @@ -7,6 +7,5 @@ /** * Thrown when the account is out of credits. */ -class InsufficientFundsException extends InvalidRequestException -{ -} +// phpcs:disable +class InsufficientFundsException extends InvalidRequestException {} diff --git a/includes/vendor/maxmind/web-service-common/src/Exception/InvalidInputException.php b/includes/vendor/maxmind/web-service-common/src/Exception/InvalidInputException.php index 0d3c51c23..e7b7a7df7 100644 --- a/includes/vendor/maxmind/web-service-common/src/Exception/InvalidInputException.php +++ b/includes/vendor/maxmind/web-service-common/src/Exception/InvalidInputException.php @@ -9,6 +9,5 @@ * web service. For example, if the array cannot be encoded as JSON or if there * is a missing or invalid field. */ -class InvalidInputException extends WebServiceException -{ -} +// phpcs:disable +class InvalidInputException extends WebServiceException {} diff --git a/includes/vendor/maxmind/web-service-common/src/Exception/InvalidRequestException.php b/includes/vendor/maxmind/web-service-common/src/Exception/InvalidRequestException.php index dd8e5eb3b..aaee45167 100644 --- a/includes/vendor/maxmind/web-service-common/src/Exception/InvalidRequestException.php +++ b/includes/vendor/maxmind/web-service-common/src/Exception/InvalidRequestException.php @@ -11,6 +11,8 @@ class InvalidRequestException extends HttpException { /** * The code returned by the MaxMind web service. + * + * @var string */ private $error; @@ -26,7 +28,7 @@ public function __construct( string $error, int $httpStatus, string $uri, - \Exception $previous = null + ?\Exception $previous = null ) { $this->error = $error; parent::__construct($message, $httpStatus, $uri, $previous); diff --git a/includes/vendor/maxmind/web-service-common/src/Exception/IpAddressNotFoundException.php b/includes/vendor/maxmind/web-service-common/src/Exception/IpAddressNotFoundException.php index 581db488b..b3bf84d59 100644 --- a/includes/vendor/maxmind/web-service-common/src/Exception/IpAddressNotFoundException.php +++ b/includes/vendor/maxmind/web-service-common/src/Exception/IpAddressNotFoundException.php @@ -4,6 +4,5 @@ namespace MaxMind\Exception; -class IpAddressNotFoundException extends InvalidRequestException -{ -} +// phpcs:disable +class IpAddressNotFoundException extends InvalidRequestException {} diff --git a/includes/vendor/maxmind/web-service-common/src/Exception/PermissionRequiredException.php b/includes/vendor/maxmind/web-service-common/src/Exception/PermissionRequiredException.php index facc1f60f..109d35d6e 100644 --- a/includes/vendor/maxmind/web-service-common/src/Exception/PermissionRequiredException.php +++ b/includes/vendor/maxmind/web-service-common/src/Exception/PermissionRequiredException.php @@ -7,6 +7,5 @@ /** * This exception is thrown when the service requires permission to access. */ -class PermissionRequiredException extends InvalidRequestException -{ -} +// phpcs:disable +class PermissionRequiredException extends InvalidRequestException {} diff --git a/includes/vendor/maxmind/web-service-common/src/Exception/WebServiceException.php b/includes/vendor/maxmind/web-service-common/src/Exception/WebServiceException.php index 9489c89f9..12363f4c0 100644 --- a/includes/vendor/maxmind/web-service-common/src/Exception/WebServiceException.php +++ b/includes/vendor/maxmind/web-service-common/src/Exception/WebServiceException.php @@ -7,6 +7,5 @@ /** * This class represents a generic web service error. */ -class WebServiceException extends \Exception -{ -} +// phpcs:disable +class WebServiceException extends \Exception {} diff --git a/includes/vendor/maxmind/web-service-common/src/WebService/Client.php b/includes/vendor/maxmind/web-service-common/src/WebService/Client.php index 4a4ad3abd..185bd4478 100644 --- a/includes/vendor/maxmind/web-service-common/src/WebService/Client.php +++ b/includes/vendor/maxmind/web-service-common/src/WebService/Client.php @@ -24,29 +24,70 @@ */ class Client { - const VERSION = '0.2.0'; + public const VERSION = '0.2.0'; + /** + * @var string|null + */ private $caBundle; + + /** + * @var float|null + */ private $connectTimeout; + + /** + * @var string + */ private $host = 'api.maxmind.com'; + + /** + * @var bool + */ + private $useHttps = true; + + /** + * @var RequestFactory + */ private $httpRequestFactory; + + /** + * @var string + */ private $licenseKey; + + /** + * @var string|null + */ private $proxy; + + /** + * @var float|null + */ private $timeout; + + /** + * @var string + */ private $userAgentPrefix; + + /** + * @var int + */ private $accountId; /** - * @param int $accountId your MaxMind account ID - * @param string $licenseKey your MaxMind license key - * @param array $options an array of options. Possible keys: - * * `host` - The host to use when connecting to the web service. - * * `userAgent` - The prefix of the User-Agent to use in the request. - * * `caBundle` - The bundle of CA root certificates to use in the request. - * * `connectTimeout` - The connect timeout to use for the request. - * * `timeout` - The timeout to use for the request. - * * `proxy` - The HTTP proxy to use. May include a schema, port, - * username, and password, e.g., `http://username:password@127.0.0.1:10`. + * @param int $accountId your MaxMind account ID + * @param string $licenseKey your MaxMind license key + * @param array $options an array of options. Possible keys: + * * `host` - The host to use when connecting to the web service. + * * `useHttps` - Set to false to disable HTTPS. + * * `userAgent` - The prefix of the User-Agent to use in the request. + * * `caBundle` - The bundle of CA root certificates to use in the request. + * * `connectTimeout` - The connect timeout to use for the request. + * * `timeout` - The timeout to use for the request. + * * `proxy` - The HTTP proxy to use. May include a schema, port, + * username, and password, e.g., `http://username:password@127.0.0.1:10`. */ public function __construct( int $accountId, @@ -63,6 +104,9 @@ public function __construct( if (isset($options['host'])) { $this->host = $options['host']; } + if (isset($options['useHttps'])) { + $this->useHttps = $options['useHttps']; + } if (isset($options['userAgent'])) { $this->userAgentPrefix = $options['userAgent'] . ' '; } @@ -83,9 +127,9 @@ public function __construct( } /** - * @param string $service name of the service querying - * @param string $path the URI path to use - * @param array $input the data to be posted as JSON + * @param string $service name of the service querying + * @param string $path the URI path to use + * @param array $input the data to be posted as JSON * * @throws InvalidInputException when the request has missing or invalid * data @@ -98,7 +142,7 @@ public function __construct( * @throws WebServiceException when some other error occurs. This also * serves as the base class for the above exceptions. * - * @return array|null The decoded content of a successful response + * @return array|null The decoded content of a successful response */ public function post(string $service, string $path, array $input): ?array { @@ -115,7 +159,7 @@ public function post(string $service, string $path, array $input): ?array ['Content-Type: application/json'] ); - list($statusCode, $contentType, $responseBody) = $request->post($requestBody); + [$statusCode, $contentType, $responseBody] = $request->post($requestBody); return $this->handleResponse( $statusCode, @@ -126,11 +170,16 @@ public function post(string $service, string $path, array $input): ?array ); } + /** + * @return array|null + */ public function get(string $service, string $path): ?array { - $request = $this->createRequest($path); + $request = $this->createRequest( + $path + ); - list($statusCode, $contentType, $responseBody) = $request->get(); + [$statusCode, $contentType, $responseBody] = $request->get(); return $this->handleResponse( $statusCode, @@ -145,11 +194,14 @@ private function userAgent(): string { $curlVersion = curl_version(); - return $this->userAgentPrefix . 'MaxMind-WS-API/' . self::VERSION . ' PHP/' . PHP_VERSION . + return $this->userAgentPrefix . 'MaxMind-WS-API/' . self::VERSION . ' PHP/' . \PHP_VERSION . ' curl/' . $curlVersion['version']; } - private function createRequest(string $path, array $headers = []): \MaxMind\WebService\Http\Request + /** + * @param array $headers + */ + private function createRequest(string $path, array $headers = []): Http\Request { array_push( $headers, @@ -187,7 +239,7 @@ private function createRequest(string $path, array $headers = []): \MaxMind\WebS * @throws WebServiceException when some other error occurs. This also * serves as the base class for the above exceptions * - * @return array|null The decoded content of a successful response + * @return array|null The decoded content of a successful response */ private function handleResponse( int $statusCode, @@ -213,17 +265,23 @@ private function handleResponse( private function jsonErrorDescription(): string { $errno = json_last_error(); + switch ($errno) { - case JSON_ERROR_DEPTH: + case \JSON_ERROR_DEPTH: return 'The maximum stack depth has been exceeded.'; - case JSON_ERROR_STATE_MISMATCH: + + case \JSON_ERROR_STATE_MISMATCH: return 'Invalid or malformed JSON.'; - case JSON_ERROR_CTRL_CHAR: + + case \JSON_ERROR_CTRL_CHAR: return 'Control character error.'; - case JSON_ERROR_SYNTAX: + + case \JSON_ERROR_SYNTAX: return 'Syntax error.'; - case JSON_ERROR_UTF8: + + case \JSON_ERROR_UTF8: return 'Malformed UTF-8 characters.'; + default: return "Other JSON error ($errno)."; } @@ -236,7 +294,7 @@ private function jsonErrorDescription(): string */ private function urlFor(string $path): string { - return 'https://' . $this->host . $path; + return ($this->useHttps ? 'https://' : 'http://') . $this->host . $path; } /** @@ -327,6 +385,7 @@ private function handleWebServiceError( $statusCode, $this->urlFor($path) ); + case 'ACCOUNT_ID_REQUIRED': case 'ACCOUNT_ID_UNKNOWN': case 'AUTHORIZATION_INVALID': @@ -339,6 +398,7 @@ private function handleWebServiceError( $statusCode, $this->urlFor($path) ); + case 'OUT_OF_QUERIES': case 'INSUFFICIENT_FUNDS': throw new InsufficientFundsException( @@ -347,6 +407,7 @@ private function handleWebServiceError( $statusCode, $this->urlFor($path) ); + case 'PERMISSION_REQUIRED': throw new PermissionRequiredException( $message, @@ -354,6 +415,7 @@ private function handleWebServiceError( $statusCode, $this->urlFor($path) ); + default: throw new InvalidRequestException( $message, @@ -407,7 +469,7 @@ private function handleUnexpectedStatus(int $statusCode, string $service, string * included, or is expected and included * but cannot be decoded as JSON * - * @return array|null the decoded request body + * @return array|null the decoded request body */ private function handleSuccess(int $statusCode, ?string $body, string $service): ?array { @@ -443,7 +505,7 @@ private function handleSuccess(int $statusCode, ?string $body, string $service): return $decodedContent; } - private function getCaBundle() + private function getCaBundle(): ?string { $curlVersion = curl_version(); diff --git a/includes/vendor/maxmind/web-service-common/src/WebService/Http/CurlRequest.php b/includes/vendor/maxmind/web-service-common/src/WebService/Http/CurlRequest.php index 14d6bbe95..73b551fbe 100644 --- a/includes/vendor/maxmind/web-service-common/src/WebService/Http/CurlRequest.php +++ b/includes/vendor/maxmind/web-service-common/src/WebService/Http/CurlRequest.php @@ -14,7 +14,7 @@ class CurlRequest implements Request { /** - * @var resource + * @var \CurlHandle */ private $ch; @@ -24,10 +24,13 @@ class CurlRequest implements Request private $url; /** - * @var array + * @var array */ private $options; + /** + * @param array $options + */ public function __construct(string $url, array $options) { $this->url = $url; @@ -37,64 +40,69 @@ public function __construct(string $url, array $options) /** * @throws HttpException + * + * @return array{0:int, 1:string|null, 2:string|null} */ public function post(string $body): array { $curl = $this->createCurl(); - curl_setopt($curl, CURLOPT_POST, true); - curl_setopt($curl, CURLOPT_POSTFIELDS, $body); + curl_setopt($curl, \CURLOPT_POST, true); + curl_setopt($curl, \CURLOPT_POSTFIELDS, $body); return $this->execute($curl); } + /** + * @return array{0:int, 1:string|null, 2:string|null} + */ public function get(): array { $curl = $this->createCurl(); - curl_setopt($curl, CURLOPT_HTTPGET, true); + curl_setopt($curl, \CURLOPT_HTTPGET, true); return $this->execute($curl); } /** - * @return resource + * @return \CurlHandle */ private function createCurl() { curl_reset($this->ch); $opts = []; - $opts[CURLOPT_URL] = $this->url; + $opts[\CURLOPT_URL] = $this->url; if (!empty($this->options['caBundle'])) { - $opts[CURLOPT_CAINFO] = $this->options['caBundle']; + $opts[\CURLOPT_CAINFO] = $this->options['caBundle']; } - $opts[CURLOPT_ENCODING] = ''; - $opts[CURLOPT_SSL_VERIFYHOST] = 2; - $opts[CURLOPT_FOLLOWLOCATION] = false; - $opts[CURLOPT_SSL_VERIFYPEER] = true; - $opts[CURLOPT_RETURNTRANSFER] = true; + $opts[\CURLOPT_ENCODING] = ''; + $opts[\CURLOPT_SSL_VERIFYHOST] = 2; + $opts[\CURLOPT_FOLLOWLOCATION] = false; + $opts[\CURLOPT_SSL_VERIFYPEER] = true; + $opts[\CURLOPT_RETURNTRANSFER] = true; - $opts[CURLOPT_HTTPHEADER] = $this->options['headers']; - $opts[CURLOPT_USERAGENT] = $this->options['userAgent']; - $opts[CURLOPT_PROXY] = $this->options['proxy']; + $opts[\CURLOPT_HTTPHEADER] = $this->options['headers']; + $opts[\CURLOPT_USERAGENT] = $this->options['userAgent']; + $opts[\CURLOPT_PROXY] = $this->options['proxy']; // The defined()s are here as the *_MS opts are not available on older // cURL versions $connectTimeout = $this->options['connectTimeout']; if (\defined('CURLOPT_CONNECTTIMEOUT_MS')) { - $opts[CURLOPT_CONNECTTIMEOUT_MS] = ceil($connectTimeout * 1000); + $opts[\CURLOPT_CONNECTTIMEOUT_MS] = ceil($connectTimeout * 1000); } else { - $opts[CURLOPT_CONNECTTIMEOUT] = ceil($connectTimeout); + $opts[\CURLOPT_CONNECTTIMEOUT] = ceil($connectTimeout); } $timeout = $this->options['timeout']; if (\defined('CURLOPT_TIMEOUT_MS')) { - $opts[CURLOPT_TIMEOUT_MS] = ceil($timeout * 1000); + $opts[\CURLOPT_TIMEOUT_MS] = ceil($timeout * 1000); } else { - $opts[CURLOPT_TIMEOUT] = ceil($timeout); + $opts[\CURLOPT_TIMEOUT] = ceil($timeout); } curl_setopt_array($this->ch, $opts); @@ -103,9 +111,11 @@ private function createCurl() } /** - * @param resource $curl + * @param \CurlHandle $curl * * @throws HttpException + * + * @return array{0:int, 1:string|null, 2:string|null} */ private function execute($curl): array { @@ -120,17 +130,17 @@ private function execute($curl): array ); } - $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); - $contentType = curl_getinfo($curl, CURLINFO_CONTENT_TYPE); + $statusCode = curl_getinfo($curl, \CURLINFO_HTTP_CODE); + $contentType = curl_getinfo($curl, \CURLINFO_CONTENT_TYPE); return [ - $statusCode, - // The PHP docs say "Content-Type: of the requested document. NULL - // indicates server did not send valid Content-Type: header" for - // CURLINFO_CONTENT_TYPE. However, it will return FALSE if no header - // is set. To keep our types simple, we return null in this case. - ($contentType === false ? null : $contentType), - $body, + $statusCode, + // The PHP docs say "Content-Type: of the requested document. NULL + // indicates server did not send valid Content-Type: header" for + // CURLINFO_CONTENT_TYPE. However, it will return FALSE if no header + // is set. To keep our types simple, we return null in this case. + $contentType === false ? null : $contentType, + $body, ]; } } diff --git a/includes/vendor/maxmind/web-service-common/src/WebService/Http/Request.php b/includes/vendor/maxmind/web-service-common/src/WebService/Http/Request.php index 994c46964..9a03e5fac 100644 --- a/includes/vendor/maxmind/web-service-common/src/WebService/Http/Request.php +++ b/includes/vendor/maxmind/web-service-common/src/WebService/Http/Request.php @@ -11,9 +11,18 @@ */ interface Request { + /** + * @param array $options + */ public function __construct(string $url, array $options); + /** + * @return array{0:int, 1:string|null, 2:string|null} + */ public function post(string $body): array; + /** + * @return array{0:int, 1:string|null, 2:string|null} + */ public function get(): array; } diff --git a/includes/vendor/maxmind/web-service-common/src/WebService/Http/RequestFactory.php b/includes/vendor/maxmind/web-service-common/src/WebService/Http/RequestFactory.php index 059f277b3..12b0421f9 100644 --- a/includes/vendor/maxmind/web-service-common/src/WebService/Http/RequestFactory.php +++ b/includes/vendor/maxmind/web-service-common/src/WebService/Http/RequestFactory.php @@ -16,7 +16,7 @@ class RequestFactory * done the connection is kept alive, SSL resumption can be used * etcetera. * - * @var resource + * @var \CurlHandle|null */ private $ch; @@ -27,6 +27,9 @@ public function __destruct() } } + /** + * @return \CurlHandle + */ private function getCurlHandle() { if (empty($this->ch)) { @@ -37,9 +40,9 @@ private function getCurlHandle() } /** - * @return Request + * @param array $options */ - public function request(string $url, array $options) + public function request(string $url, array $options): Request { $options['curlHandle'] = $this->getCurlHandle(); diff --git a/includes/vendor/ozh/bookmarkletgen/README.md b/includes/vendor/ozh/bookmarkletgen/README.md deleted file mode 100644 index e091b3a25..000000000 --- a/includes/vendor/ozh/bookmarkletgen/README.md +++ /dev/null @@ -1,74 +0,0 @@ -# Bookmarklet Gen [![](https://travis-ci.org/ozh/bookmarkletgen.svg?branch=master)](https://travis-ci.org/ozh/bookmarkletgen) - -Convert readable Javascript code into bookmarklet links - -## Features - -- removes comments - -- compresses code by removing extraneous spaces, but not within literal strings. - Example: - ```javascript - function someName( param ) { - alert( "this is a string" ) - } - ``` - will return: - ```javascript - function%20someName(param){alert("this%20is%20a%20string")} - ``` -- encodes what needs to be encoded - -- wraps code into a self invoking function ready for bookmarking - -This is basically a slightly enhanced PHP port of the excellent Bookmarklet Crunchinator: -http://ted.mielczarek.org/code/mozilla/bookmarklet.html - -## Installation - -If you are using Composer, add this requirement to your `composer.json` file and run `composer install`: - - { - "require": { - "ozh/phpass": "1.2.0" - } - } - -Or simply in the command line : `composer install ozh/bookmarkletgen` - -If you're not using composer, download the class file and include it manually. - -## Example - -```php -crunch( $javascript ); - -printf( 'bookmarklet', $link ); -``` - -will print: - -```html -bookmarklet -``` - -## Tests - -This library comes with unit tests to make sure the resulting crunched Javascript is valid code. - -This library requires PHP 5.3. Tests are failing on HHVM because of an external binary issue (`phantomjs`) but things should work anyway on HHVM too. - -## License - -Do whatever the hell you want to do with it - diff --git a/includes/vendor/ozh/phpass/README.md b/includes/vendor/ozh/phpass/README.md deleted file mode 100644 index 89603713f..000000000 --- a/includes/vendor/ozh/phpass/README.md +++ /dev/null @@ -1,55 +0,0 @@ -Openwall Phpass, modernized -=========================== - -[![Build Status](https://secure.travis-ci.org/ozh/phpass.png?branch=master)](http://travis-ci.org/ozh/phpass) - -This is Openwall's [Phpass](http://openwall.com/phpass/), based on the 0.5 release, but modernized slightly: - -- Namespaced -- Composer support (Autoloading) -- Unit Tested - -The modernization has been done by Hautelook, from whom I stole this library to originally repackage it for PHP 5.3 to 7.0 compatibility in a single file and branch (Hautelook's port consisting of two branches, one for PHP 5.3 to 5.5, and another one for 5.6+). - -Current version requires PHP 5.6+ - -## Installation ## - -Add this requirement to your `composer.json` file and run `composer install`: - - { - "require": { - "ozh/phpass": "1.3.0" - } - } - -## Usage ## - -The following example shows how to hash a password (to then store the hash in the database), and how to check whether a provided password is correct (hashes to the same value): - -``` php -HashPassword('secret'); -var_dump($password); - // Will output something like: - // '$2a$08$a6XFLs8SrjClF1szoDDkI.6gtWVb4//QnzUjkxlus83AKCNjuD8Ha' (length=60) - // '$2a$08$Qze1smZ//VAwHJ1t52zklOY/yLwlbKR6Ighf6B7uqGXdYVozTPEdG' (length=60) - // '$2a$08$u2uKfE9igO.Cz0SptWxlXeVi0CQglfl3FdRK3YpbGm1NfF1d.CFPm' (length=60) - -// Decrypt -var_dump( $passwordHasher->CheckPassword('secret', '$2a$08$0RK6Yw6j9kSIXrrEOc3dwuDPQuT78HgR0S3/ghOFDEpOGpOkARoSu') ); - // true -var_dump( $passwordHasher->CheckPassword('secret', '$2a$08$Qze1smZ//VAwHJ1t52zklOY/yLwlbKR6Ighf6B7uqGXdYVozTPEdG') ); - // true -var_dump( $passwordHasher->CheckPassword('secret', '$2a$08$u2uKfE9igO.Cz0SptWxlXeVi0CQglfl3FdRK3YpbGm1NfF1d.CFPm') ); - // true diff --git a/includes/vendor/ozh/phpass/src/Ozh/Phpass/PasswordHash.php b/includes/vendor/ozh/phpass/src/Ozh/Phpass/PasswordHash.php deleted file mode 100644 index 16b03772c..000000000 --- a/includes/vendor/ozh/phpass/src/Ozh/Phpass/PasswordHash.php +++ /dev/null @@ -1,333 +0,0 @@ - in 2004-2006 - * - * Modernized by Hautelook at https://github.com/hautelook/phpass - * - * Slightly repacked by Ozh to extend compatibility from PHP 5.3 to 7+ in a single file - * - * There's absolutely no warranty. - * - * The homepage URL for this framework is: - * - * http://www.openwall.com/phpass/ - * - * Please be sure to update the Version line if you edit this file in any way. - * It is suggested that you leave the main version number intact, but indicate - * your project name (after the slash) and add your own revision information. - * - * Please do not change the "private" password hashing method implemented in - * here, thereby making your hashes incompatible. However, if you must, please - * change the hash type identifier (the "$P$") to something different. - * - * Obviously, since this code is in the public domain, the above are not - * requirements (there can be none), but merely suggestions. - * - * @author Solar Designer - */ -class PasswordHash -{ - private $itoa64; - private $iteration_count_log2; - private $portable_hashes; - private $random_state; - - /** - * Constructor - * - * @param int $iteration_count_log2 - * @param boolean $portable_hashes - */ - public function __construct($iteration_count_log2, $portable_hashes) - { - $this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; - - if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31) { - $iteration_count_log2 = 8; - } - $this->iteration_count_log2 = $iteration_count_log2; - - $this->portable_hashes = $portable_hashes; - - $this->random_state = microtime(); - if (function_exists('getmypid')) { - $this->random_state .= getmypid(); - } - } - - /** - * @param int $count - * @return String - */ - public function get_random_bytes($count) - { - $output = ''; - - // PHP 7+ - if (is_callable('random_bytes')) { - return random_bytes($count); - } - - if (@is_readable('/dev/urandom') && - ($fh = @fopen('/dev/urandom', 'rb'))) { - $output = fread($fh, $count); - fclose($fh); - } - - if (strlen($output) < $count) { - $output = ''; - for ($i = 0; $i < $count; $i += 16) { - $this->random_state = - md5(microtime() . $this->random_state); - $output .= md5($this->random_state, TRUE); - } - $output = substr($output, 0, $count); - } - - return $output; - } - - /** - * @param String $input - * @param int $count - * @return String - */ - public function encode64($input, $count) - { - $output = ''; - $i = 0; - do { - $value = ord($input[$i++]); - $output .= $this->itoa64[$value & 0x3f]; - if ($i < $count) { - $value |= ord($input[$i]) << 8; - } - $output .= $this->itoa64[($value >> 6) & 0x3f]; - if ($i++ >= $count) { - break; - } - if ($i < $count) { - $value |= ord($input[$i]) << 16; - } - $output .= $this->itoa64[($value >> 12) & 0x3f]; - if ($i++ >= $count) { - break; - } - $output .= $this->itoa64[($value >> 18) & 0x3f]; - } while ($i < $count); - - return $output; - } - - /** - * @param String $input - * @return String - */ - public function gensalt_private($input) - { - $output = '$P$'; - $output .= $this->itoa64[min($this->iteration_count_log2 + - ((PHP_VERSION >= '5') ? 5 : 3), 30)]; - $output .= $this->encode64($input, 6); - - return $output; - } - - /** - * @param String $password - * @param String $setting - * @return String - */ - public function crypt_private($password, $setting) - { - $output = '*0'; - if (substr($setting, 0, 2) === $output) { - $output = '*1'; - } - - $id = substr($setting, 0, 3); - # We use "$P$", phpBB3 uses "$H$" for the same thing - if ($id !== '$P$' && $id !== '$H$') { - return $output; - } - - $count_log2 = strpos($this->itoa64, $setting[3]); - if ($count_log2 < 7 || $count_log2 > 30) { - return $output; - } - - $count = 1 << $count_log2; - - $salt = substr($setting, 4, 8); - if (strlen($salt) != 8) { - return $output; - } - - // We're kind of forced to use MD5 here since it's the only - // cryptographic primitive available in all versions of PHP - // currently in use. To implement our own low-level crypto - // in PHP would result in much worse performance and - // consequently in lower iteration counts and hashes that are - // quicker to crack (by non-PHP code). - $hash = md5($salt . $password, TRUE); - do { - $hash = md5($hash . $password, TRUE); - } while (--$count); - - $output = substr($setting, 0, 12); - $output .= $this->encode64($hash, 16); - - return $output; - } - - /** - * @param String $input - * @return String - */ - public function gensalt_blowfish($input) - { - // This one needs to use a different order of characters and a - // different encoding scheme from the one in encode64() above. - // We care because the last character in our encoded string will - // only represent 2 bits. While two known implementations of - // bcrypt will happily accept and correct a salt string which - // has the 4 unused bits set to non-zero, we do not want to take - // chances and we also do not want to waste an additional byte - // of entropy. - $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - - $output = '$2a$'; - $output .= chr(ord('0') + $this->iteration_count_log2 / 10); - $output .= chr(ord('0') + $this->iteration_count_log2 % 10); - $output .= '$'; - - $i = 0; - do { - $c1 = ord($input[$i++]); - $output .= $itoa64[$c1 >> 2]; - $c1 = ($c1 & 0x03) << 4; - if ($i >= 16) { - $output .= $itoa64[$c1]; - break; - } - - $c2 = ord($input[$i++]); - $c1 |= $c2 >> 4; - $output .= $itoa64[$c1]; - $c1 = ($c2 & 0x0f) << 2; - - $c2 = ord($input[$i++]); - $c1 |= $c2 >> 6; - $output .= $itoa64[$c1]; - $output .= $itoa64[$c2 & 0x3f]; - } while (1); - - return $output; - } - - /** - * @param String $password - */ - public function HashPassword($password) - { - $random = ''; - - if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) { - $random = $this->get_random_bytes(16); - $hash = - crypt($password, $this->gensalt_blowfish($random)); - if (strlen($hash) == 60) { - return $hash; - } - } - - if (strlen($random) < 6) { - $random = $this->get_random_bytes(6); - } - - $hash = - $this->crypt_private($password, - $this->gensalt_private($random)); - if (strlen($hash) == 34) { - return $hash; - } - - // Returning '*' on error is safe here, but would _not_ be safe - // in a crypt(3)-like function used _both_ for generating new - // hashes and for validating passwords against existing hashes. - return '*'; - } - - /** - * @param String $password - * @param String $stored_hash - * @return boolean - */ - public function CheckPassword($password, $stored_hash) - { - $hash = $this->crypt_private($password, $stored_hash); - if ($hash[0] == '*') { - $hash = crypt($password, $stored_hash); - } - - return hash_equals($stored_hash, $hash); - } -} - - -/** - * hash_equals compatibility function - * - * @package CodeIgniter - * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/) - * @copyright Copyright (c) 2014 - 2017, British Columbia Institute of Technology (http://bcit.ca/) - * @license http://opensource.org/licenses/MIT MIT License - * @link https://codeigniter.com - * - * Source: https://github.com/bcit-ci/CodeIgniter/blob/3.1.4/system/core/compat/hash.php - * For PHP < 5.6 - */ -// @codeCoverageIgnoreStart -if ( ! function_exists('hash_equals')) -{ - /** - * hash_equals() - * - * @link http://php.net/hash_equals - * @param string $known_string - * @param string $user_string - * @return bool - */ - function hash_equals($known_string, $user_string) - { - if ( ! is_string($known_string)) - { - trigger_error('hash_equals(): Expected known_string to be a string, '.strtolower(gettype($known_string)).' given', E_USER_WARNING); - return FALSE; - } - elseif ( ! is_string($user_string)) - { - trigger_error('hash_equals(): Expected user_string to be a string, '.strtolower(gettype($user_string)).' given', E_USER_WARNING); - return FALSE; - } - elseif (($length = strlen($known_string)) !== strlen($user_string)) - { - return FALSE; - } - $diff = 0; - for ($i = 0; $i < $length; $i++) - { - $diff |= ord($known_string[$i]) ^ ord($user_string[$i]); - } - return ($diff === 0); - } -} -// @codeCoverageIgnoreEnd - diff --git a/includes/vendor/pomo/pomo/README.md b/includes/vendor/pomo/pomo/README.md index eb5426466..2ed078655 100644 --- a/includes/vendor/pomo/pomo/README.md +++ b/includes/vendor/pomo/pomo/README.md @@ -1,14 +1,15 @@ -POMO -==== +# POMO + +> Gettext library to translate with i18n + [![Latest Release](https://img.shields.io/packagist/v/pomo/pomo.svg)](https://packagist.org/packages/pomo/pomo) -[![Build Status](https://travis-ci.org/LeoColomb/pomo.svg?branch=master)](https://travis-ci.org/LeoColomb/pomo) -[![Code Climate](https://img.shields.io/codeclimate/github/LeoColomb/pomo.svg)](https://codeclimate.com/github/LeoColomb/pomo) -**Gettext library to translate with I18n**. -[Why use it](http://codex.wordpress.org/I18n_for_WordPress_Developers). +## About + +[Why use it](https://codex.wordpress.org/I18n_for_WordPress_Developers). + +## Usage -Usage ------ ```php import_from_file($the_mo_filepath); $translations->translate($text); ``` -Installation ------------- +## Installation + The easiest way to install POMO is via [composer](http://getcomposer.org/). -Create the following `composer.json` file and run the `php composer.phar install` command to install it. - -```json -{ - "require": { - "pomo/pomo": "*" - } -} + +```console +composer require pomo/pomo ``` ```php is_resource()) { + + if (! $reader->is_resource()) { return false; } @@ -58,18 +64,16 @@ public function import_from_file($filename) /** * @param string $filename - * * @return bool */ public function export_to_file($filename) { $fh = fopen($filename, 'wb'); - if (!$fh) { + if (! $fh) { return false; } $res = $this->export_to_file_handle($fh); fclose($fh); - return $res; } @@ -79,12 +83,11 @@ public function export_to_file($filename) public function export() { $tmp_fh = fopen('php://temp', 'r+'); - if (!$tmp_fh) { + if (! $tmp_fh) { return false; } $this->export_to_file_handle($tmp_fh); rewind($tmp_fh); - return stream_get_contents($tmp_fh); } @@ -99,7 +102,7 @@ public function is_entry_good_for_export(EntryTranslations $entry) return false; } - if (!array_filter($entry->translations)) { + if (! array_filter($entry->translations)) { return false; } @@ -108,69 +111,63 @@ public function is_entry_good_for_export(EntryTranslations $entry) /** * @param resource $fh - * * @return true */ public function export_to_file_handle($fh) { - $entries = array_filter( - $this->entries, - array($this, 'is_entry_good_for_export') - ); + $entries = array_filter($this->entries, array($this, 'is_entry_good_for_export')); ksort($entries); - $magic = 0x950412de; - $revision = 0; - $total = count($entries) + 1; // all the headers are one entry - $originals_lenghts_addr = 28; - $translations_lenghts_addr = $originals_lenghts_addr + 8 * $total; - $size_of_hash = 0; - $hash_addr = $translations_lenghts_addr + 8 * $total; - $current_addr = $hash_addr; - fwrite($fh, pack( - 'V*', - $magic, - $revision, - $total, - $originals_lenghts_addr, - $translations_lenghts_addr, - $size_of_hash, - $hash_addr - )); - fseek($fh, $originals_lenghts_addr); - - // headers' msgid is an empty string + $magic = 0x950412de; + $revision = 0; + $total = count($entries) + 1; // All the headers are one entry. + $originals_lengths_addr = 28; + $translations_lengths_addr = $originals_lengths_addr + 8 * $total; + $size_of_hash = 0; + $hash_addr = $translations_lengths_addr + 8 * $total; + $current_addr = $hash_addr; + fwrite( + $fh, + pack( + 'V*', + $magic, + $revision, + $total, + $originals_lengths_addr, + $translations_lengths_addr, + $size_of_hash, + $hash_addr + ) + ); + fseek($fh, $originals_lengths_addr); + + // Headers' msgid is an empty string. fwrite($fh, pack('VV', 0, $current_addr)); $current_addr++; - $originals_table = chr(0); + $originals_table = "\0"; $reader = new NOOPReader(); foreach ($entries as $entry) { - $originals_table .= $this->export_original($entry).chr(0); - $length = $reader->strlen($this->export_original($entry)); + $originals_table .= $this->export_original($entry) . "\0"; + $length = $reader->strlen($this->export_original($entry)); fwrite($fh, pack('VV', $length, $current_addr)); - $current_addr += $length + 1; // account for the NULL byte after + $current_addr += $length + 1; // Account for the NULL byte after. } $exported_headers = $this->export_headers(); - fwrite($fh, pack( - 'VV', - $reader->strlen($exported_headers), - $current_addr - )); - $current_addr += strlen($exported_headers) + 1; - $translations_table = $exported_headers.chr(0); + fwrite($fh, pack('VV', $reader->strlen($exported_headers), $current_addr)); + $current_addr += strlen($exported_headers) + 1; + $translations_table = $exported_headers . "\0"; foreach ($entries as $entry) { - $translations_table .= $this->export_translations($entry).chr(0); - $length = $reader->strlen($this->export_translations($entry)); + $translations_table .= $this->export_translations($entry) . "\0"; + $length = $reader->strlen($this->export_translations($entry)); fwrite($fh, pack('VV', $length, $current_addr)); $current_addr += $length + 1; } fwrite($fh, $originals_table); fwrite($fh, $translations_table); - return true; } @@ -181,15 +178,14 @@ public function export_to_file_handle($fh) */ public function export_original(EntryTranslations $entry) { - //TODO: warnings for control characters + // TODO: Warnings for control characters. $exported = $entry->singular; if ($entry->is_plural) { - $exported .= chr(0).$entry->plural; + $exported .= "\0" . $entry->plural; } - if (!is_null($entry->context)) { - $exported = $entry->context.chr(4).$exported; + if ($entry->context) { + $exported = $entry->context . "\4" . $exported; } - return $exported; } @@ -200,8 +196,8 @@ public function export_original(EntryTranslations $entry) */ public function export_translations(EntryTranslations $entry) { - //TODO: warnings for control characters - return $entry->is_plural ? implode(chr(0), $entry->translations) : $entry->translations[0]; + // TODO: Warnings for control characters. + return $entry->is_plural ? implode("\0", $entry->translations) : $entry->translations[0]; } /** @@ -213,22 +209,22 @@ public function export_headers() foreach ($this->headers as $header => $value) { $exported .= "$header: $value\n"; } - return $exported; } /** * @param int $magic - * * @return string|false */ public function get_byteorder($magic) { - // The magic is 0x950412de - $magic_little = (int) -1794895138; + // The magic is 0x950412de. + + // bug in PHP 5.0.2, see https://savannah.nongnu.org/bugs/?func=detailitem&item_id=10565 + $magic_little = (int) - 1794895138; $magic_little_64 = (int) 2500072158; // 0xde120495 - $magic_big = ((int) -569244523) & 0xFFFFFFFF; + $magic_big = ((int) - 569244523) & 0xFFFFFFFF; if ($magic_little == $magic || $magic_little_64 == $magic) { return 'little'; } elseif ($magic_big == $magic) { @@ -240,8 +236,7 @@ public function get_byteorder($magic) /** * @param FileReader $reader - * - * @return bool + * @return bool True if the import was successful, otherwise false. */ public function import_from_reader(FileReader $reader) { @@ -251,29 +246,29 @@ public function import_from_reader(FileReader $reader) } $reader->setEndian($endian_string); - $endian = ('big' == $endian_string) ? 'N' : 'V'; + $endian = ('big' === $endian_string) ? 'N' : 'V'; $header = $reader->read(24); if ($reader->strlen($header) != 24) { return false; } - // parse header - $header = unpack("{$endian}revision/{$endian}total/{$endian}originals_lenghts_addr/{$endian}translations_lenghts_addr/{$endian}hash_length/{$endian}hash_addr", $header); - if (!is_array($header)) { + // Parse header. + $header = unpack("{$endian}revision/{$endian}total/{$endian}originals_lengths_addr/{$endian}translations_lengths_addr/{$endian}hash_length/{$endian}hash_addr", $header); + if (! is_array($header)) { return false; } - // support revision 0 of MO format specs, only - if ($header['revision'] != 0) { + // Support revision 0 of MO format specs, only. + if (0 != $header['revision']) { return false; } - // seek to data blocks - $reader->seekto($header['originals_lenghts_addr']); + // Seek to data blocks. + $reader->seekto($header['originals_lengths_addr']); - // read originals' indices - $originals_lengths_length = $header['translations_lenghts_addr'] - $header['originals_lenghts_addr']; + // Read originals' indices. + $originals_lengths_length = $header['translations_lengths_addr'] - $header['originals_lengths_addr']; if ($originals_lengths_length != $header['total'] * 8) { return false; } @@ -283,22 +278,22 @@ public function import_from_reader(FileReader $reader) return false; } - // read translations' indices - $translations_lenghts_length = $header['hash_addr'] - $header['translations_lenghts_addr']; - if ($translations_lenghts_length != $header['total'] * 8) { + // Read translations' indices. + $translations_lengths_length = $header['hash_addr'] - $header['translations_lengths_addr']; + if ($translations_lengths_length != $header['total'] * 8) { return false; } - $translations = $reader->read($translations_lenghts_length); - if ($reader->strlen($translations) != $translations_lenghts_length) { + $translations = $reader->read($translations_lengths_length); + if ($reader->strlen($translations) != $translations_lengths_length) { return false; } - // transform raw data into set of indices - $originals = $reader->str_split($originals, 8); + // Transform raw data into set of indices. + $originals = $reader->str_split($originals, 8); $translations = $reader->str_split($translations, 8); - // skip hash table + // Skip hash table. $strings_addr = $header['hash_addr'] + $header['hash_length'] * 4; $reader->seekto($strings_addr); @@ -307,67 +302,63 @@ public function import_from_reader(FileReader $reader) $reader->close(); for ($i = 0; $i < $header['total']; $i++) { - $o = unpack("{$endian}length/{$endian}pos", $originals[$i]); - $t = unpack("{$endian}length/{$endian}pos", $translations[$i]); - if (!$o || !$t) { + $o = unpack("{$endian}length/{$endian}pos", $originals[ $i ]); + $t = unpack("{$endian}length/{$endian}pos", $translations[ $i ]); + if (! $o || ! $t) { return false; } - // adjust offset due to reading strings to separate space before + // Adjust offset due to reading strings to separate space before. $o['pos'] -= $strings_addr; $t['pos'] -= $strings_addr; - $original = $reader->substr($strings, $o['pos'], $o['length']); + $original = $reader->substr($strings, $o['pos'], $o['length']); $translation = $reader->substr($strings, $t['pos'], $t['length']); if ('' === $original) { $this->set_headers($this->make_headers($translation)); } else { - $entry = &static::make_entry($original, $translation); - $this->entries[$entry->key()] = &$entry; + $entry = &static::make_entry($original, $translation); + $this->entries[ $entry->key() ] = &$entry; } } - return true; } /** - * Build a from original string and translation strings, - * found in a MO file. + * Build a EntryTranslations from original string and translation strings, + * found in a MO file * - * @param string $original original string to translate from MO file. - * Might contain 0x04 as context separator or - * 0x00 as singular/plural separator - * @param string $translation translation string from MO file.Might contain - * 0x00 as a plural translations separator - * - * @return EntryTranslations New entry + * @static + * @param string $original original string to translate from MO file. Might contain + * 0x04 as context separator or 0x00 as singular/plural separator + * @param string $translation translation string from MO file. Might contain + * 0x00 as a plural translations separator + * @return EntryTranslations Entry instance. */ public static function &make_entry($original, $translation) { $entry = new EntryTranslations(); - // look for context - $parts = explode(chr(4), $original); + // Look for context, separated by \4. + $parts = explode("\4", $original); if (isset($parts[1])) { - $original = $parts[1]; + $original = $parts[1]; $entry->context = $parts[0]; } - // look for plural original - $parts = explode(chr(0), $original); + // Look for plural original. + $parts = explode("\0", $original); $entry->singular = $parts[0]; if (isset($parts[1])) { $entry->is_plural = true; - $entry->plural = $parts[1]; + $entry->plural = $parts[1]; } - // plural translations are also separated by \0 - $entry->translations = explode(chr(0), $translation); - + // Plural translations are also separated by \0. + $entry->translations = explode("\0", $translation); return $entry; } /** * @param int $count - * * @return string */ public function select_plural_form($count) diff --git a/includes/vendor/pomo/pomo/src/PO.php b/includes/vendor/pomo/pomo/src/PO.php index 27d7c9737..278e065e0 100644 --- a/includes/vendor/pomo/pomo/src/PO.php +++ b/includes/vendor/pomo/pomo/src/PO.php @@ -1,4 +1,5 @@ comments_before_headers) { - $before_headers = self::prepend_each_line( - rtrim($this->comments_before_headers)."\n", - '# ' - ); + $before_headers = self::prepend_each_line(rtrim($this->comments_before_headers) . "\n", '# '); } else { $before_headers = ''; } - return rtrim("{$before_headers}msgid \"\"\nmsgstr $poified"); } /** - * Exports all entries to PO format. + * Exports all entries to PO format * - * @return string sequence of mgsgid/msgstr PO strings, doesn't containt - * newline at the end + * @return string sequence of mgsgid/msgstr PO strings, doesn't containt newline at the end */ public function export_entries() { - //TODO: sorting - return implode("\n\n", array_map( - array(__NAMESPACE__.'\PO', 'export_entry'), - $this->entries - )); + // TODO: Sorting. + return implode("\n\n", array_map(array(__NAMESPACE__ . '\PO', 'export_entry'), $this->entries)); } /** - * Exports the whole PO file as a string. + * Exports the whole PO file as a string * - * @param bool $include_headers whether to include the headers in the - * export - * - * @return string ready for inclusion in PO file string for headers and all - * the enrtries + * @param bool $include_headers whether to include the headers in the export + * @return string ready for inclusion in PO file string for headers and all the enrtries */ public function export($include_headers = true) { @@ -79,17 +68,14 @@ public function export($include_headers = true) $res .= "\n\n"; } $res .= $this->export_entries(); - return $res; } /** - * Same as {@link export}, but writes the result to a file. - * - * @param string $filename where to write the PO string - * @param bool $include_headers whether to include tje headers in the - * export + * Same as {@link export}, but writes the result to a file * + * @param string $filename Where to write the PO string. + * @param bool $include_headers Whether to include the headers in the export. * @return bool true on success, false on error */ public function export_to_file($filename, $include_headers = true) @@ -99,7 +85,7 @@ public function export_to_file($filename, $include_headers = true) return false; } $export = $this->export($include_headers); - $res = fwrite($fh, $export); + $res = fwrite($fh, $export); if (false === $res) { return false; } @@ -108,12 +94,11 @@ public function export_to_file($filename, $include_headers = true) } /** - * Text to include as a comment before the start of the PO contents. + * Text to include as a comment before the start of the PO contents * - * Doesn't need to include # in the beginning of lines, these are added - * automatically + * Doesn't need to include # in the beginning of lines, these are added automatically * - * @param string $text Comment text + * @param string $text Text to include as a comment. */ public function set_comment_before_headers($text) { @@ -121,120 +106,114 @@ public function set_comment_before_headers($text) } /** - * Formats a string in PO-style. - * - * @param string $string the string to format + * Formats a string in PO-style * + * @param string $input_string the string to format * @return string the poified string */ - public static function poify($string) + public static function poify($input_string) { - $quote = '"'; - $slash = '\\'; + $quote = '"'; + $slash = '\\'; $newline = "\n"; $replaces = array( - "$slash" => "$slash$slash", - "$quote" => "$slash$quote", - "\t" => '\t', + "$slash" => "$slash$slash", + "$quote" => "$slash$quote", + "\t" => '\t', ); - $string = str_replace( - array_keys($replaces), - array_values($replaces), - $string - ); + $input_string = str_replace(array_keys($replaces), array_values($replaces), $input_string); - $po = $quote.implode( - "${slash}n$quote$newline$quote", - explode($newline, $string) - ).$quote; - // add empty string on first line for readbility - if (false !== strpos($string, $newline) && - (substr_count($string, $newline) > 1 || - !($newline === substr($string, -strlen($newline))))) { + $po = $quote . implode("{$slash}n{$quote}{$newline}{$quote}", explode($newline, $input_string)) . $quote; + // Add empty string on first line for readbility. + if ( + false !== strpos($input_string, $newline) && + (substr_count($input_string, $newline) > 1 || substr($input_string, -strlen($newline)) !== $newline) + ) { $po = "$quote$quote$newline$po"; } - // remove empty strings + // Remove empty strings. $po = str_replace("$newline$quote$quote", '', $po); - return $po; } /** - * Gives back the original string from a PO-formatted string. - * - * @param string $string PO-formatted string + * Gives back the original string from a PO-formatted string * + * @param string $input_string PO-formatted string * @return string enascaped string */ - public static function unpoify($string) + public static function unpoify($input_string) { - $escapes = array('t' => "\t", 'n' => "\n", 'r' => "\r", '\\' => '\\'); - $lines = array_map('trim', explode("\n", $string)); - $lines = array_map(array(__NAMESPACE__.'\PO', 'trim_quotes'), $lines); - $unpoified = ''; + $escapes = array( + 't' => "\t", + 'n' => "\n", + 'r' => "\r", + '\\' => '\\', + ); + $lines = array_map('trim', explode("\n", $input_string)); + $lines = array_map(array(__NAMESPACE__ . '\PO', 'trim_quotes'), $lines); + $unpoified = ''; $previous_is_backslash = false; foreach ($lines as $line) { preg_match_all('/./u', $line, $chars); $chars = $chars[0]; foreach ($chars as $char) { - if (!$previous_is_backslash) { - if ('\\' == $char) { + if (! $previous_is_backslash) { + if ('\\' === $char) { $previous_is_backslash = true; } else { $unpoified .= $char; } } else { $previous_is_backslash = false; - $unpoified .= isset($escapes[$char]) ? $escapes[$char] : $char; + $unpoified .= isset($escapes[ $char ]) ? $escapes[ $char ] : $char; } } } - // Standardise the line endings on imported content, technically PO files shouldn't contain \r + // Standardize the line endings on imported content, technically PO files shouldn't contain \r. $unpoified = str_replace(array("\r\n", "\r"), "\n", $unpoified); return $unpoified; } /** - * Inserts $with in the beginning of every new line of $string and - * returns the modified string. + * Inserts $with in the beginning of every new line of $input_string and + * returns the modified string * - * @param string $string prepend lines in this string - * @param string $with prepend lines with this string - * - * @return string The modified string + * @param string $input_string prepend lines in this string + * @param string $with prepend lines with this string */ - public static function prepend_each_line($string, $with) + public static function prepend_each_line($input_string, $with) { - $lines = explode("\n", $string); + $lines = explode("\n", $input_string); $append = ''; - if ("\n" === substr($string, -1) && '' === end($lines)) { - // Last line might be empty because $string was terminated - // with a newline, remove it from the $lines array, - // we'll restore state by re-terminating the string at the end + if ("\n" === substr($input_string, -1) && '' === end($lines)) { + /* + * Last line might be empty because $input_string was terminated + * with a newline, remove it from the $lines array, + * we'll restore state by re-terminating the string at the end. + */ array_pop($lines); $append = "\n"; } foreach ($lines as &$line) { - $line = $with.$line; + $line = $with . $line; } unset($line); - return implode("\n", $lines).$append; + return implode("\n", $lines) . $append; } /** * Prepare a text as a comment -- wraps the lines and prepends # - * and a special character to each line. + * and a special character to each line * * @param string $text the comment text * @param string $char character to denote a special PO comment, - * like :, default is a space - * - * @return string The modified string + * like :, default is a space */ private static function comment_block($text, $char = ' ') { @@ -244,14 +223,11 @@ private static function comment_block($text, $char = ' ') } /** - * Builds a string from the entry for inclusion in PO file. + * Builds a string from the entry for inclusion in PO file * - * @static - * - * @param EntryTranslations &$entry the entry to convert to po string - * - * @return false|string PO-style formatted string for the entry or - * false if the entry is empty + * @param EntryTranslations $entry the entry to convert to po string. + * @return string|false PO-style formatted string for the entry or + * false if the entry is empty */ public static function export_entry(EntryTranslations &$entry) { @@ -259,67 +235,58 @@ public static function export_entry(EntryTranslations &$entry) return false; } $po = array(); - if (!empty($entry->translator_comments)) { + if (! empty($entry->translator_comments)) { $po[] = self::comment_block($entry->translator_comments); } - if (!empty($entry->extracted_comments)) { + if (! empty($entry->extracted_comments)) { $po[] = self::comment_block($entry->extracted_comments, '.'); } - if (!empty($entry->references)) { + if (! empty($entry->references)) { $po[] = self::comment_block(implode(' ', $entry->references), ':'); } - if (!empty($entry->flags)) { + if (! empty($entry->flags)) { $po[] = self::comment_block(implode(', ', $entry->flags), ','); } - if (!is_null($entry->context)) { - $po[] = 'msgctxt '.self::poify($entry->context); + if ($entry->context) { + $po[] = 'msgctxt ' . self::poify($entry->context); } - $po[] = 'msgid '.self::poify($entry->singular); - if (!$entry->is_plural) { - $translation = empty($entry->translations) ? - '' : - $entry->translations[0]; + $po[] = 'msgid ' . self::poify($entry->singular); + if (! $entry->is_plural) { + $translation = empty($entry->translations) ? '' : $entry->translations[0]; $translation = self::match_begin_and_end_newlines($translation, $entry->singular); - $po[] = 'msgstr '.self::poify($translation); + $po[] = 'msgstr ' . self::poify($translation); } else { - $po[] = 'msgid_plural '.self::poify($entry->plural); - $translations = empty($entry->translations) ? - array('', '') : - $entry->translations; + $po[] = 'msgid_plural ' . self::poify($entry->plural); + $translations = empty($entry->translations) ? array( '', '' ) : $entry->translations; foreach ($translations as $i => $translation) { $translation = self::match_begin_and_end_newlines($translation, $entry->plural); - $po[] = "msgstr[$i] ".self::poify($translation); + $po[] = "msgstr[$i] " . self::poify($translation); } } - return implode("\n", $po); } - /** - * @param $translation - * @param $original - * - * @return string - */ public static function match_begin_and_end_newlines($translation, $original) { if ('' === $translation) { return $translation; } - $original_begin = "\n" === substr($original, 0, 1); - $original_end = "\n" === substr($original, -1); + $original_begin = "\n" === substr($original, 0, 1); + $original_end = "\n" === substr($original, -1); $translation_begin = "\n" === substr($translation, 0, 1); - $translation_end = "\n" === substr($translation, -1); + $translation_end = "\n" === substr($translation, -1); + if ($original_begin) { - if (!$translation_begin) { - $translation = "\n".$translation; + if (! $translation_begin) { + $translation = "\n" . $translation; } } elseif ($translation_begin) { $translation = ltrim($translation, "\n"); } + if ($original_end) { - if (!$translation_end) { + if (! $translation_end) { $translation .= "\n"; } } elseif ($translation_end) { @@ -337,20 +304,17 @@ public static function match_begin_and_end_newlines($translation, $original) public function import_from_file($filename) { $f = fopen($filename, 'r'); - if (!$f) { + if (! $f) { return false; } $lineno = 0; - $res = false; while (true) { $res = $this->read_entry($f, $lineno); - if (!$res) { + if (! $res) { break; } - if ($res['entry']->singular == '') { - $this->set_headers( - $this->make_headers($res['entry']->translations[0]) - ); + if ('' === $res['entry']->singular) { + $this->set_headers($this->make_headers($res['entry']->translations[0])); } else { $this->add_entry($res['entry']); } @@ -359,47 +323,44 @@ public function import_from_file($filename) if (false === $res) { return false; } - if (!$this->headers && !$this->entries) { + if (! $this->headers && ! $this->entries) { return false; } - return true; } /** - * Helper function for read_entry. + * Helper function for read_entry * * @param string $context - * * @return bool */ protected static function is_final($context) { - return ($context === 'msgstr') || ($context === 'msgstr_plural'); + return ('msgstr' === $context) || ('msgstr_plural' === $context); } /** * @param resource $f * @param int $lineno - * * @return null|false|array */ public function read_entry($f, $lineno = 0) { $entry = new EntryTranslations(); - // where were we in the last step - // can be: comment, msgctxt, msgid, msgid_plural, msgstr, msgstr_plural - $context = ''; + // Where were we in the last step. + // Can be: comment, msgctxt, msgid, msgid_plural, msgstr, msgstr_plural. + $context = ''; $msgstr_index = 0; while (true) { $lineno++; $line = self::read_line($f); - if (!$line) { + if (! $line) { if (feof($f)) { if (self::is_final($context)) { break; - } elseif (!$context) { // we haven't read a line and eof came - return; + } elseif (! $context) { // We haven't read a line and EOF came. + return null; } else { return false; } @@ -407,23 +368,22 @@ public function read_entry($f, $lineno = 0) return false; } } - if ($line == "\n") { + if ("\n" === $line) { continue; } - $line = trim($line); if (preg_match('/^#/', $line, $m)) { - // the comment is the start of a new entry + // The comment is the start of a new entry. if (self::is_final($context)) { self::read_line($f, 'put-back'); $lineno--; break; } - // comments have to be at the beginning - if ($context && $context != 'comment') { + // Comments have to be at the beginning. + if ($context && 'comment' !== $context) { return false; } - // add comment + // Add comment. $this->add_comment_to_entry($entry, $line); } elseif (preg_match('/^msgctxt\s+(".*")/', $line, $m)) { if (self::is_final($context)) { @@ -431,10 +391,10 @@ public function read_entry($f, $lineno = 0) $lineno--; break; } - if ($context && $context != 'comment') { + if ($context && 'comment' !== $context) { return false; } - $context = 'msgctxt'; + $context = 'msgctxt'; $entry->context .= self::unpoify($m[1]); } elseif (preg_match('/^msgid\s+(".*")/', $line, $m)) { if (self::is_final($context)) { @@ -442,32 +402,30 @@ public function read_entry($f, $lineno = 0) $lineno--; break; } - if ($context && - $context != 'msgctxt' && - $context != 'comment') { + if ($context && 'msgctxt' !== $context && 'comment' !== $context) { return false; } - $context = 'msgid'; + $context = 'msgid'; $entry->singular .= self::unpoify($m[1]); } elseif (preg_match('/^msgid_plural\s+(".*")/', $line, $m)) { - if ($context != 'msgid') { + if ('msgid' !== $context) { return false; } - $context = 'msgid_plural'; + $context = 'msgid_plural'; $entry->is_plural = true; - $entry->plural .= self::unpoify($m[1]); + $entry->plural .= self::unpoify($m[1]); } elseif (preg_match('/^msgstr\s+(".*")/', $line, $m)) { - if ($context != 'msgid') { + if ('msgid' !== $context) { return false; } - $context = 'msgstr'; + $context = 'msgstr'; $entry->translations = array(self::unpoify($m[1])); } elseif (preg_match('/^msgstr\[(\d+)\]\s+(".*")/', $line, $m)) { - if ($context != 'msgid_plural' && $context != 'msgstr_plural') { + if ('msgid_plural' !== $context && 'msgstr_plural' !== $context) { return false; } - $context = 'msgstr_plural'; - $msgstr_index = $m[1]; + $context = 'msgstr_plural'; + $msgstr_index = $m[1]; $entry->translations[$m[1]] = self::unpoify($m[2]); } elseif (preg_match('/^".*"$/', $line)) { $unpoified = self::unpoify($line); @@ -506,36 +464,33 @@ public function read_entry($f, $lineno = 0) $entry->translations = array(); } - return array('entry' => $entry, 'lineno' => $lineno); + return array( + 'entry' => $entry, + 'lineno' => $lineno, + ); } /** * @param resource $f * @param string $action - * * @return bool */ public static function read_line($f, $action = 'read') { - static $last_line = ''; + static $last_line = ''; static $use_last_line = false; - if ('clear' == $action) { + if ('clear' === $action) { $last_line = ''; - return true; } - if ('put-back' == $action) { + if ('put-back' === $action) { $use_last_line = true; - return true; } - $line = $use_last_line ? $last_line : fgets($f); - $line = ("\r\n" == substr($line, -2)) ? - rtrim($line, "\r\n")."\n" : - $line; - $last_line = $line; + $line = $use_last_line ? $last_line : fgets($f); + $line = ("\r\n" === substr($line, -2)) ? rtrim($line, "\r\n") . "\n" : $line; + $last_line = $line; $use_last_line = false; - return $line; } @@ -546,42 +501,30 @@ public static function read_line($f, $action = 'read') public function add_comment_to_entry(EntryTranslations &$entry, $po_comment_line) { $first_two = substr($po_comment_line, 0, 2); - $comment = trim(substr($po_comment_line, 2)); - if ('#:' == $first_two) { - $entry->references = array_merge( - $entry->references, - preg_split('/\s+/', $comment) - ); - } elseif ('#.' == $first_two) { - $entry->extracted_comments = trim( - $entry->extracted_comments."\n".$comment - ); - } elseif ('#,' == $first_two) { - $entry->flags = array_merge( - $entry->flags, - preg_split('/,\s*/', $comment) - ); + $comment = trim(substr($po_comment_line, 2)); + if ('#:' === $first_two) { + $entry->references = array_merge($entry->references, preg_split('/\s+/', $comment)); + } elseif ('#.' === $first_two) { + $entry->extracted_comments = trim($entry->extracted_comments . "\n" . $comment); + } elseif ('#,' === $first_two) { + $entry->flags = array_merge($entry->flags, preg_split('/,\s*/', $comment)); } else { - $entry->translator_comments = trim( - $entry->translator_comments."\n".$comment - ); + $entry->translator_comments = trim($entry->translator_comments . "\n" . $comment); } } /** * @param string $s - * * @return string */ public static function trim_quotes($s) { - if (substr($s, 0, 1) == '"') { + if ('"' === substr($s, 0, 1)) { $s = substr($s, 1); } - if (substr($s, -1, 1) == '"') { + if ('"' === substr($s, -1, 1)) { $s = substr($s, 0, -1); } - return $s; } } diff --git a/includes/vendor/pomo/pomo/src/Parser/PluralForms.php b/includes/vendor/pomo/pomo/src/Parser/PluralForms.php index 867ac20a4..899519692 100644 --- a/includes/vendor/pomo/pomo/src/Parser/PluralForms.php +++ b/includes/vendor/pomo/pomo/src/Parser/PluralForms.php @@ -1,4 +1,5 @@ */ class CachedFileReader extends StringReader implements StreamInterface { diff --git a/includes/vendor/pomo/pomo/src/Streams/CachedIntFileReader.php b/includes/vendor/pomo/pomo/src/Streams/CachedIntFileReader.php index fe6c67a49..4817041a1 100644 --- a/includes/vendor/pomo/pomo/src/Streams/CachedIntFileReader.php +++ b/includes/vendor/pomo/pomo/src/Streams/CachedIntFileReader.php @@ -1,4 +1,5 @@ _f = fopen($filename, 'rb'); } + /** + * @param int $bytes + * @return string|false Returns read string, otherwise false. + */ public function read($bytes) { return fread($this->_f, $bytes); } + /** + * @param int $pos + * @return bool + */ public function seekto($pos) { if (-1 == fseek($this->_f, $pos, SEEK_SET)) { return false; } $this->_pos = $pos; - return true; } + /** + * @return bool + */ public function is_resource() { return is_resource($this->_f); @@ -51,18 +69,19 @@ public function feof() return feof($this->_f); } + /** + * @return bool + */ public function close() { return fclose($this->_f); } + /** + * @return string + */ public function read_all() { - $all = ''; - while (!$this->feof()) { - $all .= $this->read(4096); - } - - return $all; + return stream_get_contents($this->_f); } } diff --git a/includes/vendor/pomo/pomo/src/Streams/NOOPReader.php b/includes/vendor/pomo/pomo/src/Streams/NOOPReader.php index 3d9b79943..0476c0250 100644 --- a/includes/vendor/pomo/pomo/src/Streams/NOOPReader.php +++ b/includes/vendor/pomo/pomo/src/Streams/NOOPReader.php @@ -1,4 +1,5 @@ */ +#[AllowDynamicProperties] abstract class Reader implements StreamInterface { public $endian = 'little'; - public $_post = ''; + public $_pos; + public $is_overloaded; public function __construct() { - $this->is_overloaded = ((ini_get('mbstring.func_overload') & 2) != 0) && - function_exists('mb_substr'); + if ( + function_exists('mb_substr') + && ((int) ini_get('mbstring.func_overload') & 2) // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.mbstring_func_overloadDeprecated + ) { + $this->is_overloaded = true; + } else { + $this->is_overloaded = false; + } + $this->_pos = 0; } - public function setEndian($endian) + /** + * Sets the endianness of the file. + * + * @param string $endian Set the endianness of the file. Accepts 'big', or 'little'. + */ + public function setEndian($endian) // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid { $this->endian = $endian; } + /** + * Reads a 32bit Integer from the Stream + * + * @return mixed The integer, corresponding to the next 32 bits from + * the stream of false if there are not enough bytes or on error + */ public function readint32() { $bytes = $this->read(4); if (4 != $this->strlen($bytes)) { return false; } - $endian_letter = ('big' == $this->endian) ? 'N' : 'V'; - $int = unpack($endian_letter, $bytes); - + $endian_letter = ('big' === $this->endian) ? 'N' : 'V'; + $int = unpack($endian_letter, $bytes); return reset($int); } + /** + * Reads an array of 32-bit Integers from the Stream + * + * @param int $count How many elements should be read + * @return mixed Array of integers or false if there isn't + * enough data or on error + */ public function readint32array($count) { $bytes = $this->read(4 * $count); if (4 * $count != $this->strlen($bytes)) { return false; } - $endian_letter = ('big' == $this->endian) ? 'N' : 'V'; - - return unpack($endian_letter.$count, $bytes); + $endian_letter = ('big' === $this->endian) ? 'N' : 'V'; + return unpack($endian_letter . $count, $bytes); } - public function substr($string, $start, $length) + /** + * @param string $input_string + * @param int $start + * @param int $length + * @return string + */ + public function substr($input_string, $start, $length) { if ($this->is_overloaded) { - return mb_substr($string, $start, $length, 'ascii'); + return mb_substr($input_string, $start, $length, 'ascii'); } else { - return substr($string, $start, $length); + return substr($input_string, $start, $length); } } - public function strlen($string) + /** + * @param string $input_string + * @return int + */ + public function strlen($input_string) { if ($this->is_overloaded) { - return mb_strlen($string, 'ascii'); + return mb_strlen($input_string, 'ascii'); } else { - return strlen($string); + return strlen($input_string); } } - public function str_split($string, $chunk_size) + /** + * @param string $input_string + * @param int $chunk_size + * @return array + */ + public function str_split($input_string, $chunk_size) { - if (!function_exists('str_split')) { - $length = $this->strlen($string); - $out = array(); + if (! function_exists('str_split')) { + $length = $this->strlen($input_string); + $out = array(); for ($i = 0; $i < $length; $i += $chunk_size) { - $out[] = $this->substr($string, $i, $chunk_size); + $out[] = $this->substr($input_string, $i, $chunk_size); } - return $out; } else { - return str_split($string, $chunk_size); + return str_split($input_string, $chunk_size); } } + /** + * @return int + */ public function pos() { return $this->_pos; } + /** + * @return true + */ public function is_resource() { return true; } + /** + * @return true + */ public function close() { return true; diff --git a/includes/vendor/pomo/pomo/src/Streams/StreamInterface.php b/includes/vendor/pomo/pomo/src/Streams/StreamInterface.php index 012b2c4ed..07f18bfd7 100644 --- a/includes/vendor/pomo/pomo/src/Streams/StreamInterface.php +++ b/includes/vendor/pomo/pomo/src/Streams/StreamInterface.php @@ -1,4 +1,5 @@ - */ + /** + * Provides file-like methods for manipulating a string instead + * of a physical file. + */ class StringReader extends Reader implements StreamInterface { public $_str = ''; @@ -22,24 +21,30 @@ public function __construct($str = '') $this->_pos = 0; } + /** + * @param string $bytes + * @return string + */ public function read($bytes) { - $data = $this->substr($this->_str, $this->_pos, $bytes); + $data = $this->substr($this->_str, $this->_pos, $bytes); $this->_pos += $bytes; if ($this->strlen($this->_str) < $this->_pos) { $this->_pos = $this->strlen($this->_str); } - return $data; } + /** + * @param int $pos + * @return int + */ public function seekto($pos) { $this->_pos = $pos; if ($this->strlen($this->_str) < $this->_pos) { $this->_pos = $this->strlen($this->_str); } - return $this->_pos; } @@ -51,12 +56,11 @@ public function length() return $this->strlen($this->_str); } + /** + * @return string + */ public function read_all() { - return $this->substr( - $this->_str, - $this->_pos, - $this->strlen($this->_str) - ); + return $this->substr($this->_str, $this->_pos, $this->strlen($this->_str)); } } diff --git a/includes/vendor/pomo/pomo/src/Translations/EntryTranslations.php b/includes/vendor/pomo/pomo/src/Translations/EntryTranslations.php index 730df676a..1c6c9b8af 100644 --- a/includes/vendor/pomo/pomo/src/Translations/EntryTranslations.php +++ b/includes/vendor/pomo/pomo/src/Translations/EntryTranslations.php @@ -1,4 +1,5 @@ $value) { $this->$varname = $value; } if (isset($args['plural']) && $args['plural']) { $this->is_plural = true; } - if (!is_array($this->translations)) { + if (! is_array($this->translations)) { $this->translations = array(); } - if (!is_array($this->references)) { + if (! is_array($this->references)) { $this->references = array(); } - if (!is_array($this->flags)) { + if (! is_array($this->flags)) { $this->flags = array(); } } @@ -68,18 +77,18 @@ public function __construct($args = array()) /** * Generates a unique key for this entry. * - * @return string|bool the key or false if the entry is empty + * @return string|false The key or false if the entry is null. */ public function key() { - if (null === $this->singular || '' === $this->singular) { + if (null === $this->singular) { return false; } - // Prepend context and EOT, like in MO files - $key = !$this->context ? $this->singular : $this->context.chr(4).$this->singular; - // Standardize on \n line endings - $key = str_replace(array("\r\n", "\r"), "\n", $key); + // Prepend context and EOT, like in MO files. + $key = ! $this->context ? $this->singular : $this->context . "\4" . $this->singular; + // Standardize on \n line endings. + $key = str_replace(array( "\r\n", "\r" ), "\n", $key); return $key; } @@ -89,7 +98,7 @@ public function key() */ public function merge_with(&$other) { - $this->flags = array_unique(array_merge($this->flags, $other->flags)); + $this->flags = array_unique(array_merge($this->flags, $other->flags)); $this->references = array_unique(array_merge($this->references, $other->references)); if ($this->extracted_comments != $other->extracted_comments) { $this->extracted_comments .= $other->extracted_comments; diff --git a/includes/vendor/pomo/pomo/src/Translations/GettextTranslations.php b/includes/vendor/pomo/pomo/src/Translations/GettextTranslations.php index 11b2a795b..dd4ca5a83 100644 --- a/includes/vendor/pomo/pomo/src/Translations/GettextTranslations.php +++ b/includes/vendor/pomo/pomo/src/Translations/GettextTranslations.php @@ -1,4 +1,5 @@ _gettext_select_plural_form) - || is_null($this->_gettext_select_plural_form)) { + if ( + !isset($this->_gettext_select_plural_form) + || is_null($this->_gettext_select_plural_form) + ) { list($nplurals, $expression) = $this->nplurals_and_expression_from_header($this->get_header('Plural-Forms')); $this->_nplurals = $nplurals; $this->_gettext_select_plural_form = $this->make_plural_form_function($nplurals, $expression); @@ -103,7 +117,7 @@ public function parenthesize_plural_exression($expression) $res .= ') : ('; break; case ';': - $res .= str_repeat(')', $depth).';'; + $res .= str_repeat(')', $depth) . ';'; $depth = 0; break; default: diff --git a/includes/vendor/pomo/pomo/src/Translations/NOOPTranslations.php b/includes/vendor/pomo/pomo/src/Translations/NOOPTranslations.php index 2c0d995c6..90388cfd0 100644 --- a/includes/vendor/pomo/pomo/src/Translations/NOOPTranslations.php +++ b/includes/vendor/pomo/pomo/src/Translations/NOOPTranslations.php @@ -1,4 +1,5 @@ translate_entry($entry); $index = $this->select_plural_form($count); $total_plural_forms = $this->get_plural_forms_count(); - if ($translated && 0 <= $index && $index < $total_plural_forms && + if ( + $translated && 0 <= $index && $index < $total_plural_forms && is_array($translated->translations) && - isset($translated->translations[$index])) { + isset($translated->translations[$index]) + ) { return $translated->translations[$index]; } else { return 1 == $count ? $singular : $plural; diff --git a/includes/vendor/pomo/pomo/src/Translations/TranslationsInterface.php b/includes/vendor/pomo/pomo/src/Translations/TranslationsInterface.php index e65c93e7c..a14aa2fe4 100644 --- a/includes/vendor/pomo/pomo/src/Translations/TranslationsInterface.php +++ b/includes/vendor/pomo/pomo/src/Translations/TranslationsInterface.php @@ -1,4 +1,5 @@ log(LogLevel::EMERGENCY, $message, $context); - } - - /** - * Action must be taken immediately. - * - * Example: Entire website down, database unavailable, etc. This should - * trigger the SMS alerts and wake you up. - * - * @param string $message - * @param array $context - * - * @return void - */ - public function alert($message, array $context = array()) - { - $this->log(LogLevel::ALERT, $message, $context); - } - - /** - * Critical conditions. - * - * Example: Application component unavailable, unexpected exception. - * - * @param string $message - * @param array $context - * - * @return void - */ - public function critical($message, array $context = array()) - { - $this->log(LogLevel::CRITICAL, $message, $context); - } - - /** - * Runtime errors that do not require immediate action but should typically - * be logged and monitored. - * - * @param string $message - * @param array $context - * - * @return void - */ - public function error($message, array $context = array()) - { - $this->log(LogLevel::ERROR, $message, $context); - } - - /** - * Exceptional occurrences that are not errors. - * - * Example: Use of deprecated APIs, poor use of an API, undesirable things - * that are not necessarily wrong. - * - * @param string $message - * @param array $context - * - * @return void - */ - public function warning($message, array $context = array()) - { - $this->log(LogLevel::WARNING, $message, $context); - } - - /** - * Normal but significant events. - * - * @param string $message - * @param array $context - * - * @return void - */ - public function notice($message, array $context = array()) - { - $this->log(LogLevel::NOTICE, $message, $context); - } - - /** - * Interesting events. - * - * Example: User logs in, SQL logs. - * - * @param string $message - * @param array $context - * - * @return void - */ - public function info($message, array $context = array()) - { - $this->log(LogLevel::INFO, $message, $context); - } - - /** - * Detailed debug information. - * - * @param string $message - * @param array $context - * - * @return void - */ - public function debug($message, array $context = array()) - { - $this->log(LogLevel::DEBUG, $message, $context); - } -} diff --git a/includes/vendor/psr/log/Psr/Log/Test/DummyTest.php b/includes/vendor/psr/log/Psr/Log/Test/DummyTest.php deleted file mode 100644 index 9638c1101..000000000 --- a/includes/vendor/psr/log/Psr/Log/Test/DummyTest.php +++ /dev/null @@ -1,18 +0,0 @@ - ". - * - * Example ->error('Foo') would yield "error Foo". - * - * @return string[] - */ - abstract public function getLogs(); - - public function testImplements() - { - $this->assertInstanceOf('Psr\Log\LoggerInterface', $this->getLogger()); - } - - /** - * @dataProvider provideLevelsAndMessages - */ - public function testLogsAtAllLevels($level, $message) - { - $logger = $this->getLogger(); - $logger->{$level}($message, array('user' => 'Bob')); - $logger->log($level, $message, array('user' => 'Bob')); - - $expected = array( - $level.' message of level '.$level.' with context: Bob', - $level.' message of level '.$level.' with context: Bob', - ); - $this->assertEquals($expected, $this->getLogs()); - } - - public function provideLevelsAndMessages() - { - return array( - LogLevel::EMERGENCY => array(LogLevel::EMERGENCY, 'message of level emergency with context: {user}'), - LogLevel::ALERT => array(LogLevel::ALERT, 'message of level alert with context: {user}'), - LogLevel::CRITICAL => array(LogLevel::CRITICAL, 'message of level critical with context: {user}'), - LogLevel::ERROR => array(LogLevel::ERROR, 'message of level error with context: {user}'), - LogLevel::WARNING => array(LogLevel::WARNING, 'message of level warning with context: {user}'), - LogLevel::NOTICE => array(LogLevel::NOTICE, 'message of level notice with context: {user}'), - LogLevel::INFO => array(LogLevel::INFO, 'message of level info with context: {user}'), - LogLevel::DEBUG => array(LogLevel::DEBUG, 'message of level debug with context: {user}'), - ); - } - - public function testThrowsOnInvalidLevel() - { - $this->expectException(\Psr\Log\InvalidArgumentException::class); - - $logger = $this->getLogger(); - $logger->log('invalid level', 'Foo'); - } - - public function testContextReplacement() - { - $logger = $this->getLogger(); - $logger->info('{Message {nothing} {user} {foo.bar} a}', array('user' => 'Bob', 'foo.bar' => 'Bar')); - - $expected = array('info {Message {nothing} Bob Bar a}'); - $this->assertEquals($expected, $this->getLogs()); - } - - public function testObjectCastToString() - { - if (method_exists($this, 'createPartialMock')) { - $dummy = $this->createPartialMock('Psr\Log\Test\DummyTest', array('__toString')); - } else { - $dummy = $this->getMock('Psr\Log\Test\DummyTest', array('__toString')); - } - $dummy->expects($this->once()) - ->method('__toString') - ->will($this->returnValue('DUMMY')); - - $this->getLogger()->warning($dummy); - - $expected = array('warning DUMMY'); - $this->assertEquals($expected, $this->getLogs()); - } - - public function testContextCanContainAnything() - { - $closed = fopen('php://memory', 'r'); - fclose($closed); - - $context = array( - 'bool' => true, - 'null' => null, - 'string' => 'Foo', - 'int' => 0, - 'float' => 0.5, - 'nested' => array('with object' => new DummyTest), - 'object' => new \DateTime, - 'resource' => fopen('php://memory', 'r'), - 'closed' => $closed, - ); - - $this->getLogger()->warning('Crazy context data', $context); - - $expected = array('warning Crazy context data'); - $this->assertEquals($expected, $this->getLogs()); - } - - public function testContextExceptionKeyCanBeExceptionOrOtherValues() - { - $logger = $this->getLogger(); - $logger->warning('Random message', array('exception' => 'oops')); - $logger->critical('Uncaught Exception!', array('exception' => new \LogicException('Fail'))); - - $expected = array( - 'warning Random message', - 'critical Uncaught Exception!' - ); - $this->assertEquals($expected, $this->getLogs()); - } -} diff --git a/includes/vendor/psr/log/Psr/Log/Test/TestLogger.php b/includes/vendor/psr/log/Psr/Log/Test/TestLogger.php deleted file mode 100644 index 1be323049..000000000 --- a/includes/vendor/psr/log/Psr/Log/Test/TestLogger.php +++ /dev/null @@ -1,147 +0,0 @@ - $level, - 'message' => $message, - 'context' => $context, - ]; - - $this->recordsByLevel[$record['level']][] = $record; - $this->records[] = $record; - } - - public function hasRecords($level) - { - return isset($this->recordsByLevel[$level]); - } - - public function hasRecord($record, $level) - { - if (is_string($record)) { - $record = ['message' => $record]; - } - return $this->hasRecordThatPasses(function ($rec) use ($record) { - if ($rec['message'] !== $record['message']) { - return false; - } - if (isset($record['context']) && $rec['context'] !== $record['context']) { - return false; - } - return true; - }, $level); - } - - public function hasRecordThatContains($message, $level) - { - return $this->hasRecordThatPasses(function ($rec) use ($message) { - return strpos($rec['message'], $message) !== false; - }, $level); - } - - public function hasRecordThatMatches($regex, $level) - { - return $this->hasRecordThatPasses(function ($rec) use ($regex) { - return preg_match($regex, $rec['message']) > 0; - }, $level); - } - - public function hasRecordThatPasses(callable $predicate, $level) - { - if (!isset($this->recordsByLevel[$level])) { - return false; - } - foreach ($this->recordsByLevel[$level] as $i => $rec) { - if (call_user_func($predicate, $rec, $i)) { - return true; - } - } - return false; - } - - public function __call($method, $args) - { - if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) { - $genericMethod = $matches[1] . ('Records' !== $matches[3] ? 'Record' : '') . $matches[3]; - $level = strtolower($matches[2]); - if (method_exists($this, $genericMethod)) { - $args[] = $level; - return call_user_func_array([$this, $genericMethod], $args); - } - } - throw new \BadMethodCallException('Call to undefined method ' . get_class($this) . '::' . $method . '()'); - } - - public function reset() - { - $this->records = []; - $this->recordsByLevel = []; - } -} diff --git a/includes/vendor/psr/log/src/AbstractLogger.php b/includes/vendor/psr/log/src/AbstractLogger.php new file mode 100644 index 000000000..d60a091af --- /dev/null +++ b/includes/vendor/psr/log/src/AbstractLogger.php @@ -0,0 +1,15 @@ +logger = $logger; } diff --git a/includes/vendor/psr/log/Psr/Log/LoggerInterface.php b/includes/vendor/psr/log/src/LoggerInterface.php similarity index 63% rename from includes/vendor/psr/log/Psr/Log/LoggerInterface.php rename to includes/vendor/psr/log/src/LoggerInterface.php index 2206cfde4..cb4cf648b 100644 --- a/includes/vendor/psr/log/Psr/Log/LoggerInterface.php +++ b/includes/vendor/psr/log/src/LoggerInterface.php @@ -22,12 +22,9 @@ interface LoggerInterface /** * System is unusable. * - * @param string $message * @param mixed[] $context - * - * @return void */ - public function emergency($message, array $context = array()); + public function emergency(string|\Stringable $message, array $context = []): void; /** * Action must be taken immediately. @@ -35,35 +32,26 @@ public function emergency($message, array $context = array()); * Example: Entire website down, database unavailable, etc. This should * trigger the SMS alerts and wake you up. * - * @param string $message * @param mixed[] $context - * - * @return void */ - public function alert($message, array $context = array()); + public function alert(string|\Stringable $message, array $context = []): void; /** * Critical conditions. * * Example: Application component unavailable, unexpected exception. * - * @param string $message * @param mixed[] $context - * - * @return void */ - public function critical($message, array $context = array()); + public function critical(string|\Stringable $message, array $context = []): void; /** * Runtime errors that do not require immediate action but should typically * be logged and monitored. * - * @param string $message * @param mixed[] $context - * - * @return void */ - public function error($message, array $context = array()); + public function error(string|\Stringable $message, array $context = []): void; /** * Exceptional occurrences that are not errors. @@ -71,55 +59,40 @@ public function error($message, array $context = array()); * Example: Use of deprecated APIs, poor use of an API, undesirable things * that are not necessarily wrong. * - * @param string $message * @param mixed[] $context - * - * @return void */ - public function warning($message, array $context = array()); + public function warning(string|\Stringable $message, array $context = []): void; /** * Normal but significant events. * - * @param string $message * @param mixed[] $context - * - * @return void */ - public function notice($message, array $context = array()); + public function notice(string|\Stringable $message, array $context = []): void; /** * Interesting events. * * Example: User logs in, SQL logs. * - * @param string $message * @param mixed[] $context - * - * @return void */ - public function info($message, array $context = array()); + public function info(string|\Stringable $message, array $context = []): void; /** * Detailed debug information. * - * @param string $message * @param mixed[] $context - * - * @return void */ - public function debug($message, array $context = array()); + public function debug(string|\Stringable $message, array $context = []): void; /** * Logs with an arbitrary level. * - * @param mixed $level - * @param string $message + * @param mixed $level * @param mixed[] $context * - * @return void - * * @throws \Psr\Log\InvalidArgumentException */ - public function log($level, $message, array $context = array()); + public function log($level, string|\Stringable $message, array $context = []): void; } diff --git a/includes/vendor/psr/log/Psr/Log/LoggerTrait.php b/includes/vendor/psr/log/src/LoggerTrait.php similarity index 57% rename from includes/vendor/psr/log/Psr/Log/LoggerTrait.php rename to includes/vendor/psr/log/src/LoggerTrait.php index e392fef0a..a5d9980b6 100644 --- a/includes/vendor/psr/log/Psr/Log/LoggerTrait.php +++ b/includes/vendor/psr/log/src/LoggerTrait.php @@ -14,13 +14,8 @@ trait LoggerTrait { /** * System is unusable. - * - * @param string $message - * @param array $context - * - * @return void */ - public function emergency($message, array $context = array()) + public function emergency(string|\Stringable $message, array $context = []): void { $this->log(LogLevel::EMERGENCY, $message, $context); } @@ -30,13 +25,8 @@ public function emergency($message, array $context = array()) * * Example: Entire website down, database unavailable, etc. This should * trigger the SMS alerts and wake you up. - * - * @param string $message - * @param array $context - * - * @return void */ - public function alert($message, array $context = array()) + public function alert(string|\Stringable $message, array $context = []): void { $this->log(LogLevel::ALERT, $message, $context); } @@ -45,13 +35,8 @@ public function alert($message, array $context = array()) * Critical conditions. * * Example: Application component unavailable, unexpected exception. - * - * @param string $message - * @param array $context - * - * @return void */ - public function critical($message, array $context = array()) + public function critical(string|\Stringable $message, array $context = []): void { $this->log(LogLevel::CRITICAL, $message, $context); } @@ -59,13 +44,8 @@ public function critical($message, array $context = array()) /** * Runtime errors that do not require immediate action but should typically * be logged and monitored. - * - * @param string $message - * @param array $context - * - * @return void */ - public function error($message, array $context = array()) + public function error(string|\Stringable $message, array $context = []): void { $this->log(LogLevel::ERROR, $message, $context); } @@ -75,26 +55,16 @@ public function error($message, array $context = array()) * * Example: Use of deprecated APIs, poor use of an API, undesirable things * that are not necessarily wrong. - * - * @param string $message - * @param array $context - * - * @return void */ - public function warning($message, array $context = array()) + public function warning(string|\Stringable $message, array $context = []): void { $this->log(LogLevel::WARNING, $message, $context); } /** * Normal but significant events. - * - * @param string $message - * @param array $context - * - * @return void */ - public function notice($message, array $context = array()) + public function notice(string|\Stringable $message, array $context = []): void { $this->log(LogLevel::NOTICE, $message, $context); } @@ -103,26 +73,16 @@ public function notice($message, array $context = array()) * Interesting events. * * Example: User logs in, SQL logs. - * - * @param string $message - * @param array $context - * - * @return void */ - public function info($message, array $context = array()) + public function info(string|\Stringable $message, array $context = []): void { $this->log(LogLevel::INFO, $message, $context); } /** * Detailed debug information. - * - * @param string $message - * @param array $context - * - * @return void */ - public function debug($message, array $context = array()) + public function debug(string|\Stringable $message, array $context = []): void { $this->log(LogLevel::DEBUG, $message, $context); } @@ -130,13 +90,9 @@ public function debug($message, array $context = array()) /** * Logs with an arbitrary level. * - * @param mixed $level - * @param string $message - * @param array $context - * - * @return void + * @param mixed $level * * @throws \Psr\Log\InvalidArgumentException */ - abstract public function log($level, $message, array $context = array()); + abstract public function log($level, string|\Stringable $message, array $context = []): void; } diff --git a/includes/vendor/psr/log/Psr/Log/NullLogger.php b/includes/vendor/psr/log/src/NullLogger.php similarity index 74% rename from includes/vendor/psr/log/Psr/Log/NullLogger.php rename to includes/vendor/psr/log/src/NullLogger.php index c8f7293b1..de0561e2a 100644 --- a/includes/vendor/psr/log/Psr/Log/NullLogger.php +++ b/includes/vendor/psr/log/src/NullLogger.php @@ -15,15 +15,11 @@ class NullLogger extends AbstractLogger /** * Logs with an arbitrary level. * - * @param mixed $level - * @param string $message - * @param array $context - * - * @return void + * @param mixed[] $context * * @throws \Psr\Log\InvalidArgumentException */ - public function log($level, $message, array $context = array()) + public function log($level, string|\Stringable $message, array $context = []): void { // noop } diff --git a/includes/vendor/rmccue/requests/README.md b/includes/vendor/rmccue/requests/README.md index 8e99a20ec..756bc5321 100644 --- a/includes/vendor/rmccue/requests/README.md +++ b/includes/vendor/rmccue/requests/README.md @@ -1,18 +1,20 @@ Requests for PHP ================ -[![Build Status](https://travis-ci.org/rmccue/Requests.svg?branch=master)](https://travis-ci.org/rmccue/Requests) -[![codecov.io](http://codecov.io/github/rmccue/Requests/coverage.svg?branch=master)](http://codecov.io/github/rmccue/Requests?branch=master) +[![CS](https://github.com/WordPress/Requests/actions/workflows/cs.yml/badge.svg)](https://github.com/WordPress/Requests/actions/workflows/cs.yml) +[![Lint](https://github.com/WordPress/Requests/actions/workflows/lint.yml/badge.svg)](https://github.com/WordPress/Requests/actions/workflows/lint.yml) +[![Test](https://github.com/WordPress/Requests/actions/workflows/test.yml/badge.svg)](https://github.com/WordPress/Requests/actions/workflows/test.yml) +[![codecov.io](https://codecov.io/gh/WordPress/Requests/branch/stable/graph/badge.svg?token=AfpxK7WMxj&branch=stable)](https://codecov.io/gh/WordPress/Requests?branch=stable) Requests is a HTTP library written in PHP, for human beings. It is roughly based on the API from the excellent [Requests Python library](http://python-requests.org/). Requests is [ISC -Licensed](https://github.com/rmccue/Requests/blob/master/LICENSE) (similar to -the new BSD license) and has no dependencies, except for PHP 5.2+. +Licensed](https://github.com/WordPress/Requests/blob/stable/LICENSE) (similar to +the new BSD license) and has no dependencies, except for PHP 5.6+. Despite PHP's use as a language for the web, its tools for sending HTTP requests are severely lacking. cURL has an -[interesting API](http://php.net/manual/en/function.curl-setopt.php), to say the +[interesting API](https://www.php.net/curl-setopt), to say the least, and you can't always rely on it being available. Sockets provide only low level access, and require you to build most of the HTTP response parsing yourself. @@ -22,7 +24,7 @@ We all have better things to do. That's why Requests was born. ```php $headers = array('Accept' => 'application/json'); $options = array('auth' => array('user', 'pass')); -$request = Requests::get('https://api.github.com/gists', $headers, $options); +$request = WpOrg\Requests\Requests::get('https://api.github.com/gists', $headers, $options); var_dump($request->status_code); // int(200) @@ -36,7 +38,7 @@ var_dump($request->body); Requests allows you to send **HEAD**, **GET**, **POST**, **PUT**, **DELETE**, and **PATCH** HTTP requests. You can add headers, form data, multipart files, -and parameters with simple arrays, and access the response data in the same way. +and parameters with basic arrays, and access the response data in the same way. Requests uses cURL and fsockopen, depending on what your system has available, but abstracts all the nasty stuff out of your way, providing a consistent API. @@ -55,7 +57,7 @@ Installation ------------ ### Install with Composer -If you're using [Composer](https://github.com/composer/composer) to manage +If you're using [Composer](https://getcomposer.org/) to manage dependencies, you can add Requests with it. ```sh @@ -63,46 +65,54 @@ composer require rmccue/requests ``` or - - { - "require": { - "rmccue/requests": ">=1.0" - } +```json +{ + "require": { + "rmccue/requests": "^2.0" } +} +``` ### Install source from GitHub To install the source code: +```bash +$ git clone git://github.com/WordPress/Requests.git +``` - $ git clone git://github.com/rmccue/Requests.git - -And include it in your scripts: - - require_once '/path/to/Requests/library/Requests.php'; - -You'll probably also want to register an autoloader: - - Requests::register_autoloader(); +Next, include the autoloader in your scripts: +```php +require_once '/path/to/Requests/src/Autoload.php'; +``` +You'll probably also want to register the autoloader: +```php +WpOrg\Requests\Autoload::register(); +``` ### Install source from zip/tarball Alternatively, you can fetch a [tarball][] or [zipball][]: - $ curl -L https://github.com/rmccue/Requests/tarball/master | tar xzv - (or) - $ wget https://github.com/rmccue/Requests/tarball/master -O - | tar xzv +```bash +$ curl -L https://github.com/WordPress/Requests/tarball/stable | tar xzv +(or) +$ wget https://github.com/WordPress/Requests/tarball/stable -O - | tar xzv +``` -[tarball]: https://github.com/rmccue/Requests/tarball/master -[zipball]: https://github.com/rmccue/Requests/zipball/master +[tarball]: https://github.com/WordPress/Requests/tarball/stable +[zipball]: https://github.com/WordPress/Requests/zipball/stable ### Using a Class Loader If you're using a class loader (e.g., [Symfony Class Loader][]) for -[PSR-0][]-style class loading: - - $loader->registerPrefix('Requests', 'path/to/vendor/Requests/library'); +[PSR-4][]-style class loading: +```php +$loader = new Psr4ClassLoader(); +$loader->addPrefix('WpOrg\\Requests\\', 'path/to/vendor/Requests/src'); +$loader->register(); +``` [Symfony Class Loader]: https://github.com/symfony/ClassLoader -[PSR-0]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md +[PSR-4]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4.md Documentation @@ -111,15 +121,15 @@ The best place to start is our [prose-based documentation][], which will guide you through using Requests. After that, take a look at [the documentation for -`Requests::request()`][request_method], where all the parameters are fully +`\WpOrg\Requests\Requests::request()`][request_method], where all the parameters are fully documented. -Requests is [100% documented with PHPDoc](http://requests.ryanmccue.info/api/). +Requests is [100% documented with PHPDoc](https://requests.ryanmccue.info/api-2.x/). If you find any problems with it, [create a new -issue](https://github.com/rmccue/Requests/issues/new)! +issue](https://github.com/WordPress/Requests/issues/new)! -[prose-based documentation]: https://github.com/rmccue/Requests/blob/master/docs/README.md -[request_method]: http://requests.ryanmccue.info/api/class-Requests.html#_request +[prose-based documentation]: https://github.com/WordPress/Requests/blob/stable/docs/README.md +[request_method]: https://requests.ryanmccue.info/api-2.x/classes/WpOrg-Requests-Requests.html#method_request Testing ------- @@ -127,26 +137,50 @@ Testing Requests strives to have 100% code-coverage of the library with an extensive set of tests. We're not quite there yet, but [we're getting close][codecov]. -[codecov]: http://codecov.io/github/rmccue/Requests +[codecov]: https://codecov.io/github/WordPress/Requests/ To run the test suite, first check that you have the [PHP -JSON extension ](http://php.net/manual/en/book.json.php) enabled. Then +JSON extension ](https://www.php.net/book.json) enabled. Then simply: - - $ cd tests - $ phpunit +```bash +$ phpunit +``` If you'd like to run a single set of tests, specify just the name: +```bash +$ phpunit Transport/cURL +``` + +Requests and PSR-7/PSR-18 +------------------------- + +[PSR-7][psr-7] describes common interfaces for representing HTTP messages. +[PSR-18][psr-18] describes a common interface for sending HTTP requests and receiving HTTP responses. + +Both PSR-7 as well as PSR-18 were created after Requests' conception. +At this time, there is no intention to add a native PSR-7/PSR-18 implementation to the Requests library. + +However, the amazing [Artur Weigandt][art4] has created a [package][requests-psr-18], which allows you to use Requests as a PSR-7 compatible PSR-18 HTTP Client. +If you are interested in a PSR-7/PSR-18 compatible version of Requests, we highly recommend you check out [this package][requests-psr-18]. + +[psr-7]: https://www.php-fig.org/psr/psr-7/ +[psr-18]: https://www.php-fig.org/psr/psr-18/ +[art4]: https://github.com/Art4 +[requests-psr-18]: https://packagist.org/packages/art4/requests-psr18-adapter - $ phpunit Transport/cURL Contribute ---------- -1. Check for open issues or open a new issue for a feature request or a bug +1. Check for open issues or open a new issue for a feature request or a bug. 2. Fork [the repository][] on Github to start making your changes to the - `master` branch (or branch off of it) -3. Write a test which shows that the bug was fixed or that the feature works as expected -4. Send a pull request and bug me until I merge it + `develop` branch (or branch off of it). +3. Write one or more tests which show that the bug was fixed or that the feature works as expected. +4. Send in a pull request. + +If you have questions while working on your contribution and you use Slack, there is +a [#core-http-api] channel available in the [WordPress Slack] in which contributions can be discussed. -[the repository]: https://github.com/rmccue/Requests +[the repository]: https://github.com/WordPress/Requests +[#core-http-api]: https://wordpress.slack.com/archives/C02BBE29V42 +[WordPress Slack]: https://make.wordpress.org/chat/ diff --git a/includes/vendor/rmccue/requests/certificates/cacert.pem b/includes/vendor/rmccue/requests/certificates/cacert.pem new file mode 100644 index 000000000..65be891ee --- /dev/null +++ b/includes/vendor/rmccue/requests/certificates/cacert.pem @@ -0,0 +1,3511 @@ +## +## Bundle of CA Root Certificates +## +## Certificate data from Mozilla as of: Tue Dec 2 04:12:02 2025 GMT +## +## Find updated versions here: https://curl.se/docs/caextract.html +## +## This is a bundle of X.509 certificates of public Certificate Authorities +## (CA). These were automatically extracted from Mozilla's root certificates +## file (certdata.txt). This file can be found in the mozilla source tree: +## https://raw.githubusercontent.com/mozilla-firefox/firefox/refs/heads/release/security/nss/lib/ckfw/builtins/certdata.txt +## +## It contains the certificates in PEM format and therefore +## can be directly used with curl / libcurl / php_curl, or with +## an Apache+mod_ssl webserver for SSL client authentication. +## Just configure this file as the SSLCACertificateFile. +## +## Conversion done with mk-ca-bundle.pl version 1.30. +## SHA256: a903b3cd05231e39332515ef7ebe37e697262f39515a52015c23c62805b73cd0 +## + + +Entrust Root Certification Authority +==================================== +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV +BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw +b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG +A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0 +MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu +MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu +Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v +dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz +A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww +Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68 +j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN +rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1 +MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH +hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM +Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa +v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS +W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 +tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +QuoVadis Root CA 2 +================== +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT +EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx +ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6 +XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk +lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB +lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy +lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt +66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn +wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh +D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy +BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie +J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud +DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU +a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv +Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3 +UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm +VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK ++JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW +IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1 +WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X +f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II +4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8 +VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE----- + +QuoVadis Root CA 3 +================== +-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT +EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx +OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg +DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij +KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K +DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv +BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp +p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8 +nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX +MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM +Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz +uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT +BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj +YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB +BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD +VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4 +ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE +AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV +qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s +hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z +POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2 +Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp +8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC +bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu +g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p +vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr +qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE----- + +DigiCert Assured ID Root CA +=========================== +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw +IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx +MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL +ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO +9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy +UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW +/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy +oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf +GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF +66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq +hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc +EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn +SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i +8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +DigiCert Global Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw +HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw +MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 +dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn +TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5 +BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H +4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y +7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB +o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm +8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF +BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr +EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt +tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886 +UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +DigiCert High Assurance EV Root CA +================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw +KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw +MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ +MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu +Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t +Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS +OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3 +MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ +NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe +h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB +Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY +JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ +V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp +myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK +mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K +-----END CERTIFICATE----- + +SwissSign Gold CA - G2 +====================== +-----BEGIN CERTIFICATE----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw +EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN +MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp +c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq +t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C +jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg +vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF +ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR +AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend +jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO +peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR +7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi +GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64 +OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm +5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr +44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf +Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m +Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp +mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk +vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf +KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br +NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj +viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----END CERTIFICATE----- + +SecureTrust CA +============== +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy +dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe +BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX +OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t +DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH +GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b +01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH +ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj +aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ +KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu +SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf +mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ +nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- + +Secure Global CA +================ +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH +bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg +MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg +Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx +YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ +bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g +8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV +HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi +0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn +oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA +MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+ +OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn +CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5 +3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- + +COMODO Certification Authority +============================== +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE +BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG +A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb +MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD +T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH ++7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww +xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV +4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA +1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI +rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k +b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC +AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP +OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc +IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN ++8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ== +-----END CERTIFICATE----- + +COMODO ECC Certification Authority +================================== +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC +R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE +ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix +GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X +4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni +wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG +FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA +U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- + +Certigna +======== +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw +EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3 +MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI +Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q +XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH +GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p +ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg +DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf +Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ +tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ +BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J +SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA +hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+ +ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu +PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY +1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- + +ePKI Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG +EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx +MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq +MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs +IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi +lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv +qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX +12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O +WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+ +ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao +lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/ +vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi +Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi +MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0 +1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq +KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV +xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP +NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r +GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE +xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx +gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy +sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD +BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- + +certSIGN ROOT CA +================ +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD +VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa +Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE +CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I +JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH +rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2 +ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD +0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943 +AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B +Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB +AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8 +SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0 +x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt +vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz +TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- + +NetLock Arany (Class Gold) Főtanúsítvány +======================================== +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G +A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610 +dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB +cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx +MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO +ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv +biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6 +c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu +0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw +/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk +H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw +fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1 +neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW +qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta +YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna +NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu +dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- + +Microsec e-Szigno Root CA 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER +MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv +c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE +BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt +U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA +fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG +0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA +pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm +1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC +AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf +QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE +FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o +lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX +I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02 +yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi +LXpUq3DDfSJlgnCW +-----END CERTIFICATE----- + +GlobalSign Root CA - R3 +======================= +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt +iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ +0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3 +rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl +OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2 +xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7 +lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8 +EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E +bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18 +YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r +kpeDMdmztcpHWD9f +-----END CERTIFICATE----- + +Izenpe.com +========== +-----BEGIN CERTIFICATE----- +MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG +EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz +MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu +QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ +03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK +ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU ++zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC +PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT +OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK +F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK +0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+ +0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB +leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID +AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+ +SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG +NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx +MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O +BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l +Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga +kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q +hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs +g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5 +aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5 +nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC +ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo +Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z +WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== +-----END CERTIFICATE----- + +Go Daddy Root Certificate Authority - G2 +======================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu +MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G +A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq +9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD ++qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd +fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl +NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9 +BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac +vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r +5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV +N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1 +-----END CERTIFICATE----- + +Starfield Root Certificate Authority - G2 +========================================= +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 +eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw +DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg +VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB +dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv +W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs +bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk +N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf +ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU +JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol +TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx +4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw +F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ +c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + +Starfield Services Root Certificate Authority - G2 +================================================== +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl +IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT +dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2 +h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa +hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP +LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB +rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG +SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP +E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy +xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza +YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6 +-----END CERTIFICATE----- + +AffirmTrust Commercial +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw +MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb +DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV +C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6 +BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww +MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV +HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG +hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi +qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv +0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh +sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +AffirmTrust Networking +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw +MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE +Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI +dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24 +/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb +h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV +HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu +UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6 +12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23 +WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9 +/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +AffirmTrust Premium +=================== +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy +OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy +dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn +BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV +5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs ++7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd +GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R +p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI +S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04 +6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5 +/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo ++Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv +MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC +6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S +L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK ++4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV +BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg +IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60 +g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb +zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw== +-----END CERTIFICATE----- + +AffirmTrust Premium ECC +======================= +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV +BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx +MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U +cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ +N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW +BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK +BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X +57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM +eQ== +-----END CERTIFICATE----- + +Certum Trusted Network CA +========================= +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK +ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy +MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU +ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC +l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J +J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4 +fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0 +cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB +Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw +DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj +jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1 +mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj +Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- + +TWCA Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ +VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG +EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB +IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx +QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC +oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP +4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r +y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG +9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC +mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW +QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY +T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny +Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- + +Security Communication RootCA2 +============================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc +U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh +dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC +SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy +aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++ ++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R +3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV +spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K +EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8 +QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB +CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj +u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk +3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q +tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29 +mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- + +Actalis Authentication Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM +BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE +AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky +MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz +IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ +wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa +by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6 +zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f +YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2 +oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l +EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7 +hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8 +EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5 +jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY +iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI +WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0 +JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx +K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+ +Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC +4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo +2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz +lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem +OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9 +vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE----- + +Buypass Class 2 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X +DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1 +g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn +9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b +/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU +CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff +awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI +zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn +Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX +Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs +M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI +osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S +aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd +DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD +LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0 +oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC +wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS +CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN +rJgWVqA= +-----END CERTIFICATE----- + +Buypass Class 3 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X +DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH +sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR +5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh +7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ +ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH +2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV +/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ +RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA +Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq +j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G +uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG +Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8 +ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2 +KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz +6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug +UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe +eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi +Cp/HuZc= +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 3 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx +MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK +9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU +NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF +iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W +0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr +AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb +fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT +ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h +P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw== +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe +Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE +LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD +ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA +BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv +KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z +p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC +AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ +4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y +eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw +MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G +PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw +OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm +2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV +dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph +X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 EV 2009 +================================= +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw +OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw +OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS +egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh +zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T +7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60 +sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35 +11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv +cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v +ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El +MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp +b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh +c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+ +PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX +ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA +NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv +w9y4AyHqnxbxLFS1 +-----END CERTIFICATE----- + +CA Disig Root R2 +================ +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw +EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp +ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx +EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp +c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC +w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia +xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7 +A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S +GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV +g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa +5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE +koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A +Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i +Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u +Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV +sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je +dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8 +1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx +mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01 +utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0 +sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg +UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV +7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE----- + +ACCVRAIZ1 +========= +-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB +SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1 +MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH +UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM +jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0 +RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD +aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ +0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG +WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7 +8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR +5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J +9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK +Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw +Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu +Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM +Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA +QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh +AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA +YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj +AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA +IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk +aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0 +dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2 +MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI +hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E +R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN +YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49 +nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ +TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3 +sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg +Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd +3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p +EfbRD0tVNEYqi4Y7 +-----END CERTIFICATE----- + +TWCA Global Root CA +=================== +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT +CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD +QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK +EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg +Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C +nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV +r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR +Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV +tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W +KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99 +sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p +yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn +kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI +zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g +cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M +8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg +/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg +lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP +A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m +i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8 +EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3 +zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0= +-----END CERTIFICATE----- + +TeliaSonera Root CA v1 +====================== +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE +CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4 +MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW +VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+ +6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA +3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k +B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn +Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH +oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3 +F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ +oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7 +gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc +TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB +AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW +DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm +zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW +pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV +G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc +c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT +JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2 +qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6 +Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems +WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 2 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx +MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ +SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F +vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970 +2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV +WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy +YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4 +r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf +vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR +3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg== +-----END CERTIFICATE----- + +Atos TrustedRoot 2011 +===================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU +cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4 +MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG +A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV +hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr +54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+ +DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320 +HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR +z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R +l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ +bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB +CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h +k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh +TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9 +61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G +3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- + +QuoVadis Root CA 1 G3 +===================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG +A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv +b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN +MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg +RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE +PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm +PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6 +Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN +ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l +g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV +7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX +9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f +iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg +t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI +hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC +MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3 +GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct +Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP ++V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh +3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa +wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6 +O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0 +FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV +hMJKzRwuJIczYOXD +-----END CERTIFICATE----- + +QuoVadis Root CA 2 G3 +===================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG +A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv +b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN +MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg +RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh +ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY +NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t +oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o +MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l +V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo +L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ +sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD +6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh +lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI +hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 +AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K +pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9 +x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz +dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X +U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw +mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD +zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN +JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr +O3jtZsSOeWmD3n+M +-----END CERTIFICATE----- + +QuoVadis Root CA 3 G3 +===================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG +A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv +b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN +MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg +RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286 +IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL +Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe +6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3 +I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U +VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7 +5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi +Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM +dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt +rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI +hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px +KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS +t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ +TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du +DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib +Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD +hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX +0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW +dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2 +PpxxVJkES/1Y+Zj0 +-----END CERTIFICATE----- + +DigiCert Assured ID Root G2 +=========================== +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw +IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw +MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL +ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH +35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq +bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw +VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP +YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn +lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO +w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv +0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz +d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW +hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M +jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- + +DigiCert Assured ID Root G3 +=========================== +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD +VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 +MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ +BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb +RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs +KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF +UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy +YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy +1vUhZscv6pZjamVFkpUBtA== +-----END CERTIFICATE----- + +DigiCert Global Root G2 +======================= +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw +HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx +MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 +dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ +kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO +3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV +BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM +UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB +o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu +5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr +F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U +WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH +QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/ +iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- + +DigiCert Global Root G3 +======================= +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD +VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw +MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k +aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C +AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O +YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp +Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y +3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34 +VOKa5Vt8sycX +-----END CERTIFICATE----- + +DigiCert Trusted Root G4 +======================== +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw +HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 +MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp +pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o +k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa +vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY +QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6 +MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm +mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7 +f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH +dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8 +oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY +ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr +yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy +7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah +ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN +5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb +/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa +5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK +G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP +82Z+ +-----END CERTIFICATE----- + +COMODO RSA Certification Authority +================================== +-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE +BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG +A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC +R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE +ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn +dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ +FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+ +5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG +x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX +2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL +OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3 +sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C +GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5 +WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w +DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt +rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+ +nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg +tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW +sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp +pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA +zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq +ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52 +7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I +LaZRfyHBNVOFBkpdn627G190 +-----END CERTIFICATE----- + +USERTrust RSA Certification Authority +===================================== +-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE +BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK +ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE +BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK +ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz +0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j +Y0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn +RghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O ++T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq +/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE +Y1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM +lXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8 +yexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+ +eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW +FPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ +7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ +Eg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM +8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi +FSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi +yA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c +J2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw +sAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx +Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE----- + +USERTrust ECC Certification Authority +===================================== +-----BEGIN CERTIFICATE----- +MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC +VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC +VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2 +0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez +nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV +HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB +HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu +9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= +-----END CERTIFICATE----- + +GlobalSign ECC Root CA - R5 +=========================== +-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb +R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD +EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb +R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD +EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6 +SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS +h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd +BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx +uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7 +yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE----- + +IdenTrust Commercial Root CA 1 +============================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG +EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS +b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES +MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB +IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld +hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/ +mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi +1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C +XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl +3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy +NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV +WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg +xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix +uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI +hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg +ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt +ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV +YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX +feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro +kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe +2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz +Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R +cGzM7vRX+Bi6hG6H +-----END CERTIFICATE----- + +IdenTrust Public Sector Root CA 1 +================================= +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG +EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv +ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV +UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS +b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy +P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6 +Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI +rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf +qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS +mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn +ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh +LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v +iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL +4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B +Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw +DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj +t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A +mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt +GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt +m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx +NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4 +Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI +ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC +ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ +3Wl9af0AVqW3rLatt8o+Ae+c +-----END CERTIFICATE----- + +Entrust Root Certification Authority - G2 +========================================= +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV +BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy +bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug +b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw +HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT +DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx +OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP +/vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz +HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU +s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y +TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx +AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6 +0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z +iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi +nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+ +vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO +e4pIb4tF9g== +-----END CERTIFICATE----- + +Entrust Root Certification Authority - EC1 +========================================== +-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx +FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn +YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl +ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw +FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs +LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg +dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt +IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy +AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef +9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h +vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8 +kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE----- + +CFCA EV ROOT +============ +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE +CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB +IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw +MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD +DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV +BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD +7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN +uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW +ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7 +xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f +py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K +gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol +hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ +tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf +BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB +/wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB +ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q +ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua +4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG +E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX +BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn +aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy +PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX +kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C +ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GB CA +=============================== +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG +EwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl +ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw +MzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD +VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds +b2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX +scriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP +rby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk +9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o +Qnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg +GUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI +hvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD +dHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0 +VQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui +HZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic +Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= +-----END CERTIFICATE----- + +SZAFIR ROOT CA2 +=============== +-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG +A1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV +BAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ +BgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD +VQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q +qEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK +DJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE +2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ +ckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi +ieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC +AQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5 +O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67 +oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul +4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6 ++/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw== +-----END CERTIFICATE----- + +Certum Trusted Network CA 2 +=========================== +-----BEGIN CERTIFICATE----- +MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE +BhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1 +bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y +ayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ +TDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB +IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9 +7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o +CgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b +Rr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p +uTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130 +GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ +9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB +Rgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye +hizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM +BhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI +hvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW +Al45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA +L55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo +clm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM +pkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb +w3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo +J/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm +ypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX +is7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7 +zAYspsbiDrW5viSP +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions RootCA 2015 +======================================================= +-----BEGIN CERTIFICATE----- +MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT +BkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0 +aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl +YXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx +MTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg +QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV +BAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw +MTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv +bTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh +iGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+ +6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd +FPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr +i5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F +GQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2 +fu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu +iNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc +Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI +hvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+ +D1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM +d/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y +d+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn +82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb +davYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F +Jej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt +J94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa +JI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q +p/UsQu0yrbYhnr68 +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions ECC RootCA 2015 +=========================================================== +-----BEGIN CERTIFICATE----- +MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0 +aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u +cyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj +aCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw +MzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj +IEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD +VQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290 +Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP +dJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK +Vlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O +BBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA +GiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn +dc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR +-----END CERTIFICATE----- + +ISRG Root X1 +============ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE +BhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD +EwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG +EwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT +DElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r +Vygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1 +3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K +b4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN +Aymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ +4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf +1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu +hjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH +usEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r +OPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G +A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY +9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV +0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt +hDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw +TdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx +e5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA +JzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD +YVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n +JEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ +m+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- + +AC RAIZ FNMT-RCM +================ +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNVBAYT +AkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTAeFw0wODEw +MjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJD +TTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBALpxgHpMhm5/yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcf +qQgfBBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAzWHFctPVr +btQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxFtBDXaEAUwED653cXeuYL +j2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z374jNUUeAlz+taibmSXaXvMiwzn15Cou +08YfxGyqxRxqAQVKL9LFwag0Jl1mpdICIfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mw +WsXmo8RZZUc1g16p6DULmbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnT +tOmlcYF7wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peSMKGJ +47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2ZSysV4999AeU14EC +ll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMetUqIJ5G+GR4of6ygnXYMgrwTJbFaa +i0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FPd9xf3E6Jobd2Sn9R2gzL+HYJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1o +dHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD +nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1RXxlDPiyN8+s +D8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYMLVN0V2Ue1bLdI4E7pWYjJ2cJ +j+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrT +Qfv6MooqtyuGC2mDOL7Nii4LcK2NJpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW ++YJF1DngoABd15jmfZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7 +Ixjp6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp1txyM/1d +8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B9kiABdcPUXmsEKvU7ANm +5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wokRqEIr9baRRmW1FMdW4R58MD3R++Lj8UG +rp1MYp3/RgT408m2ECVAdf4WqslKYIYvuu8wd+RU4riEmViAqhOLUTpPSPaLtrM= +-----END CERTIFICATE----- + +Amazon Root CA 1 +================ +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD +VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1 +MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv +bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH +FzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ +gLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t +dHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce +VOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3 +DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM +CCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy +8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa +2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2 +xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE----- + +Amazon Root CA 2 +================ +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD +VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1 +MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv +bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4 +kHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp +N+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9 +AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd +fLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx +kv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS +btqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0 +Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN +c/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf+ +3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw +DPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA +A7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY ++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE +YFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW +xkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ +gj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW +aQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV +Yh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3 +KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi +JUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw= +-----END CERTIFICATE----- + +Amazon Root CA 3 +================ +-----BEGIN CERTIFICATE----- +MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG +EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy +NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ +MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB +f8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr +Zt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43 +rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc +eGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw== +-----END CERTIFICATE----- + +Amazon Root CA 4 +================ +-----BEGIN CERTIFICATE----- +MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG +EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy +NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ +MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN +/sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri +83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA +MGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1 +AE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA== +-----END CERTIFICATE----- + +TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 +============================================= +-----BEGIN CERTIFICATE----- +MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIxGDAWBgNVBAcT +D0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxpbXNlbCB2ZSBUZWtub2xvamlr +IEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0wKwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24g +TWVya2V6aSAtIEthbXUgU00xNjA0BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRp +ZmlrYXNpIC0gU3VydW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYD +VQQGEwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXllIEJpbGlt +c2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklUQUsxLTArBgNVBAsTJEth +bXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBTTTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11 +IFNNIFNTTCBLb2sgU2VydGlmaWthc2kgLSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAr3UwM6q7a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y8 +6Ij5iySrLqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INrN3wc +wv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2XYacQuFWQfw4tJzh0 +3+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/iSIzL+aFCr2lqBs23tPcLG07xxO9 +WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4fAJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQU +ZT/HiobGPN08VFw1+DrtUgxHV8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ +KoZIhvcNAQELBQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh +AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPfIPP54+M638yc +lNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4lzwDGrpDxpa5RXI4s6ehlj2R +e37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0j +q5Rm+K37DwhuJi1/FwcJsoz7UMCflo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= +-----END CERTIFICATE----- + +GDCA TrustAUTH R5 ROOT +====================== +-----BEGIN CERTIFICATE----- +MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCQ04xMjAw +BgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8wHQYDVQQD +DBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVow +YjELMAkGA1UEBhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ +IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJjDp6L3TQs +AlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBjTnnEt1u9ol2x8kECK62p +OqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+uKU49tm7srsHwJ5uu4/Ts765/94Y9cnrr +pftZTqfrlYwiOXnhLQiPzLyRuEH3FMEjqcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ +9Cy5WmYqsBebnh52nUpmMUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQ +xXABZG12ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloPzgsM +R6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3GkL30SgLdTMEZeS1SZ +D2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeCjGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4 +oR24qoAATILnsn8JuLwwoC8N9VKejveSswoAHQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx +9hoh49pwBiFYFIeFd3mqgnkCAwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlR +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg +p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZmDRd9FBUb1Ov9 +H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5COmSdI31R9KrO9b7eGZONn35 +6ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ryL3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd ++PwyvzeG5LuOmCd+uh8W4XAR8gPfJWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQ +HtZa37dG/OaG+svgIHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBD +F8Io2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV09tL7ECQ +8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQXR4EzzffHqhmsYzmIGrv +/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrqT8p+ck0LcIymSLumoRT2+1hEmRSuqguT +aaApJUqlyyvdimYHFngVV3Eb7PVHhPOeMTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== +-----END CERTIFICATE----- + +SSL.com Root Certification Authority RSA +======================================== +-----BEGIN CERTIFICATE----- +MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxDjAM +BgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24x +MTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYw +MjEyMTczOTM5WhcNNDEwMjEyMTczOTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx +EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NM +LmNvbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2RxFdHaxh3a3by/ZPkPQ/C +Fp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aXqhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8 +P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcCC52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/ge +oeOy3ZExqysdBP+lSgQ36YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkp +k8zruFvh/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrFYD3Z +fBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93EJNyAKoFBbZQ+yODJ +gUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVcUS4cK38acijnALXRdMbX5J+tB5O2 +UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi8 +1xtZPCvM8hnIk2snYxnP/Okm+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4s +bE6x/c+cCbqiM+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGVcpNxJK1ok1iOMq8bs3AD/CUr +dIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBcHadm47GUBwwyOabqG7B52B2ccETjit3E+ZUf +ijhDPwGFpUenPUayvOUiaPd7nNgsPgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAsl +u1OJD7OAUN5F7kR/q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjq +erQ0cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jra6x+3uxj +MxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90IH37hVZkLId6Tngr75qNJ +vTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/YK9f1JmzJBjSWFupwWRoyeXkLtoh/D1JI +Pb9s2KJELtFOt3JY04kTlf5Eq/jXixtunLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406y +wKBjYZC6VWg3dGq2ktufoYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NI +WuuA8ShYIc2wBlX7Jz9TkHCpBB5XJ7k= +-----END CERTIFICATE----- + +SSL.com Root Certification Authority ECC +======================================== +-----BEGIN CERTIFICATE----- +MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMCVVMxDjAMBgNV +BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xMTAv +BgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEy +MTgxNDAzWhcNNDEwMjEyMTgxNDAzWjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO +BgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv +bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuBBAAiA2IA +BEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI7Z4INcgn64mMU1jrYor+ +8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPgCemB+vNH06NjMGEwHQYDVR0OBBYEFILR +hXMw5zUE044CkvvlpNHEIejNMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTT +jgKS++Wk0cQh6M0wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCW +e+0F+S8Tkdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+gA0z +5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl +-----END CERTIFICATE----- + +SSL.com EV Root Certification Authority RSA R2 +============================================== +-----BEGIN CERTIFICATE----- +MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAlVTMQ4w +DAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9u +MTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy +MB4XDTE3MDUzMTE4MTQzN1oXDTQyMDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQI +DAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYD +VQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvqM0fNTPl9fb69LT3w23jh +hqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssufOePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7w +cXHswxzpY6IXFJ3vG2fThVUCAtZJycxa4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTO +Zw+oz12WGQvE43LrrdF9HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+ +B6KjBSYRaZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcAb9Zh +CBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQGp8hLH94t2S42Oim +9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQVPWKchjgGAGYS5Fl2WlPAApiiECto +RHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMOpgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+Slm +JuwgUHfbSguPvuUCYHBBXtSuUDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48 ++qvWBkofZ6aYMBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV +HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa49QaAJadz20Zp +qJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBWs47LCp1Jjr+kxJG7ZhcFUZh1 +++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nx +Y/hoLVUE0fKNsKTPvDxeH3jnpaAgcLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2G +guDKBAdRUNf/ktUM79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDz +OFSz/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXtll9ldDz7 +CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEmKf7GUmG6sXP/wwyc5Wxq +lD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKKQbNmC1r7fSOl8hqw/96bg5Qu0T/fkreR +rwU7ZcegbLHNYhLDkBvjJc40vG93drEQw/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1 +hlMYegouCRw2n5H9gooiS9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX +9hwJ1C07mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== +-----END CERTIFICATE----- + +SSL.com EV Root Certification Authority ECC +=========================================== +-----BEGIN CERTIFICATE----- +MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMCVVMxDjAMBgNV +BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNDAy +BgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYw +MjEyMTgxNTIzWhcNNDEwMjEyMTgxNTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx +EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NM +LmNvbSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMAVIbc/R/fALhBYlzccBYy +3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1KthkuWnBaBu2+8KGwytAJKaNjMGEwHQYDVR0O +BBYEFFvKXuXe0oGqzagtZFG22XKbl+ZPMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe +5d7SgarNqC1kUbbZcpuX5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJ +N+vp1RPZytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZgh5Mm +m7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== +-----END CERTIFICATE----- + +GlobalSign Root CA - R6 +======================= +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEgMB4GA1UECxMX +R2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds +b2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQxMjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9i +YWxTaWduIFJvb3QgQ0EgLSBSNjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFs +U2lnbjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQss +grRIxutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1kZguSgMpE +3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxDaNc9PIrFsmbVkJq3MQbF +vuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJwLnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqM +PKq0pPbzlUoSB239jLKJz9CgYXfIWHSw1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+ +azayOeSsJDa38O+2HBNXk7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05O +WgtH8wY2SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/hbguy +CLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4nWUx2OVvq+aWh2IMP +0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpYrZxCRXluDocZXFSxZba/jJvcE+kN +b7gu3GduyYsRtYQUigAZcIN5kZeR1BonvzceMgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQE +AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNV +HSMEGDAWgBSubAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN +nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGtIxg93eFyRJa0 +lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr6155wsTLxDKZmOMNOsIeDjHfrY +BzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLjvUYAGm0CuiVdjaExUd1URhxN25mW7xocBFym +Fe944Hn+Xds+qkxV/ZoVqW/hpvvfcDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr +3TsTjxKM4kEaSHpzoHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB1 +0jZpnOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfspA9MRf/T +uTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+vJJUEeKgDu+6B5dpffItK +oZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+t +JDfLRVpOoERIyNiwmcUVhAn21klJwGW45hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GC CA +=============================== +-----BEGIN CERTIFICATE----- +MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQswCQYDVQQGEwJD +SDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEo +MCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRa +Fw00MjA1MDkwOTU4MzNaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQL +ExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh +bCBSb290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4nieUqjFqdr +VCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4Wp2OQ0jnUsYd4XxiWD1Ab +NTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd +BgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7TrYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0E +AwMDaAAwZQIwJsdpW9zV57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtk +AjEA2zQgMgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 +-----END CERTIFICATE----- + +UCA Global G2 Root +================== +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9MQswCQYDVQQG +EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBHbG9iYWwgRzIgUm9vdDAeFw0x +NjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0xCzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlU +cnVzdDEbMBkGA1UEAwwSVUNBIEdsb2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxeYrb3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmT +oni9kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzmVHqUwCoV +8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/RVogvGjqNO7uCEeBHANBS +h6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDcC/Vkw85DvG1xudLeJ1uK6NjGruFZfc8o +LTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIjtm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/ +R+zvWr9LesGtOxdQXGLYD0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBe +KW4bHAyvj5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6DlNaBa +4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6iIis7nCs+dwp4wwc +OxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznPO6Q0ibd5Ei9Hxeepl2n8pndntd97 +8XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFIHEjMz15DD/pQwIX4wVZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo +5sOASD0Ee/ojL3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 +1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl1qnN3e92mI0A +Ds0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oUb3n09tDh05S60FdRvScFDcH9 +yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LVPtateJLbXDzz2K36uGt/xDYotgIVilQsnLAX +c47QN6MUPJiVAAwpBVueSUmxX8fjy88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHo +jhJi6IjMtX9Gl8CbEGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZk +bxqgDMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI+Vg7RE+x +ygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGyYiGqhkCyLmTTX8jjfhFn +RR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bXUB+K+wb1whnw0A== +-----END CERTIFICATE----- + +UCA Extended Validation Root +============================ +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQG +EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9u +IFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMxMDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8G +A1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrs +iWogD4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvSsPGP2KxF +Rv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aopO2z6+I9tTcg1367r3CTu +eUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dksHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR +59mzLC52LqGj3n5qiAno8geK+LLNEOfic0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH +0mK1lTnj8/FtDw5lhIpjVMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KR +el7sFsLzKuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/TuDv +B0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41Gsx2VYVdWf6/wFlth +WG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs1+lvK9JKBZP8nm9rZ/+I8U6laUpS +NwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQDfwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS +3H5aBZ8eNJr34RQwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL +BQADggIBADaNl8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR +ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQVBcZEhrxH9cM +aVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5c6sq1WnIeJEmMX3ixzDx/BR4 +dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb ++7lsq+KePRXBOy5nAliRn+/4Qh8st2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOW +F3sGPjLtx7dCvHaj2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwi +GpWOvpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2CxR9GUeOc +GMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmxcmtpzyKEC2IPrNkZAJSi +djzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbMfjKaiJUINlK73nZfdklJrX+9ZSCyycEr +dhh2n1ax +-----END CERTIFICATE----- + +Certigna Root CA +================ +-----BEGIN CERTIFICATE----- +MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAwWjELMAkGA1UE +BhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAwMiA0ODE0NjMwODEwMDAzNjEZ +MBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0xMzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjda +MFoxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYz +MDgxMDAwMzYxGTAXBgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sOty3tRQgX +stmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9MCiBtnyN6tMbaLOQdLNyz +KNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPuI9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8 +JXrJhFwLrN1CTivngqIkicuQstDuI7pmTLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16 +XdG+RCYyKfHx9WzMfgIhC59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq +4NYKpkDfePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3YzIoej +wpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWTCo/1VTp2lc5ZmIoJ +lXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1kJWumIWmbat10TWuXekG9qxf5kBdI +jzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp/ +/TBt2dzhauH8XwIDAQABo4IBGjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +HQYDVR0OBBYEFBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of +1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczovL3d3d3cuY2Vy +dGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilodHRwOi8vY3JsLmNlcnRpZ25h +LmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYraHR0cDovL2NybC5kaGlteW90aXMuY29tL2Nl +cnRpZ25hcm9vdGNhLmNybDANBgkqhkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOIt +OoldaDgvUSILSo3L6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxP +TGRGHVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH60BGM+RFq +7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncBlA2c5uk5jR+mUYyZDDl3 +4bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdio2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd +8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS +6Cvu5zHbugRqh5jnxV/vfaci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaY +tlu3zM63Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayhjWZS +aX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw3kAP+HwV96LOPNde +E4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= +-----END CERTIFICATE----- + +emSign Root CA - G1 +=================== +-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJJTjET +MBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl +ZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBHMTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgx +ODMwMDBaMGcxCzAJBgNVBAYTAklOMRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVk +aHJhIFRlY2hub2xvZ2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQzf2N4aLTN +LnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO8oG0x5ZOrRkVUkr+PHB1 +cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aqd7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHW +DV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhMtTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ +6DqS0hdW5TUaQBw+jSztOd9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrH +hQIDAQABo0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQDAgEG +MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31xPaOfG1vR2vjTnGs2 +vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjMwiI/aTvFthUvozXGaCocV685743Q +NcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6dGNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q ++Mri/Tm3R7nrft8EI6/6nAYH6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeih +U80Bv2noWgbyRQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx +iN66zB+Afko= +-----END CERTIFICATE----- + +emSign ECC Root CA - G3 +======================= +-----BEGIN CERTIFICATE----- +MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQGEwJJTjETMBEG +A1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEg +MB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4 +MTgzMDAwWjBrMQswCQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11 +ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g +RzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0WXTsuwYc +58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xySfvalY8L1X44uT6EYGQIr +MgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuBzhccLikenEhjQjAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+D +CBeQyh+KTOgNG3qxrdWBCUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7 +jHvrZQnD+JbNR6iC8hZVdyR+EhCVBCyj +-----END CERTIFICATE----- + +emSign Root CA - C1 +=================== +-----BEGIN CERTIFICATE----- +MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCVVMx +EzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNp +Z24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UE +BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQD +ExNlbVNpZ24gUm9vdCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+up +ufGZBczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZHdPIWoU/ +Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH3DspVpNqs8FqOp099cGX +OFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvHGPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4V +I5b2P/AgNBbeCsbEBEV5f6f9vtKppa+cxSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleooms +lMuoaJuvimUnzYnu3Yy1aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+ +XJGFehiqTbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQAD +ggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87/kOXSTKZEhVb3xEp +/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4kqNPEjE2NuLe/gDEo2APJ62gsIq1 +NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrGYQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9 +wC68AivTxEDkigcxHpvOJpkT+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQ +BmIMMMAVSKeoWXzhriKi4gp6D/piq1JM4fHfyr6DDUI= +-----END CERTIFICATE----- + +emSign ECC Root CA - C3 +======================= +-----BEGIN CERTIFICATE----- +MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQGEwJVUzETMBEG +A1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMxIDAeBgNVBAMTF2VtU2lnbiBF +Q0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UE +BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQD +ExdlbVNpZ24gRUNDIFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd +6bciMK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4OjavtisIGJAnB9 +SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0OBBYEFPtaSNCAIEDyqOkA +B2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gA +MGUCMQC02C8Cif22TGK6Q04ThHK1rt0c3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwU +ZOR8loMRnLDRWmFLpg9J0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== +-----END CERTIFICATE----- + +Hongkong Post Root CA 3 +======================= +-----BEGIN CERTIFICATE----- +MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQELBQAwbzELMAkG +A1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJSG9uZyBLb25nMRYwFAYDVQQK +Ew1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25na29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2 +MDMwMjI5NDZaFw00MjA2MDMwMjI5NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtv +bmcxEjAQBgNVBAcTCUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMX +SG9uZ2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz +iNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFOdem1p+/l6TWZ5Mwc50tf +jTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mIVoBc+L0sPOFMV4i707mV78vH9toxdCim +5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOe +sL4jpNrcyCse2m5FHomY2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj +0mRiikKYvLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+TtbNe/ +JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZbx39ri1UbSsUgYT2u +y1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+l2oBlKN8W4UdKjk60FSh0Tlxnf0h ++bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YKTE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsG +xVd7GYYKecsAyVKvQv83j+GjHno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwID +AQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e +i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEwDQYJKoZIhvcN +AQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG7BJ8dNVI0lkUmcDrudHr9Egw +W62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCkMpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWld +y8joRTnU+kLBEUx3XZL7av9YROXrgZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov ++BS5gLNdTaqX4fnkGMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDc +eqFS3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJmOzj/2ZQw +9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+l6mc1X5VTMbeRRAc6uk7 +nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6cJfTzPV4e0hz5sy229zdcxsshTrD3mUcY +hcErulWuBurQB7Lcq9CClnXO0lD+mefPL5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB +60PZ2Pierc+xYw5F9KBaLJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fq +dBb9HxEGmpv0 +-----END CERTIFICATE----- + +Microsoft ECC Root Certificate Authority 2017 +============================================= +-----BEGIN CERTIFICATE----- +MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV +UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQgRUND +IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4 +MjMxNjA0WjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw +NAYDVQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQ +BgcqhkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZRogPZnZH6 +thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYbhGBKia/teQ87zvH2RPUB +eMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTIy5lycFIM ++Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlf +Xu5gKcs68tvWMoQZP3zVL8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaR +eNtUjGUBiudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= +-----END CERTIFICATE----- + +Microsoft RSA Root Certificate Authority 2017 +============================================= +-----BEGIN CERTIFICATE----- +MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQG +EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQg +UlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIw +NzE4MjMwMDIzWjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u +MTYwNAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZNt9GkMml +7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0ZdDMbRnMlfl7rEqUrQ7e +S0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw7 +1VdyvD/IybLeS2v4I2wDwAW9lcfNcztmgGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+ +dkC0zVJhUXAoP8XFWvLJjEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49F +yGcohJUcaDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaGYaRS +MLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6W6IYZVcSn2i51BVr +lMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4KUGsTuqwPN1q3ErWQgR5WrlcihtnJ +0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH+FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJ +ClTUFLkqqNfs+avNJVgyeY+QW5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZCLgLNFgVZJ8og +6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OCgMNPOsduET/m4xaRhPtthH80 +dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk ++ONVFT24bcMKpBLBaYVu32TxU5nhSnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex +/2kskZGT4d9Mozd2TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDy +AmH3pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGRxpl/j8nW +ZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiAppGWSZI1b7rCoucL5mxAyE +7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKT +c0QWbej09+CVgI+WXTik9KveCjCHk9hNAHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D +5KbvtwEwXlGjefVwaaZBRA+GsCyRxj3qrg+E +-----END CERTIFICATE----- + +e-Szigno Root CA 2017 +===================== +-----BEGIN CERTIFICATE----- +MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNVBAYTAkhVMREw +DwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUt +MjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJvb3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZa +Fw00MjA4MjIxMjA3MDZaMHExCzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UE +CgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3pp +Z25vIFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtvxie+RJCx +s1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+HWyx7xf58etqjYzBhMA8G +A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSHERUI0arBeAyxr87GyZDv +vzAEwDAfBgNVHSMEGDAWgBSHERUI0arBeAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEA +tVfd14pVCzbhhkT61NlojbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxO +svxyqltZ+efcMQ== +-----END CERTIFICATE----- + +certSIGN Root CA G2 +=================== +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNVBAYTAlJPMRQw +EgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjAeFw0xNzAy +MDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJBgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lH +TiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBAMDFdRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05 +N0IwvlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZuIt4Imfk +abBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhpn+Sc8CnTXPnGFiWeI8Mg +wT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKscpc/I1mbySKEwQdPzH/iV8oScLumZfNp +dWO9lfsbl83kqK/20U6o2YpxJM02PbyWxPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91Qqh +ngLjYl/rNUssuHLoPj1PrCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732 +jcZZroiFDsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fxDTvf +95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgyLcsUDFDYg2WD7rlc +z8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6CeWRgKRM+o/1Pcmqr4tTluCRVLERL +iohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1Ud +DgQWBBSCIS1mxteg4BXrzkwJd8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOB +ywaK8SJJ6ejqkX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC +b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQlqiCA2ClV9+BB +/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0OJD7uNGzcgbJceaBxXntC6Z5 +8hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+cNywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5 +BiKDUyUM/FHE5r7iOZULJK2v0ZXkltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklW +atKcsWMy5WHgUyIOpwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tU +Sxfj03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZkPuXaTH4M +NMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE1LlSVHJ7liXMvGnjSG4N +0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MXQRBdJ3NghVdJIgc= +-----END CERTIFICATE----- + +Trustwave Global Certification Authority +======================================== +-----BEGIN CERTIFICATE----- +MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJV +UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2 +ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTAeFw0xNzA4MjMxOTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJV +UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2 +ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALldUShLPDeS0YLOvR29 +zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0XznswuvCAAJWX/NKSqIk4cXGIDtiLK0thAf +LdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4Bq +stTnoApTAbqOl5F2brz81Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9o +WN0EACyW80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotPJqX+ +OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1lRtzuzWniTY+HKE40 +Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfwhI0Vcnyh78zyiGG69Gm7DIwLdVcE +uE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm ++9jaJXLE9gCxInm943xZYkqcBW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqj +ifLJS3tBEW1ntwiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1UdDwEB/wQEAwIB +BjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W0OhUKDtkLSGm+J1WE2pIPU/H +PinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfeuyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0H +ZJDmHvUqoai7PF35owgLEQzxPy0QlG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla +4gt5kNdXElE1GYhBaCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5R +vbbEsLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPTMaCm/zjd +zyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qequ5AvzSxnI9O4fKSTx+O +856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxhVicGaeVyQYHTtgGJoC86cnn+OjC/QezH +Yj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu +3R3y4G5OBVixwJAWKqQ9EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP +29FpHOTKyeC2nOnOcXHebD8WpHk= +-----END CERTIFICATE----- + +Trustwave Global ECC P256 Certification Authority +================================================= +-----BEGIN CERTIFICATE----- +MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYDVQQGEwJVUzER +MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI +b2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy +dXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1 +NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABH77bOYj +43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoNFWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqm +P62jQzBBMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt +0UrrdaVKEJmzsaGLSvcwCgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjz +RM4q3wghDDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 +-----END CERTIFICATE----- + +Trustwave Global ECC P384 Certification Authority +================================================= +-----BEGIN CERTIFICATE----- +MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYDVQQGEwJVUzER +MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI +b2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy +dXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4 +NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuBBAAiA2IABGvaDXU1CDFH +Ba5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJj9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr +/TklZvFe/oyujUF5nQlgziip04pt89ZF1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNV +HQ8BAf8EBQMDBwYAMB0GA1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNn +ADBkAjA3AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsCMGcl +CrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVuSw== +-----END CERTIFICATE----- + +NAVER Global Root Certification Authority +========================================= +-----BEGIN CERTIFICATE----- +MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEMBQAwaTELMAkG +A1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRGT1JNIENvcnAuMTIwMAYDVQQD +DClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4 +NDJaFw0zNzA4MTgyMzU5NTlaMGkxCzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVT +UyBQTEFURk9STSBDb3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVAiQqrDZBb +UGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH38dq6SZeWYp34+hInDEW ++j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lEHoSTGEq0n+USZGnQJoViAbbJAh2+g1G7 +XNr4rRVqmfeSVPc0W+m/6imBEtRTkZazkVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2 +aacp+yPOiNgSnABIqKYPszuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4 +Yb8ObtoqvC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHfnZ3z +VHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaGYQ5fG8Ir4ozVu53B +A0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo0es+nPxdGoMuK8u180SdOqcXYZai +cdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3aCJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejy +YhbLgGvtPe31HzClrkvJE+2KAQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNV +HQ4EFgQU0p+I36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB +Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoNqo0hV4/GPnrK +21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatjcu3cvuzHV+YwIHHW1xDBE1UB +jCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm+LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bx +hYTeodoS76TiEJd6eN4MUZeoIUCLhr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTg +E34h5prCy8VCZLQelHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTH +D8z7p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8piKCk5XQ +A76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLRLBT/DShycpWbXgnbiUSY +qqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oG +I/hGoiLtk/bdmuYqh7GYVPEi92tF4+KOdh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmg +kpzNNIaRkPpkUZ3+/uul9XXeifdy +-----END CERTIFICATE----- + +AC RAIZ FNMT-RCM SERVIDORES SEGUROS +=================================== +-----BEGIN CERTIFICATE----- +MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQswCQYDVQQGEwJF +UzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgwFgYDVQRhDA9WQVRFUy1RMjgy +NjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1SQ00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4 +MTIyMDA5MzczM1oXDTQzMTIyMDA5MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQt +UkNNMQ4wDAYDVQQLDAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNB +QyBSQUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuBBAAiA2IA +BPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LHsbI6GA60XYyzZl2hNPk2 +LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oKUm8BA06Oi6NCMEAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqG +SM49BAMDA2kAMGYCMQCuSuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoD +zBOQn5ICMQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJyv+c= +-----END CERTIFICATE----- + +GlobalSign Root R46 +=================== +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUAMEYxCzAJBgNV +BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJv +b3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAX +BgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08Es +CVeJOaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQGvGIFAha/ +r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud316HCkD7rRlr+/fKYIje +2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo0q3v84RLHIf8E6M6cqJaESvWJ3En7YEt +bWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSEy132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvj +K8Cd+RTyG/FWaha/LIWFzXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD4 +12lPFzYE+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCNI/on +ccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzsx2sZy/N78CsHpdls +eVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqaByFrgY/bxFn63iLABJzjqls2k+g9 +vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEM +BQADggIBAHx47PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg +JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti2kM3S+LGteWy +gxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIkpnnpHs6i58FZFZ8d4kuaPp92 +CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRFFRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZm +OUdkLG5NrmJ7v2B0GbhWrJKsFjLtrWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qq +JZ4d16GLuc1CLgSkZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwye +qiv5u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP4vkYxboz +nxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6N3ec592kD3ZDZopD8p/7 +DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3vouXsXgxT7PntgMTzlSdriVZzH81Xwj3 +QEUxeCp6 +-----END CERTIFICATE----- + +GlobalSign Root E46 +=================== +-----BEGIN CERTIFICATE----- +MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYxCzAJBgNVBAYT +AkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJvb3Qg +RTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNV +BAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkB +jtjqR+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGddyXqBPCCj +QjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQxCpCPtsad0kRL +gLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZk +vLtoURMMA/cVi4RguYv/Uo7njLwcAjA8+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+ +CAezNIm8BZ/3Hobui3A= +-----END CERTIFICATE----- + +GLOBALTRUST 2020 +================ +-----BEGIN CERTIFICATE----- +MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkGA1UEBhMCQVQx +IzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVT +VCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYxMDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAh +BgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAy +MDIwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWi +D59bRatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9ZYybNpyrO +VPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3QWPKzv9pj2gOlTblzLmM +CcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPwyJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCm +fecqQjuCgGOlYx8ZzHyyZqjC0203b+J+BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKA +A1GqtH6qRNdDYfOiaxaJSaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9OR +JitHHmkHr96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj04KlG +DfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9MedKZssCz3AwyIDMvU +clOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIwq7ejMZdnrY8XD2zHc+0klGvIg5rQ +mjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1Ud +IwQYMBaAFNwuH9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA +VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJCXtzoRlgHNQIw +4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd6IwPS3BD0IL/qMy/pJTAvoe9 +iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf+I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS +8cE54+X1+NZK3TTN+2/BT+MAi1bikvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2 +HcqtbepBEX4tdJP7wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxS +vTOBTI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6CMUO+1918 +oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn4rnvyOL2NSl6dPrFf4IF +YqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+IaFvowdlxfv1k7/9nR4hYJS8+hge9+6jl +gqispdNpQ80xiEmEU5LAsTkbOYMBMMTyqfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== +-----END CERTIFICATE----- + +ANF Secure Server Root CA +========================= +-----BEGIN CERTIFICATE----- +MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNVBAUTCUc2MzI4 +NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lv +bjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNVBAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3Qg +Q0EwHhcNMTkwOTA0MTAwMDM4WhcNMzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEw +MQswCQYDVQQGEwJFUzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQw +EgYDVQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9vdCBDQTCC +AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCjcqQZAZ2cC4Ffc0m6p6zz +BE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9qyGFOtibBTI3/TO80sh9l2Ll49a2pcbnv +T1gdpd50IJeh7WhM3pIXS7yr/2WanvtH2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcv +B2VSAKduyK9o7PQUlrZXH1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXse +zx76W0OLzc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyRp1RM +VwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQzW7i1o0TJrH93PB0j +7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/SiOL9V8BY9KHcyi1Swr1+KuCLH5z +JTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJnLNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe +8TZBAQIvfXOn3kLMTOmJDVb3n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVO +Hj1tyRRM4y5Bu8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj +o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAOBgNVHQ8BAf8E +BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEATh65isagmD9uw2nAalxJ +UqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzx +j6ptBZNscsdW699QIyjlRRA96Gejrw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDt +dD+4E5UGUcjohybKpFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM +5gf0vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjqOknkJjCb +5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ/zo1PqVUSlJZS2Db7v54 +EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ92zg/LFis6ELhDtjTO0wugumDLmsx2d1H +hk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI+PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGy +g77FGr8H6lnco4g175x2MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3 +r5+qPeoott7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw= +-----END CERTIFICATE----- + +Certum EC-384 CA +================ +-----BEGIN CERTIFICATE----- +MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQswCQYDVQQGEwJQ +TDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2 +MDcyNDU0WhcNNDMwMzI2MDcyNDU0WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERh +dGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx +GTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATEKI6rGFtq +vm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7TmFy8as10CW4kjPMIRBSqn +iBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68KjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFI0GZnQkdjrzife81r1HfS+8EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNo +ADBlAjADVS2m5hjEfO/JUG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0 +QoSZ/6vnnvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= +-----END CERTIFICATE----- + +Certum Trusted Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6MQswCQYDVQQG +EwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0g +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0Ew +HhcNMTgwMzE2MTIxMDEzWhcNNDMwMzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMY +QXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZn0EGze2jusDbCSzBfN8p +fktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/qp1x4EaTByIVcJdPTsuclzxFUl6s1wB52 +HO8AU5853BSlLCIls3Jy/I2z5T4IHhQqNwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2 +fJmItdUDmj0VDT06qKhF8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGt +g/BKEiJ3HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGamqi4 +NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi7VdNIuJGmj8PkTQk +fVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSFytKAQd8FqKPVhJBPC/PgP5sZ0jeJ +P/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0PqafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSY +njYJdmZm/Bo/6khUHL4wvYBQv3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHK +HRzQ+8S1h9E6Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1 +vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQADggIBAEii1QAL +LtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4WxmB82M+w85bj/UvXgF2Ez8s +ALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvozMrnadyHncI013nR03e4qllY/p0m+jiGPp2K +h2RX5Rc64vmNueMzeMGQ2Ljdt4NR5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8 +CYyqOhNf6DR5UMEQGfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA +4kZf5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq0Uc9Nneo +WWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7DP78v3DSk+yshzWePS/Tj +6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTMqJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmT +OPQD8rv7gmsHINFSH5pkAnuYZttcTVoP0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZck +bxJF0WddCajJFdr60qZfE2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb +-----END CERTIFICATE----- + +TunTrust Root CA +================ +-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQELBQAwYTELMAkG +A1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUgQ2VydGlmaWNhdGlvbiBFbGVj +dHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJvb3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQw +NDI2MDg1NzU2WjBhMQswCQYDVQQGEwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBD +ZXJ0aWZpY2F0aW9uIEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZn56eY+hz +2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd2JQDoOw05TDENX37Jk0b +bjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgFVwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7 +NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZGoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAd +gjH8KcwAWJeRTIAAHDOFli/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViW +VSHbhlnUr8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2eY8f +Tpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIbMlEsPvLfe/ZdeikZ +juXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISgjwBUFfyRbVinljvrS5YnzWuioYas +DXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwS +VXAkPcvCFDVDXSdOvsC9qnyW5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI +04Y+oXNZtPdEITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0 +90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+zxiD2BkewhpMl +0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYuQEkHDVneixCwSQXi/5E/S7fd +Ao74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRY +YdZ2vyJ/0Adqp2RT8JeNnYA/u8EH22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJp +adbGNjHh/PqAulxPxOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65x +xBzndFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5Xc0yGYuP +jCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7bnV2UqL1g52KAdoGDDIzM +MEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQCvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9z +ZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZHu/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3r +AZ3r2OvEhJn7wAzMMujjd9qDRIueVSjAi1jTkD5OGwDxFa2DK5o= +-----END CERTIFICATE----- + +HARICA TLS RSA Root CA 2021 +=========================== +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQG +EwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u +cyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0EgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUz +OFoXDTQ1MDIxMzEwNTUzN1owbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRl +bWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNB +IFJvb3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569lmwVnlskN +JLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE4VGC/6zStGndLuwRo0Xu +a2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uva9of08WRiFukiZLRgeaMOVig1mlDqa2Y +Ulhu2wr7a89o+uOkXjpFc5gH6l8Cct4MpbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K +5FrZx40d/JiZ+yykgmvwKh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEv +dmn8kN3bLW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcYAuUR +0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqBAGMUuTNe3QvboEUH +GjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYqE613TBoYm5EPWNgGVMWX+Ko/IIqm +haZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHrW2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQ +CPxrvrNQKlr9qEgYRtaQQJKQCoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8G +A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAUX15QvWiWkKQU +EapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3f5Z2EMVGpdAgS1D0NTsY9FVq +QRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxajaH6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxD +QpSbIPDRzbLrLFPCU3hKTwSUQZqPJzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcR +j88YxeMn/ibvBZ3PzzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5 +vZStjBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0/L5H9MG0 +qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pTBGIBnfHAT+7hOtSLIBD6 +Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79aPib8qXPMThcFarmlwDB31qlpzmq6YR/ +PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YWxw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnn +kf3/W9b3raYvAwtt41dU63ZTGI0RmLo= +-----END CERTIFICATE----- + +HARICA TLS ECC Root CA 2021 +=========================== +-----BEGIN CERTIFICATE----- +MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQswCQYDVQQGEwJH +UjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBD +QTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoX +DTQ1MDIxMzExMDEwOVowbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWlj +IGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJv +b3QgQ0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7KKrxcm1l +AEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9YSTHMmE5gEYd103KUkE+b +ECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW +0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAi +rcJRQO9gcS3ujwLEXQNwSaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/Qw +CZ61IygNnxS2PFOiTAZpffpskcYqSUXm7LcT4Tps +-----END CERTIFICATE----- + +Autoridad de Certificacion Firmaprofesional CIF A62634068 +========================================================= +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCRVMxQjBA +BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 +MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIw +QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB +NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD +Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P +B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY +7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH +ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI +plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX +MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX +LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK +bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU +vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1Ud +DgQWBBRlzeurNR4APn7VdMActHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4w +gZswgZgGBFUdIAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j +b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABCAG8AbgBhAG4A +bwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAwADEANzAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9miWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL +4QjbEwj4KKE1soCzC1HA01aajTNFSa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDb +LIpgD7dvlAceHabJhfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1il +I45PVf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZEEAEeiGaP +cjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV1aUsIC+nmCjuRfzxuIgA +LI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2tCsvMo2ebKHTEm9caPARYpoKdrcd7b/+A +lun4jWq9GJAd/0kakFI3ky88Al2CdgtR5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH +9IBk9W6VULgRfhVwOEqwf9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpf +NIbnYrX9ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNKGbqE +ZycPvEJdvSRUDewdcAZfpLz6IHxV +-----END CERTIFICATE----- + +vTrus ECC Root CA +================= +-----BEGIN CERTIFICATE----- +MIICDzCCAZWgAwIBAgIUbmq8WapTvpg5Z6LSa6Q75m0c1towCgYIKoZIzj0EAwMwRzELMAkGA1UE +BhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBS +b290IENBMB4XDTE4MDczMTA3MjY0NFoXDTQzMDczMTA3MjY0NFowRzELMAkGA1UEBhMCQ04xHDAa +BgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBSb290IENBMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEZVBKrox5lkqqHAjDo6LN/llWQXf9JpRCux3NCNtzslt188+c +ToL0v/hhJoVs1oVbcnDS/dtitN9Ti72xRFhiQgnH+n9bEOf+QP3A2MMrMudwpremIFUde4BdS49n +TPEQo0IwQDAdBgNVHQ4EFgQUmDnNvtiyjPeyq+GtJK97fKHbH88wDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIwV53dVvHH4+m4SVBrm2nDb+zDfSXkV5UT +QJtS0zvzQBm8JsctBp61ezaf9SXUY2sAAjEA6dPGnlaaKsyh2j/IZivTWJwghfqrkYpwcBE4YGQL +YgmRWAD5Tfs0aNoJrSEGGJTO +-----END CERTIFICATE----- + +vTrus Root CA +============= +-----BEGIN CERTIFICATE----- +MIIFVjCCAz6gAwIBAgIUQ+NxE9izWRRdt86M/TX9b7wFjUUwDQYJKoZIhvcNAQELBQAwQzELMAkG +A1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xFjAUBgNVBAMTDXZUcnVzIFJv +b3QgQ0EwHhcNMTgwNzMxMDcyNDA1WhcNNDMwNzMxMDcyNDA1WjBDMQswCQYDVQQGEwJDTjEcMBoG +A1UEChMTaVRydXNDaGluYSBDby4sTHRkLjEWMBQGA1UEAxMNdlRydXMgUm9vdCBDQTCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAL1VfGHTuB0EYgWgrmy3cLRB6ksDXhA/kFocizuwZots +SKYcIrrVQJLuM7IjWcmOvFjai57QGfIvWcaMY1q6n6MLsLOaXLoRuBLpDLvPbmyAhykUAyyNJJrI +ZIO1aqwTLDPxn9wsYTwaP3BVm60AUn/PBLn+NvqcwBauYv6WTEN+VRS+GrPSbcKvdmaVayqwlHeF +XgQPYh1jdfdr58tbmnDsPmcF8P4HCIDPKNsFxhQnL4Z98Cfe/+Z+M0jnCx5Y0ScrUw5XSmXX+6KA +YPxMvDVTAWqXcoKv8R1w6Jz1717CbMdHflqUhSZNO7rrTOiwCcJlwp2dCZtOtZcFrPUGoPc2BX70 +kLJrxLT5ZOrpGgrIDajtJ8nU57O5q4IikCc9Kuh8kO+8T/3iCiSn3mUkpF3qwHYw03dQ+A0Em5Q2 +AXPKBlim0zvc+gRGE1WKyURHuFE5Gi7oNOJ5y1lKCn+8pu8fA2dqWSslYpPZUxlmPCdiKYZNpGvu +/9ROutW04o5IWgAZCfEF2c6Rsffr6TlP9m8EQ5pV9T4FFL2/s1m02I4zhKOQUqqzApVg+QxMaPnu +1RcN+HFXtSXkKe5lXa/R7jwXC1pDxaWG6iSe4gUH3DRCEpHWOXSuTEGC2/KmSNGzm/MzqvOmwMVO +9fSddmPmAsYiS8GVP1BkLFTltvA8Kc9XAgMBAAGjQjBAMB0GA1UdDgQWBBRUYnBj8XWEQ1iO0RYg +scasGrz2iTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOC +AgEAKbqSSaet8PFww+SX8J+pJdVrnjT+5hpk9jprUrIQeBqfTNqK2uwcN1LgQkv7bHbKJAs5EhWd +nxEt/Hlk3ODg9d3gV8mlsnZwUKT+twpw1aA08XXXTUm6EdGz2OyC/+sOxL9kLX1jbhd47F18iMjr +jld22VkE+rxSH0Ws8HqA7Oxvdq6R2xCOBNyS36D25q5J08FsEhvMKar5CKXiNxTKsbhm7xqC5PD4 +8acWabfbqWE8n/Uxy+QARsIvdLGx14HuqCaVvIivTDUHKgLKeBRtRytAVunLKmChZwOgzoy8sHJn +xDHO2zTlJQNgJXtxmOTAGytfdELSS8VZCAeHvsXDf+eW2eHcKJfWjwXj9ZtOyh1QRwVTsMo554Wg +icEFOwE30z9J4nfrI8iIZjs9OXYhRvHsXyO466JmdXTBQPfYaJqT4i2pLr0cox7IdMakLXogqzu4 +sEb9b91fUlV1YvCXoHzXOP0l382gmxDPi7g4Xl7FtKYCNqEeXxzP4padKar9mK5S4fNBUvupLnKW +nyfjqnN9+BojZns7q2WwMgFLFT49ok8MKzWixtlnEjUwzXYuFrOZnk1PTi07NEPhmg4NpGaXutIc +SkwsKouLgU9xGqndXHt7CMUADTdA43x7VF8vhV929vensBxXVsFy6K2ir40zSbofitzmdHxghm+H +l3s= +-----END CERTIFICATE----- + +ISRG Root X2 +============ +-----BEGIN CERTIFICATE----- +MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQswCQYDVQQGEwJV +UzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElT +UkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVT +MSkwJwYDVQQKEyBJbnRlcm5ldCBTZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNS +RyBSb290IFgyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0H +ttwW+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9ItgKbppb +d9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZIzj0EAwMDaAAwZQIwe3lORlCEwkSHRhtF +cP9Ymd70/aTSVaYgLXTWNLxBo1BfASdWtL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5 +U6VR5CmD1/iQMVtCnwr1/q4AaOeMSQ+2b1tbFfLn +-----END CERTIFICATE----- + +HiPKI Root CA - G1 +================== +-----BEGIN CERTIFICATE----- +MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQG +EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xGzAZBgNVBAMMEkhpUEtJ +IFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRaFw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYT +AlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kg +Um9vdCBDQSAtIEcxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0 +o9QwqNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twvVcg3Px+k +wJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6lZgRZq2XNdZ1AYDgr/SE +YYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnzQs7ZngyzsHeXZJzA9KMuH5UHsBffMNsA +GJZMoYFL3QRtU6M9/Aes1MU3guvklQgZKILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfd +hSi8MEyr48KxRURHH+CKFgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj +1jOXTyFjHluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDry+K4 +9a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ/W3c1pzAtH2lsN0/ +Vm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgMa/aOEmem8rJY5AIJEzypuxC00jBF +8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQD +AgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi +7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqcSE5XCV0vrPSl +tJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6FzaZsT0pPBWGTMpWmWSBUdGSquE +wx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9TcXzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07Q +JNBAsNB1CI69aO4I1258EHBGG3zgiLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv +5wiZqAxeJoBF1PhoL5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+Gpz +jLrFNe85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wrkkVbbiVg +hUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+vhV4nYWBSipX3tUZQ9rb +yltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQUYDksswBVLuT1sw5XxJFBAJw/6KXf6vb/ +yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ== +-----END CERTIFICATE----- + +GlobalSign ECC Root CA - R4 +=========================== +-----BEGIN CERTIFICATE----- +MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYDVQQLExtHbG9i +YWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds +b2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgwMTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9i +YWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds +b2JhbFNpZ24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkW +ymOxuYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNVHQ8BAf8E +BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/+wpu+74zyTyjhNUwCgYI +KoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147bmF0774BxL4YSFlhgjICICadVGNA3jdg +UM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm +-----END CERTIFICATE----- + +GTS Root R1 +=========== +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQGEwJV +UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg +UjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE +ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM +f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7wCl7raKb0 +xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjwTcLCeoiKu7rPWRnWr4+w +B7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0PfyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXW +nOunVmSPlk9orj2XwoSPwLxAwAtcvfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk +9+aCEI3oncKKiPo4Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zq +kUspzBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92wO1A +K/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70paDPvOmbsB4om3xPX +V2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDW +cfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQAD +ggIBAJ+qQibbC5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe +QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuyh6f88/qBVRRi +ClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM47HLwEXWdyzRSjeZ2axfG34ar +J45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8JZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYci +NuaCp+0KueIHoI17eko8cdLiA6EfMgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5me +LMFrUKTX5hgUvYU/Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJF +fbdT6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ0E6yove+ +7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm2tIMPNuzjsmhDYAPexZ3 +FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bbbP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3 +gm3c +-----END CERTIFICATE----- + +GTS Root R2 +=========== +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQGEwJV +UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg +UjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE +ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv +CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY6Dlo7JUl +e3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAuMC6C/Pq8tBcKSOWIm8Wb +a96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS ++LFjKBC4swm4VndAoiaYecb+3yXuPuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7M +kogwTZq9TwtImoS1mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJG +r61K8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RWIr9q +S34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKaG73VululycslaVNV +J1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCqgc7dGtxRcw1PcOnlthYhGXmy5okL +dWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQAD +ggIBAB/Kzt3HvqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8 +0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyCB19m3H0Q/gxh +swWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2uNmSRXbBoGOqKYcl3qJfEycel +/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMgyALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVn +jWQye+mew4K6Ki3pHrTgSAai/GevHyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y5 +9PYjJbigapordwj6xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M +7YNRTOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924SgJPFI/2R8 +0L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV7LXTWtiBmelDGDfrs7vR +WGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjW +HYbL +-----END CERTIFICATE----- + +GTS Root R3 +=========== +-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJVUzEi +MCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMw +HhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZ +R29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjO +PQIBBgUrgQQAIgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout +736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL24CejQjBA +MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTB8Sa6oC2uhYHP0/Eq +Er24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azT +L818+FsuVbu/3ZL3pAzcMeGiAjEA/JdmZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV +11RZt+cRLInUue4X +-----END CERTIFICATE----- + +GTS Root R4 +=========== +-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJVUzEi +MCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQw +HhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZ +R29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjO +PQIBBgUrgQQAIgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu +hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvRHYqjQjBA +MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSATNbrdP9JNqPV2Py1 +PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/C +r8deVl5c1RxYIigL9zC2L7F8AjEA8GE8p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh +4rsUecrNIdSUtUlD +-----END CERTIFICATE----- + +Telia Root CA v2 +================ +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQxCzAJBgNVBAYT +AkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2 +MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQK +DBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZI +hvcNAQEBBQADggIPADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ7 +6zBqAMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9vVYiQJ3q +9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9lRdU2HhE8Qx3FZLgmEKn +pNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTODn3WhUidhOPFZPY5Q4L15POdslv5e2QJl +tI5c0BE0312/UqeBAMN/mUWZFdUXyApT7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW +5olWK8jjfN7j/4nlNW4o6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNr +RBH0pUPCTEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6WT0E +BXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63RDolUK5X6wK0dmBR4 +M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZIpEYslOqodmJHixBTB0hXbOKSTbau +BcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGjYzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7W +xy+G2CQ5MB0GA1UdDgQWBBRyrOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ +8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi0f6X+J8wfBj5 +tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMMA8iZGok1GTzTyVR8qPAs5m4H +eW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBSSRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+C +y748fdHif64W1lZYudogsYMVoe+KTTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygC +QMez2P2ccGrGKMOF6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15 +h2Er3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMtTy3EHD70 +sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pTVmBds9hCG1xLEooc6+t9 +xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAWysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQ +raVplI/owd8k+BsHMYeB2F326CjYSlKArBPuUBQemMc= +-----END CERTIFICATE----- + +D-TRUST BR Root CA 1 2020 +========================= +-----BEGIN CERTIFICATE----- +MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE +RTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEJSIFJvb3QgQ0EgMSAy +MDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNV +BAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7 +dPYSzuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0QVK5buXu +QqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/VbNafAkl1bK6CKBrqx9t +MA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu +bmV0L2NybC9kLXRydXN0X2JyX3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj +dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP +PUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD +AwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFWwKrY7RjEsK70Pvom +AjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHVdWNbFJWcHwHP2NVypw87 +-----END CERTIFICATE----- + +D-TRUST EV Root CA 1 2020 +========================= +-----BEGIN CERTIFICATE----- +MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE +RTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEVWIFJvb3QgQ0EgMSAy +MDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNV +BAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8 +ZRCC/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rDwpdhQntJ +raOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3OqQo5FD4pPfsazK2/umL +MA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu +bmV0L2NybC9kLXRydXN0X2V2X3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj +dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP +PUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD +AwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CAy/m0sRtW9XLS/BnR +AjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJbgfM0agPnIjhQW+0ZT0MW +-----END CERTIFICATE----- + +DigiCert TLS ECC P384 Root G5 +============================= +-----BEGIN CERTIFICATE----- +MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURpZ2lDZXJ0IFRMUyBFQ0MgUDM4 +NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQg +Um9vdCBHNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1Tzvd +lHJS7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp0zVozptj +n4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICISB4CIfBFqMA4GA1UdDwEB +/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQCJao1H5+z8blUD2Wds +Jk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQLgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIx +AJSdYsiJvRmEFOml+wG4DXZDjC5Ty3zfDBeWUA== +-----END CERTIFICATE----- + +DigiCert TLS RSA4096 Root G5 +============================ +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBNMQswCQYDVQQG +EwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0 +MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcNNDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2 +IFJvb3QgRzUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS8 +7IE+ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG02C+JFvuU +AT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgpwgscONyfMXdcvyej/Ces +tyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZMpG2T6T867jp8nVid9E6P/DsjyG244gXa +zOvswzH016cpVIDPRFtMbzCe88zdH5RDnU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnV +DdXifBBiqmvwPXbzP6PosMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9q +TXeXAaDxZre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cdLvvy +z6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvXKyY//SovcfXWJL5/ +MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNeXoVPzthwiHvOAbWWl9fNff2C+MIk +wcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPLtgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4E +FgQUUTMc7TZArxfTJc1paPKvTiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8w +DQYJKoZIhvcNAQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw +GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7HPNtQOa27PShN +lnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLFO4uJ+DQtpBflF+aZfTCIITfN +MBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQREtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/ +u4cnYiWB39yhL/btp/96j1EuMPikAdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9G +OUrYU9DzLjtxpdRv/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh +47a+p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilwMUc/dNAU +FvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WFqUITVuwhd4GTWgzqltlJ +yqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCKovfepEWFJqgejF0pW8hL2JpqA15w8oVP +bEtoL8pU9ozaMv7Da4M/OMZ+ +-----END CERTIFICATE----- + +Certainly Root R1 +================= +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAwPTELMAkGA1UE +BhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2VydGFpbmx5IFJvb3QgUjEwHhcN +MjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2Vy +dGFpbmx5MRowGAYDVQQDExFDZXJ0YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBANA21B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O +5MQTvqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbedaFySpvXl +8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b01C7jcvk2xusVtyWMOvwl +DbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGI +XsXwClTNSaa/ApzSRKft43jvRl5tcdF5cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkN +KPl6I7ENPT2a/Z2B7yyQwHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQ +AjeZjOVJ6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA2Cnb +rlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyHWyf5QBGenDPBt+U1 +VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMReiFPCyEQtkA6qyI6BJyLm4SGcprS +p6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBTgqj8ljZ9EXME66C6ud0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAsz +HQNTVfSVcOQrPbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d +8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi1wrykXprOQ4v +MMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrdrRT90+7iIgXr0PK3aBLXWopB +GsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9ditaY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+ +gjwN/KUD+nsa2UUeYNrEjvn8K8l7lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgH +JBu6haEaBQmAupVjyTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7 +fpYnKx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLyyCwzk5Iw +x06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5nwXARPbv0+Em34yaXOp/S +X3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6OV+KmalBWQewLK8= +-----END CERTIFICATE----- + +Certainly Root E1 +================= +-----BEGIN CERTIFICATE----- +MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQswCQYDVQQGEwJV +UzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlubHkgUm9vdCBFMTAeFw0yMTA0 +MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJBgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlu +bHkxGjAYBgNVBAMTEUNlcnRhaW5seSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4 +fxzf7flHh4axpMCK+IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9 +YBk2QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4hevIIgcwCgYIKoZIzj0E +AwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozmut6Dacpps6kFtZaSF4fC0urQe87YQVt8 +rgIwRt7qy12a7DLCZRawTDBcMPPaTnOGBtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR +-----END CERTIFICATE----- + +Security Communication ECC RootCA1 +================================== +-----BEGIN CERTIFICATE----- +MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYTAkpQMSUwIwYD +VQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYDVQQDEyJTZWN1cml0eSBDb21t +dW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYxNjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTEL +MAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNV +BAMTIlNlY3VyaXR5IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+CnnfdldB9sELLo +5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpKULGjQjBAMB0GA1UdDgQW +BBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAK +BggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3L +snNdo4gIxwwCMQDAqy0Obe0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70e +N9k= +-----END CERTIFICATE----- + +BJCA Global Root CA1 +==================== +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIQVW9l47TZkGobCdFsPsBsIDANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQG +EwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJVFkxHTAbBgNVBAMMFEJK +Q0EgR2xvYmFsIFJvb3QgQ0ExMB4XDTE5MTIxOTAzMTYxN1oXDTQ0MTIxMjAzMTYxN1owVDELMAkG +A1UEBhMCQ04xJjAkBgNVBAoMHUJFSUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQD +DBRCSkNBIEdsb2JhbCBSb290IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPFm +CL3ZxRVhy4QEQaVpN3cdwbB7+sN3SJATcmTRuHyQNZ0YeYjjlwE8R4HyDqKYDZ4/N+AZspDyRhyS +sTphzvq3Rp4Dhtczbu33RYx2N95ulpH3134rhxfVizXuhJFyV9xgw8O558dnJCNPYwpj9mZ9S1Wn +P3hkSWkSl+BMDdMJoDIwOvqfwPKcxRIqLhy1BDPapDgRat7GGPZHOiJBhyL8xIkoVNiMpTAK+BcW +yqw3/XmnkRd4OJmtWO2y3syJfQOcs4ll5+M7sSKGjwZteAf9kRJ/sGsciQ35uMt0WwfCyPQ10WRj +eulumijWML3mG90Vr4TqnMfK9Q7q8l0ph49pczm+LiRvRSGsxdRpJQaDrXpIhRMsDQa4bHlW/KNn +MoH1V6XKV0Jp6VwkYe/iMBhORJhVb3rCk9gZtt58R4oRTklH2yiUAguUSiz5EtBP6DF+bHq/pj+b +OT0CFqMYs2esWz8sgytnOYFcuX6U1WTdno9uruh8W7TXakdI136z1C2OVnZOz2nxbkRs1CTqjSSh +GL+9V/6pmTW12xB3uD1IutbB5/EjPtffhZ0nPNRAvQoMvfXnjSXWgXSHRtQpdaJCbPdzied9v3pK +H9MiyRVVz99vfFXQpIsHETdfg6YmV6YBW37+WGgHqel62bno/1Afq8K0wM7o6v0PvY1NuLxxAgMB +AAGjQjBAMB0GA1UdDgQWBBTF7+3M2I0hxkjk49cULqcWk+WYATAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAUoKsITQfI/Ki2Pm4rzc2IInRNwPWaZ+4 +YRC6ojGYWUfo0Q0lHhVBDOAqVdVXUsv45Mdpox1NcQJeXyFFYEhcCY5JEMEE3KliawLwQ8hOnThJ +dMkycFRtwUf8jrQ2ntScvd0g1lPJGKm1Vrl2i5VnZu69mP6u775u+2D2/VnGKhs/I0qUJDAnyIm8 +60Qkmss9vk/Ves6OF8tiwdneHg56/0OGNFK8YT88X7vZdrRTvJez/opMEi4r89fO4aL/3Xtw+zuh +TaRjAv04l5U/BXCga99igUOLtFkNSoxUnMW7gZ/NfaXvCyUeOiDbHPwfmGcCCtRzRBPbUYQaVQNW +4AB+dAb/OMRyHdOoP2gxXdMJxy6MW2Pg6Nwe0uxhHvLe5e/2mXZgLR6UcnHGCyoyx5JO1UbXHfmp +GQrI+pXObSOYqgs4rZpWDW+N8TEAiMEXnM0ZNjX+VVOg4DwzX5Ze4jLp3zO7Bkqp2IRzznfSxqxx +4VyjHQy7Ct9f4qNx2No3WqB4K/TUfet27fJhcKVlmtOJNBir+3I+17Q9eVzYH6Eze9mCUAyTF6ps +3MKCuwJXNq+YJyo5UOGwifUll35HaBC07HPKs5fRJNz2YqAo07WjuGS3iGJCz51TzZm+ZGiPTx4S +SPfSKcOYKMryMguTjClPPGAyzQWWYezyr/6zcCwupvI= +-----END CERTIFICATE----- + +BJCA Global Root CA2 +==================== +-----BEGIN CERTIFICATE----- +MIICJTCCAaugAwIBAgIQLBcIfWQqwP6FGFkGz7RK6zAKBggqhkjOPQQDAzBUMQswCQYDVQQGEwJD +TjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJVFkxHTAbBgNVBAMMFEJKQ0Eg +R2xvYmFsIFJvb3QgQ0EyMB4XDTE5MTIxOTAzMTgyMVoXDTQ0MTIxMjAzMTgyMVowVDELMAkGA1UE +BhMCQ04xJjAkBgNVBAoMHUJFSUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRC +SkNBIEdsb2JhbCBSb290IENBMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABJ3LgJGNU2e1uVCxA/jl +SR9BIgmwUVJY1is0j8USRhTFiy8shP8sbqjV8QnjAyEUxEM9fMEsxEtqSs3ph+B99iK++kpRuDCK +/eHeGBIK9ke35xe/J4rUQUyWPGCWwf0VHKNCMEAwHQYDVR0OBBYEFNJKsVF/BvDRgh9Obl+rg/xI +1LCRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUCMBq8 +W9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8g +UXOQwKhbYdDFUDn9hf7B43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w== +-----END CERTIFICATE----- + +Sectigo Public Server Authentication Root E46 +============================================= +-----BEGIN CERTIFICATE----- +MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQswCQYDVQQGEwJH +QjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBTZXJ2 +ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5 +WjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0 +aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUr +gQQAIgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccCWvkEN/U0 +NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+6xnOQ6OjQjBAMB0GA1Ud +DgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAKBggqhkjOPQQDAwNnADBkAjAn7qRaqCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RH +lAFWovgzJQxC36oCMB3q4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21U +SAGKcw== +-----END CERTIFICATE----- + +Sectigo Public Server Authentication Root R46 +============================================= +-----BEGIN CERTIFICATE----- +MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBfMQswCQYDVQQG +EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT +ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1 +OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T +ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3 +DQEBAQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDaef0rty2k +1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnzSDBh+oF8HqcIStw+Kxwf +GExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xfiOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMP +FF1bFOdLvt30yNoDN9HWOaEhUTCDsG3XME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vu +ZDCQOc2TZYEhMbUjUDM3IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5Qaz +Yw6A3OASVYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgESJ/A +wSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu+Zd4KKTIRJLpfSYF +plhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt8uaZFURww3y8nDnAtOFr94MlI1fZ +EoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+LHaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW +6aWWrL3DkJiy4Pmi1KZHQ3xtzwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWI +IUkwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c +mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQYKlJfp/imTYp +E0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52gDY9hAaLMyZlbcp+nv4fjFg4 +exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZAFv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M +0ejf5lG5Nkc/kLnHvALcWxxPDkjBJYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI +84HxZmduTILA7rpXDhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9m +pFuiTdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5dHn5Hrwd +Vw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65LvKRRFHQV80MNNVIIb/b +E/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmm +J1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAYQqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL +-----END CERTIFICATE----- + +SSL.com TLS RSA Root CA 2022 +============================ +-----BEGIN CERTIFICATE----- +MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQG +EwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBSU0Eg +Um9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloXDTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMC +VVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJv +b3QgQ0EgMjAyMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u +9nTPL3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OYt6/wNr/y +7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0insS657Lb85/bRi3pZ7Qcac +oOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3PnxEX4MN8/HdIGkWCVDi1FW24IBydm5M +R7d1VVm0U3TZlMZBrViKMWYPHqIbKUBOL9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDG +D6C1vBdOSHtRwvzpXGk3R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEW +TO6Af77wdr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS+YCk +8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYSd66UNHsef8JmAOSq +g+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoGAtUjHBPW6dvbxrB6y3snm/vg1UYk +7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2fgTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1Ud +EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsu +N+7jhHonLs0ZNbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt +hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsMQtfhWsSWTVTN +j8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvfR4iyrT7gJ4eLSYwfqUdYe5by +iB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJDPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjU +o3KUQyxi4U5cMj29TH0ZR6LDSeeWP4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqo +ENjwuSfr98t67wVylrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7Egkaib +MOlqbLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2wAgDHbICi +vRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3qr5nsLFR+jM4uElZI7xc7 +P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sjiMho6/4UIyYOf8kpIEFR3N+2ivEC+5BB0 +9+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA= +-----END CERTIFICATE----- + +SSL.com TLS ECC Root CA 2022 +============================ +-----BEGIN CERTIFICATE----- +MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV +UzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBFQ0MgUm9v +dCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMx +GDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3Qg +Q0EgMjAyMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWy +JGYmacCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFNSeR7T5v1 +5wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSJjy+j6CugFFR7 +81a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NWuCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGG +MAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w +7deedWo1dlJF4AIxAMeNb0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5 +Zn6g6g== +-----END CERTIFICATE----- + +Atos TrustedRoot Root CA ECC TLS 2021 +===================================== +-----BEGIN CERTIFICATE----- +MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4wLAYDVQQDDCVB +dG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQswCQYD +VQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3Mg +VHJ1c3RlZFJvb3QgUm9vdCBDQSBFQ0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYT +AkRFMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6K +DP/XtXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4AjJn8ZQS +b+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2KCXWfeBmmnoJsmo7jjPX +NtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMDaAAwZQIwW5kp85wxtolrbNa9d+F851F+ +uDrNozZffPc8dz7kUK2o59JZDCaOMDtuCCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGY +a3cpetskz2VAv9LcjBHo9H1/IISpQuQo +-----END CERTIFICATE----- + +Atos TrustedRoot Root CA RSA TLS 2021 +===================================== +-----BEGIN CERTIFICATE----- +MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBMMS4wLAYDVQQD +DCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQsw +CQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0 +b3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNV +BAYTAkRFMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BB +l01Z4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYvYe+W/CBG +vevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZkmGbzSoXfduP9LVq6hdK +ZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDsGY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt +0xU6kGpn8bRrZtkh68rZYnxGEFzedUlnnkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVK +PNe0OwANwI8f4UDErmwh3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMY +sluMWuPD0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzygeBY +Br3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8ANSbhqRAvNncTFd+ +rrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezBc6eUWsuSZIKmAMFwoW4sKeFYV+xa +fJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lIpw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUdEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0G +CSqGSIb3DQEBDAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS +4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPso0UvFJ/1TCpl +Q3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJqM7F78PRreBrAwA0JrRUITWX +AdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuywxfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9G +slA9hGCZcbUztVdF5kJHdWoOsAgMrr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2Vkt +afcxBPTy+av5EzH4AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9q +TFsR0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuYo7Ey7Nmj +1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5dDTedk+SKlOxJTnbPP/l +PqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcEoji2jbDwN/zIIX8/syQbPYtuzE2wFg2W +HYMfRsCbvUOZ58SWLs5fyQ== +-----END CERTIFICATE----- + +TrustAsia Global Root CA G3 +=========================== +-----BEGIN CERTIFICATE----- +MIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEMBQAwWjELMAkG +A1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMM +G1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAeFw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEw +MTlaMFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMu +MSQwIgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNST1QY4Sxz +lZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqKAtCWHwDNBSHvBm3dIZwZ +Q0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/V +P68czH5GX6zfZBCK70bwkPAPLfSIC7Epqq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1Ag +dB4SQXMeJNnKziyhWTXAyB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm +9WAPzJMshH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gXzhqc +D0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAvkV34PmVACxmZySYg +WmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msTf9FkPz2ccEblooV7WIQn3MSAPmea +mseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jAuPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCF +TIcQcf+eQxuulXUtgQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj +7zjKsK5Xf/IhMBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E +BAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4wM8zAQLpw6o1 +D/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2XFNFV1pF1AWZLy4jVe5jaN/T +G3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNj +duMNhXJEIlU/HHzp/LgV6FL6qj6jITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstl +cHboCoWASzY9M/eVVHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys ++TIxxHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1onAX1daBli +2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d7XB4tmBZrOFdRWOPyN9y +aFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2NtjjgKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsAS +ZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV+Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFR +JQJ6+N1rZdVtTTDIZbpoFGWsJwt0ivKH +-----END CERTIFICATE----- + +TrustAsia Global Root CA G4 +=========================== +-----BEGIN CERTIFICATE----- +MIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMwWjELMAkGA1UE +BhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMMG1Ry +dXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0yMTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJa +MFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQw +IgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AATxs8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbwLxYI+hW8 +m7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJijYzBhMA8GA1UdEwEB/wQF +MAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mDpm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/ +pDHel4NZg6ZvccveMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AA +bbd+NvBNEU/zy4k6LHiRUKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xk +dUfFVZDj/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA== +-----END CERTIFICATE----- + +Telekom Security TLS ECC Root 2020 +================================== +-----BEGIN CERTIFICATE----- +MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQswCQYDVQQGEwJE +RTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJUZWxl +a29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIwMB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIz +NTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkg +R21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqG +SM49AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/OtdKPD/M1 +2kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDPf8iAC8GXs7s1J8nCG6NC +MEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6fMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMAoGCCqGSM49BAMDA2cAMGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZ +Mo7k+5Dck2TOrbRBR2Diz6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdU +ga/sf+Rn27iQ7t0l +-----END CERTIFICATE----- + +Telekom Security TLS RSA Root 2023 +================================== +-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBjMQswCQYDVQQG +EwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJU +ZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAyMDIzMB4XDTIzMDMyODEyMTY0NVoXDTQ4MDMy +NzIzNTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJp +dHkgR21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgUlNBIFJvb3QgMjAyMzCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAO01oYGA88tKaVvC+1GDrib94W7zgRJ9cUD/h3VC +KSHtgVIs3xLBGYSJwb3FKNXVS2xE1kzbB5ZKVXrKNoIENqil/Cf2SfHVcp6R+SPWcHu79ZvB7JPP +GeplfohwoHP89v+1VmLhc2o0mD6CuKyVU/QBoCcHcqMAU6DksquDOFczJZSfvkgdmOGjup5czQRx +UX11eKvzWarE4GC+j4NSuHUaQTXtvPM6Y+mpFEXX5lLRbtLevOP1Czvm4MS9Q2QTps70mDdsipWo +l8hHD/BeEIvnHRz+sTugBTNoBUGCwQMrAcjnj02r6LX2zWtEtefdi+zqJbQAIldNsLGyMcEWzv/9 +FIS3R/qy8XDe24tsNlikfLMR0cN3f1+2JeANxdKz+bi4d9s3cXFH42AYTyS2dTd4uaNir73Jco4v +zLuu2+QVUhkHM/tqty1LkCiCc/4YizWN26cEar7qwU02OxY2kTLvtkCJkUPg8qKrBC7m8kwOFjQg +rIfBLX7JZkcXFBGk8/ehJImr2BrIoVyxo/eMbcgByU/J7MT8rFEz0ciD0cmfHdRHNCk+y7AO+oML +KFjlKdw/fKifybYKu6boRhYPluV75Gp6SG12mAWl3G0eQh5C2hrgUve1g8Aae3g1LDj1H/1Joy7S +WWO/gLCMk3PLNaaZlSJhZQNg+y+TS/qanIA7AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAdBgNV +HQ4EFgQUtqeXgj10hZv3PJ+TmpV5dVKMbUcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS2 +p5eCPXSFm/c8n5OalXl1UoxtRzANBgkqhkiG9w0BAQwFAAOCAgEAqMxhpr51nhVQpGv7qHBFfLp+ +sVr8WyP6Cnf4mHGCDG3gXkaqk/QeoMPhk9tLrbKmXauw1GLLXrtm9S3ul0A8Yute1hTWjOKWi0Fp +kzXmuZlrYrShF2Y0pmtjxrlO8iLpWA1WQdH6DErwM807u20hOq6OcrXDSvvpfeWxm4bu4uB9tPcy +/SKE8YXJN3nptT+/XOR0so8RYgDdGGah2XsjX/GO1WfoVNpbOms2b/mBsTNHM3dA+VKq3dSDz4V4 +mZqTuXNnQkYRIer+CqkbGmVps4+uFrb2S1ayLfmlyOw7YqPta9BO1UAJpB+Y1zqlklkg5LB9zVtz +aL1txKITDmcZuI1CfmwMmm6gJC3VRRvcxAIU/oVbZZfKTpBQCHpCNfnqwmbU+AGuHrS+w6jv/naa +oqYfRvaE7fzbzsQCzndILIyy7MMAo+wsVRjBfhnu4S/yrYObnqsZ38aKL4x35bcF7DvB7L6Gs4a8 +wPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+ljX273CXE2whJdV/LItM3z7gLfEdxquVeE +HVlNjM7IDiPCtyaaEBRx/pOyiriA8A4QntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0 +o82bNSQ3+pCTE4FCxpgmdTdmQRCsu/WU48IxK63nI1bMNSWSs1A= +-----END CERTIFICATE----- + +FIRMAPROFESIONAL CA ROOT-A WEB +============================== +-----BEGIN CERTIFICATE----- +MIICejCCAgCgAwIBAgIQMZch7a+JQn81QYehZ1ZMbTAKBggqhkjOPQQDAzBuMQswCQYDVQQGEwJF +UzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25hbCBTQTEYMBYGA1UEYQwPVkFURVMtQTYyNjM0MDY4 +MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFMIENBIFJPT1QtQSBXRUIwHhcNMjIwNDA2MDkwMTM2 +WhcNNDcwMzMxMDkwMTM2WjBuMQswCQYDVQQGEwJFUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25h +bCBTQTEYMBYGA1UEYQwPVkFURVMtQTYyNjM0MDY4MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFM +IENBIFJPT1QtQSBXRUIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARHU+osEaR3xyrq89Zfe9MEkVz6 +iMYiuYMQYneEMy3pA4jU4DP37XcsSmDq5G+tbbT4TIqk5B/K6k84Si6CcyvHZpsKjECcfIr28jlg +st7L7Ljkb+qbXbdTkBgyVcUgt5SjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUk+FD +Y1w8ndYn81LsF7Kpryz3dvgwHQYDVR0OBBYEFJPhQ2NcPJ3WJ/NS7Beyqa8s93b4MA4GA1UdDwEB +/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjAdfKR7w4l1M+E7qUW/Runpod3JIha3RxEL2Jq68cgL +cFBTApFwhVmpHqTm6iMxoAACMQD94vizrxa5HnPEluPBMBnYfubDl94cT7iJLzPrSA8Z94dGXSaQ +pYXFuXqUPoeovQA= +-----END CERTIFICATE----- + +TWCA CYBER Root CA +================== +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIQQAE0jMIAAAAAAAAAATzyxjANBgkqhkiG9w0BAQwFADBQMQswCQYDVQQG +EwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NB +IENZQkVSIFJvb3QgQ0EwHhcNMjIxMTIyMDY1NDI5WhcNNDcxMTIyMTU1OTU5WjBQMQswCQYDVQQG +EwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NB +IENZQkVSIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDG+Moe2Qkgfh1s +Ts6P40czRJzHyWmqOlt47nDSkvgEs1JSHWdyKKHfi12VCv7qze33Kc7wb3+szT3vsxxFavcokPFh +V8UMxKNQXd7UtcsZyoC5dc4pztKFIuwCY8xEMCDa6pFbVuYdHNWdZsc/34bKS1PE2Y2yHer43CdT +o0fhYcx9tbD47nORxc5zb87uEB8aBs/pJ2DFTxnk684iJkXXYJndzk834H/nY62wuFm40AZoNWDT +Nq5xQwTxaWV4fPMf88oon1oglWa0zbfuj3ikRRjpJi+NmykosaS3Om251Bw4ckVYsV7r8Cibt4LK +/c/WMw+f+5eesRycnupfXtuq3VTpMCEobY5583WSjCb+3MX2w7DfRFlDo7YDKPYIMKoNM+HvnKkH +IuNZW0CP2oi3aQiotyMuRAlZN1vH4xfyIutuOVLF3lSnmMlLIJXcRolftBL5hSmO68gnFSDAS9TM +fAxsNAwmmyYxpjyn9tnQS6Jk/zuZQXLB4HCX8SS7K8R0IrGsayIyJNN4KsDAoS/xUgXJP+92ZuJF +2A09rZXIx4kmyA+upwMu+8Ff+iDhcK2wZSA3M2Cw1a/XDBzCkHDXShi8fgGwsOsVHkQGzaRP6AzR +wyAQ4VRlnrZR0Bp2a0JaWHY06rc3Ga4udfmW5cFZ95RXKSWNOkyrTZpB0F8mAwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSdhWEUfMFib5do5E83 +QOGt4A1WNzAdBgNVHQ4EFgQUnYVhFHzBYm+XaORPN0DhreANVjcwDQYJKoZIhvcNAQEMBQADggIB +AGSPesRiDrWIzLjHhg6hShbNcAu3p4ULs3a2D6f/CIsLJc+o1IN1KriWiLb73y0ttGlTITVX1olN +c79pj3CjYcya2x6a4CD4bLubIp1dhDGaLIrdaqHXKGnK/nZVekZn68xDiBaiA9a5F/gZbG0jAn/x +X9AKKSM70aoK7akXJlQKTcKlTfjF/biBzysseKNnTKkHmvPfXvt89YnNdJdhEGoHK4Fa0o635yDR +IG4kqIQnoVesqlVYL9zZyvpoBJ7tRCT5dEA7IzOrg1oYJkK2bVS1FmAwbLGg+LhBoF1JSdJlBTrq +/p1hvIbZv97Tujqxf36SNI7JAG7cmL3c7IAFrQI932XtCwP39xaEBDG6k5TY8hL4iuO/Qq+n1M0R +FxbIQh0UqEL20kCGoE8jypZFVmAGzbdVAaYBlGX+bgUJurSkquLvWL69J1bY73NxW0Qz8ppy6rBe +Pm6pUlvscG21h483XjyMnM7k8M4MZ0HMzvaAq07MTFb1wWFZk7Q+ptq4NxKfKjLji7gh7MMrZQzv +It6IKTtM1/r+t+FHvpw+PoP7UV31aPcuIYXcv/Fa4nzXxeSDwWrruoBa3lwtcHb4yOWHh8qgnaHl +IhInD0Q9HWzq1MKLL295q39QpsQZp6F6t5b5wR9iWqJDB0BeJsas7a5wFsWqynKKTbDPAYsDP27X +-----END CERTIFICATE----- + +SecureSign Root CA12 +==================== +-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUZvnHwa/swlG07VOX5uaCwysckBYwDQYJKoZIhvcNAQELBQAwUTELMAkG +A1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRT +ZWN1cmVTaWduIFJvb3QgQ0ExMjAeFw0yMDA0MDgwNTM2NDZaFw00MDA0MDgwNTM2NDZaMFExCzAJ +BgNVBAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMU +U2VjdXJlU2lnbiBSb290IENBMTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6OcE3 +emhFKxS06+QT61d1I02PJC0W6K6OyX2kVzsqdiUzg2zqMoqUm048luT9Ub+ZyZN+v/mtp7JIKwcc +J/VMvHASd6SFVLX9kHrko+RRWAPNEHl57muTH2SOa2SroxPjcf59q5zdJ1M3s6oYwlkm7Fsf0uZl +fO+TvdhYXAvA42VvPMfKWeP+bl+sg779XSVOKik71gurFzJ4pOE+lEa+Ym6b3kaosRbnhW70CEBF +EaCeVESE99g2zvVQR9wsMJvuwPWW0v4JhscGWa5Pro4RmHvzC1KqYiaqId+OJTN5lxZJjfU+1Uef +NzFJM3IFTQy2VYzxV4+Kh9GtxRESOaCtAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMB0GA1UdDgQWBBRXNPN0zwRL1SXm8UC2LEzZLemgrTANBgkqhkiG9w0BAQsFAAOC +AQEAPrvbFxbS8hQBICw4g0utvsqFepq2m2um4fylOqyttCg6r9cBg0krY6LdmmQOmFxv3Y67ilQi +LUoT865AQ9tPkbeGGuwAtEGBpE/6aouIs3YIcipJQMPTw4WJmBClnW8Zt7vPemVV2zfrPIpyMpce +mik+rY3moxtt9XUa5rBouVui7mlHJzWhhpmA8zNL4WukJsPvdFlseqJkth5Ew1DgDzk9qTPxpfPS +vWKErI4cqc1avTc7bgoitPQV55FYxTpE05Uo2cBl6XLK0A+9H7MV2anjpEcJnuDLN/v9vZfVvhga +aaI5gdka9at/yOPiZwud9AzqVN/Ssq+xIvEg37xEHA== +-----END CERTIFICATE----- + +SecureSign Root CA14 +==================== +-----BEGIN CERTIFICATE----- +MIIFcjCCA1qgAwIBAgIUZNtaDCBO6Ncpd8hQJ6JaJ90t8sswDQYJKoZIhvcNAQEMBQAwUTELMAkG +A1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRT +ZWN1cmVTaWduIFJvb3QgQ0ExNDAeFw0yMDA0MDgwNzA2MTlaFw00NTA0MDgwNzA2MTlaMFExCzAJ +BgNVBAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMU +U2VjdXJlU2lnbiBSb290IENBMTQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDF0nqh +1oq/FjHQmNE6lPxauG4iwWL3pwon71D2LrGeaBLwbCRjOfHw3xDG3rdSINVSW0KZnvOgvlIfX8xn +bacuUKLBl422+JX1sLrcneC+y9/3OPJH9aaakpUqYllQC6KxNedlsmGy6pJxaeQp8E+BgQQ8sqVb +1MWoWWd7VRxJq3qdwudzTe/NCcLEVxLbAQ4jeQkHO6Lo/IrPj8BGJJw4J+CDnRugv3gVEOuGTgpa +/d/aLIJ+7sr2KeH6caH3iGicnPCNvg9JkdjqOvn90Ghx2+m1K06Ckm9mH+Dw3EzsytHqunQG+bOE +kJTRX45zGRBdAuVwpcAQ0BB8b8VYSbSwbprafZX1zNoCr7gsfXmPvkPx+SgojQlD+Ajda8iLLCSx +jVIHvXiby8posqTdDEx5YMaZ0ZPxMBoH064iwurO8YQJzOAUbn8/ftKChazcqRZOhaBgy/ac18iz +ju3Gm5h1DVXoX+WViwKkrkMpKBGk5hIwAUt1ax5mnXkvpXYvHUC0bcl9eQjs0Wq2XSqypWa9a4X0 +dFbD9ed1Uigspf9mR6XU/v6eVL9lfgHWMI+lNpyiUBzuOIABSMbHdPTGrMNASRZhdCyvjG817XsY +AFs2PJxQDcqSMxDxJklt33UkN4Ii1+iW/RVLApY+B3KVfqs9TC7XyvDf4Fg/LS8EmjijAQIDAQAB +o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUBpOjCl4oaTeq +YR3r6/wtbyPk86AwDQYJKoZIhvcNAQEMBQADggIBAJaAcgkGfpzMkwQWu6A6jZJOtxEaCnFxEM0E +rX+lRVAQZk5KQaID2RFPeje5S+LGjzJmdSX7684/AykmjbgWHfYfM25I5uj4V7Ibed87hwriZLoA +ymzvftAj63iP/2SbNDefNWWipAA9EiOWWF3KY4fGoweITedpdopTzfFP7ELyk+OZpDc8h7hi2/Ds +Hzc/N19DzFGdtfCXwreFamgLRB7lUe6TzktuhsHSDCRZNhqfLJGP4xjblJUK7ZGqDpncllPjYYPG +FrojutzdfhrGe0K22VoF3Jpf1d+42kd92jjbrDnVHmtsKheMYc2xbXIBw8MgAGJoFjHVdqqGuw6q +nsb58Nn4DSEC5MUoFlkRudlpcyqSeLiSV5sI8jrlL5WwWLdrIBRtFO8KvH7YVdiI2i/6GaX7i+B/ +OfVyK4XELKzvGUWSTLNhB9xNH27SgRNcmvMSZ4PPmz+Ln52kuaiWA3rF7iDeM9ovnhp6dB7h7sxa +OgTdsxoEqBRjrLdHEoOabPXm6RUVkRqEGQ6UROcSjiVbgGcZ3GOTEAtlLor6CZpO2oYofaphNdgO +pygau1LgePhsumywbrmHXumZNTfxPWQrqaA0k89jL9WB365jJ6UeTo3cKXhZ+PmhIIynJkBugnLN +eLLIjzwec+fBH7/PzqUqm9tEZDKgu39cJRNItX+S +-----END CERTIFICATE----- + +SecureSign Root CA15 +==================== +-----BEGIN CERTIFICATE----- +MIICIzCCAamgAwIBAgIUFhXHw9hJp75pDIqI7fBw+d23PocwCgYIKoZIzj0EAwMwUTELMAkGA1UE +BhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRTZWN1 +cmVTaWduIFJvb3QgQ0ExNTAeFw0yMDA0MDgwODMyNTZaFw00NTA0MDgwODMyNTZaMFExCzAJBgNV +BAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2Vj +dXJlU2lnbiBSb290IENBMTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQLUHSNZDKZmbPSYAi4Io5G +dCx4wCtELW1fHcmuS1Iggz24FG1Th2CeX2yF2wYUleDHKP+dX+Sq8bOLbe1PL0vJSpSRZHX+AezB +2Ot6lHhWGENfa4HL9rzatAy2KZMIaY+jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBTrQciu/NWeUUj1vYv0hyCTQSvT9DAKBggqhkjOPQQDAwNoADBlAjEA2S6J +fl5OpBEHvVnCB96rMjhTKkZEBhd6zlHp4P9mLQlO4E/0BdGF9jVg3PVys0Z9AjBEmEYagoUeYWmJ +SwdLZrWeqrqgHkHZAXQ6bkU6iYAZezKYVWOr62Nuk22rGwlgMU4= +-----END CERTIFICATE----- + +D-TRUST BR Root CA 2 2023 +========================= +-----BEGIN CERTIFICATE----- +MIIFqTCCA5GgAwIBAgIQczswBEhb2U14LnNLyaHcZjANBgkqhkiG9w0BAQ0FADBIMQswCQYDVQQG +EwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEJSIFJvb3QgQ0Eg +MiAyMDIzMB4XDTIzMDUwOTA4NTYzMVoXDTM4MDUwOTA4NTYzMFowSDELMAkGA1UEBhMCREUxFTAT +BgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDIgMjAyMzCC +AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK7/CVmRgApKaOYkP7in5Mg6CjoWzckjYaCT +cfKri3OPoGdlYNJUa2NRb0kz4HIHE304zQaSBylSa053bATTlfrdTIzZXcFhfUvnKLNEgXtRr90z +sWh81k5M/itoucpmacTsXld/9w3HnDY25QdgrMBM6ghs7wZ8T1soegj8k12b9py0i4a6Ibn08OhZ +WiihNIQaJZG2tY/vsvmA+vk9PBFy2OMvhnbFeSzBqZCTRphny4NqoFAjpzv2gTng7fC5v2Xx2Mt6 +++9zA84A9H3X4F07ZrjcjrqDy4d2A/wl2ecjbwb9Z/Pg/4S8R7+1FhhGaRTMBffb00msa8yr5LUL +QyReS2tNZ9/WtT5PeB+UcSTq3nD88ZP+npNa5JRal1QMNXtfbO4AHyTsA7oC9Xb0n9Sa7YUsOCIv +x9gvdhFP/Wxc6PWOJ4d/GUohR5AdeY0cW/jPSoXk7bNbjb7EZChdQcRurDhaTyN0dKkSw/bSuREV +MweR2Ds3OmMwBtHFIjYoYiMQ4EbMl6zWK11kJNXuHA7e+whadSr2Y23OC0K+0bpwHJwh5Q8xaRfX +/Aq03u2AnMuStIv13lmiWAmlY0cL4UEyNEHZmrHZqLAbWt4NDfTisl01gLmB1IRpkQLLddCNxbU9 +CZEJjxShFHR5PtbJFR2kWVki3PaKRT08EtY+XTIvAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUZ5Dw1t61GNVGKX5cq/ieCLxklRAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRC +MEAwPqA8oDqGOGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfYnJfcm9vdF9jYV8y +XzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQA097N3U9swFrktpSHxQCF16+tIFoE9c+CeJyrr +d6kTpGoKWloUMz1oH4Guaf2Mn2VsNELZLdB/eBaxOqwjMa1ef67nriv6uvw8l5VAk1/DLQOj7aRv +U9f6QA4w9QAgLABMjDu0ox+2v5Eyq6+SmNMW5tTRVFxDWy6u71cqqLRvpO8NVhTaIasgdp4D/Ca4 +nj8+AybmTNudX0KEPUUDAxxZiMrcLmEkWqTqJwtzEr5SswrPMhfiHocaFpVIbVrg0M8JkiZmkdij +YQ6qgYF/6FKC0ULn4B0Y+qSFNueG4A3rvNTJ1jxD8V1Jbn6Bm2m1iWKPiFLY1/4nwSPFyysCu7Ff +/vtDhQNGvl3GyiEm/9cCnnRK3PgTFbGBVzbLZVzRHTF36SXDw7IyN9XxmAnkbWOACKsGkoHU6XCP +pz+y7YaMgmo1yEJagtFSGkUPFaUA8JR7ZSdXOUPPfH/mvTWze/EZTN46ls/pdu4D58JDUjxqgejB +WoC9EV2Ta/vH5mQ/u2kc6d0li690yVRAysuTEwrt+2aSEcr1wPrYg1UDfNPFIkZ1cGt5SAYqgpq/ +5usWDiJFAbzdNpQ0qTUmiteXue4Icr80knCDgKs4qllo3UCkGJCy89UDyibK79XH4I9TjvAA46jt +n/mtd+ArY0+ew+43u3gJhJ65bvspmZDogNOfJA== +-----END CERTIFICATE----- + +TrustAsia TLS ECC Root CA +========================= +-----BEGIN CERTIFICATE----- +MIICMTCCAbegAwIBAgIUNnThTXxlE8msg1UloD5Sfi9QaMcwCgYIKoZIzj0EAwMwWDELMAkGA1UE +BhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xIjAgBgNVBAMTGVRy +dXN0QXNpYSBUTFMgRUNDIFJvb3QgQ0EwHhcNMjQwNTE1MDU0MTU2WhcNNDQwNTE1MDU0MTU1WjBY +MQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEiMCAG +A1UEAxMZVHJ1c3RBc2lhIFRMUyBFQ0MgUm9vdCBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLh/ +pVs/AT598IhtrimY4ZtcU5nb9wj/1WrgjstEpvDBjL1P1M7UiFPoXlfXTr4sP/MSpwDpguMqWzJ8 +S5sUKZ74LYO1644xST0mYekdcouJtgq7nDM1D9rs3qlKH8kzsaNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQULIVTu7FDzTLqnqOH/qKYqKaT6RAwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49 +BAMDA2gAMGUCMFRH18MtYYZI9HlaVQ01L18N9mdsd0AaRuf4aFtOJx24mH1/k78ITcTaRTChD15K +eAIxAKORh/IRM4PDwYqROkwrULG9IpRdNYlzg8WbGf60oenUoWa2AaU2+dhoYSi3dOGiMQ== +-----END CERTIFICATE----- + +TrustAsia TLS RSA Root CA +========================= +-----BEGIN CERTIFICATE----- +MIIFgDCCA2igAwIBAgIUHBjYz+VTPyI1RlNUJDxsR9FcSpwwDQYJKoZIhvcNAQEMBQAwWDELMAkG +A1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xIjAgBgNVBAMT +GVRydXN0QXNpYSBUTFMgUlNBIFJvb3QgQ0EwHhcNMjQwNTE1MDU0MTU3WhcNNDQwNTE1MDU0MTU2 +WjBYMQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEi +MCAGA1UEAxMZVHJ1c3RBc2lhIFRMUyBSU0EgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBAMMWuBtqpERz5dZO9LnPWwvB0ZqB9WOwj0PBuwhaGnrhB3YmH49pVr7+NmDQDIPN +lOrnxS1cLwUWAp4KqC/lYCZUlviYQB2srp10Zy9U+5RjmOMmSoPGlbYJQ1DNDX3eRA5gEk9bNb2/ +mThtfWza4mhzH/kxpRkQcwUqwzIZheo0qt1CHjCNP561HmHVb70AcnKtEj+qpklz8oYVlQwQX1Fk +zv93uMltrOXVmPGZLmzjyUT5tUMnCE32ft5EebuyjBza00tsLtbDeLdM1aTk2tyKjg7/D8OmYCYo +zza/+lcK7Fs/6TAWe8TbxNRkoDD75f0dcZLdKY9BWN4ArTr9PXwaqLEX8E40eFgl1oUh63kd0Nyr +z2I8sMeXi9bQn9P+PN7F4/w6g3CEIR0JwqH8uyghZVNgepBtljhb//HXeltt08lwSUq6HTrQUNoy +IBnkiz/r1RYmNzz7dZ6wB3C4FGB33PYPXFIKvF1tjVEK2sUYyJtt3LCDs3+jTnhMmCWr8n4uIF6C +FabW2I+s5c0yhsj55NqJ4js+k8UTav/H9xj8Z7XvGCxUq0DTbE3txci3OE9kxJRMT6DNrqXGJyV1 +J23G2pyOsAWZ1SgRxSHUuPzHlqtKZFlhaxP8S8ySpg+kUb8OWJDZgoM5pl+z+m6Ss80zDoWo8SnT +q1mt1tve1CuBAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLgHkXlcBvRG/XtZ +ylomkadFK/hTMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQwFAAOCAgEAIZtqBSBdGBanEqT3 +Rz/NyjuujsCCztxIJXgXbODgcMTWltnZ9r96nBO7U5WS/8+S4PPFJzVXqDuiGev4iqME3mmL5Dw8 +veWv0BIb5Ylrc5tvJQJLkIKvQMKtuppgJFqBTQUYo+IzeXoLH5Pt7DlK9RME7I10nYEKqG/odv6L +TytpEoYKNDbdgptvT+Bz3Ul/KD7JO6NXBNiT2Twp2xIQaOHEibgGIOcberyxk2GaGUARtWqFVwHx +tlotJnMnlvm5P1vQiJ3koP26TpUJg3933FEFlJ0gcXax7PqJtZwuhfG5WyRasQmr2soaB82G39tp +27RIGAAtvKLEiUUjpQ7hRGU+isFqMB3iYPg6qocJQrmBktwliJiJ8Xw18WLK7nn4GS/+X/jbh87q +qA8MpugLoDzga5SYnH+tBuYc6kIQX+ImFTw3OffXvO645e8D7r0i+yiGNFjEWn9hongPXvPKnbwb +PKfILfanIhHKA9jnZwqKDss1jjQ52MjqjZ9k4DewbNfFj8GQYSbbJIweSsCI3zWQzj8C9GRh3sfI +B5XeMhg6j6JCQCTl1jNdfK7vsU1P1FeQNWrcrgSXSYk0ly4wBOeY99sLAZDBHwo/+ML+TvrbmnNz +FrwFuHnYWa8G5z9nODmxfKuU4CkUpijy323imttUQ/hHWKNddBWcwauwxzQ= +-----END CERTIFICATE----- + +D-TRUST EV Root CA 2 2023 +========================= +-----BEGIN CERTIFICATE----- +MIIFqTCCA5GgAwIBAgIQaSYJfoBLTKCnjHhiU19abzANBgkqhkiG9w0BAQ0FADBIMQswCQYDVQQG +EwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEVWIFJvb3QgQ0Eg +MiAyMDIzMB4XDTIzMDUwOTA5MTAzM1oXDTM4MDUwOTA5MTAzMlowSDELMAkGA1UEBhMCREUxFTAT +BgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDIgMjAyMzCC +AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANiOo4mAC7JXUtypU0w3uX9jFxPvp1sjW2l1 +sJkKF8GLxNuo4MwxusLyzV3pt/gdr2rElYfXR8mV2IIEUD2BCP/kPbOx1sWy/YgJ25yE7CUXFId/ +MHibaljJtnMoPDT3mfd/06b4HEV8rSyMlD/YZxBTfiLNTiVR8CUkNRFeEMbsh2aJgWi6zCudR3Mf +vc2RpHJqnKIbGKBv7FD0fUDCqDDPvXPIEysQEx6Lmqg6lHPTGGkKSv/BAQP/eX+1SH977ugpbzZM +lWGG2Pmic4ruri+W7mjNPU0oQvlFKzIbRlUWaqZLKfm7lVa/Rh3sHZMdwGWyH6FDrlaeoLGPaxK3 +YG14C8qKXO0elg6DpkiVjTujIcSuWMYAsoS0I6SWhjW42J7YrDRJmGOVxcttSEfi8i4YHtAxq910 +7PncjLgcjmgjutDzUNzPZY9zOjLHfP7KgiJPvo5iR2blzYfi6NUPGJ/lBHJLRjwQ8kTCZFZxTnXo +nMkmdMV9WdEKWw9t/p51HBjGGjp82A0EzM23RWV6sY+4roRIPrN6TagD4uJ+ARZZaBhDM7DS3LAa +QzXupdqpRlyuhoFBAUp0JuyfBr/CBTdkdXgpaP3F9ev+R/nkhbDhezGdpn9yo7nELC7MmVcOIQxF +AZRl62UJxmMiCzNJkkg8/M3OsD6Onov4/knFNXJHAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUqvyREBuHkV8Wub9PS5FeAByxMoAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRC +MEAwPqA8oDqGOGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfZXZfcm9vdF9jYV8y +XzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQCTy6UfmRHsmg1fLBWTxj++EI14QvBukEdHjqOS +Mo1wj/Zbjb6JzkcBahsgIIlbyIIQbODnmaprxiqgYzWRaoUlrRc4pZt+UPJ26oUFKidBK7GB0aL2 +QHWpDsvxVUjY7NHss+jOFKE17MJeNRqrphYBBo7q3C+jisosketSjl8MmxfPy3MHGcRqwnNU73xD +UmPBEcrCRbH0O1P1aa4846XerOhUt7KR/aypH/KH5BfGSah82ApB9PI+53c0BFLd6IHyTS9URZ0V +4U/M5d40VxDJI3IXcI1QcB9WbMy5/zpaT2N6w25lBx2Eof+pDGOJbbJAiDnXH3dotfyc1dZnaVuo +dNv8ifYbMvekJKZ2t0dT741Jj6m2g1qllpBFYfXeA08mD6iL8AOWsKwV0HFaanuU5nCT2vFp4LJi +TZ6P/4mdm13NRemUAiKN4DV/6PEEeXFsVIP4M7kFMhtYVRFP0OUnR3Hs7dpn1mKmS00PaaLJvOwi +S5THaJQXfuKOKD62xur1NGyfN4gHONuGcfrNlUhDbqNPgofXNJhuS5N5YHVpD/Aa1VP6IQzCP+k/ +HxiMkl14p3ZnGbuy6n/pcAlWVqOwDAstNl7F6cTVg8uGF5csbBNvh1qvSaYd2804BC5f4ko1Di1L ++KIkBI3Y4WNeApI02phhXBxvWHZks/wCuPWdCg== +-----END CERTIFICATE----- + +SwissSign RSA TLS Root CA 2022 - 1 +================================== +-----BEGIN CERTIFICATE----- +MIIFkzCCA3ugAwIBAgIUQ/oMX04bgBhE79G0TzUfRPSA7cswDQYJKoZIhvcNAQELBQAwUTELMAkG +A1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzErMCkGA1UEAxMiU3dpc3NTaWduIFJTQSBU +TFMgUm9vdCBDQSAyMDIyIC0gMTAeFw0yMjA2MDgxMTA4MjJaFw00NzA2MDgxMTA4MjJaMFExCzAJ +BgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxKzApBgNVBAMTIlN3aXNzU2lnbiBSU0Eg +VExTIFJvb3QgQ0EgMjAyMiAtIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDLKmji +C8NXvDVjvHClO/OMPE5Xlm7DTjak9gLKHqquuN6orx122ro10JFwB9+zBvKK8i5VUXu7LCTLf5Im +gKO0lPaCoaTo+nUdWfMHamFk4saMla+ju45vVs9xzF6BYQ1t8qsCLqSX5XH8irCRIFucdFJtrhUn +WXjyCcplDn/L9Ovn3KlMd/YrFgSVrpxxpT8q2kFC5zyEEPThPYxr4iuRR1VPuFa+Rd4iUU1OKNlf +GUEGjw5NBuBwQCMBauTLE5tzrE0USJIt/m2n+IdreXXhvhCxqohAWVTXz8TQm0SzOGlkjIHRI36q +OTw7D59Ke4LKa2/KIj4x0LDQKhySio/YGZxH5D4MucLNvkEM+KRHBdvBFzA4OmnczcNpI/2aDwLO +EGrOyvi5KaM2iYauC8BPY7kGWUleDsFpswrzd34unYyzJ5jSmY0lpx+Gs6ZUcDj8fV3oT4MM0ZPl +EuRU2j7yrTrePjxF8CgPBrnh25d7mUWe3f6VWQQvdT/TromZhqwUtKiE+shdOxtYk8EXlFXIC+OC +eYSf8wCENO7cMdWP8vpPlkwGqnj73mSiI80fPsWMvDdUDrtaclXvyFu1cvh43zcgTFeRc5JzrBh3 +Q4IgaezprClG5QtO+DdziZaKHG29777YtvTKwP1H8K4LWCDFyB02rpeNUIMmJCn3nTsPBQIDAQAB +o2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBRvjmKLk0Ow +4UD2p8P98Q+4DxU4pTAdBgNVHQ4EFgQUb45ii5NDsOFA9qfD/fEPuA8VOKUwDQYJKoZIhvcNAQEL +BQADggIBAKwsKUF9+lz1GpUYvyypiqkkVHX1uECry6gkUSsYP2OprphWKwVDIqO310aewCoSPY6W +lkDfDDOLazeROpW7OSltwAJsipQLBwJNGD77+3v1dj2b9l4wBlgzHqp41eZUBDqyggmNzhYzWUUo +8aWjlw5DI/0LIICQ/+Mmz7hkkeUFjxOgdg3XNwwQiJb0Pr6VvfHDffCjw3lHC1ySFWPtUnWK50Zp +y1FVCypM9fJkT6lc/2cyjlUtMoIcgC9qkfjLvH4YoiaoLqNTKIftV+Vlek4ASltOU8liNr3Cjlvr +zG4ngRhZi0Rjn9UMZfQpZX+RLOV/fuiJz48gy20HQhFRJjKKLjpHE7iNvUcNCfAWpO2Whi4Z2L6M +OuhFLhG6rlrnub+xzI/goP+4s9GFe3lmozm1O2bYQL7Pt2eLSMkZJVX8vY3PXtpOpvJpzv1/THfQ +wUY1mFwjmwJFQ5Ra3bxHrSL+ul4vkSkphnsh3m5kt8sNjzdbowhq6/TdAo9QAwKxuDdollDruF/U +KIqlIgyKhPBZLtU30WHlQnNYKoH3dtvi4k0NX/a3vgW0rk4N3hY9A4GzJl5LuEsAz/+MF7psYC0n +hzck5npgL7XTgwSqT0N1osGDsieYK7EOgLrAhV5Cud+xYJHT6xh+cHiudoO+cVrQkOPKwRYlZ0rw +tnu64ZzZ +-----END CERTIFICATE----- + +OISTE Server Root ECC G1 +======================== +-----BEGIN CERTIFICATE----- +MIICNTCCAbqgAwIBAgIQI/nD1jWvjyhLH/BU6n6XnTAKBggqhkjOPQQDAzBLMQswCQYDVQQGEwJD +SDEZMBcGA1UECgwQT0lTVEUgRm91bmRhdGlvbjEhMB8GA1UEAwwYT0lTVEUgU2VydmVyIFJvb3Qg +RUNDIEcxMB4XDTIzMDUzMTE0NDIyOFoXDTQ4MDUyNDE0NDIyN1owSzELMAkGA1UEBhMCQ0gxGTAX +BgNVBAoMEE9JU1RFIEZvdW5kYXRpb24xITAfBgNVBAMMGE9JU1RFIFNlcnZlciBSb290IEVDQyBH +MTB2MBAGByqGSM49AgEGBSuBBAAiA2IABBcv+hK8rBjzCvRE1nZCnrPoH7d5qVi2+GXROiFPqOuj +vqQycvO2Ackr/XeFblPdreqqLiWStukhEaivtUwL85Zgmjvn6hp4LrQ95SjeHIC6XG4N2xml4z+c +KrhAS93mT6NjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBQ3TYhlz/w9itWj8UnATgwQ +b0K0nDAdBgNVHQ4EFgQUN02IZc/8PYrVo/FJwE4MEG9CtJwwDgYDVR0PAQH/BAQDAgGGMAoGCCqG +SM49BAMDA2kAMGYCMQCpKjAd0MKfkFFRQD6VVCHNFmb3U2wIFjnQEnx/Yxvf4zgAOdktUyBFCxxg +ZzFDJe0CMQCSia7pXGKDYmH5LVerVrkR3SW+ak5KGoJr3M/TvEqzPNcum9v4KGm8ay3sMaE641c= +-----END CERTIFICATE----- + + OISTE Server Root RSA G1 +========================= +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIQVaXZZ5Qoxu0M+ifdWwFNGDANBgkqhkiG9w0BAQwFADBLMQswCQYDVQQG +EwJDSDEZMBcGA1UECgwQT0lTVEUgRm91bmRhdGlvbjEhMB8GA1UEAwwYT0lTVEUgU2VydmVyIFJv +b3QgUlNBIEcxMB4XDTIzMDUzMTE0MzcxNloXDTQ4MDUyNDE0MzcxNVowSzELMAkGA1UEBhMCQ0gx +GTAXBgNVBAoMEE9JU1RFIEZvdW5kYXRpb24xITAfBgNVBAMMGE9JU1RFIFNlcnZlciBSb290IFJT +QSBHMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKqu9KuCz/vlNwvn1ZatkOhLKdxV +YOPMvLO8LZK55KN68YG0nnJyQ98/qwsmtO57Gmn7KNByXEptaZnwYx4M0rH/1ow00O7brEi56rAU +jtgHqSSY3ekJvqgiG1k50SeH3BzN+Puz6+mTeO0Pzjd8JnduodgsIUzkik/HEzxux9UTl7Ko2yRp +g1bTacuCErudG/L4NPKYKyqOBGf244ehHa1uzjZ0Dl4zO8vbUZeUapU8zhhabkvG/AePLhq5Svdk +NCncpo1Q4Y2LS+VIG24ugBA/5J8bZT8RtOpXaZ+0AOuFJJkk9SGdl6r7NH8CaxWQrbueWhl/pIzY ++m0o/DjH40ytas7ZTpOSjswMZ78LS5bOZmdTaMsXEY5Z96ycG7mOaES3GK/m5Q9l3JUJsJMStR8+ +lKXHiHUhsd4JJCpM4rzsTGdHwimIuQq6+cF0zowYJmXa92/GjHtoXAvuY8BeS/FOzJ8vD+HomnqT +8eDI278n5mUpezbgMxVz8p1rhAhoKzYHKyfMeNhqhw5HdPSqoBNdZH702xSu+zrkL8Fl47l6QGzw +Brd7KJvX4V84c5Ss2XCTLdyEr0YconosP4EmQufU2MVshGYRi3drVByjtdgQ8K4p92cIiBdcuJd5 +z+orKu5YM+Vt6SmqZQENghPsJQtdLEByFSnTkCz3GkPVavBpAgMBAAGjYzBhMA8GA1UdEwEB/wQF +MAMBAf8wHwYDVR0jBBgwFoAU8snBDw1jALvsRQ5KH7WxszbNDo0wHQYDVR0OBBYEFPLJwQ8NYwC7 +7EUOSh+1sbM2zQ6NMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQwFAAOCAgEANGd5sjrG5T33 +I3K5Ce+SrScfoE4KsvXaFwyihdJ+klH9FWXXXGtkFu6KRcoMQzZENdl//nk6HOjG5D1rd9QhEOP2 +8yBOqb6J8xycqd+8MDoX0TJD0KqKchxRKEzdNsjkLWd9kYccnbz8qyiWXmFcuCIzGEgWUOrKL+ml +Sdx/PKQZvDatkuK59EvV6wit53j+F8Bdh3foZ3dPAGav9LEDOr4SfEE15fSmG0eLy3n31r8Xbk5l +8PjaV8GUgeV6Vg27Rn9vkf195hfkgSe7BYhW3SCl95gtkRlpMV+bMPKZrXJAlszYd2abtNUOshD+ +FKrDgHGdPY3ofRRsYWSGRqbXVMW215AWRqWFyp464+YTFrYVI8ypKVL9AMb2kI5Wj4kI3Zaq5tNq +qYY19tVFeEJKRvwDyF7YZvZFZSS0vod7VSCd9521Kvy5YhnLbDuv0204bKt7ph6N/Ome/msVuduC +msuY33OhkKCgxeDoAaijFJzIwZqsFVAzje18KotzlUBDJvyBpCpfOZC3J8tRd/iWkx7P8nd9H0aT +olkelUTFLXVksNb54Dxp6gS1HAviRkRNQzuXSXERvSS2wq1yVAb+axj5d9spLFKebXd7Yv0PTY6Y +MjAwcRLWJTXjn/hvnLXrahut6hDTlhZyBiElxky8j3C7DOReIoMt0r7+hVu05L0= +-----END CERTIFICATE----- diff --git a/includes/vendor/rmccue/requests/certificates/cacert.pem.sha256 b/includes/vendor/rmccue/requests/certificates/cacert.pem.sha256 new file mode 100644 index 000000000..394e4a9a4 --- /dev/null +++ b/includes/vendor/rmccue/requests/certificates/cacert.pem.sha256 @@ -0,0 +1 @@ +f1407d974c5ed87d544bd931a278232e13925177e239fca370619aba63c757b4 cacert.pem diff --git a/includes/vendor/rmccue/requests/library/Deprecated.php b/includes/vendor/rmccue/requests/library/Deprecated.php new file mode 100644 index 000000000..471eed57e --- /dev/null +++ b/includes/vendor/rmccue/requests/library/Deprecated.php @@ -0,0 +1,19 @@ +dispatch('requests.before_request', array(&$url, &$headers, &$data, &$type, &$options)); - - if (!empty($options['transport'])) { - $transport = $options['transport']; - - if (is_string($options['transport'])) { - $transport = new $transport(); - } - } - else { - $need_ssl = (0 === stripos($url, 'https://')); - $capabilities = array('ssl' => $need_ssl); - $transport = self::get_transport($capabilities); - } - $response = $transport->request($url, $headers, $data, $options); - - $options['hooks']->dispatch('requests.before_parse', array(&$response, $url, $headers, $data, $type, $options)); - - return self::parse_response($response, $url, $headers, $data, $options); - } - - /** - * Send multiple HTTP requests simultaneously - * - * The `$requests` parameter takes an associative or indexed array of - * request fields. The key of each request can be used to match up the - * request with the returned data, or with the request passed into your - * `multiple.request.complete` callback. - * - * The request fields value is an associative array with the following keys: - * - * - `url`: Request URL Same as the `$url` parameter to - * {@see Requests::request} - * (string, required) - * - `headers`: Associative array of header fields. Same as the `$headers` - * parameter to {@see Requests::request} - * (array, default: `array()`) - * - `data`: Associative array of data fields or a string. Same as the - * `$data` parameter to {@see Requests::request} - * (array|string, default: `array()`) - * - `type`: HTTP request type (use Requests constants). Same as the `$type` - * parameter to {@see Requests::request} - * (string, default: `Requests::GET`) - * - `cookies`: Associative array of cookie name to value, or cookie jar. - * (array|Requests_Cookie_Jar) - * - * If the `$options` parameter is specified, individual requests will - * inherit options from it. This can be used to use a single hooking system, - * or set all the types to `Requests::POST`, for example. - * - * In addition, the `$options` parameter takes the following global options: - * - * - `complete`: A callback for when a request is complete. Takes two - * parameters, a Requests_Response/Requests_Exception reference, and the - * ID from the request array (Note: this can also be overridden on a - * per-request basis, although that's a little silly) - * (callback) - * - * @param array $requests Requests data (see description for more information) - * @param array $options Global and default options (see {@see Requests::request}) - * @return array Responses (either Requests_Response or a Requests_Exception object) - */ - public static function request_multiple($requests, $options = array()) { - $options = array_merge(self::get_default_options(true), $options); - - if (!empty($options['hooks'])) { - $options['hooks']->register('transport.internal.parse_response', array('Requests', 'parse_multiple')); - if (!empty($options['complete'])) { - $options['hooks']->register('multiple.request.complete', $options['complete']); - } - } - - foreach ($requests as $id => &$request) { - if (!isset($request['headers'])) { - $request['headers'] = array(); - } - if (!isset($request['data'])) { - $request['data'] = array(); - } - if (!isset($request['type'])) { - $request['type'] = self::GET; - } - if (!isset($request['options'])) { - $request['options'] = $options; - $request['options']['type'] = $request['type']; - } - else { - if (empty($request['options']['type'])) { - $request['options']['type'] = $request['type']; - } - $request['options'] = array_merge($options, $request['options']); - } - - self::set_defaults($request['url'], $request['headers'], $request['data'], $request['type'], $request['options']); - - // Ensure we only hook in once - if ($request['options']['hooks'] !== $options['hooks']) { - $request['options']['hooks']->register('transport.internal.parse_response', array('Requests', 'parse_multiple')); - if (!empty($request['options']['complete'])) { - $request['options']['hooks']->register('multiple.request.complete', $request['options']['complete']); - } - } - } - unset($request); - - if (!empty($options['transport'])) { - $transport = $options['transport']; - - if (is_string($options['transport'])) { - $transport = new $transport(); - } - } - else { - $transport = self::get_transport(); - } - $responses = $transport->request_multiple($requests, $options); - - foreach ($responses as $id => &$response) { - // If our hook got messed with somehow, ensure we end up with the - // correct response - if (is_string($response)) { - $request = $requests[$id]; - self::parse_multiple($response, $request); - $request['options']['hooks']->dispatch('multiple.request.complete', array(&$response, $id)); - } - } - - return $responses; - } - - /** - * Get the default options - * - * @see Requests::request() for values returned by this method - * @param boolean $multirequest Is this a multirequest? - * @return array Default option values - */ - protected static function get_default_options($multirequest = false) { - $defaults = array( - 'timeout' => 10, - 'connect_timeout' => 10, - 'useragent' => 'php-requests/' . self::VERSION, - 'protocol_version' => 1.1, - 'redirected' => 0, - 'redirects' => 10, - 'follow_redirects' => true, - 'blocking' => true, - 'type' => self::GET, - 'filename' => false, - 'auth' => false, - 'proxy' => false, - 'cookies' => false, - 'max_bytes' => false, - 'idn' => true, - 'hooks' => null, - 'transport' => null, - 'verify' => Requests::get_certificate_path(), - 'verifyname' => true, - ); - if ($multirequest !== false) { - $defaults['complete'] = null; - } - return $defaults; - } - - /** - * Get default certificate path. - * - * @return string Default certificate path. - */ - public static function get_certificate_path() { - if ( ! empty( Requests::$certificate_path ) ) { - return Requests::$certificate_path; - } - - return dirname(__FILE__) . '/Requests/Transport/cacert.pem'; - } - - /** - * Set default certificate path. - * - * @param string $path Certificate path, pointing to a PEM file. - */ - public static function set_certificate_path( $path ) { - Requests::$certificate_path = $path; - } - - /** - * Set the default values - * - * @param string $url URL to request - * @param array $headers Extra headers to send with the request - * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests - * @param string $type HTTP request type - * @param array $options Options for the request - * @return array $options - */ - protected static function set_defaults(&$url, &$headers, &$data, &$type, &$options) { - if (!preg_match('/^http(s)?:\/\//i', $url, $matches)) { - throw new Requests_Exception('Only HTTP(S) requests are handled.', 'nonhttp', $url); - } - - if (empty($options['hooks'])) { - $options['hooks'] = new Requests_Hooks(); - } - - if (is_array($options['auth'])) { - $options['auth'] = new Requests_Auth_Basic($options['auth']); - } - if ($options['auth'] !== false) { - $options['auth']->register($options['hooks']); - } - - if (is_string($options['proxy']) || is_array($options['proxy'])) { - $options['proxy'] = new Requests_Proxy_HTTP($options['proxy']); - } - if ($options['proxy'] !== false) { - $options['proxy']->register($options['hooks']); - } - - if (is_array($options['cookies'])) { - $options['cookies'] = new Requests_Cookie_Jar($options['cookies']); - } - elseif (empty($options['cookies'])) { - $options['cookies'] = new Requests_Cookie_Jar(); - } - if ($options['cookies'] !== false) { - $options['cookies']->register($options['hooks']); - } - - if ($options['idn'] !== false) { - $iri = new Requests_IRI($url); - $iri->host = Requests_IDNAEncoder::encode($iri->ihost); - $url = $iri->uri; - } - - // Massage the type to ensure we support it. - $type = strtoupper($type); - - if (!isset($options['data_format'])) { - if (in_array($type, array(self::HEAD, self::GET, self::DELETE))) { - $options['data_format'] = 'query'; - } - else { - $options['data_format'] = 'body'; - } - } - } - - /** - * HTTP response parser - * - * @throws Requests_Exception On missing head/body separator (`requests.no_crlf_separator`) - * @throws Requests_Exception On missing head/body separator (`noversion`) - * @throws Requests_Exception On missing head/body separator (`toomanyredirects`) - * - * @param string $headers Full response text including headers and body - * @param string $url Original request URL - * @param array $req_headers Original $headers array passed to {@link request()}, in case we need to follow redirects - * @param array $req_data Original $data array passed to {@link request()}, in case we need to follow redirects - * @param array $options Original $options array passed to {@link request()}, in case we need to follow redirects - * @return Requests_Response - */ - protected static function parse_response($headers, $url, $req_headers, $req_data, $options) { - $return = new Requests_Response(); - if (!$options['blocking']) { - return $return; - } - - $return->raw = $headers; - $return->url = $url; - - if (!$options['filename']) { - if (($pos = strpos($headers, "\r\n\r\n")) === false) { - // Crap! - throw new Requests_Exception('Missing header/body separator', 'requests.no_crlf_separator'); - } - - $headers = substr($return->raw, 0, $pos); - $return->body = substr($return->raw, $pos + strlen("\n\r\n\r")); - } - else { - $return->body = ''; - } - // Pretend CRLF = LF for compatibility (RFC 2616, section 19.3) - $headers = str_replace("\r\n", "\n", $headers); - // Unfold headers (replace [CRLF] 1*( SP | HT ) with SP) as per RFC 2616 (section 2.2) - $headers = preg_replace('/\n[ \t]/', ' ', $headers); - $headers = explode("\n", $headers); - preg_match('#^HTTP/(1\.\d)[ \t]+(\d+)#i', array_shift($headers), $matches); - if (empty($matches)) { - throw new Requests_Exception('Response could not be parsed', 'noversion', $headers); - } - $return->protocol_version = (float) $matches[1]; - $return->status_code = (int) $matches[2]; - if ($return->status_code >= 200 && $return->status_code < 300) { - $return->success = true; - } - - foreach ($headers as $header) { - list($key, $value) = explode(':', $header, 2); - $value = trim($value); - preg_replace('#(\s+)#i', ' ', $value); - $return->headers[$key] = $value; - } - if (isset($return->headers['transfer-encoding'])) { - $return->body = self::decode_chunked($return->body); - unset($return->headers['transfer-encoding']); - } - if (isset($return->headers['content-encoding'])) { - $return->body = self::decompress($return->body); - } - - //fsockopen and cURL compatibility - if (isset($return->headers['connection'])) { - unset($return->headers['connection']); - } - - $options['hooks']->dispatch('requests.before_redirect_check', array(&$return, $req_headers, $req_data, $options)); - - if ($return->is_redirect() && $options['follow_redirects'] === true) { - if (isset($return->headers['location']) && $options['redirected'] < $options['redirects']) { - if ($return->status_code === 303) { - $options['type'] = self::GET; - } - $options['redirected']++; - $location = $return->headers['location']; - if (strpos($location, 'http://') !== 0 && strpos($location, 'https://') !== 0) { - // relative redirect, for compatibility make it absolute - $location = Requests_IRI::absolutize($url, $location); - $location = $location->uri; - } - - $hook_args = array( - &$location, - &$req_headers, - &$req_data, - &$options, - $return - ); - $options['hooks']->dispatch('requests.before_redirect', $hook_args); - $redirected = self::request($location, $req_headers, $req_data, $options['type'], $options); - $redirected->history[] = $return; - return $redirected; - } - elseif ($options['redirected'] >= $options['redirects']) { - throw new Requests_Exception('Too many redirects', 'toomanyredirects', $return); - } - } - - $return->redirects = $options['redirected']; - - $options['hooks']->dispatch('requests.after_request', array(&$return, $req_headers, $req_data, $options)); - return $return; - } - - /** - * Callback for `transport.internal.parse_response` - * - * Internal use only. Converts a raw HTTP response to a Requests_Response - * while still executing a multiple request. - * - * @param string $response Full response text including headers and body (will be overwritten with Response instance) - * @param array $request Request data as passed into {@see Requests::request_multiple()} - * @return null `$response` is either set to a Requests_Response instance, or a Requests_Exception object - */ - public static function parse_multiple(&$response, $request) { - try { - $url = $request['url']; - $headers = $request['headers']; - $data = $request['data']; - $options = $request['options']; - $response = self::parse_response($response, $url, $headers, $data, $options); - } - catch (Requests_Exception $e) { - $response = $e; - } - } - - /** - * Decoded a chunked body as per RFC 2616 - * - * @see https://tools.ietf.org/html/rfc2616#section-3.6.1 - * @param string $data Chunked body - * @return string Decoded body - */ - protected static function decode_chunked($data) { - if (!preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', trim($data))) { - return $data; - } - - - - $decoded = ''; - $encoded = $data; - - while (true) { - $is_chunked = (bool) preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', $encoded, $matches); - if (!$is_chunked) { - // Looks like it's not chunked after all - return $data; - } - - $length = hexdec(trim($matches[1])); - if ($length === 0) { - // Ignore trailer headers - return $decoded; - } - - $chunk_length = strlen($matches[0]); - $decoded .= substr($encoded, $chunk_length, $length); - $encoded = substr($encoded, $chunk_length + $length + 2); - - if (trim($encoded) === '0' || empty($encoded)) { - return $decoded; - } - } - - // We'll never actually get down here - // @codeCoverageIgnoreStart - } - // @codeCoverageIgnoreEnd - - /** - * Convert a key => value array to a 'key: value' array for headers - * - * @param array $array Dictionary of header values - * @return array List of headers - */ - public static function flatten($array) { - $return = array(); - foreach ($array as $key => $value) { - $return[] = sprintf('%s: %s', $key, $value); - } - return $return; - } - - /** - * Convert a key => value array to a 'key: value' array for headers + * @deprecated 2.0.0 Include the `WpOrg\Requests\Autoload` class and + * call `WpOrg\Requests\Autoload::register()` instead. * * @codeCoverageIgnore - * @deprecated Misspelling of {@see Requests::flatten} - * @param array $array Dictionary of header values - * @return array List of headers - */ - public static function flattern($array) { - return self::flatten($array); - } - - /** - * Decompress an encoded body - * - * Implements gzip, compress and deflate. Guesses which it is by attempting - * to decode. - * - * @param string $data Compressed data in one of the above formats - * @return string Decompressed string - */ - public static function decompress($data) { - if (substr($data, 0, 2) !== "\x1f\x8b" && substr($data, 0, 2) !== "\x78\x9c") { - // Not actually compressed. Probably cURL ruining this for us. - return $data; - } - - if (function_exists('gzdecode') && ($decoded = @gzdecode($data)) !== false) { - return $decoded; - } - elseif (function_exists('gzinflate') && ($decoded = @gzinflate($data)) !== false) { - return $decoded; - } - elseif (($decoded = self::compatible_gzinflate($data)) !== false) { - return $decoded; - } - elseif (function_exists('gzuncompress') && ($decoded = @gzuncompress($data)) !== false) { - return $decoded; - } - - return $data; - } - - /** - * Decompression of deflated string while staying compatible with the majority of servers. - * - * Certain Servers will return deflated data with headers which PHP's gzinflate() - * function cannot handle out of the box. The following function has been created from - * various snippets on the gzinflate() PHP documentation. - * - * Warning: Magic numbers within. Due to the potential different formats that the compressed - * data may be returned in, some "magic offsets" are needed to ensure proper decompression - * takes place. For a simple progmatic way to determine the magic offset in use, see: - * https://core.trac.wordpress.org/ticket/18273 - * - * @since 2.8.1 - * @link https://core.trac.wordpress.org/ticket/18273 - * @link https://secure.php.net/manual/en/function.gzinflate.php#70875 - * @link https://secure.php.net/manual/en/function.gzinflate.php#77336 - * - * @param string $gzData String to decompress. - * @return string|bool False on failure. */ - public static function compatible_gzinflate($gzData) { - // Compressed data might contain a full zlib header, if so strip it for - // gzinflate() - if (substr($gzData, 0, 3) == "\x1f\x8b\x08") { - $i = 10; - $flg = ord(substr($gzData, 3, 1)); - if ($flg > 0) { - if ($flg & 4) { - list($xlen) = unpack('v', substr($gzData, $i, 2)); - $i = $i + 2 + $xlen; - } - if ($flg & 8) { - $i = strpos($gzData, "\0", $i) + 1; - } - if ($flg & 16) { - $i = strpos($gzData, "\0", $i) + 1; - } - if ($flg & 2) { - $i = $i + 2; - } - } - $decompressed = self::compatible_gzinflate(substr($gzData, $i)); - if (false !== $decompressed) { - return $decompressed; - } - } - - // If the data is Huffman Encoded, we must first strip the leading 2 - // byte Huffman marker for gzinflate() - // The response is Huffman coded by many compressors such as - // java.util.zip.Deflater, Ruby’s Zlib::Deflate, and .NET's - // System.IO.Compression.DeflateStream. - // - // See https://decompres.blogspot.com/ for a quick explanation of this - // data type - $huffman_encoded = false; - - // low nibble of first byte should be 0x08 - list(, $first_nibble) = unpack('h', $gzData); - - // First 2 bytes should be divisible by 0x1F - list(, $first_two_bytes) = unpack('n', $gzData); - - if (0x08 == $first_nibble && 0 == ($first_two_bytes % 0x1F)) { - $huffman_encoded = true; - } - - if ($huffman_encoded) { - if (false !== ($decompressed = @gzinflate(substr($gzData, 2)))) { - return $decompressed; - } - } - - if ("\x50\x4b\x03\x04" == substr($gzData, 0, 4)) { - // ZIP file format header - // Offset 6: 2 bytes, General-purpose field - // Offset 26: 2 bytes, filename length - // Offset 28: 2 bytes, optional field length - // Offset 30: Filename field, followed by optional field, followed - // immediately by data - list(, $general_purpose_flag) = unpack('v', substr($gzData, 6, 2)); - - // If the file has been compressed on the fly, 0x08 bit is set of - // the general purpose field. We can use this to differentiate - // between a compressed document, and a ZIP file - $zip_compressed_on_the_fly = (0x08 == (0x08 & $general_purpose_flag)); - - if (!$zip_compressed_on_the_fly) { - // Don't attempt to decode a compressed zip file - return $gzData; - } - - // Determine the first byte of data, based on the above ZIP header - // offsets: - $first_file_start = array_sum(unpack('v2', substr($gzData, 26, 4))); - if (false !== ($decompressed = @gzinflate(substr($gzData, 30 + $first_file_start)))) { - return $decompressed; - } - return false; - } - - // Finally fall back to straight gzinflate - if (false !== ($decompressed = @gzinflate($gzData))) { - return $decompressed; - } - - // Fallback for all above failing, not expected, but included for - // debugging and preventing regressions and to track stats - if (false !== ($decompressed = @gzinflate(substr($gzData, 2)))) { - return $decompressed; - } - - return false; - } - - public static function match_domain($host, $reference) { - // Check for a direct match - if ($host === $reference) { - return true; - } - - // Calculate the valid wildcard match if the host is not an IP address - // Also validates that the host has 3 parts or more, as per Firefox's - // ruleset. - $parts = explode('.', $host); - if (ip2long($host) === false && count($parts) >= 3) { - $parts[0] = '*'; - $wildcard = implode('.', $parts); - if ($wildcard === $reference) { - return true; - } - } - - return false; + public static function register_autoloader() { + require_once dirname(__DIR__) . '/src/Autoload.php'; + WpOrg\Requests\Autoload::register(); } } diff --git a/includes/vendor/rmccue/requests/library/Requests/Auth.php b/includes/vendor/rmccue/requests/library/Requests/Auth.php deleted file mode 100644 index bca410920..000000000 --- a/includes/vendor/rmccue/requests/library/Requests/Auth.php +++ /dev/null @@ -1,33 +0,0 @@ -user, $this->pass) = $args; - } - } - - /** - * Register the necessary callbacks - * - * @see curl_before_send - * @see fsockopen_header - * @param Requests_Hooks $hooks Hook system - */ - public function register(Requests_Hooks &$hooks) { - $hooks->register('curl.before_send', array(&$this, 'curl_before_send')); - $hooks->register('fsockopen.after_headers', array(&$this, 'fsockopen_header')); - } - - /** - * Set cURL parameters before the data is sent - * - * @param resource $handle cURL resource - */ - public function curl_before_send(&$handle) { - curl_setopt($handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); - curl_setopt($handle, CURLOPT_USERPWD, $this->getAuthString()); - } - - /** - * Add extra headers to the request before sending - * - * @param string $out HTTP header string - */ - public function fsockopen_header(&$out) { - $out .= sprintf("Authorization: Basic %s\r\n", base64_encode($this->getAuthString())); - } - - /** - * Get the authentication string (user:pass) - * - * @return string - */ - public function getAuthString() { - return $this->user . ':' . $this->pass; - } -} \ No newline at end of file diff --git a/includes/vendor/rmccue/requests/library/Requests/Cookie/Jar.php b/includes/vendor/rmccue/requests/library/Requests/Cookie/Jar.php deleted file mode 100644 index 69be0fb57..000000000 --- a/includes/vendor/rmccue/requests/library/Requests/Cookie/Jar.php +++ /dev/null @@ -1,175 +0,0 @@ -cookies = $cookies; - } - - /** - * Normalise cookie data into a Requests_Cookie - * - * @param string|Requests_Cookie $cookie - * @return Requests_Cookie - */ - public function normalize_cookie($cookie, $key = null) { - if ($cookie instanceof Requests_Cookie) { - return $cookie; - } - - return Requests_Cookie::parse($cookie, $key); - } - - /** - * Normalise cookie data into a Requests_Cookie - * - * @codeCoverageIgnore - * @deprecated Use {@see Requests_Cookie_Jar::normalize_cookie} - * @return Requests_Cookie - */ - public function normalizeCookie($cookie, $key = null) { - return $this->normalize_cookie($cookie, $key); - } - - /** - * Check if the given item exists - * - * @param string $key Item key - * @return boolean Does the item exist? - */ - public function offsetExists($key) { - return isset($this->cookies[$key]); - } - - /** - * Get the value for the item - * - * @param string $key Item key - * @return string Item value - */ - public function offsetGet($key) { - if (!isset($this->cookies[$key])) { - return null; - } - - return $this->cookies[$key]; - } - - /** - * Set the given item - * - * @throws Requests_Exception On attempting to use dictionary as list (`invalidset`) - * - * @param string $key Item name - * @param string $value Item value - */ - public function offsetSet($key, $value) { - if ($key === null) { - throw new Requests_Exception('Object is a dictionary, not a list', 'invalidset'); - } - - $this->cookies[$key] = $value; - } - - /** - * Unset the given header - * - * @param string $key - */ - public function offsetUnset($key) { - unset($this->cookies[$key]); - } - - /** - * Get an iterator for the data - * - * @return ArrayIterator - */ - public function getIterator() { - return new ArrayIterator($this->cookies); - } - - /** - * Register the cookie handler with the request's hooking system - * - * @param Requests_Hooker $hooks Hooking system - */ - public function register(Requests_Hooker $hooks) { - $hooks->register('requests.before_request', array($this, 'before_request')); - $hooks->register('requests.before_redirect_check', array($this, 'before_redirect_check')); - } - - /** - * Add Cookie header to a request if we have any - * - * As per RFC 6265, cookies are separated by '; ' - * - * @param string $url - * @param array $headers - * @param array $data - * @param string $type - * @param array $options - */ - public function before_request($url, &$headers, &$data, &$type, &$options) { - if (!$url instanceof Requests_IRI) { - $url = new Requests_IRI($url); - } - - if (!empty($this->cookies)) { - $cookies = array(); - foreach ($this->cookies as $key => $cookie) { - $cookie = $this->normalize_cookie($cookie, $key); - - // Skip expired cookies - if ($cookie->is_expired()) { - continue; - } - - if ($cookie->domain_matches($url->host)) { - $cookies[] = $cookie->format_for_header(); - } - } - - $headers['Cookie'] = implode('; ', $cookies); - } - } - - /** - * Parse all cookies from a response and attach them to the response - * - * @var Requests_Response $response - */ - public function before_redirect_check(Requests_Response &$return) { - $url = $return->url; - if (!$url instanceof Requests_IRI) { - $url = new Requests_IRI($url); - } - - $cookies = Requests_Cookie::parse_from_headers($return->headers, $url); - $this->cookies = array_merge($this->cookies, $cookies); - $return->cookies = $this; - } -} \ No newline at end of file diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/429.php b/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/429.php deleted file mode 100644 index 2a21fb345..000000000 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/429.php +++ /dev/null @@ -1,29 +0,0 @@ -0 is executed later - */ - public function register($hook, $callback, $priority = 0) { - if (!isset($this->hooks[$hook])) { - $this->hooks[$hook] = array(); - } - if (!isset($this->hooks[$hook][$priority])) { - $this->hooks[$hook][$priority] = array(); - } - - $this->hooks[$hook][$priority][] = $callback; - } - - /** - * Dispatch a message - * - * @param string $hook Hook name - * @param array $parameters Parameters to pass to callbacks - * @return boolean Successfulness - */ - public function dispatch($hook, $parameters = array()) { - if (empty($this->hooks[$hook])) { - return false; - } - - foreach ($this->hooks[$hook] as $priority => $hooked) { - foreach ($hooked as $callback) { - call_user_func_array($callback, $parameters); - } - } - - return true; - } -} \ No newline at end of file diff --git a/includes/vendor/rmccue/requests/library/Requests/IDNAEncoder.php b/includes/vendor/rmccue/requests/library/Requests/IDNAEncoder.php deleted file mode 100644 index ebbe2111b..000000000 --- a/includes/vendor/rmccue/requests/library/Requests/IDNAEncoder.php +++ /dev/null @@ -1,388 +0,0 @@ - 0) { - if ($position + $length > $strlen) { - throw new Requests_Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character); - } - for ($position++; $remaining > 0; $position++) { - $value = ord($input[$position]); - - // If it is invalid, count the sequence as invalid and reprocess the current byte: - if (($value & 0xC0) !== 0x80) { - throw new Requests_Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character); - } - - $character |= ($value & 0x3F) << (--$remaining * 6); - } - $position--; - } - - if ( - // Non-shortest form sequences are invalid - $length > 1 && $character <= 0x7F - || $length > 2 && $character <= 0x7FF - || $length > 3 && $character <= 0xFFFF - // Outside of range of ucschar codepoints - // Noncharacters - || ($character & 0xFFFE) === 0xFFFE - || $character >= 0xFDD0 && $character <= 0xFDEF - || ( - // Everything else not in ucschar - $character > 0xD7FF && $character < 0xF900 - || $character < 0x20 - || $character > 0x7E && $character < 0xA0 - || $character > 0xEFFFD - ) - ) { - throw new Requests_Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character); - } - - $codepoints[] = $character; - } - - return $codepoints; - } - - /** - * RFC3492-compliant encoder - * - * @internal Pseudo-code from Section 6.3 is commented with "#" next to relevant code - * @throws Requests_Exception On character outside of the domain (never happens with Punycode) (`idna.character_outside_domain`) - * - * @param string $input UTF-8 encoded string to encode - * @return string Punycode-encoded string - */ - public static function punycode_encode($input) { - $output = ''; -# let n = initial_n - $n = self::BOOTSTRAP_INITIAL_N; -# let delta = 0 - $delta = 0; -# let bias = initial_bias - $bias = self::BOOTSTRAP_INITIAL_BIAS; -# let h = b = the number of basic code points in the input - $h = $b = 0; // see loop -# copy them to the output in order - $codepoints = self::utf8_to_codepoints($input); - $extended = array(); - - foreach ($codepoints as $char) { - if ($char < 128) { - // Character is valid ASCII - // TODO: this should also check if it's valid for a URL - $output .= chr($char); - $h++; - } - // Check if the character is non-ASCII, but below initial n - // This never occurs for Punycode, so ignore in coverage - // @codeCoverageIgnoreStart - elseif ($char < $n) { - throw new Requests_Exception('Invalid character', 'idna.character_outside_domain', $char); - } - // @codeCoverageIgnoreEnd - else { - $extended[$char] = true; - } - } - $extended = array_keys($extended); - sort($extended); - $b = $h; -# [copy them] followed by a delimiter if b > 0 - if (strlen($output) > 0) { - $output .= '-'; - } -# {if the input contains a non-basic code point < n then fail} -# while h < length(input) do begin - while ($h < count($codepoints)) { -# let m = the minimum code point >= n in the input - $m = array_shift($extended); - //printf('next code point to insert is %s' . PHP_EOL, dechex($m)); -# let delta = delta + (m - n) * (h + 1), fail on overflow - $delta += ($m - $n) * ($h + 1); -# let n = m - $n = $m; -# for each code point c in the input (in order) do begin - for ($num = 0; $num < count($codepoints); $num++) { - $c = $codepoints[$num]; -# if c < n then increment delta, fail on overflow - if ($c < $n) { - $delta++; - } -# if c == n then begin - elseif ($c === $n) { -# let q = delta - $q = $delta; -# for k = base to infinity in steps of base do begin - for ($k = self::BOOTSTRAP_BASE; ; $k += self::BOOTSTRAP_BASE) { -# let t = tmin if k <= bias {+ tmin}, or -# tmax if k >= bias + tmax, or k - bias otherwise - if ($k <= ($bias + self::BOOTSTRAP_TMIN)) { - $t = self::BOOTSTRAP_TMIN; - } - elseif ($k >= ($bias + self::BOOTSTRAP_TMAX)) { - $t = self::BOOTSTRAP_TMAX; - } - else { - $t = $k - $bias; - } -# if q < t then break - if ($q < $t) { - break; - } -# output the code point for digit t + ((q - t) mod (base - t)) - $digit = $t + (($q - $t) % (self::BOOTSTRAP_BASE - $t)); - $output .= self::digit_to_char($digit); -# let q = (q - t) div (base - t) - $q = floor(($q - $t) / (self::BOOTSTRAP_BASE - $t)); -# end - } -# output the code point for digit q - $output .= self::digit_to_char($q); -# let bias = adapt(delta, h + 1, test h equals b?) - $bias = self::adapt($delta, $h + 1, $h === $b); -# let delta = 0 - $delta = 0; -# increment h - $h++; -# end - } -# end - } -# increment delta and n - $delta++; - $n++; -# end - } - - return $output; - } - - /** - * Convert a digit to its respective character - * - * @see https://tools.ietf.org/html/rfc3492#section-5 - * @throws Requests_Exception On invalid digit (`idna.invalid_digit`) - * - * @param int $digit Digit in the range 0-35 - * @return string Single character corresponding to digit - */ - protected static function digit_to_char($digit) { - // @codeCoverageIgnoreStart - // As far as I know, this never happens, but still good to be sure. - if ($digit < 0 || $digit > 35) { - throw new Requests_Exception(sprintf('Invalid digit %d', $digit), 'idna.invalid_digit', $digit); - } - // @codeCoverageIgnoreEnd - $digits = 'abcdefghijklmnopqrstuvwxyz0123456789'; - return substr($digits, $digit, 1); - } - - /** - * Adapt the bias - * - * @see https://tools.ietf.org/html/rfc3492#section-6.1 - * @param int $delta - * @param int $numpoints - * @param bool $firsttime - * @return int New bias - */ - protected static function adapt($delta, $numpoints, $firsttime) { -# function adapt(delta,numpoints,firsttime): -# if firsttime then let delta = delta div damp - if ($firsttime) { - $delta = floor($delta / self::BOOTSTRAP_DAMP); - } -# else let delta = delta div 2 - else { - $delta = floor($delta / 2); - } -# let delta = delta + (delta div numpoints) - $delta += floor($delta / $numpoints); -# let k = 0 - $k = 0; -# while delta > ((base - tmin) * tmax) div 2 do begin - $max = floor(((self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN) * self::BOOTSTRAP_TMAX) / 2); - while ($delta > $max) { -# let delta = delta div (base - tmin) - $delta = floor($delta / (self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN)); -# let k = k + base - $k += self::BOOTSTRAP_BASE; -# end - } -# return k + (((base - tmin + 1) * delta) div (delta + skew)) - return $k + floor(((self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN + 1) * $delta) / ($delta + self::BOOTSTRAP_SKEW)); - } -} \ No newline at end of file diff --git a/includes/vendor/rmccue/requests/library/Requests/Proxy.php b/includes/vendor/rmccue/requests/library/Requests/Proxy.php deleted file mode 100644 index ac7c1d6b0..000000000 --- a/includes/vendor/rmccue/requests/library/Requests/Proxy.php +++ /dev/null @@ -1,35 +0,0 @@ -headers = new Requests_Response_Headers(); - $this->cookies = new Requests_Cookie_Jar(); - } - - /** - * Response body - * - * @var string - */ - public $body = ''; - - /** - * Raw HTTP data from the transport - * - * @var string - */ - public $raw = ''; - - /** - * Headers, as an associative array - * - * @var Requests_Response_Headers Array-like object representing headers - */ - public $headers = array(); - - /** - * Status code, false if non-blocking - * - * @var integer|boolean - */ - public $status_code = false; - - /** - * Protocol version, false if non-blocking - * @var float|boolean - */ - public $protocol_version = false; - - /** - * Whether the request succeeded or not - * - * @var boolean - */ - public $success = false; - - /** - * Number of redirects the request used - * - * @var integer - */ - public $redirects = 0; - - /** - * URL requested - * - * @var string - */ - public $url = ''; - - /** - * Previous requests (from redirects) - * - * @var array Array of Requests_Response objects - */ - public $history = array(); - - /** - * Cookies from the request - * - * @var Requests_Cookie_Jar Array-like object representing a cookie jar - */ - public $cookies = array(); - - /** - * Is the response a redirect? - * - * @return boolean True if redirect (3xx status), false if not. - */ - public function is_redirect() { - $code = $this->status_code; - return in_array($code, array(300, 301, 302, 303, 307)) || $code > 307 && $code < 400; - } - - /** - * Throws an exception if the request was not successful - * - * @throws Requests_Exception If `$allow_redirects` is false, and code is 3xx (`response.no_redirects`) - * @throws Requests_Exception_HTTP On non-successful status code. Exception class corresponds to code (e.g. {@see Requests_Exception_HTTP_404}) - * @param boolean $allow_redirects Set to false to throw on a 3xx as well - */ - public function throw_for_status($allow_redirects = true) { - if ($this->is_redirect()) { - if (!$allow_redirects) { - throw new Requests_Exception('Redirection not allowed', 'response.no_redirects', $this); - } - } - elseif (!$this->success) { - $exception = Requests_Exception_HTTP::get_class($this->status_code); - throw new $exception(null, $this); - } - } -} diff --git a/includes/vendor/rmccue/requests/library/Requests/Response/Headers.php b/includes/vendor/rmccue/requests/library/Requests/Response/Headers.php deleted file mode 100644 index cc6a20872..000000000 --- a/includes/vendor/rmccue/requests/library/Requests/Response/Headers.php +++ /dev/null @@ -1,98 +0,0 @@ -data[$key])) { - return null; - } - - return $this->flatten($this->data[$key]); - } - - /** - * Set the given item - * - * @throws Requests_Exception On attempting to use dictionary as list (`invalidset`) - * - * @param string $key Item name - * @param string $value Item value - */ - public function offsetSet($key, $value) { - if ($key === null) { - throw new Requests_Exception('Object is a dictionary, not a list', 'invalidset'); - } - - $key = strtolower($key); - - if (!isset($this->data[$key])) { - $this->data[$key] = array(); - } - - $this->data[$key][] = $value; - } - - /** - * Get all values for a given header - * - * @param string $key - * @return array Header values - */ - public function getValues($key) { - $key = strtolower($key); - if (!isset($this->data[$key])) { - return null; - } - - return $this->data[$key]; - } - - /** - * Flattens a value into a string - * - * Converts an array into a string by imploding values with a comma, as per - * RFC2616's rules for folding headers. - * - * @param string|array $value Value to flatten - * @return string Flattened value - */ - public function flatten($value) { - if (is_array($value)) { - $value = implode(',', $value); - } - - return $value; - } - - /** - * Get an iterator for the data - * - * Converts the internal - * @return ArrayIterator - */ - public function getIterator() { - return new Requests_Utility_FilteredIterator($this->data, array($this, 'flatten')); - } -} diff --git a/includes/vendor/rmccue/requests/library/Requests/Transport.php b/includes/vendor/rmccue/requests/library/Requests/Transport.php deleted file mode 100644 index 7e4a26293..000000000 --- a/includes/vendor/rmccue/requests/library/Requests/Transport.php +++ /dev/null @@ -1,41 +0,0 @@ -dispatch('fsockopen.before_request'); - - $url_parts = parse_url($url); - if (empty($url_parts)) { - throw new Requests_Exception('Invalid URL.', 'invalidurl', $url); - } - $host = $url_parts['host']; - $context = stream_context_create(); - $verifyname = false; - $case_insensitive_headers = new Requests_Utility_CaseInsensitiveDictionary($headers); - - // HTTPS support - if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https') { - $remote_socket = 'ssl://' . $host; - if (!isset($url_parts['port'])) { - $url_parts['port'] = 443; - } - - $context_options = array( - 'verify_peer' => true, - // 'CN_match' => $host, - 'capture_peer_cert' => true - ); - $verifyname = true; - - // SNI, if enabled (OpenSSL >=0.9.8j) - if (defined('OPENSSL_TLSEXT_SERVER_NAME') && OPENSSL_TLSEXT_SERVER_NAME) { - $context_options['SNI_enabled'] = true; - if (isset($options['verifyname']) && $options['verifyname'] === false) { - $context_options['SNI_enabled'] = false; - } - } - - if (isset($options['verify'])) { - if ($options['verify'] === false) { - $context_options['verify_peer'] = false; - } - elseif (is_string($options['verify'])) { - $context_options['cafile'] = $options['verify']; - } - } - - if (isset($options['verifyname']) && $options['verifyname'] === false) { - $context_options['verify_peer_name'] = false; - $verifyname = false; - } - - stream_context_set_option($context, array('ssl' => $context_options)); - } - else { - $remote_socket = 'tcp://' . $host; - } - - $this->max_bytes = $options['max_bytes']; - - if (!isset($url_parts['port'])) { - $url_parts['port'] = 80; - } - $remote_socket .= ':' . $url_parts['port']; - - set_error_handler(array($this, 'connect_error_handler'), E_WARNING | E_NOTICE); - - $options['hooks']->dispatch('fsockopen.remote_socket', array(&$remote_socket)); - - $socket = stream_socket_client($remote_socket, $errno, $errstr, ceil($options['connect_timeout']), STREAM_CLIENT_CONNECT, $context); - - restore_error_handler(); - - if ($verifyname && !$this->verify_certificate_from_context($host, $context)) { - throw new Requests_Exception('SSL certificate did not match the requested domain name', 'ssl.no_match'); - } - - if (!$socket) { - if ($errno === 0) { - // Connection issue - throw new Requests_Exception(rtrim($this->connect_error), 'fsockopen.connect_error'); - } - - throw new Requests_Exception($errstr, 'fsockopenerror', null, $errno); - } - - $data_format = $options['data_format']; - - if ($data_format === 'query') { - $path = self::format_get($url_parts, $data); - $data = ''; - } - else { - $path = self::format_get($url_parts, array()); - } - - $options['hooks']->dispatch('fsockopen.remote_host_path', array(&$path, $url)); - - $request_body = ''; - $out = sprintf("%s %s HTTP/%.1f\r\n", $options['type'], $path, $options['protocol_version']); - - if ($options['type'] !== Requests::TRACE) { - if (is_array($data)) { - $request_body = http_build_query($data, null, '&'); - } - else { - $request_body = $data; - } - - if (!empty($data)) { - if (!isset($case_insensitive_headers['Content-Length'])) { - $headers['Content-Length'] = strlen($request_body); - } - - if (!isset($case_insensitive_headers['Content-Type'])) { - $headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; - } - } - } - - if (!isset($case_insensitive_headers['Host'])) { - $out .= sprintf('Host: %s', $url_parts['host']); - - if (( 'http' === strtolower($url_parts['scheme']) && $url_parts['port'] !== 80 ) || ( 'https' === strtolower($url_parts['scheme']) && $url_parts['port'] !== 443 )) { - $out .= ':' . $url_parts['port']; - } - $out .= "\r\n"; - } - - if (!isset($case_insensitive_headers['User-Agent'])) { - $out .= sprintf("User-Agent: %s\r\n", $options['useragent']); - } - - $accept_encoding = $this->accept_encoding(); - if (!isset($case_insensitive_headers['Accept-Encoding']) && !empty($accept_encoding)) { - $out .= sprintf("Accept-Encoding: %s\r\n", $accept_encoding); - } - - $headers = Requests::flatten($headers); - - if (!empty($headers)) { - $out .= implode($headers, "\r\n") . "\r\n"; - } - - $options['hooks']->dispatch('fsockopen.after_headers', array(&$out)); - - if (substr($out, -2) !== "\r\n") { - $out .= "\r\n"; - } - - if (!isset($case_insensitive_headers['Connection'])) { - $out .= "Connection: Close\r\n"; - } - - $out .= "\r\n" . $request_body; - - $options['hooks']->dispatch('fsockopen.before_send', array(&$out)); - - fwrite($socket, $out); - $options['hooks']->dispatch('fsockopen.after_send', array($out)); - - if (!$options['blocking']) { - fclose($socket); - $fake_headers = ''; - $options['hooks']->dispatch('fsockopen.after_request', array(&$fake_headers)); - return ''; - } - - $timeout_sec = (int) floor($options['timeout']); - if ($timeout_sec == $options['timeout']) { - $timeout_msec = 0; - } - else { - $timeout_msec = self::SECOND_IN_MICROSECONDS * $options['timeout'] % self::SECOND_IN_MICROSECONDS; - } - stream_set_timeout($socket, $timeout_sec, $timeout_msec); - - $response = $body = $headers = ''; - $this->info = stream_get_meta_data($socket); - $size = 0; - $doingbody = false; - $download = false; - if ($options['filename']) { - $download = fopen($options['filename'], 'wb'); - } - - while (!feof($socket)) { - $this->info = stream_get_meta_data($socket); - if ($this->info['timed_out']) { - throw new Requests_Exception('fsocket timed out', 'timeout'); - } - - $block = fread($socket, Requests::BUFFER_SIZE); - if (!$doingbody) { - $response .= $block; - if (strpos($response, "\r\n\r\n")) { - list($headers, $block) = explode("\r\n\r\n", $response, 2); - $doingbody = true; - } - } - - // Are we in body mode now? - if ($doingbody) { - $options['hooks']->dispatch('request.progress', array($block, $size, $this->max_bytes)); - $data_length = strlen($block); - if ($this->max_bytes) { - // Have we already hit a limit? - if ($size === $this->max_bytes) { - continue; - } - if (($size + $data_length) > $this->max_bytes) { - // Limit the length - $limited_length = ($this->max_bytes - $size); - $block = substr($block, 0, $limited_length); - } - } - - $size += strlen($block); - if ($download) { - fwrite($download, $block); - } - else { - $body .= $block; - } - } - } - $this->headers = $headers; - - if ($download) { - fclose($download); - } - else { - $this->headers .= "\r\n\r\n" . $body; - } - fclose($socket); - - $options['hooks']->dispatch('fsockopen.after_request', array(&$this->headers, &$this->info)); - return $this->headers; - } - - /** - * Send multiple requests simultaneously - * - * @param array $requests Request data (array of 'url', 'headers', 'data', 'options') as per {@see Requests_Transport::request} - * @param array $options Global options, see {@see Requests::response()} for documentation - * @return array Array of Requests_Response objects (may contain Requests_Exception or string responses as well) - */ - public function request_multiple($requests, $options) { - $responses = array(); - $class = get_class($this); - foreach ($requests as $id => $request) { - try { - $handler = new $class(); - $responses[$id] = $handler->request($request['url'], $request['headers'], $request['data'], $request['options']); - - $request['options']['hooks']->dispatch('transport.internal.parse_response', array(&$responses[$id], $request)); - } - catch (Requests_Exception $e) { - $responses[$id] = $e; - } - - if (!is_string($responses[$id])) { - $request['options']['hooks']->dispatch('multiple.request.complete', array(&$responses[$id], $id)); - } - } - - return $responses; - } - - /** - * Retrieve the encodings we can accept - * - * @return string Accept-Encoding header value - */ - protected static function accept_encoding() { - $type = array(); - if (function_exists('gzinflate')) { - $type[] = 'deflate;q=1.0'; - } - - if (function_exists('gzuncompress')) { - $type[] = 'compress;q=0.5'; - } - - $type[] = 'gzip;q=0.5'; - - return implode(', ', $type); - } - - /** - * Format a URL given GET data - * - * @param array $url_parts - * @param array|object $data Data to build query using, see {@see https://secure.php.net/http_build_query} - * @return string URL with data - */ - protected static function format_get($url_parts, $data) { - if (!empty($data)) { - if (empty($url_parts['query'])) { - $url_parts['query'] = ''; - } - - $url_parts['query'] .= '&' . http_build_query($data, null, '&'); - $url_parts['query'] = trim($url_parts['query'], '&'); - } - if (isset($url_parts['path'])) { - if (isset($url_parts['query'])) { - $get = $url_parts['path'] . '?' . $url_parts['query']; - } - else { - $get = $url_parts['path']; - } - } - else { - $get = '/'; - } - return $get; - } - - /** - * Error handler for stream_socket_client() - * - * @param int $errno Error number (e.g. E_WARNING) - * @param string $errstr Error message - */ - public function connect_error_handler($errno, $errstr) { - // Double-check we can handle it - if (($errno & E_WARNING) === 0 && ($errno & E_NOTICE) === 0) { - // Return false to indicate the default error handler should engage - return false; - } - - $this->connect_error .= $errstr . "\n"; - return true; - } - - /** - * Verify the certificate against common name and subject alternative names - * - * Unfortunately, PHP doesn't check the certificate against the alternative - * names, leading things like 'https://www.github.com/' to be invalid. - * Instead - * - * @see https://tools.ietf.org/html/rfc2818#section-3.1 RFC2818, Section 3.1 - * - * @throws Requests_Exception On failure to connect via TLS (`fsockopen.ssl.connect_error`) - * @throws Requests_Exception On not obtaining a match for the host (`fsockopen.ssl.no_match`) - * @param string $host Host name to verify against - * @param resource $context Stream context - * @return bool - */ - public function verify_certificate_from_context($host, $context) { - $meta = stream_context_get_options($context); - - // If we don't have SSL options, then we couldn't make the connection at - // all - if (empty($meta) || empty($meta['ssl']) || empty($meta['ssl']['peer_certificate'])) { - throw new Requests_Exception(rtrim($this->connect_error), 'ssl.connect_error'); - } - - $cert = openssl_x509_parse($meta['ssl']['peer_certificate']); - - return Requests_SSL::verify_certificate($host, $cert); - } - - /** - * Whether this transport is valid - * - * @codeCoverageIgnore - * @return boolean True if the transport is valid, false otherwise. - */ - public static function test($capabilities = array()) { - if (!function_exists('fsockopen')) { - return false; - } - - // If needed, check that streams support SSL - if (isset($capabilities['ssl']) && $capabilities['ssl']) { - if (!extension_loaded('openssl') || !function_exists('openssl_x509_parse')) { - return false; - } - - // Currently broken, thanks to https://github.com/facebook/hhvm/issues/2156 - if (defined('HHVM_VERSION')) { - return false; - } - } - - return true; - } -} diff --git a/includes/vendor/rmccue/requests/library/Requests/Utility/CaseInsensitiveDictionary.php b/includes/vendor/rmccue/requests/library/Requests/Utility/CaseInsensitiveDictionary.php deleted file mode 100644 index 2c97893a1..000000000 --- a/includes/vendor/rmccue/requests/library/Requests/Utility/CaseInsensitiveDictionary.php +++ /dev/null @@ -1,103 +0,0 @@ - $value) { - $this->offsetSet($key, $value); - } - } - - /** - * Check if the given item exists - * - * @param string $key Item key - * @return boolean Does the item exist? - */ - public function offsetExists($key) { - $key = strtolower($key); - return isset($this->data[$key]); - } - - /** - * Get the value for the item - * - * @param string $key Item key - * @return string Item value - */ - public function offsetGet($key) { - $key = strtolower($key); - if (!isset($this->data[$key])) { - return null; - } - - return $this->data[$key]; - } - - /** - * Set the given item - * - * @throws Requests_Exception On attempting to use dictionary as list (`invalidset`) - * - * @param string $key Item name - * @param string $value Item value - */ - public function offsetSet($key, $value) { - if ($key === null) { - throw new Requests_Exception('Object is a dictionary, not a list', 'invalidset'); - } - - $key = strtolower($key); - $this->data[$key] = $value; - } - - /** - * Unset the given header - * - * @param string $key - */ - public function offsetUnset($key) { - unset($this->data[strtolower($key)]); - } - - /** - * Get an iterator for the data - * - * @return ArrayIterator - */ - public function getIterator() { - return new ArrayIterator($this->data); - } - - /** - * Get the headers as an array - * - * @return array Header data - */ - public function getAll() { - return $this->data; - } -} diff --git a/includes/vendor/rmccue/requests/library/Requests/Utility/FilteredIterator.php b/includes/vendor/rmccue/requests/library/Requests/Utility/FilteredIterator.php deleted file mode 100644 index 76a29e722..000000000 --- a/includes/vendor/rmccue/requests/library/Requests/Utility/FilteredIterator.php +++ /dev/null @@ -1,45 +0,0 @@ -callback = $callback; - } - - /** - * Get the current item's value after filtering - * - * @return string - */ - public function current() { - $value = parent::current(); - $value = call_user_func($this->callback, $value); - return $value; - } -} diff --git a/includes/vendor/rmccue/requests/src/Auth.php b/includes/vendor/rmccue/requests/src/Auth.php new file mode 100644 index 000000000..63ebb0833 --- /dev/null +++ b/includes/vendor/rmccue/requests/src/Auth.php @@ -0,0 +1,36 @@ +user, $this->pass) = $args; + return; + } + + if ($args !== null) { + throw InvalidArgument::create(1, '$args', 'array|null', gettype($args)); + } + } + + /** + * Register the necessary callbacks + * + * @see \WpOrg\Requests\Auth\Basic::curl_before_send() + * @see \WpOrg\Requests\Auth\Basic::fsockopen_header() + * @param \WpOrg\Requests\Hooks $hooks Hook system + */ + public function register(Hooks $hooks) { + $hooks->register('curl.before_send', [$this, 'curl_before_send']); + $hooks->register('fsockopen.after_headers', [$this, 'fsockopen_header']); + } + + /** + * Set cURL parameters before the data is sent + * + * @param resource|\CurlHandle $handle cURL handle + */ + public function curl_before_send(&$handle) { + curl_setopt($handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + curl_setopt($handle, CURLOPT_USERPWD, $this->getAuthString()); + } + + /** + * Add extra headers to the request before sending + * + * @param string $out HTTP header string + */ + public function fsockopen_header(&$out) { + $out .= sprintf("Authorization: Basic %s\r\n", base64_encode($this->getAuthString())); + } + + /** + * Get the authentication string (user:pass) + * + * @return string + */ + public function getAuthString() { + return $this->user . ':' . $this->pass; + } +} diff --git a/includes/vendor/rmccue/requests/src/Autoload.php b/includes/vendor/rmccue/requests/src/Autoload.php new file mode 100644 index 000000000..669ddecaf --- /dev/null +++ b/includes/vendor/rmccue/requests/src/Autoload.php @@ -0,0 +1,187 @@ + '\WpOrg\Requests\Auth', + 'requests_hooker' => '\WpOrg\Requests\HookManager', + 'requests_proxy' => '\WpOrg\Requests\Proxy', + 'requests_transport' => '\WpOrg\Requests\Transport', + + // Classes. + 'requests_cookie' => '\WpOrg\Requests\Cookie', + 'requests_exception' => '\WpOrg\Requests\Exception', + 'requests_hooks' => '\WpOrg\Requests\Hooks', + 'requests_idnaencoder' => '\WpOrg\Requests\IdnaEncoder', + 'requests_ipv6' => '\WpOrg\Requests\Ipv6', + 'requests_iri' => '\WpOrg\Requests\Iri', + 'requests_response' => '\WpOrg\Requests\Response', + 'requests_session' => '\WpOrg\Requests\Session', + 'requests_ssl' => '\WpOrg\Requests\Ssl', + 'requests_auth_basic' => '\WpOrg\Requests\Auth\Basic', + 'requests_cookie_jar' => '\WpOrg\Requests\Cookie\Jar', + 'requests_proxy_http' => '\WpOrg\Requests\Proxy\Http', + 'requests_response_headers' => '\WpOrg\Requests\Response\Headers', + 'requests_transport_curl' => '\WpOrg\Requests\Transport\Curl', + 'requests_transport_fsockopen' => '\WpOrg\Requests\Transport\Fsockopen', + 'requests_utility_caseinsensitivedictionary' => '\WpOrg\Requests\Utility\CaseInsensitiveDictionary', + 'requests_utility_filterediterator' => '\WpOrg\Requests\Utility\FilteredIterator', + 'requests_exception_http' => '\WpOrg\Requests\Exception\Http', + 'requests_exception_transport' => '\WpOrg\Requests\Exception\Transport', + 'requests_exception_transport_curl' => '\WpOrg\Requests\Exception\Transport\Curl', + 'requests_exception_http_304' => '\WpOrg\Requests\Exception\Http\Status304', + 'requests_exception_http_305' => '\WpOrg\Requests\Exception\Http\Status305', + 'requests_exception_http_306' => '\WpOrg\Requests\Exception\Http\Status306', + 'requests_exception_http_400' => '\WpOrg\Requests\Exception\Http\Status400', + 'requests_exception_http_401' => '\WpOrg\Requests\Exception\Http\Status401', + 'requests_exception_http_402' => '\WpOrg\Requests\Exception\Http\Status402', + 'requests_exception_http_403' => '\WpOrg\Requests\Exception\Http\Status403', + 'requests_exception_http_404' => '\WpOrg\Requests\Exception\Http\Status404', + 'requests_exception_http_405' => '\WpOrg\Requests\Exception\Http\Status405', + 'requests_exception_http_406' => '\WpOrg\Requests\Exception\Http\Status406', + 'requests_exception_http_407' => '\WpOrg\Requests\Exception\Http\Status407', + 'requests_exception_http_408' => '\WpOrg\Requests\Exception\Http\Status408', + 'requests_exception_http_409' => '\WpOrg\Requests\Exception\Http\Status409', + 'requests_exception_http_410' => '\WpOrg\Requests\Exception\Http\Status410', + 'requests_exception_http_411' => '\WpOrg\Requests\Exception\Http\Status411', + 'requests_exception_http_412' => '\WpOrg\Requests\Exception\Http\Status412', + 'requests_exception_http_413' => '\WpOrg\Requests\Exception\Http\Status413', + 'requests_exception_http_414' => '\WpOrg\Requests\Exception\Http\Status414', + 'requests_exception_http_415' => '\WpOrg\Requests\Exception\Http\Status415', + 'requests_exception_http_416' => '\WpOrg\Requests\Exception\Http\Status416', + 'requests_exception_http_417' => '\WpOrg\Requests\Exception\Http\Status417', + 'requests_exception_http_418' => '\WpOrg\Requests\Exception\Http\Status418', + 'requests_exception_http_428' => '\WpOrg\Requests\Exception\Http\Status428', + 'requests_exception_http_429' => '\WpOrg\Requests\Exception\Http\Status429', + 'requests_exception_http_431' => '\WpOrg\Requests\Exception\Http\Status431', + 'requests_exception_http_500' => '\WpOrg\Requests\Exception\Http\Status500', + 'requests_exception_http_501' => '\WpOrg\Requests\Exception\Http\Status501', + 'requests_exception_http_502' => '\WpOrg\Requests\Exception\Http\Status502', + 'requests_exception_http_503' => '\WpOrg\Requests\Exception\Http\Status503', + 'requests_exception_http_504' => '\WpOrg\Requests\Exception\Http\Status504', + 'requests_exception_http_505' => '\WpOrg\Requests\Exception\Http\Status505', + 'requests_exception_http_511' => '\WpOrg\Requests\Exception\Http\Status511', + 'requests_exception_http_unknown' => '\WpOrg\Requests\Exception\Http\StatusUnknown', + ]; + + /** + * Register the autoloader. + * + * Note: the autoloader is *prepended* in the autoload queue. + * This is done to ensure that the Requests 2.0 autoloader takes precedence + * over a potentially (dependency-registered) Requests 1.x autoloader. + * + * @internal This method contains a safeguard against the autoloader being + * registered multiple times. This safeguard uses a global constant to + * (hopefully/in most cases) still function correctly, even if the + * class would be renamed. + * + * @return void + */ + public static function register() { + if (defined('REQUESTS_AUTOLOAD_REGISTERED') === false) { + spl_autoload_register([self::class, 'load'], true); + define('REQUESTS_AUTOLOAD_REGISTERED', true); + } + } + + /** + * Autoloader. + * + * @param string $class_name Name of the class name to load. + * + * @return bool Whether a class was loaded or not. + */ + public static function load($class_name) { + // Check that the class starts with "Requests" (PSR-0) or "WpOrg\Requests" (PSR-4). + $psr_4_prefix_pos = strpos($class_name, 'WpOrg\\Requests\\'); + + if (stripos($class_name, 'Requests') !== 0 && $psr_4_prefix_pos !== 0) { + return false; + } + + $class_lower = strtolower($class_name); + + if ($class_lower === 'requests') { + // Reference to the original PSR-0 Requests class. + $file = dirname(__DIR__) . '/library/Requests.php'; + } elseif ($psr_4_prefix_pos === 0) { + // PSR-4 classname. + $file = __DIR__ . '/' . strtr(substr($class_name, 15), '\\', '/') . '.php'; + } + + if (isset($file) && file_exists($file)) { + include $file; + return true; + } + + /* + * Okay, so the class starts with "Requests", but we couldn't find the file. + * If this is one of the deprecated/renamed PSR-0 classes being requested, + * let's alias it to the new name and throw a deprecation notice. + */ + if (isset(self::$deprecated_classes[$class_lower])) { + /* + * Integrators who cannot yet upgrade to the PSR-4 class names can silence deprecations + * by defining a `REQUESTS_SILENCE_PSR0_DEPRECATIONS` constant and setting it to `true`. + * The constant needs to be defined before the first deprecated class is requested + * via this autoloader. + */ + if (!defined('REQUESTS_SILENCE_PSR0_DEPRECATIONS') || REQUESTS_SILENCE_PSR0_DEPRECATIONS !== true) { + // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error + trigger_error( + 'The PSR-0 `Requests_...` class names in the Requests library are deprecated.' + . ' Switch to the PSR-4 `WpOrg\Requests\...` class names at your earliest convenience.', + E_USER_DEPRECATED + ); + + // Prevent the deprecation notice from being thrown twice. + if (!defined('REQUESTS_SILENCE_PSR0_DEPRECATIONS')) { + define('REQUESTS_SILENCE_PSR0_DEPRECATIONS', true); + } + } + + // Create an alias and let the autoloader recursively kick in to load the PSR-4 class. + return class_alias(self::$deprecated_classes[$class_lower], $class_name, true); + } + + return false; + } + } +} diff --git a/includes/vendor/rmccue/requests/src/Capability.php b/includes/vendor/rmccue/requests/src/Capability.php new file mode 100644 index 000000000..30572bab2 --- /dev/null +++ b/includes/vendor/rmccue/requests/src/Capability.php @@ -0,0 +1,36 @@ +name = $name; - $this->value = $value; + public function __construct($name, $value, $attributes = [], $flags = [], $reference_time = null) { + if (is_string($name) === false) { + throw InvalidArgument::create(1, '$name', 'string', gettype($name)); + } + + if (is_string($value) === false) { + throw InvalidArgument::create(2, '$value', 'string', gettype($value)); + } + + if (InputValidator::has_array_access($attributes) === false || InputValidator::is_iterable($attributes) === false) { + throw InvalidArgument::create(3, '$attributes', 'array|ArrayAccess&Traversable', gettype($attributes)); + } + + if (is_array($flags) === false) { + throw InvalidArgument::create(4, '$flags', 'array', gettype($flags)); + } + + if ($reference_time !== null && is_int($reference_time) === false) { + throw InvalidArgument::create(5, '$reference_time', 'integer|null', gettype($reference_time)); + } + + $this->name = $name; + $this->value = $value; $this->attributes = $attributes; - $default_flags = array( - 'creation' => time(), + $default_flags = [ + 'creation' => time(), 'last-access' => time(), - 'persistent' => false, - 'host-only' => true, - ); - $this->flags = array_merge($default_flags, $flags); + 'persistent' => false, + 'host-only' => true, + ]; + $this->flags = array_merge($default_flags, $flags); $this->reference_time = time(); if ($reference_time !== null) { @@ -84,6 +119,15 @@ public function __construct($name, $value, $attributes = array(), $flags = array $this->normalize(); } + /** + * Get the cookie value + * + * Attributes and other data can be accessed via methods. + */ + public function __toString() { + return $this->value; + } + /** * Check if a cookie is expired. * @@ -113,10 +157,10 @@ public function is_expired() { /** * Check if a cookie is valid for a given URI * - * @param Requests_IRI $uri URI to check + * @param \WpOrg\Requests\Iri $uri URI to check * @return boolean Whether the cookie is valid for the given URI */ - public function uri_matches(Requests_IRI $uri) { + public function uri_matches(Iri $uri) { if (!$this->domain_matches($uri->host)) { return false; } @@ -131,19 +175,23 @@ public function uri_matches(Requests_IRI $uri) { /** * Check if a cookie is valid for a given domain * - * @param string $string Domain to check + * @param string $domain Domain to check * @return boolean Whether the cookie is valid for the given domain */ - public function domain_matches($string) { + public function domain_matches($domain) { + if (is_string($domain) === false) { + return false; + } + if (!isset($this->attributes['domain'])) { // Cookies created manually; cookies created by Requests will set // the domain to the requested domain return true; } - $domain_string = $this->attributes['domain']; - if ($domain_string === $string) { - // The domain string and the string are identical. + $cookie_domain = $this->attributes['domain']; + if ($cookie_domain === $domain) { + // The cookie domain and the passed domain are identical. return true; } @@ -153,26 +201,26 @@ public function domain_matches($string) { return false; } - if (strlen($string) <= strlen($domain_string)) { - // For obvious reasons, the string cannot be a suffix if the domain - // is shorter than the domain string + if (strlen($domain) <= strlen($cookie_domain)) { + // For obvious reasons, the cookie domain cannot be a suffix if the passed domain + // is shorter than the cookie domain return false; } - if (substr($string, -1 * strlen($domain_string)) !== $domain_string) { - // The domain string should be a suffix of the string. + if (substr($domain, -1 * strlen($cookie_domain)) !== $cookie_domain) { + // The cookie domain should be a suffix of the passed domain. return false; } - $prefix = substr($string, 0, strlen($string) - strlen($domain_string)); + $prefix = substr($domain, 0, strlen($domain) - strlen($cookie_domain)); if (substr($prefix, -1) !== '.') { - // The last character of the string that is not included in the + // The last character of the passed domain that is not included in the // domain string should be a %x2E (".") character. return false; } - // The string should be a host name (i.e., not an IP address). - return !preg_match('#^(.+\.)\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$#', $string); + // The passed domain should be a host name (i.e., not an IP address). + return !preg_match('#^(.+\.)\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$#', $domain); } /** @@ -195,6 +243,10 @@ public function path_matches($request_path) { return true; } + if (is_scalar($request_path) === false) { + return false; + } + $cookie_path = $this->attributes['path']; if ($cookie_path === $request_path) { @@ -228,7 +280,11 @@ public function path_matches($request_path) { public function normalize() { foreach ($this->attributes as $key => $value) { $orig_value = $value; - $value = $this->normalize_attribute($key, $value); + + if (is_string($key)) { + $value = $this->normalize_attribute($key, $value); + } + if ($value === null) { unset($this->attributes[$key]); continue; @@ -248,7 +304,7 @@ public function normalize() { * Handles parsing individual attributes from the cookie values. * * @param string $name Attribute name - * @param string|boolean $value Attribute value (string value, or true if empty/flag) + * @param string|int|bool $value Attribute value (string/integer value, or true if empty/flag) * @return mixed Value if available, or null if the attribute value is invalid (and should be skipped) */ protected function normalize_attribute($name, $value) { @@ -280,14 +336,18 @@ protected function normalize_attribute($name, $value) { $delta_seconds = (int) $value; if ($delta_seconds <= 0) { $expiry_time = 0; - } - else { + } else { $expiry_time = $this->reference_time + $delta_seconds; } return $expiry_time; case 'domain': + // Domains are not required as per RFC 6265 section 5.2.3 + if (empty($value)) { + return null; + } + // Domain normalization, as per RFC 6265 section 5.2.3 if ($value[0] === '.') { $value = substr($value, 1); @@ -311,17 +371,6 @@ public function format_for_header() { return sprintf('%s=%s', $this->name, $this->value); } - /** - * Format a cookie for a Cookie header - * - * @codeCoverageIgnore - * @deprecated Use {@see Requests_Cookie::format_for_header} - * @return string - */ - public function formatForHeader() { - return $this->format_for_header(); - } - /** * Format a cookie for a Set-Cookie header * @@ -333,40 +382,20 @@ public function formatForHeader() { public function format_for_set_cookie() { $header_value = $this->format_for_header(); if (!empty($this->attributes)) { - $parts = array(); + $parts = []; foreach ($this->attributes as $key => $value) { // Ignore non-associative attributes if (is_numeric($key)) { $parts[] = $value; - } - else { + } else { $parts[] = sprintf('%s=%s', $key, $value); } } $header_value .= '; ' . implode('; ', $parts); } - return $header_value; - } - /** - * Format a cookie for a Set-Cookie header - * - * @codeCoverageIgnore - * @deprecated Use {@see Requests_Cookie::format_for_set_cookie} - * @return string - */ - public function formatForSetCookie() { - return $this->format_for_set_cookie(); - } - - /** - * Get the cookie value - * - * Attributes and other data can be accessed via methods. - */ - public function __toString() { - return $this->value; + return $header_value; } /** @@ -376,77 +405,93 @@ public function __toString() { * is an intentional deviation from RFC 2109 and RFC 2616. RFC 6265 * specifies some of this handling, but not in a thorough manner. * - * @param string Cookie header value (from a Set-Cookie header) - * @return Requests_Cookie Parsed cookie object + * @param string $cookie_header Cookie header value (from a Set-Cookie header) + * @param string $name + * @param int|null $reference_time + * @return \WpOrg\Requests\Cookie Parsed cookie object + * + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $cookie_header argument is not a string. + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $name argument is not a string. */ - public static function parse($string, $name = '', $reference_time = null) { - $parts = explode(';', $string); + public static function parse($cookie_header, $name = '', $reference_time = null) { + if (is_string($cookie_header) === false) { + throw InvalidArgument::create(1, '$cookie_header', 'string', gettype($cookie_header)); + } + + if (is_string($name) === false) { + throw InvalidArgument::create(2, '$name', 'string', gettype($name)); + } + + $parts = explode(';', $cookie_header); $kvparts = array_shift($parts); if (!empty($name)) { - $value = $string; - } - elseif (strpos($kvparts, '=') === false) { + $value = $cookie_header; + } elseif (strpos($kvparts, '=') === false) { // Some sites might only have a value without the equals separator. // Deviate from RFC 6265 and pretend it was actually a blank name // (`=foo`) // // https://bugzilla.mozilla.org/show_bug.cgi?id=169091 - $name = ''; + $name = ''; $value = $kvparts; - } - else { + } else { list($name, $value) = explode('=', $kvparts, 2); } - $name = trim($name); + + $name = trim($name); $value = trim($value); - // Attribute key are handled case-insensitively - $attributes = new Requests_Utility_CaseInsensitiveDictionary(); + // Attribute keys are handled case-insensitively + $attributes = new CaseInsensitiveDictionary(); if (!empty($parts)) { foreach ($parts as $part) { if (strpos($part, '=') === false) { - $part_key = $part; + $part_key = $part; $part_value = true; - } - else { + } else { list($part_key, $part_value) = explode('=', $part, 2); - $part_value = trim($part_value); + $part_value = trim($part_value); } - $part_key = trim($part_key); + $part_key = trim($part_key); $attributes[$part_key] = $part_value; } } - return new Requests_Cookie($name, $value, $attributes, array(), $reference_time); + return new static($name, $value, $attributes, [], $reference_time); } /** * Parse all Set-Cookie headers from request headers * - * @param Requests_Response_Headers $headers Headers to parse from - * @param Requests_IRI|null $origin URI for comparing cookie origins + * @param \WpOrg\Requests\Response\Headers $headers Headers to parse from + * @param \WpOrg\Requests\Iri|null $origin URI for comparing cookie origins * @param int|null $time Reference time for expiration calculation * @return array + * + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $origin argument is not null or an instance of the Iri class. */ - public static function parse_from_headers(Requests_Response_Headers $headers, Requests_IRI $origin = null, $time = null) { + public static function parse_from_headers(Headers $headers, $origin = null, $time = null) { $cookie_headers = $headers->getValues('Set-Cookie'); if (empty($cookie_headers)) { - return array(); + return []; + } + + if ($origin !== null && !($origin instanceof Iri)) { + throw InvalidArgument::create(2, '$origin', Iri::class . ' or null', gettype($origin)); } - $cookies = array(); + $cookies = []; foreach ($cookie_headers as $header) { $parsed = self::parse($header, '', $time); // Default domain/path attributes if (empty($parsed->attributes['domain']) && !empty($origin)) { $parsed->attributes['domain'] = $origin->host; - $parsed->flags['host-only'] = true; - } - else { + $parsed->flags['host-only'] = true; + } else { $parsed->flags['host-only'] = false; } @@ -460,19 +505,18 @@ public static function parse_from_headers(Requests_Response_Headers $headers, Re // the uri-path is not a %x2F ("/") character, output // %x2F ("/") and skip the remaining steps. $path = '/'; - } - elseif (substr_count($path, '/') === 1) { + } elseif (substr_count($path, '/') === 1) { // If the uri-path contains no more than one %x2F ("/") // character, output %x2F ("/") and skip the remaining // step. $path = '/'; - } - else { + } else { // Output the characters of the uri-path from the first // character up to, but not including, the right-most // %x2F ("/"). $path = substr($path, 0, strrpos($path, '/')); } + $parsed->attributes['path'] = $path; } @@ -486,15 +530,4 @@ public static function parse_from_headers(Requests_Response_Headers $headers, Re return $cookies; } - - /** - * Parse all Set-Cookie headers from request headers - * - * @codeCoverageIgnore - * @deprecated Use {@see Requests_Cookie::parse_from_headers} - * @return string - */ - public static function parseFromHeaders(Requests_Response_Headers $headers) { - return self::parse_from_headers($headers); - } } diff --git a/includes/vendor/rmccue/requests/src/Cookie/Jar.php b/includes/vendor/rmccue/requests/src/Cookie/Jar.php new file mode 100644 index 000000000..7633786b9 --- /dev/null +++ b/includes/vendor/rmccue/requests/src/Cookie/Jar.php @@ -0,0 +1,187 @@ +cookies = $cookies; + } + + /** + * Normalise cookie data into a \WpOrg\Requests\Cookie + * + * @param string|\WpOrg\Requests\Cookie $cookie Cookie header value, possibly pre-parsed (object). + * @param string $key Optional. The name for this cookie. + * @return \WpOrg\Requests\Cookie + */ + public function normalize_cookie($cookie, $key = '') { + if ($cookie instanceof Cookie) { + return $cookie; + } + + return Cookie::parse($cookie, $key); + } + + /** + * Check if the given item exists + * + * @param string $offset Item key + * @return boolean Does the item exist? + */ + #[ReturnTypeWillChange] + public function offsetExists($offset) { + return isset($this->cookies[$offset]); + } + + /** + * Get the value for the item + * + * @param string $offset Item key + * @return string|null Item value (null if offsetExists is false) + */ + #[ReturnTypeWillChange] + public function offsetGet($offset) { + if (!isset($this->cookies[$offset])) { + return null; + } + + return $this->cookies[$offset]; + } + + /** + * Set the given item + * + * @param string $offset Item name + * @param string $value Item value + * + * @throws \WpOrg\Requests\Exception On attempting to use dictionary as list (`invalidset`) + */ + #[ReturnTypeWillChange] + public function offsetSet($offset, $value) { + if ($offset === null) { + throw new Exception('Object is a dictionary, not a list', 'invalidset'); + } + + $this->cookies[$offset] = $value; + } + + /** + * Unset the given header + * + * @param string $offset The key for the item to unset. + */ + #[ReturnTypeWillChange] + public function offsetUnset($offset) { + unset($this->cookies[$offset]); + } + + /** + * Get an iterator for the data + * + * @return \ArrayIterator + */ + #[ReturnTypeWillChange] + public function getIterator() { + return new ArrayIterator($this->cookies); + } + + /** + * Register the cookie handler with the request's hooking system + * + * @param \WpOrg\Requests\HookManager $hooks Hooking system + */ + public function register(HookManager $hooks) { + $hooks->register('requests.before_request', [$this, 'before_request']); + $hooks->register('requests.before_redirect_check', [$this, 'before_redirect_check']); + } + + /** + * Add Cookie header to a request if we have any + * + * As per RFC 6265, cookies are separated by '; ' + * + * @param string $url + * @param array $headers + * @param array $data + * @param string $type + * @param array $options + */ + public function before_request($url, &$headers, &$data, &$type, &$options) { + if (!$url instanceof Iri) { + $url = new Iri($url); + } + + if (!empty($this->cookies)) { + $cookies = []; + foreach ($this->cookies as $key => $cookie) { + $cookie = $this->normalize_cookie($cookie, $key); + + // Skip expired cookies + if ($cookie->is_expired()) { + continue; + } + + if ($cookie->domain_matches($url->host)) { + $cookies[] = $cookie->format_for_header(); + } + } + + $headers['Cookie'] = implode('; ', $cookies); + } + } + + /** + * Parse all cookies from a response and attach them to the response + * + * @param \WpOrg\Requests\Response $response Response as received. + */ + public function before_redirect_check(Response $response) { + $url = $response->url; + if (!$url instanceof Iri) { + $url = new Iri($url); + } + + $cookies = Cookie::parse_from_headers($response->headers, $url); + $this->cookies = array_merge($this->cookies, $cookies); + $response->cookies = $this; + } +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception.php b/includes/vendor/rmccue/requests/src/Exception.php similarity index 80% rename from includes/vendor/rmccue/requests/library/Requests/Exception.php rename to includes/vendor/rmccue/requests/src/Exception.php index 37d4711c1..b67d1b1a4 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception.php +++ b/includes/vendor/rmccue/requests/src/Exception.php @@ -2,15 +2,19 @@ /** * Exception for HTTP requests * - * @package Requests + * @package Requests\Exceptions */ +namespace WpOrg\Requests; + +use Exception as PHPException; + /** * Exception for HTTP requests * - * @package Requests + * @package Requests\Exceptions */ -class Requests_Exception extends Exception { +class Exception extends PHPException { /** * Type of exception * @@ -41,7 +45,7 @@ public function __construct($message, $type, $data = null, $code = 0) { } /** - * Like {@see getCode()}, but a string code. + * Like {@see \Exception::getCode()}, but a string code. * * @codeCoverageIgnore * @return string @@ -59,4 +63,4 @@ public function getType() { public function getData() { return $this->data; } -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/src/Exception/ArgumentCount.php b/includes/vendor/rmccue/requests/src/Exception/ArgumentCount.php new file mode 100644 index 000000000..b5773ddf3 --- /dev/null +++ b/includes/vendor/rmccue/requests/src/Exception/ArgumentCount.php @@ -0,0 +1,47 @@ +reason; @@ -58,14 +65,14 @@ public function getReason() { */ public static function get_class($code) { if (!$code) { - return 'Requests_Exception_HTTP_Unknown'; + return StatusUnknown::class; } - $class = sprintf('Requests_Exception_HTTP_%d', $code); + $class = sprintf('\WpOrg\Requests\Exception\Http\Status%d', $code); if (class_exists($class)) { return $class; } - return 'Requests_Exception_HTTP_Unknown'; + return StatusUnknown::class; } -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/304.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status304.php similarity index 60% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/304.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status304.php index 679903358..d510ae7d4 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/304.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status304.php @@ -2,15 +2,19 @@ /** * Exception for 304 Not Modified responses * - * @package Requests + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 304 Not Modified responses * - * @package Requests + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_304 extends Requests_Exception_HTTP { +final class Status304 extends Http { /** * HTTP status code * @@ -24,4 +28,4 @@ class Requests_Exception_HTTP_304 extends Requests_Exception_HTTP { * @var string */ protected $reason = 'Not Modified'; -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/305.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status305.php similarity index 60% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/305.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status305.php index 37d115a81..8be63c3f2 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/305.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status305.php @@ -2,15 +2,19 @@ /** * Exception for 305 Use Proxy responses * - * @package Requests + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 305 Use Proxy responses * - * @package Requests + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_305 extends Requests_Exception_HTTP { +final class Status305 extends Http { /** * HTTP status code * diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/306.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status306.php similarity index 61% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/306.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status306.php index 743a4ed1d..2f3534ab9 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/306.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status306.php @@ -2,15 +2,19 @@ /** * Exception for 306 Switch Proxy responses * - * @package Requests + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 306 Switch Proxy responses * - * @package Requests + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_306 extends Requests_Exception_HTTP { +final class Status306 extends Http { /** * HTTP status code * diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/400.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status400.php similarity index 60% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/400.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status400.php index b3ad77435..4e3962357 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/400.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status400.php @@ -2,15 +2,19 @@ /** * Exception for 400 Bad Request responses * - * @package Requests + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 400 Bad Request responses * - * @package Requests + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_400 extends Requests_Exception_HTTP { +final class Status400 extends Http { /** * HTTP status code * @@ -24,4 +28,4 @@ class Requests_Exception_HTTP_400 extends Requests_Exception_HTTP { * @var string */ protected $reason = 'Bad Request'; -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/401.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status401.php similarity index 60% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/401.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status401.php index 2e1e3d0b2..2a76429ce 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/401.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status401.php @@ -2,15 +2,19 @@ /** * Exception for 401 Unauthorized responses * - * @package Requests + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 401 Unauthorized responses * - * @package Requests + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_401 extends Requests_Exception_HTTP { +final class Status401 extends Http { /** * HTTP status code * @@ -24,4 +28,4 @@ class Requests_Exception_HTTP_401 extends Requests_Exception_HTTP { * @var string */ protected $reason = 'Unauthorized'; -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/402.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status402.php similarity index 61% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/402.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status402.php index 1d965d232..09d42879d 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/402.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status402.php @@ -2,15 +2,19 @@ /** * Exception for 402 Payment Required responses * - * @package Requests + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 402 Payment Required responses * - * @package Requests + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_402 extends Requests_Exception_HTTP { +final class Status402 extends Http { /** * HTTP status code * @@ -24,4 +28,4 @@ class Requests_Exception_HTTP_402 extends Requests_Exception_HTTP { * @var string */ protected $reason = 'Payment Required'; -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/403.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status403.php similarity index 59% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/403.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status403.php index 5ca3cafc1..0b1fc3963 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/403.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status403.php @@ -2,15 +2,19 @@ /** * Exception for 403 Forbidden responses * - * @package Requests + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 403 Forbidden responses * - * @package Requests + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_403 extends Requests_Exception_HTTP { +final class Status403 extends Http { /** * HTTP status code * @@ -24,4 +28,4 @@ class Requests_Exception_HTTP_403 extends Requests_Exception_HTTP { * @var string */ protected $reason = 'Forbidden'; -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/404.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status404.php similarity index 59% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/404.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status404.php index f08be2d27..ef39a853e 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/404.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status404.php @@ -2,15 +2,19 @@ /** * Exception for 404 Not Found responses * - * @package Requests + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 404 Not Found responses * - * @package Requests + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_404 extends Requests_Exception_HTTP { +final class Status404 extends Http { /** * HTTP status code * @@ -24,4 +28,4 @@ class Requests_Exception_HTTP_404 extends Requests_Exception_HTTP { * @var string */ protected $reason = 'Not Found'; -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/405.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status405.php similarity index 62% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/405.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status405.php index b8419e1ee..666fbfe7c 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/405.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status405.php @@ -2,15 +2,19 @@ /** * Exception for 405 Method Not Allowed responses * - * @package Requests + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 405 Method Not Allowed responses * - * @package Requests + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_405 extends Requests_Exception_HTTP { +final class Status405 extends Http { /** * HTTP status code * @@ -24,4 +28,4 @@ class Requests_Exception_HTTP_405 extends Requests_Exception_HTTP { * @var string */ protected $reason = 'Method Not Allowed'; -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/406.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status406.php similarity index 61% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/406.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status406.php index 09d0622b1..37952f80a 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/406.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status406.php @@ -2,15 +2,19 @@ /** * Exception for 406 Not Acceptable responses * - * @package Requests + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 406 Not Acceptable responses * - * @package Requests + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_406 extends Requests_Exception_HTTP { +final class Status406 extends Http { /** * HTTP status code * @@ -24,4 +28,4 @@ class Requests_Exception_HTTP_406 extends Requests_Exception_HTTP { * @var string */ protected $reason = 'Not Acceptable'; -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/407.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status407.php similarity index 64% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/407.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status407.php index c21d1ec64..d8796f9b5 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/407.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status407.php @@ -2,15 +2,19 @@ /** * Exception for 407 Proxy Authentication Required responses * - * @package Requests + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 407 Proxy Authentication Required responses * - * @package Requests + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_407 extends Requests_Exception_HTTP { +final class Status407 extends Http { /** * HTTP status code * @@ -24,4 +28,4 @@ class Requests_Exception_HTTP_407 extends Requests_Exception_HTTP { * @var string */ protected $reason = 'Proxy Authentication Required'; -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/408.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status408.php similarity index 61% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/408.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status408.php index 0691863a9..6718d064a 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/408.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status408.php @@ -2,15 +2,19 @@ /** * Exception for 408 Request Timeout responses * - * @package Requests + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 408 Request Timeout responses * - * @package Requests + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_408 extends Requests_Exception_HTTP { +final class Status408 extends Http { /** * HTTP status code * @@ -24,4 +28,4 @@ class Requests_Exception_HTTP_408 extends Requests_Exception_HTTP { * @var string */ protected $reason = 'Request Timeout'; -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/409.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status409.php similarity index 59% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/409.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status409.php index 5a3e0d1f1..711a5c43f 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/409.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status409.php @@ -2,15 +2,19 @@ /** * Exception for 409 Conflict responses * - * @package Requests + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 409 Conflict responses * - * @package Requests + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_409 extends Requests_Exception_HTTP { +final class Status409 extends Http { /** * HTTP status code * @@ -24,4 +28,4 @@ class Requests_Exception_HTTP_409 extends Requests_Exception_HTTP { * @var string */ protected $reason = 'Conflict'; -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/410.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status410.php similarity index 58% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/410.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status410.php index 8eb3dafa6..127443b78 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/410.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status410.php @@ -2,15 +2,19 @@ /** * Exception for 410 Gone responses * - * @package Requests + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 410 Gone responses * - * @package Requests + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_410 extends Requests_Exception_HTTP { +final class Status410 extends Http { /** * HTTP status code * @@ -24,4 +28,4 @@ class Requests_Exception_HTTP_410 extends Requests_Exception_HTTP { * @var string */ protected $reason = 'Gone'; -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/411.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status411.php similarity index 61% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/411.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status411.php index cee6496ac..e70e63c64 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/411.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status411.php @@ -2,15 +2,19 @@ /** * Exception for 411 Length Required responses * - * @package Requests + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 411 Length Required responses * - * @package Requests + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_411 extends Requests_Exception_HTTP { +final class Status411 extends Http { /** * HTTP status code * @@ -24,4 +28,4 @@ class Requests_Exception_HTTP_411 extends Requests_Exception_HTTP { * @var string */ protected $reason = 'Length Required'; -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/412.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status412.php similarity index 62% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/412.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status412.php index e377d7975..4a8b9185b 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/412.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status412.php @@ -2,15 +2,19 @@ /** * Exception for 412 Precondition Failed responses * - * @package Requests + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 412 Precondition Failed responses * - * @package Requests + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_412 extends Requests_Exception_HTTP { +final class Status412 extends Http { /** * HTTP status code * @@ -24,4 +28,4 @@ class Requests_Exception_HTTP_412 extends Requests_Exception_HTTP { * @var string */ protected $reason = 'Precondition Failed'; -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/413.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status413.php similarity index 63% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/413.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status413.php index 3b5fe276a..96a96fb16 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/413.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status413.php @@ -2,15 +2,19 @@ /** * Exception for 413 Request Entity Too Large responses * - * @package Requests + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 413 Request Entity Too Large responses * - * @package Requests + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_413 extends Requests_Exception_HTTP { +final class Status413 extends Http { /** * HTTP status code * @@ -24,4 +28,4 @@ class Requests_Exception_HTTP_413 extends Requests_Exception_HTTP { * @var string */ protected $reason = 'Request Entity Too Large'; -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/414.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status414.php similarity index 62% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/414.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status414.php index 14d5a59d3..b65ec937a 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/414.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status414.php @@ -2,15 +2,19 @@ /** * Exception for 414 Request-URI Too Large responses * - * @package Requests + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 414 Request-URI Too Large responses * - * @package Requests + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_414 extends Requests_Exception_HTTP { +final class Status414 extends Http { /** * HTTP status code * @@ -24,4 +28,4 @@ class Requests_Exception_HTTP_414 extends Requests_Exception_HTTP { * @var string */ protected $reason = 'Request-URI Too Large'; -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/415.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status415.php similarity index 63% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/415.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status415.php index 32446c854..cb45655e9 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/415.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status415.php @@ -2,15 +2,19 @@ /** * Exception for 415 Unsupported Media Type responses * - * @package Requests + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 415 Unsupported Media Type responses * - * @package Requests + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_415 extends Requests_Exception_HTTP { +final class Status415 extends Http { /** * HTTP status code * @@ -24,4 +28,4 @@ class Requests_Exception_HTTP_415 extends Requests_Exception_HTTP { * @var string */ protected $reason = 'Unsupported Media Type'; -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/416.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status416.php similarity index 64% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/416.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status416.php index 8c5f833db..c3661a193 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/416.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status416.php @@ -2,15 +2,19 @@ /** * Exception for 416 Requested Range Not Satisfiable responses * - * @package Requests + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 416 Requested Range Not Satisfiable responses * - * @package Requests + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_416 extends Requests_Exception_HTTP { +final class Status416 extends Http { /** * HTTP status code * @@ -24,4 +28,4 @@ class Requests_Exception_HTTP_416 extends Requests_Exception_HTTP { * @var string */ protected $reason = 'Requested Range Not Satisfiable'; -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/417.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status417.php similarity index 62% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/417.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status417.php index 8807c7171..4adba9a23 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/417.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status417.php @@ -2,15 +2,19 @@ /** * Exception for 417 Expectation Failed responses * - * @package Requests + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 417 Expectation Failed responses * - * @package Requests + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_417 extends Requests_Exception_HTTP { +final class Status417 extends Http { /** * HTTP status code * @@ -24,4 +28,4 @@ class Requests_Exception_HTTP_417 extends Requests_Exception_HTTP { * @var string */ protected $reason = 'Expectation Failed'; -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/418.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status418.php similarity index 50% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/418.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status418.php index d6af806c4..5bcb2b84a 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/418.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status418.php @@ -2,17 +2,23 @@ /** * Exception for 418 I'm A Teapot responses * - * @see https://tools.ietf.org/html/rfc2324 - * @package Requests + * @link https://tools.ietf.org/html/rfc2324 + * + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 418 I'm A Teapot responses * - * @see https://tools.ietf.org/html/rfc2324 - * @package Requests + * @link https://tools.ietf.org/html/rfc2324 + * + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_418 extends Requests_Exception_HTTP { +final class Status418 extends Http { /** * HTTP status code * @@ -26,4 +32,4 @@ class Requests_Exception_HTTP_418 extends Requests_Exception_HTTP { * @var string */ protected $reason = "I'm A Teapot"; -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/428.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status428.php similarity index 52% rename from includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/428.php rename to includes/vendor/rmccue/requests/src/Exception/Http/Status428.php index 469e95454..4d7ea51f5 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Exception/HTTP/428.php +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status428.php @@ -2,17 +2,23 @@ /** * Exception for 428 Precondition Required responses * - * @see https://tools.ietf.org/html/rfc6585 - * @package Requests + * @link https://tools.ietf.org/html/rfc6585 + * + * @package Requests\Exceptions */ +namespace WpOrg\Requests\Exception\Http; + +use WpOrg\Requests\Exception\Http; + /** * Exception for 428 Precondition Required responses * - * @see https://tools.ietf.org/html/rfc6585 - * @package Requests + * @link https://tools.ietf.org/html/rfc6585 + * + * @package Requests\Exceptions */ -class Requests_Exception_HTTP_428 extends Requests_Exception_HTTP { +final class Status428 extends Http { /** * HTTP status code * @@ -26,4 +32,4 @@ class Requests_Exception_HTTP_428 extends Requests_Exception_HTTP { * @var string */ protected $reason = 'Precondition Required'; -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/src/Exception/Http/Status429.php b/includes/vendor/rmccue/requests/src/Exception/Http/Status429.php new file mode 100644 index 000000000..2018196c7 --- /dev/null +++ b/includes/vendor/rmccue/requests/src/Exception/Http/Status429.php @@ -0,0 +1,35 @@ +code = $data->status_code; + if ($data instanceof Response) { + $this->code = (int) $data->status_code; } parent::__construct($reason, $data); } -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/src/Exception/InvalidArgument.php b/includes/vendor/rmccue/requests/src/Exception/InvalidArgument.php new file mode 100644 index 000000000..0ab7332f4 --- /dev/null +++ b/includes/vendor/rmccue/requests/src/Exception/InvalidArgument.php @@ -0,0 +1,41 @@ +type = $type; } if ($code !== null) { - $this->code = $code; + $this->code = (int) $code; } if ($message !== null) { @@ -47,7 +69,9 @@ public function __construct($message, $type, $data = null, $code = 0) { } /** - * Get the error message + * Get the error message. + * + * @return string */ public function getReason() { return $this->reason; diff --git a/includes/vendor/rmccue/requests/library/Requests/Hooker.php b/includes/vendor/rmccue/requests/src/HookManager.php similarity index 65% rename from includes/vendor/rmccue/requests/library/Requests/Hooker.php rename to includes/vendor/rmccue/requests/src/HookManager.php index f667ae9c5..f2920170b 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Hooker.php +++ b/includes/vendor/rmccue/requests/src/HookManager.php @@ -2,22 +2,22 @@ /** * Event dispatcher * - * @package Requests - * @subpackage Utilities + * @package Requests\EventDispatcher */ +namespace WpOrg\Requests; + /** * Event dispatcher * - * @package Requests - * @subpackage Utilities + * @package Requests\EventDispatcher */ -interface Requests_Hooker { +interface HookManager { /** * Register a callback for a hook * * @param string $hook Hook name - * @param callback $callback Function/method to call on event + * @param callable $callback Function/method to call on event * @param int $priority Priority number. <0 is executed earlier, >0 is executed later */ public function register($hook, $callback, $priority = 0); @@ -29,5 +29,5 @@ public function register($hook, $callback, $priority = 0); * @param array $parameters Parameters to pass to callbacks * @return boolean Successfulness */ - public function dispatch($hook, $parameters = array()); -} \ No newline at end of file + public function dispatch($hook, $parameters = []); +} diff --git a/includes/vendor/rmccue/requests/src/Hooks.php b/includes/vendor/rmccue/requests/src/Hooks.php new file mode 100644 index 000000000..74fba0b3e --- /dev/null +++ b/includes/vendor/rmccue/requests/src/Hooks.php @@ -0,0 +1,99 @@ +0 is executed later + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $hook argument is not a string. + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $callback argument is not callable. + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $priority argument is not an integer. + */ + public function register($hook, $callback, $priority = 0) { + if (is_string($hook) === false) { + throw InvalidArgument::create(1, '$hook', 'string', gettype($hook)); + } + + if (is_callable($callback) === false) { + throw InvalidArgument::create(2, '$callback', 'callable', gettype($callback)); + } + + if (InputValidator::is_numeric_array_key($priority) === false) { + throw InvalidArgument::create(3, '$priority', 'integer', gettype($priority)); + } + + if (!isset($this->hooks[$hook])) { + $this->hooks[$hook] = [ + $priority => [], + ]; + } elseif (!isset($this->hooks[$hook][$priority])) { + $this->hooks[$hook][$priority] = []; + } + + $this->hooks[$hook][$priority][] = $callback; + } + + /** + * Dispatch a message + * + * @param string $hook Hook name + * @param array $parameters Parameters to pass to callbacks + * @return boolean Successfulness + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $hook argument is not a string. + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $parameters argument is not an array. + */ + public function dispatch($hook, $parameters = []) { + if (is_string($hook) === false) { + throw InvalidArgument::create(1, '$hook', 'string', gettype($hook)); + } + + // Check strictly against array, as Array* objects don't work in combination with `call_user_func_array()`. + if (is_array($parameters) === false) { + throw InvalidArgument::create(2, '$parameters', 'array', gettype($parameters)); + } + + if (empty($this->hooks[$hook])) { + return false; + } + + if (!empty($parameters)) { + // Strip potential keys from the array to prevent them being interpreted as parameter names in PHP 8.0. + $parameters = array_values($parameters); + } + + ksort($this->hooks[$hook]); + + foreach ($this->hooks[$hook] as $priority => $hooked) { + foreach ($hooked as $callback) { + $callback(...$parameters); + } + } + + return true; + } +} diff --git a/includes/vendor/rmccue/requests/src/IdnaEncoder.php b/includes/vendor/rmccue/requests/src/IdnaEncoder.php new file mode 100644 index 000000000..9f235527b --- /dev/null +++ b/includes/vendor/rmccue/requests/src/IdnaEncoder.php @@ -0,0 +1,412 @@ + 0) { + if ($position + $length > $strlen) { + throw new Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character); + } + + for ($position++; $remaining > 0; $position++) { + $value = ord($input[$position]); + + // If it is invalid, count the sequence as invalid and reprocess the current byte: + if (($value & 0xC0) !== 0x80) { + throw new Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character); + } + + --$remaining; + $character |= ($value & 0x3F) << ($remaining * 6); + } + + $position--; + } + + if (// Non-shortest form sequences are invalid + ($length > 1 && $character <= 0x7F) + || ($length > 2 && $character <= 0x7FF) + || ($length > 3 && $character <= 0xFFFF) + // Outside of range of ucschar codepoints + // Noncharacters + || ($character & 0xFFFE) === 0xFFFE + || ($character >= 0xFDD0 && $character <= 0xFDEF) + || ( + // Everything else not in ucschar + ($character > 0xD7FF && $character < 0xF900) + || $character < 0x20 + || ($character > 0x7E && $character < 0xA0) + || $character > 0xEFFFD + ) + ) { + throw new Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character); + } + + $codepoints[] = $character; + } + + return $codepoints; + } + + /** + * RFC3492-compliant encoder + * + * @internal Pseudo-code from Section 6.3 is commented with "#" next to relevant code + * + * @param string $input UTF-8 encoded string to encode + * @return string Punycode-encoded string + * + * @throws \WpOrg\Requests\Exception On character outside of the domain (never happens with Punycode) (`idna.character_outside_domain`) + */ + public static function punycode_encode($input) { + $output = ''; + // let n = initial_n + $n = self::BOOTSTRAP_INITIAL_N; + // let delta = 0 + $delta = 0; + // let bias = initial_bias + $bias = self::BOOTSTRAP_INITIAL_BIAS; + // let h = b = the number of basic code points in the input + $h = 0; + $b = 0; // see loop + // copy them to the output in order + $codepoints = self::utf8_to_codepoints($input); + $extended = []; + + foreach ($codepoints as $char) { + if ($char < 128) { + // Character is valid ASCII + // TODO: this should also check if it's valid for a URL + $output .= chr($char); + $h++; + + // Check if the character is non-ASCII, but below initial n + // This never occurs for Punycode, so ignore in coverage + // @codeCoverageIgnoreStart + } elseif ($char < $n) { + throw new Exception('Invalid character', 'idna.character_outside_domain', $char); + // @codeCoverageIgnoreEnd + } else { + $extended[$char] = true; + } + } + + $extended = array_keys($extended); + sort($extended); + $b = $h; + // [copy them] followed by a delimiter if b > 0 + if (strlen($output) > 0) { + $output .= '-'; + } + + // {if the input contains a non-basic code point < n then fail} + // while h < length(input) do begin + $codepointcount = count($codepoints); + while ($h < $codepointcount) { + // let m = the minimum code point >= n in the input + $m = array_shift($extended); + //printf('next code point to insert is %s' . PHP_EOL, dechex($m)); + // let delta = delta + (m - n) * (h + 1), fail on overflow + $delta += ($m - $n) * ($h + 1); + // let n = m + $n = $m; + // for each code point c in the input (in order) do begin + for ($num = 0; $num < $codepointcount; $num++) { + $c = $codepoints[$num]; + // if c < n then increment delta, fail on overflow + if ($c < $n) { + $delta++; + } elseif ($c === $n) { // if c == n then begin + // let q = delta + $q = $delta; + // for k = base to infinity in steps of base do begin + for ($k = self::BOOTSTRAP_BASE; ; $k += self::BOOTSTRAP_BASE) { + // let t = tmin if k <= bias {+ tmin}, or + // tmax if k >= bias + tmax, or k - bias otherwise + if ($k <= ($bias + self::BOOTSTRAP_TMIN)) { + $t = self::BOOTSTRAP_TMIN; + } elseif ($k >= ($bias + self::BOOTSTRAP_TMAX)) { + $t = self::BOOTSTRAP_TMAX; + } else { + $t = $k - $bias; + } + + // if q < t then break + if ($q < $t) { + break; + } + + // output the code point for digit t + ((q - t) mod (base - t)) + $digit = (int) ($t + (($q - $t) % (self::BOOTSTRAP_BASE - $t))); + $output .= self::digit_to_char($digit); + // let q = (q - t) div (base - t) + $q = (int) floor(($q - $t) / (self::BOOTSTRAP_BASE - $t)); + } // end + // output the code point for digit q + $output .= self::digit_to_char($q); + // let bias = adapt(delta, h + 1, test h equals b?) + $bias = self::adapt($delta, $h + 1, $h === $b); + // let delta = 0 + $delta = 0; + // increment h + $h++; + } // end + } // end + // increment delta and n + $delta++; + $n++; + } // end + + return $output; + } + + /** + * Convert a digit to its respective character + * + * @link https://tools.ietf.org/html/rfc3492#section-5 + * + * @param int $digit Digit in the range 0-35 + * @return string Single character corresponding to digit + * + * @throws \WpOrg\Requests\Exception On invalid digit (`idna.invalid_digit`) + */ + protected static function digit_to_char($digit) { + // @codeCoverageIgnoreStart + // As far as I know, this never happens, but still good to be sure. + if ($digit < 0 || $digit > 35) { + throw new Exception(sprintf('Invalid digit %d', $digit), 'idna.invalid_digit', $digit); + } + + // @codeCoverageIgnoreEnd + $digits = 'abcdefghijklmnopqrstuvwxyz0123456789'; + return substr($digits, $digit, 1); + } + + /** + * Adapt the bias + * + * @link https://tools.ietf.org/html/rfc3492#section-6.1 + * @param int $delta + * @param int $numpoints + * @param bool $firsttime + * @return int|float New bias + * + * function adapt(delta,numpoints,firsttime): + */ + protected static function adapt($delta, $numpoints, $firsttime) { + // if firsttime then let delta = delta div damp + if ($firsttime) { + $delta = floor($delta / self::BOOTSTRAP_DAMP); + } else { + // else let delta = delta div 2 + $delta = floor($delta / 2); + } + + // let delta = delta + (delta div numpoints) + $delta += floor($delta / $numpoints); + // let k = 0 + $k = 0; + // while delta > ((base - tmin) * tmax) div 2 do begin + $max = floor(((self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN) * self::BOOTSTRAP_TMAX) / 2); + while ($delta > $max) { + // let delta = delta div (base - tmin) + $delta = floor($delta / (self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN)); + // let k = k + base + $k += self::BOOTSTRAP_BASE; + } // end + // return k + (((base - tmin + 1) * delta) div (delta + skew)) + return $k + floor(((self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN + 1) * $delta) / ($delta + self::BOOTSTRAP_SKEW)); + } +} diff --git a/includes/vendor/rmccue/requests/library/Requests/IPv6.php b/includes/vendor/rmccue/requests/src/Ipv6.php similarity index 69% rename from includes/vendor/rmccue/requests/library/Requests/IPv6.php rename to includes/vendor/rmccue/requests/src/Ipv6.php index 204dbd7e6..bcdd63649 100644 --- a/includes/vendor/rmccue/requests/library/Requests/IPv6.php +++ b/includes/vendor/rmccue/requests/src/Ipv6.php @@ -2,20 +2,23 @@ /** * Class to validate and to work with IPv6 addresses * - * @package Requests - * @subpackage Utilities + * @package Requests\Utilities */ +namespace WpOrg\Requests; + +use WpOrg\Requests\Exception\InvalidArgument; +use WpOrg\Requests\Utility\InputValidator; + /** * Class to validate and to work with IPv6 addresses * * This was originally based on the PEAR class of the same name, but has been * entirely rewritten. * - * @package Requests - * @subpackage Utilities + * @package Requests\Utilities */ -class Requests_IPv6 { +final class Ipv6 { /** * Uncompresses an IPv6 address * @@ -30,41 +33,49 @@ class Requests_IPv6 { * @author elfrink at introweb dot nl * @author Josh Peck * @copyright 2003-2005 The PHP Group - * @license http://www.opensource.org/licenses/bsd-license.php - * @param string $ip An IPv6 address + * @license https://opensource.org/licenses/bsd-license.php + * + * @param string|Stringable $ip An IPv6 address * @return string The uncompressed IPv6 address + * + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string or a stringable object. */ public static function uncompress($ip) { + if (InputValidator::is_string_or_stringable($ip) === false) { + throw InvalidArgument::create(1, '$ip', 'string|Stringable', gettype($ip)); + } + + $ip = (string) $ip; + if (substr_count($ip, '::') !== 1) { return $ip; } list($ip1, $ip2) = explode('::', $ip); - $c1 = ($ip1 === '') ? -1 : substr_count($ip1, ':'); - $c2 = ($ip2 === '') ? -1 : substr_count($ip2, ':'); + $c1 = ($ip1 === '') ? -1 : substr_count($ip1, ':'); + $c2 = ($ip2 === '') ? -1 : substr_count($ip2, ':'); if (strpos($ip2, '.') !== false) { $c2++; } - // :: + if ($c1 === -1 && $c2 === -1) { + // :: $ip = '0:0:0:0:0:0:0:0'; - } - // ::xxx - else if ($c1 === -1) { + } elseif ($c1 === -1) { + // ::xxx $fill = str_repeat('0:', 7 - $c2); - $ip = str_replace('::', $fill, $ip); - } - // xxx:: - else if ($c2 === -1) { + $ip = str_replace('::', $fill, $ip); + } elseif ($c2 === -1) { + // xxx:: $fill = str_repeat(':0', 7 - $c1); - $ip = str_replace('::', $fill, $ip); - } - // xxx::xxx - else { + $ip = str_replace('::', $fill, $ip); + } else { + // xxx::xxx $fill = ':' . str_repeat('0:', 6 - $c2 - $c1); - $ip = str_replace('::', $fill, $ip); + $ip = str_replace('::', $fill, $ip); } + return $ip; } @@ -78,13 +89,15 @@ public static function uncompress($ip) { * Example: FF01:0:0:0:0:0:0:101 -> FF01::101 * 0:0:0:0:0:0:0:1 -> ::1 * - * @see uncompress() + * @see \WpOrg\Requests\Ipv6::uncompress() + * * @param string $ip An IPv6 address * @return string The compressed IPv6 address */ public static function compress($ip) { - // Prepare the IP to be compressed - $ip = self::uncompress($ip); + // Prepare the IP to be compressed. + // Note: Input validation is handled in the `uncompress()` method, which is the first call made in this method. + $ip = self::uncompress($ip); $ip_parts = self::split_v6_v4($ip); // Replace all leading zeros @@ -106,8 +119,7 @@ public static function compress($ip) { if ($ip_parts[1] !== '') { return implode(':', $ip_parts); - } - else { + } else { return $ip_parts[0]; } } @@ -124,15 +136,14 @@ public static function compress($ip) { * @param string $ip An IPv6 address * @return string[] [0] contains the IPv6 represented part, and [1] the IPv4 represented part */ - protected static function split_v6_v4($ip) { + private static function split_v6_v4($ip) { if (strpos($ip, '.') !== false) { - $pos = strrpos($ip, ':'); + $pos = strrpos($ip, ':'); $ipv6_part = substr($ip, 0, $pos); $ipv4_part = substr($ip, $pos + 1); - return array($ipv6_part, $ipv4_part); - } - else { - return array($ip, ''); + return [$ipv6_part, $ipv4_part]; + } else { + return [$ip, '']; } } @@ -145,11 +156,12 @@ protected static function split_v6_v4($ip) { * @return bool true if $ip is a valid IPv6 address */ public static function check_ipv6($ip) { - $ip = self::uncompress($ip); + // Note: Input validation is handled in the `uncompress()` method, which is the first call made in this method. + $ip = self::uncompress($ip); list($ipv6, $ipv4) = self::split_v6_v4($ip); - $ipv6 = explode(':', $ipv6); - $ipv4 = explode('.', $ipv4); - if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4) { + $ipv6 = explode(':', $ipv6); + $ipv4 = explode('.', $ipv4); + if ((count($ipv6) === 8 && count($ipv4) === 1) || (count($ipv6) === 6 && count($ipv4) === 4)) { foreach ($ipv6 as $ipv6_part) { // The section can't be empty if ($ipv6_part === '') { @@ -173,6 +185,7 @@ public static function check_ipv6($ip) { return false; } } + if (count($ipv4) === 4) { foreach ($ipv4 as $ipv4_part) { $value = (int) $ipv4_part; @@ -181,9 +194,9 @@ public static function check_ipv6($ip) { } } } + return true; - } - else { + } else { return false; } } diff --git a/includes/vendor/rmccue/requests/library/Requests/IRI.php b/includes/vendor/rmccue/requests/src/Iri.php similarity index 89% rename from includes/vendor/rmccue/requests/library/Requests/IRI.php rename to includes/vendor/rmccue/requests/src/Iri.php index 8dc2fa284..c452c7365 100644 --- a/includes/vendor/rmccue/requests/library/Requests/IRI.php +++ b/includes/vendor/rmccue/requests/src/Iri.php @@ -2,10 +2,17 @@ /** * IRI parser/serialiser/normaliser * - * @package Requests - * @subpackage Utilities + * @package Requests\Utilities */ +namespace WpOrg\Requests; + +use WpOrg\Requests\Exception; +use WpOrg\Requests\Exception\InvalidArgument; +use WpOrg\Requests\Ipv6; +use WpOrg\Requests\Port; +use WpOrg\Requests\Utility\InputValidator; + /** * IRI parser/serialiser/normaliser * @@ -38,16 +45,15 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - * @package Requests - * @subpackage Utilities + * @package Requests\Utilities * @author Geoffrey Sneddon * @author Steve Minutillo * @copyright 2007-2009 Geoffrey Sneddon and Steve Minutillo - * @license http://www.opensource.org/licenses/bsd-license.php + * @license https://opensource.org/licenses/bsd-license.php * @link http://hg.gsnedders.com/iri/ * * @property string $iri IRI we're working with - * @property-read string $uri IRI in URI form, {@see to_uri} + * @property-read string $uri IRI in URI form, {@see \WpOrg\Requests\Iri::to_uri()} * @property string $scheme Scheme part of the IRI * @property string $authority Authority part, formatted for a URI (userinfo + host + port) * @property string $iauthority Authority part of the IRI (userinfo + host + port) @@ -63,32 +69,32 @@ * @property string $fragment Fragment, formatted for a URI (after '#') * @property string $ifragment Fragment part of the IRI (after '#') */ -class Requests_IRI { +class Iri { /** * Scheme * - * @var string + * @var string|null */ protected $scheme = null; /** * User Information * - * @var string + * @var string|null */ protected $iuserinfo = null; /** * ihost * - * @var string + * @var string|null */ protected $ihost = null; /** * Port * - * @var string + * @var string|null */ protected $port = null; @@ -102,12 +108,12 @@ class Requests_IRI { /** * iquery * - * @var string + * @var string|null */ protected $iquery = null; /** - * ifragment + * ifragment|null * * @var string */ @@ -118,22 +124,24 @@ class Requests_IRI { * * Each key is the scheme, each value is an array with each key as the IRI * part and value as the default value for that part. + * + * @var array */ protected $normalization = array( 'acap' => array( - 'port' => 674 + 'port' => Port::ACAP, ), 'dict' => array( - 'port' => 2628 + 'port' => Port::DICT, ), 'file' => array( - 'ihost' => 'localhost' + 'ihost' => 'localhost', ), 'http' => array( - 'port' => 80, + 'port' => Port::HTTP, ), 'https' => array( - 'port' => 443, + 'port' => Port::HTTPS, ), ); @@ -238,9 +246,15 @@ public function __unset($name) { /** * Create a new IRI object, from a specified string * - * @param string|null $iri + * @param string|Stringable|null $iri + * + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $iri argument is not a string, Stringable or null. */ public function __construct($iri = null) { + if ($iri !== null && InputValidator::is_string_or_stringable($iri) === false) { + throw InvalidArgument::create(1, '$iri', 'string|Stringable|null', gettype($iri)); + } + $this->set_iri($iri); } @@ -249,13 +263,13 @@ public function __construct($iri = null) { * * Returns false if $base is not absolute, otherwise an IRI. * - * @param IRI|string $base (Absolute) Base IRI - * @param IRI|string $relative Relative IRI - * @return IRI|false + * @param \WpOrg\Requests\Iri|string $base (Absolute) Base IRI + * @param \WpOrg\Requests\Iri|string $relative Relative IRI + * @return \WpOrg\Requests\Iri|false */ public static function absolutize($base, $relative) { - if (!($relative instanceof Requests_IRI)) { - $relative = new Requests_IRI($relative); + if (!($relative instanceof self)) { + $relative = new self($relative); } if (!$relative->is_valid()) { return false; @@ -264,8 +278,8 @@ public static function absolutize($base, $relative) { return clone $relative; } - if (!($base instanceof Requests_IRI)) { - $base = new Requests_IRI($base); + if (!($base instanceof self)) { + $base = new self($base); } if ($base->scheme === null || !$base->is_valid()) { return false; @@ -277,7 +291,7 @@ public static function absolutize($base, $relative) { $target->scheme = $base->scheme; } else { - $target = new Requests_IRI; + $target = new self; $target->scheme = $base->scheme; $target->iuserinfo = $base->iuserinfo; $target->ihost = $base->ihost; @@ -328,7 +342,7 @@ protected function parse_iri($iri) { $iri = trim($iri, "\x20\x09\x0A\x0C\x0D"); $has_match = preg_match('/^((?P[^:\/?#]+):)?(\/\/(?P[^\/?#]*))?(?P[^?#]*)(\?(?P[^#]*))?(#(?P.*))?$/', $iri, $match); if (!$has_match) { - throw new Requests_Exception('Cannot parse supplied IRI', 'iri.cannot_parse', $iri); + throw new Exception('Cannot parse supplied IRI', 'iri.cannot_parse', $iri); } if ($match[1] === '') { @@ -381,11 +395,11 @@ protected function remove_dot_segments($input) { // preceding "/" (if any) from the output buffer; otherwise, elseif (strpos($input, '/../') === 0) { $input = substr($input, 3); - $output = substr_replace($output, '', strrpos($output, '/')); + $output = substr_replace($output, '', (strrpos($output, '/') ?: 0)); } elseif ($input === '/..') { $input = '/'; - $output = substr_replace($output, '', strrpos($output, '/')); + $output = substr_replace($output, '', (strrpos($output, '/') ?: 0)); } // D: if the input buffer consists only of "." or "..", then remove // that from the input buffer; otherwise, @@ -411,18 +425,18 @@ protected function remove_dot_segments($input) { /** * Replace invalid character with percent encoding * - * @param string $string Input string + * @param string $text Input string * @param string $extra_chars Valid characters not in iunreserved or * iprivate (this is ASCII-only) * @param bool $iprivate Allow iprivate * @return string */ - protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false) { + protected function replace_invalid_with_pct_encoding($text, $extra_chars, $iprivate = false) { // Normalize as many pct-encoded sections as possible - $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array(&$this, 'remove_iunreserved_percent_encoded'), $string); + $text = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array($this, 'remove_iunreserved_percent_encoded'), $text); // Replace invalid percent characters - $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string); + $text = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $text); // Add unreserved and % to $extra_chars (the latter is safe because all // pct-encoded sections are now valid). @@ -430,9 +444,9 @@ protected function replace_invalid_with_pct_encoding($string, $extra_chars, $ipr // Now replace any bytes that aren't allowed with their pct-encoded versions $position = 0; - $strlen = strlen($string); - while (($position += strspn($string, $extra_chars, $position)) < $strlen) { - $value = ord($string[$position]); + $strlen = strlen($text); + while (($position += strspn($text, $extra_chars, $position)) < $strlen) { + $value = ord($text[$position]); // Start position $start = $position; @@ -469,7 +483,7 @@ protected function replace_invalid_with_pct_encoding($string, $extra_chars, $ipr if ($remaining) { if ($position + $length <= $strlen) { for ($position++; $remaining; $position++) { - $value = ord($string[$position]); + $value = ord($text[$position]); // Check that the byte is valid, then add it to the character: if (($value & 0xC0) === 0x80) { @@ -520,7 +534,7 @@ protected function replace_invalid_with_pct_encoding($string, $extra_chars, $ipr } for ($j = $start; $j <= $position; $j++) { - $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1); + $text = substr_replace($text, sprintf('%%%02X', ord($text[$j])), $j, 1); $j += 2; $position += 2; $strlen += 2; @@ -528,7 +542,7 @@ protected function replace_invalid_with_pct_encoding($string, $extra_chars, $ipr } } - return $string; + return $text; } /** @@ -537,13 +551,13 @@ protected function replace_invalid_with_pct_encoding($string, $extra_chars, $ipr * Removes sequences of percent encoded bytes that represent UTF-8 * encoded characters in iunreserved * - * @param array $match PCRE match + * @param array $regex_match PCRE match * @return string Replacement */ - protected function remove_iunreserved_percent_encoded($match) { + protected function remove_iunreserved_percent_encoded($regex_match) { // As we just have valid percent encoded sequences we can just explode // and ignore the first member of the returned array (an empty string). - $bytes = explode('%', $match[0]); + $bytes = explode('%', $regex_match[0]); // Initialize the new string (this is what will be returned) and that // there are no bytes remaining in the current sequence (unsurprising @@ -719,6 +733,9 @@ protected function set_iri($iri) { if ($iri === null) { return true; } + + $iri = (string) $iri; + if (isset($cache[$iri])) { list($this->scheme, $this->iuserinfo, @@ -731,7 +748,7 @@ protected function set_iri($iri) { return $return; } - $parsed = $this->parse_iri((string) $iri); + $parsed = $this->parse_iri($iri); $return = $this->set_scheme($parsed['scheme']) && $this->set_authority($parsed['authority']) @@ -807,7 +824,8 @@ protected function set_authority($authority) { else { $iuserinfo = null; } - if (($port_start = strpos($remaining, ':', strpos($remaining, ']'))) !== false) { + + if (($port_start = strpos($remaining, ':', (strpos($remaining, ']') ?: 0))) !== false) { $port = substr($remaining, $port_start + 1); if ($port === false || $port === '') { $port = null; @@ -861,8 +879,8 @@ protected function set_host($ihost) { return true; } if (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']') { - if (Requests_IPv6::check_ipv6(substr($ihost, 1, -1))) { - $this->ihost = '[' . Requests_IPv6::compress(substr($ihost, 1, -1)) . ']'; + if (Ipv6::check_ipv6(substr($ihost, 1, -1))) { + $this->ihost = '[' . Ipv6::compress(substr($ihost, 1, -1)) . ']'; } else { $this->ihost = null; @@ -983,11 +1001,11 @@ protected function set_fragment($ifragment) { /** * Convert an IRI to a URI (or parts thereof) * - * @param string|bool IRI to convert (or false from {@see get_iri}) + * @param string|bool $iri IRI to convert (or false from {@see \WpOrg\Requests\Iri::get_iri()}) * @return string|false URI if IRI is valid, false otherwise. */ - protected function to_uri($string) { - if (!is_string($string)) { + protected function to_uri($iri) { + if (!is_string($iri)) { return false; } @@ -997,20 +1015,20 @@ protected function to_uri($string) { } $position = 0; - $strlen = strlen($string); - while (($position += strcspn($string, $non_ascii, $position)) < $strlen) { - $string = substr_replace($string, sprintf('%%%02X', ord($string[$position])), $position, 1); + $strlen = strlen($iri); + while (($position += strcspn($iri, $non_ascii, $position)) < $strlen) { + $iri = substr_replace($iri, sprintf('%%%02X', ord($iri[$position])), $position, 1); $position += 3; $strlen += 2; } - return $string; + return $iri; } /** * Get the complete IRI * - * @return string + * @return string|false */ protected function get_iri() { if (!$this->is_valid()) { @@ -1047,7 +1065,7 @@ protected function get_uri() { /** * Get the complete iauthority * - * @return string + * @return string|null */ protected function get_iauthority() { if ($this->iuserinfo === null && $this->ihost === null && $this->port === null) { diff --git a/includes/vendor/rmccue/requests/src/Port.php b/includes/vendor/rmccue/requests/src/Port.php new file mode 100644 index 000000000..554540938 --- /dev/null +++ b/includes/vendor/rmccue/requests/src/Port.php @@ -0,0 +1,75 @@ +proxy = $args; - } - elseif (is_array($args)) { - if (count($args) == 1) { + } elseif (is_array($args)) { + if (count($args) === 1) { list($this->proxy) = $args; - } - elseif (count($args) == 3) { + } elseif (count($args) === 3) { list($this->proxy, $this->user, $this->pass) = $args; - $this->use_authentication = true; - } - else { - throw new Requests_Exception('Invalid number of arguments', 'proxyhttpbadargs'); + $this->use_authentication = true; + } else { + throw ArgumentCount::create( + 'an array with exactly one element or exactly three elements', + count($args), + 'proxyhttpbadargs' + ); } + } elseif ($args !== null) { + throw InvalidArgument::create(1, '$args', 'array|string|null', gettype($args)); } } @@ -76,19 +89,19 @@ public function __construct($args = null) { * Register the necessary callbacks * * @since 1.6 - * @see curl_before_send - * @see fsockopen_remote_socket - * @see fsockopen_remote_host_path - * @see fsockopen_header - * @param Requests_Hooks $hooks Hook system + * @see \WpOrg\Requests\Proxy\Http::curl_before_send() + * @see \WpOrg\Requests\Proxy\Http::fsockopen_remote_socket() + * @see \WpOrg\Requests\Proxy\Http::fsockopen_remote_host_path() + * @see \WpOrg\Requests\Proxy\Http::fsockopen_header() + * @param \WpOrg\Requests\Hooks $hooks Hook system */ - public function register(Requests_Hooks &$hooks) { - $hooks->register('curl.before_send', array(&$this, 'curl_before_send')); + public function register(Hooks $hooks) { + $hooks->register('curl.before_send', [$this, 'curl_before_send']); - $hooks->register('fsockopen.remote_socket', array(&$this, 'fsockopen_remote_socket')); - $hooks->register('fsockopen.remote_host_path', array(&$this, 'fsockopen_remote_host_path')); + $hooks->register('fsockopen.remote_socket', [$this, 'fsockopen_remote_socket']); + $hooks->register('fsockopen.remote_host_path', [$this, 'fsockopen_remote_host_path']); if ($this->use_authentication) { - $hooks->register('fsockopen.after_headers', array(&$this, 'fsockopen_header')); + $hooks->register('fsockopen.after_headers', [$this, 'fsockopen_header']); } } @@ -96,7 +109,7 @@ public function register(Requests_Hooks &$hooks) { * Set cURL parameters before the data is sent * * @since 1.6 - * @param resource $handle cURL resource + * @param resource|\CurlHandle $handle cURL handle */ public function curl_before_send(&$handle) { curl_setopt($handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); @@ -148,4 +161,4 @@ public function fsockopen_header(&$out) { public function get_auth_string() { return $this->user . ':' . $this->pass; } -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/src/Requests.php b/includes/vendor/rmccue/requests/src/Requests.php new file mode 100644 index 000000000..9dec0abe4 --- /dev/null +++ b/includes/vendor/rmccue/requests/src/Requests.php @@ -0,0 +1,1099 @@ + 10, + 'connect_timeout' => 10, + 'useragent' => 'php-requests/' . self::VERSION, + 'protocol_version' => 1.1, + 'redirected' => 0, + 'redirects' => 10, + 'follow_redirects' => true, + 'blocking' => true, + 'type' => self::GET, + 'filename' => false, + 'auth' => false, + 'proxy' => false, + 'cookies' => false, + 'max_bytes' => false, + 'idn' => true, + 'hooks' => null, + 'transport' => null, + 'verify' => null, + 'verifyname' => true, + ]; + + /** + * Default supported Transport classes. + * + * @since 2.0.0 + * + * @var array + */ + const DEFAULT_TRANSPORTS = [ + Curl::class => Curl::class, + Fsockopen::class => Fsockopen::class, + ]; + + /** + * Current version of Requests + * + * @var string + */ + const VERSION = '2.0.15'; + + /** + * Selected transport name + * + * Use {@see \WpOrg\Requests\Requests::get_transport()} instead + * + * @var array + */ + public static $transport = []; + + /** + * Registered transport classes + * + * @var array + */ + protected static $transports = []; + + /** + * Default certificate path. + * + * @see \WpOrg\Requests\Requests::get_certificate_path() + * @see \WpOrg\Requests\Requests::set_certificate_path() + * + * @var string + */ + protected static $certificate_path = __DIR__ . '/../certificates/cacert.pem'; + + /** + * All (known) valid deflate, gzip header magic markers. + * + * These markers relate to different compression levels. + * + * @link https://stackoverflow.com/a/43170354/482864 Marker source. + * + * @since 2.0.0 + * + * @var array + */ + private static $magic_compression_headers = [ + "\x1f\x8b" => true, // Gzip marker. + "\x78\x01" => true, // Zlib marker - level 1. + "\x78\x5e" => true, // Zlib marker - level 2 to 5. + "\x78\x9c" => true, // Zlib marker - level 6. + "\x78\xda" => true, // Zlib marker - level 7 to 9. + ]; + + /** + * This is a static class, do not instantiate it + * + * @codeCoverageIgnore + */ + private function __construct() {} + + /** + * Register a transport + * + * @param string $transport Transport class to add, must support the \WpOrg\Requests\Transport interface + */ + public static function add_transport($transport) { + if (empty(self::$transports)) { + self::$transports = self::DEFAULT_TRANSPORTS; + } + + self::$transports[$transport] = $transport; + } + + /** + * Get the fully qualified class name (FQCN) for a working transport. + * + * @param array $capabilities Optional. Associative array of capabilities to test against, i.e. `['' => true]`. + * @return string FQCN of the transport to use, or an empty string if no transport was + * found which provided the requested capabilities. + */ + protected static function get_transport_class(array $capabilities = []) { + // Caching code, don't bother testing coverage. + // @codeCoverageIgnoreStart + // Array of capabilities as a string to be used as an array key. + ksort($capabilities); + $cap_string = serialize($capabilities); + + // Don't search for a transport if it's already been done for these $capabilities. + if (isset(self::$transport[$cap_string])) { + return self::$transport[$cap_string]; + } + + // Ensure we will not run this same check again later on. + self::$transport[$cap_string] = ''; + // @codeCoverageIgnoreEnd + + if (empty(self::$transports)) { + self::$transports = self::DEFAULT_TRANSPORTS; + } + + // Find us a working transport. + foreach (self::$transports as $class) { + if (!class_exists($class)) { + continue; + } + + $result = $class::test($capabilities); + if ($result === true) { + self::$transport[$cap_string] = $class; + break; + } + } + + return self::$transport[$cap_string]; + } + + /** + * Get a working transport. + * + * @param array $capabilities Optional. Associative array of capabilities to test against, i.e. `['' => true]`. + * @return \WpOrg\Requests\Transport + * @throws \WpOrg\Requests\Exception If no valid transport is found (`notransport`). + */ + protected static function get_transport(array $capabilities = []) { + $class = self::get_transport_class($capabilities); + + if ($class === '') { + throw new Exception('No working transports found', 'notransport', self::$transports); + } + + return new $class(); + } + + /** + * Checks to see if we have a transport for the capabilities requested. + * + * Supported capabilities can be found in the {@see \WpOrg\Requests\Capability} + * interface as constants. + * + * Example usage: + * `Requests::has_capabilities([Capability::SSL => true])`. + * + * @param array $capabilities Optional. Associative array of capabilities to test against, i.e. `['' => true]`. + * @return bool Whether the transport has the requested capabilities. + */ + public static function has_capabilities(array $capabilities = []) { + return self::get_transport_class($capabilities) !== ''; + } + + /**#@+ + * @see \WpOrg\Requests\Requests::request() + * @param string $url + * @param array $headers + * @param array $options + * @return \WpOrg\Requests\Response + */ + /** + * Send a GET request + */ + public static function get($url, $headers = [], $options = []) { + return self::request($url, $headers, null, self::GET, $options); + } + + /** + * Send a HEAD request + */ + public static function head($url, $headers = [], $options = []) { + return self::request($url, $headers, null, self::HEAD, $options); + } + + /** + * Send a DELETE request + */ + public static function delete($url, $headers = [], $options = []) { + return self::request($url, $headers, null, self::DELETE, $options); + } + + /** + * Send a TRACE request + */ + public static function trace($url, $headers = [], $options = []) { + return self::request($url, $headers, null, self::TRACE, $options); + } + /**#@-*/ + + /**#@+ + * @see \WpOrg\Requests\Requests::request() + * @param string $url + * @param array $headers + * @param array $data + * @param array $options + * @return \WpOrg\Requests\Response + */ + /** + * Send a POST request + */ + public static function post($url, $headers = [], $data = [], $options = []) { + return self::request($url, $headers, $data, self::POST, $options); + } + /** + * Send a PUT request + */ + public static function put($url, $headers = [], $data = [], $options = []) { + return self::request($url, $headers, $data, self::PUT, $options); + } + + /** + * Send an OPTIONS request + */ + public static function options($url, $headers = [], $data = [], $options = []) { + return self::request($url, $headers, $data, self::OPTIONS, $options); + } + + /** + * Send a PATCH request + * + * Note: Unlike {@see \WpOrg\Requests\Requests::post()} and {@see \WpOrg\Requests\Requests::put()}, + * `$headers` is required, as the specification recommends that should send an ETag + * + * @link https://tools.ietf.org/html/rfc5789 + */ + public static function patch($url, $headers, $data = [], $options = []) { + return self::request($url, $headers, $data, self::PATCH, $options); + } + /**#@-*/ + + /** + * Main interface for HTTP requests + * + * This method initiates a request and sends it via a transport before + * parsing. + * + * The `$options` parameter takes an associative array with the following + * options: + * + * - `timeout`: How long should we wait for a response? + * Note: for cURL, a minimum of 1 second applies, as DNS resolution + * operates at second-resolution only. + * (float, seconds with a millisecond precision, default: 10, example: 0.01) + * - `connect_timeout`: How long should we wait while trying to connect? + * (float, seconds with a millisecond precision, default: 10, example: 0.01) + * - `useragent`: Useragent to send to the server + * (string, default: php-requests/$version) + * - `follow_redirects`: Should we follow 3xx redirects? + * (boolean, default: true) + * - `redirects`: How many times should we redirect before erroring? + * (integer, default: 10) + * - `blocking`: Should we block processing on this request? + * (boolean, default: true) + * - `filename`: File to stream the body to instead. + * (string|boolean, default: false) + * - `auth`: Authentication handler or array of user/password details to use + * for Basic authentication + * (\WpOrg\Requests\Auth|array|boolean, default: false) + * - `proxy`: Proxy details to use for proxy by-passing and authentication + * (\WpOrg\Requests\Proxy|array|string|boolean, default: false) + * - `max_bytes`: Limit for the response body size. + * (integer|boolean, default: false) + * - `idn`: Enable IDN parsing + * (boolean, default: true) + * - `transport`: Custom transport. Either a class name, or a + * transport object. Defaults to the first working transport from + * {@see \WpOrg\Requests\Requests::getTransport()} + * (string|\WpOrg\Requests\Transport, default: {@see \WpOrg\Requests\Requests::getTransport()}) + * - `hooks`: Hooks handler. + * (\WpOrg\Requests\HookManager, default: new WpOrg\Requests\Hooks()) + * - `verify`: Should we verify SSL certificates? Allows passing in a custom + * certificate file as a string. (Using true uses the system-wide root + * certificate store instead, but this may have different behaviour + * across transports.) + * (string|boolean, default: certificates/cacert.pem) + * - `verifyname`: Should we verify the common name in the SSL certificate? + * (boolean, default: true) + * - `data_format`: How should we send the `$data` parameter? + * (string, one of 'query' or 'body', default: 'query' for + * HEAD/GET/DELETE, 'body' for POST/PUT/OPTIONS/PATCH) + * + * @param string|Stringable $url URL to request + * @param array $headers Extra headers to send with the request + * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests + * @param string $type HTTP request type (use Requests constants) + * @param array $options Options for the request (see description for more information) + * @return \WpOrg\Requests\Response + * + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $url argument is not a string or Stringable. + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $type argument is not a string. + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array. + * @throws \WpOrg\Requests\Exception On invalid URLs (`nonhttp`) + */ + public static function request($url, $headers = [], $data = [], $type = self::GET, $options = []) { + if (InputValidator::is_string_or_stringable($url) === false) { + throw InvalidArgument::create(1, '$url', 'string|Stringable', gettype($url)); + } + + if (is_string($type) === false) { + throw InvalidArgument::create(4, '$type', 'string', gettype($type)); + } + + if (is_array($options) === false) { + throw InvalidArgument::create(5, '$options', 'array', gettype($options)); + } + + if (empty($options['type'])) { + $options['type'] = $type; + } + + $options = array_merge(self::get_default_options(), $options); + + self::set_defaults($url, $headers, $data, $type, $options); + + $options['hooks']->dispatch('requests.before_request', [&$url, &$headers, &$data, &$type, &$options]); + + if (!empty($options['transport'])) { + $transport = $options['transport']; + + if (is_string($options['transport'])) { + $transport = new $transport(); + } + } else { + $need_ssl = (stripos($url, 'https://') === 0); + $capabilities = [Capability::SSL => $need_ssl]; + $transport = self::get_transport($capabilities); + } + + $response = $transport->request($url, $headers, $data, $options); + + $options['hooks']->dispatch('requests.before_parse', [&$response, $url, $headers, $data, $type, $options]); + + return self::parse_response($response, $url, $headers, $data, $options); + } + + /** + * Send multiple HTTP requests simultaneously + * + * The `$requests` parameter takes an associative or indexed array of + * request fields. The key of each request can be used to match up the + * request with the returned data, or with the request passed into your + * `multiple.request.complete` callback. + * + * The request fields value is an associative array with the following keys: + * + * - `url`: Request URL Same as the `$url` parameter to + * {@see \WpOrg\Requests\Requests::request()} + * (string, required) + * - `headers`: Associative array of header fields. Same as the `$headers` + * parameter to {@see \WpOrg\Requests\Requests::request()} + * (array, default: `array()`) + * - `data`: Associative array of data fields or a string. Same as the + * `$data` parameter to {@see \WpOrg\Requests\Requests::request()} + * (array|string, default: `array()`) + * - `type`: HTTP request type (use \WpOrg\Requests\Requests constants). Same as the `$type` + * parameter to {@see \WpOrg\Requests\Requests::request()} + * (string, default: `\WpOrg\Requests\Requests::GET`) + * - `cookies`: Associative array of cookie name to value, or cookie jar. + * (array|\WpOrg\Requests\Cookie\Jar) + * + * If the `$options` parameter is specified, individual requests will + * inherit options from it. This can be used to use a single hooking system, + * or set all the types to `\WpOrg\Requests\Requests::POST`, for example. + * + * In addition, the `$options` parameter takes the following global options: + * + * - `complete`: A callback for when a request is complete. Takes two + * parameters, a \WpOrg\Requests\Response/\WpOrg\Requests\Exception reference, and the + * ID from the request array (Note: this can also be overridden on a + * per-request basis, although that's a little silly) + * (callback) + * + * @param array $requests Requests data (see description for more information) + * @param array $options Global and default options (see {@see \WpOrg\Requests\Requests::request()}) + * @return array Responses (either \WpOrg\Requests\Response or a \WpOrg\Requests\Exception object) + * + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $requests argument is not an array or iterable object with array access. + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array. + */ + public static function request_multiple($requests, $options = []) { + if (InputValidator::has_array_access($requests) === false || InputValidator::is_iterable($requests) === false) { + throw InvalidArgument::create(1, '$requests', 'array|ArrayAccess&Traversable', gettype($requests)); + } + + if (is_array($options) === false) { + throw InvalidArgument::create(2, '$options', 'array', gettype($options)); + } + + $options = array_merge(self::get_default_options(true), $options); + + if (!empty($options['hooks'])) { + $options['hooks']->register('transport.internal.parse_response', [static::class, 'parse_multiple']); + if (!empty($options['complete'])) { + $options['hooks']->register('multiple.request.complete', $options['complete']); + } + } + + foreach ($requests as $id => &$request) { + if (!isset($request['headers'])) { + $request['headers'] = []; + } + + if (!isset($request['data'])) { + $request['data'] = []; + } + + if (!isset($request['type'])) { + $request['type'] = self::GET; + } + + if (!isset($request['options'])) { + $request['options'] = $options; + $request['options']['type'] = $request['type']; + } else { + if (empty($request['options']['type'])) { + $request['options']['type'] = $request['type']; + } + + $request['options'] = array_merge($options, $request['options']); + } + + self::set_defaults($request['url'], $request['headers'], $request['data'], $request['type'], $request['options']); + + // Ensure we only hook in once + if ($request['options']['hooks'] !== $options['hooks']) { + $request['options']['hooks']->register('transport.internal.parse_response', [static::class, 'parse_multiple']); + if (!empty($request['options']['complete'])) { + $request['options']['hooks']->register('multiple.request.complete', $request['options']['complete']); + } + } + } + + unset($request); + + if (!empty($options['transport'])) { + $transport = $options['transport']; + + if (is_string($options['transport'])) { + $transport = new $transport(); + } + } else { + $transport = self::get_transport(); + } + + $responses = $transport->request_multiple($requests, $options); + + foreach ($responses as $id => &$response) { + // If our hook got messed with somehow, ensure we end up with the + // correct response + if (is_string($response)) { + $request = $requests[$id]; + self::parse_multiple($response, $request); + $request['options']['hooks']->dispatch('multiple.request.complete', [&$response, $id]); + } + } + + return $responses; + } + + /** + * Get the default options + * + * @see \WpOrg\Requests\Requests::request() for values returned by this method + * @param boolean $multirequest Is this a multirequest? + * @return array Default option values + */ + protected static function get_default_options($multirequest = false) { + $defaults = static::OPTION_DEFAULTS; + $defaults['verify'] = self::$certificate_path; + + if ($multirequest !== false) { + $defaults['complete'] = null; + } + + return $defaults; + } + + /** + * Get default certificate path. + * + * @return string Default certificate path. + */ + public static function get_certificate_path() { + return self::$certificate_path; + } + + /** + * Set default certificate path. + * + * @param string|Stringable|bool $path Certificate path, pointing to a PEM file. + * + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $url argument is not a string, Stringable or boolean. + */ + public static function set_certificate_path($path) { + if (InputValidator::is_string_or_stringable($path) === false && is_bool($path) === false) { + throw InvalidArgument::create(1, '$path', 'string|Stringable|bool', gettype($path)); + } + + self::$certificate_path = $path; + } + + /** + * Set the default values + * + * The $options parameter is updated with the results. + * + * @param string $url URL to request + * @param array $headers Extra headers to send with the request + * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests + * @param string $type HTTP request type + * @param array $options Options for the request + * @return void + * + * @throws \WpOrg\Requests\Exception When the $url is not an http(s) URL. + */ + protected static function set_defaults(&$url, &$headers, &$data, &$type, &$options) { + if (!preg_match('/^http(s)?:\/\//i', $url, $matches)) { + throw new Exception('Only HTTP(S) requests are handled.', 'nonhttp', $url); + } + + if (empty($options['hooks'])) { + $options['hooks'] = new Hooks(); + } + + if (is_array($options['auth'])) { + $options['auth'] = new Basic($options['auth']); + } + + if ($options['auth'] !== false) { + $options['auth']->register($options['hooks']); + } + + if (is_string($options['proxy']) || is_array($options['proxy'])) { + $options['proxy'] = new Http($options['proxy']); + } + + if ($options['proxy'] !== false) { + $options['proxy']->register($options['hooks']); + } + + if (is_array($options['cookies'])) { + $options['cookies'] = new Jar($options['cookies']); + } elseif (empty($options['cookies'])) { + $options['cookies'] = new Jar(); + } + + if ($options['cookies'] !== false) { + $options['cookies']->register($options['hooks']); + } + + if ($options['idn'] !== false) { + $iri = new Iri($url); + $iri->host = IdnaEncoder::encode($iri->ihost); + $url = $iri->uri; + } + + // Massage the type to ensure we support it. + $type = strtoupper($type); + + if (!isset($options['data_format'])) { + if (in_array($type, [self::HEAD, self::GET, self::DELETE], true)) { + $options['data_format'] = 'query'; + } else { + $options['data_format'] = 'body'; + } + } + } + + /** + * HTTP response parser + * + * @param string $headers Full response text including headers and body + * @param string $url Original request URL + * @param array $req_headers Original $headers array passed to {@link request()}, in case we need to follow redirects + * @param array $req_data Original $data array passed to {@link request()}, in case we need to follow redirects + * @param array $options Original $options array passed to {@link request()}, in case we need to follow redirects + * @return \WpOrg\Requests\Response + * + * @throws \WpOrg\Requests\Exception On missing head/body separator (`requests.no_crlf_separator`) + * @throws \WpOrg\Requests\Exception On missing head/body separator (`noversion`) + * @throws \WpOrg\Requests\Exception On missing head/body separator (`toomanyredirects`) + */ + protected static function parse_response($headers, $url, $req_headers, $req_data, $options) { + $return = new Response(); + if (!$options['blocking']) { + return $return; + } + + $return->raw = $headers; + $return->url = (string) $url; + $return->body = ''; + + if (!$options['filename']) { + $pos = strpos($headers, "\r\n\r\n"); + if ($pos === false) { + // Crap! + throw new Exception('Missing header/body separator', 'requests.no_crlf_separator'); + } + + $headers = substr($return->raw, 0, $pos); + // Headers will always be separated from the body by two new lines - `\n\r\n\r`. + $body = substr($return->raw, $pos + 4); + if (!empty($body)) { + $return->body = $body; + } + } + + // Pretend CRLF = LF for compatibility (RFC 2616, section 19.3) + $headers = str_replace("\r\n", "\n", $headers); + // Unfold headers (replace [CRLF] 1*( SP | HT ) with SP) as per RFC 2616 (section 2.2) + $headers = preg_replace('/\n[ \t]/', ' ', $headers); + $headers = explode("\n", $headers); + preg_match('#^HTTP/(1\.\d)[ \t]+(\d+)#i', array_shift($headers), $matches); + if (empty($matches)) { + throw new Exception('Response could not be parsed', 'noversion', $headers); + } + + $return->protocol_version = (float) $matches[1]; + $return->status_code = (int) $matches[2]; + if ($return->status_code >= 200 && $return->status_code < 300) { + $return->success = true; + } + + foreach ($headers as $header) { + list($key, $value) = explode(':', $header, 2); + $value = trim($value); + preg_replace('#(\s+)#i', ' ', $value); + $return->headers[$key] = $value; + } + + if (isset($return->headers['transfer-encoding'])) { + $return->body = self::decode_chunked($return->body); + unset($return->headers['transfer-encoding']); + } + + if (isset($return->headers['content-encoding'])) { + $return->body = self::decompress($return->body); + } + + //fsockopen and cURL compatibility + if (isset($return->headers['connection'])) { + unset($return->headers['connection']); + } + + $options['hooks']->dispatch('requests.before_redirect_check', [&$return, $req_headers, $req_data, $options]); + + if ($return->is_redirect() && $options['follow_redirects'] === true) { + if (isset($return->headers['location']) && $options['redirected'] < $options['redirects']) { + if ($return->status_code === 303) { + $options['type'] = self::GET; + } + + $options['redirected']++; + $location = $return->headers['location']; + if (strpos($location, 'http://') !== 0 && strpos($location, 'https://') !== 0) { + // relative redirect, for compatibility make it absolute + $location = Iri::absolutize($url, $location); + $location = $location->uri; + } + + $hook_args = [ + &$location, + &$req_headers, + &$req_data, + &$options, + $return, + ]; + $options['hooks']->dispatch('requests.before_redirect', $hook_args); + $redirected = self::request($location, $req_headers, $req_data, $options['type'], $options); + $redirected->history[] = $return; + return $redirected; + } elseif ($options['redirected'] >= $options['redirects']) { + throw new Exception('Too many redirects', 'toomanyredirects', $return); + } + } + + $return->redirects = $options['redirected']; + + $options['hooks']->dispatch('requests.after_request', [&$return, $req_headers, $req_data, $options]); + return $return; + } + + /** + * Callback for `transport.internal.parse_response` + * + * Internal use only. Converts a raw HTTP response to a \WpOrg\Requests\Response + * while still executing a multiple request. + * + * `$response` is either set to a \WpOrg\Requests\Response instance, or a \WpOrg\Requests\Exception object + * + * @param string $response Full response text including headers and body (will be overwritten with Response instance) + * @param array $request Request data as passed into {@see \WpOrg\Requests\Requests::request_multiple()} + * @return void + */ + public static function parse_multiple(&$response, $request) { + try { + $url = $request['url']; + $headers = $request['headers']; + $data = $request['data']; + $options = $request['options']; + $response = self::parse_response($response, $url, $headers, $data, $options); + } catch (Exception $e) { + $response = $e; + } + } + + /** + * Decoded a chunked body as per RFC 2616 + * + * @link https://tools.ietf.org/html/rfc2616#section-3.6.1 + * @param string $data Chunked body + * @return string Decoded body + */ + protected static function decode_chunked($data) { + if (!preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', trim($data))) { + return $data; + } + + $decoded = ''; + $encoded = $data; + + while (true) { + $is_chunked = (bool) preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', $encoded, $matches); + if (!$is_chunked) { + // Looks like it's not chunked after all + return $data; + } + + $length = hexdec(trim($matches[1])); + if ($length === 0) { + // Ignore trailer headers + return $decoded; + } + + $chunk_length = strlen($matches[0]); + $decoded .= substr($encoded, $chunk_length, $length); + $encoded = substr($encoded, $chunk_length + $length + 2); + + if (trim($encoded) === '0' || empty($encoded)) { + return $decoded; + } + } + + // We'll never actually get down here + // @codeCoverageIgnoreStart + } + // @codeCoverageIgnoreEnd + + /** + * Convert a key => value array to a 'key: value' array for headers + * + * @param iterable $dictionary Dictionary of header values + * @return array List of headers + * + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not iterable. + */ + public static function flatten($dictionary) { + if (InputValidator::is_iterable($dictionary) === false) { + throw InvalidArgument::create(1, '$dictionary', 'iterable', gettype($dictionary)); + } + + $return = []; + foreach ($dictionary as $key => $value) { + $return[] = sprintf('%s: %s', $key, $value); + } + + return $return; + } + + /** + * Decompress an encoded body + * + * Implements gzip, compress and deflate. Guesses which it is by attempting + * to decode. + * + * @param string $data Compressed data in one of the above formats + * @return string Decompressed string + * + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string. + */ + public static function decompress($data) { + if (is_string($data) === false) { + throw InvalidArgument::create(1, '$data', 'string', gettype($data)); + } + + if (trim($data) === '') { + // Empty body does not need further processing. + return $data; + } + + $marker = substr($data, 0, 2); + if (!isset(self::$magic_compression_headers[$marker])) { + // Not actually compressed. Probably cURL ruining this for us. + return $data; + } + + if (function_exists('gzdecode')) { + $decoded = @gzdecode($data); + if ($decoded !== false) { + return $decoded; + } + } + + if (function_exists('gzinflate')) { + $decoded = @gzinflate($data); + if ($decoded !== false) { + return $decoded; + } + } + + $decoded = self::compatible_gzinflate($data); + if ($decoded !== false) { + return $decoded; + } + + if (function_exists('gzuncompress')) { + $decoded = @gzuncompress($data); + if ($decoded !== false) { + return $decoded; + } + } + + return $data; + } + + /** + * Decompression of deflated string while staying compatible with the majority of servers. + * + * Certain Servers will return deflated data with headers which PHP's gzinflate() + * function cannot handle out of the box. The following function has been created from + * various snippets on the gzinflate() PHP documentation. + * + * Warning: Magic numbers within. Due to the potential different formats that the compressed + * data may be returned in, some "magic offsets" are needed to ensure proper decompression + * takes place. For a simple progmatic way to determine the magic offset in use, see: + * https://core.trac.wordpress.org/ticket/18273 + * + * @since 1.6.0 + * @link https://core.trac.wordpress.org/ticket/18273 + * @link https://www.php.net/gzinflate#70875 + * @link https://www.php.net/gzinflate#77336 + * + * @param string $gz_data String to decompress. + * @return string|bool False on failure. + * + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string. + */ + public static function compatible_gzinflate($gz_data) { + if (is_string($gz_data) === false) { + throw InvalidArgument::create(1, '$gz_data', 'string', gettype($gz_data)); + } + + if (trim($gz_data) === '') { + return false; + } + + // Compressed data might contain a full zlib header, if so strip it for + // gzinflate() + if (substr($gz_data, 0, 3) === "\x1f\x8b\x08") { + $i = 10; + $flg = ord(substr($gz_data, 3, 1)); + if ($flg > 0) { + if ($flg & 4) { + list($xlen) = unpack('v', substr($gz_data, $i, 2)); + $i += 2 + $xlen; + } + + if ($flg & 8) { + $i = strpos($gz_data, "\0", $i) + 1; + } + + if ($flg & 16) { + $i = strpos($gz_data, "\0", $i) + 1; + } + + if ($flg & 2) { + $i += 2; + } + } + + $decompressed = self::compatible_gzinflate(substr($gz_data, $i)); + if ($decompressed !== false) { + return $decompressed; + } + } + + // If the data is Huffman Encoded, we must first strip the leading 2 + // byte Huffman marker for gzinflate() + // The response is Huffman coded by many compressors such as + // java.util.zip.Deflater, Ruby's Zlib::Deflate, and .NET's + // System.IO.Compression.DeflateStream. + // + // See https://decompres.blogspot.com/ for a quick explanation of this + // data type + $huffman_encoded = false; + + // low nibble of first byte should be 0x08 + list(, $first_nibble) = unpack('h', $gz_data); + + // First 2 bytes should be divisible by 0x1F + list(, $first_two_bytes) = unpack('n', $gz_data); + + if ($first_nibble === 0x08 && ($first_two_bytes % 0x1F) === 0) { + $huffman_encoded = true; + } + + if ($huffman_encoded) { + $decompressed = @gzinflate(substr($gz_data, 2)); + if ($decompressed !== false) { + return $decompressed; + } + } + + if (substr($gz_data, 0, 4) === "\x50\x4b\x03\x04") { + // ZIP file format header + // Offset 6: 2 bytes, General-purpose field + // Offset 26: 2 bytes, filename length + // Offset 28: 2 bytes, optional field length + // Offset 30: Filename field, followed by optional field, followed + // immediately by data + list(, $general_purpose_flag) = unpack('v', substr($gz_data, 6, 2)); + + // If the file has been compressed on the fly, 0x08 bit is set of + // the general purpose field. We can use this to differentiate + // between a compressed document, and a ZIP file + $zip_compressed_on_the_fly = ((0x08 & $general_purpose_flag) === 0x08); + + if (!$zip_compressed_on_the_fly) { + // Don't attempt to decode a compressed zip file + return $gz_data; + } + + // Determine the first byte of data, based on the above ZIP header + // offsets: + $first_file_start = array_sum(unpack('v2', substr($gz_data, 26, 4))); + $decompressed = @gzinflate(substr($gz_data, 30 + $first_file_start)); + if ($decompressed !== false) { + return $decompressed; + } + + return false; + } + + // Finally fall back to straight gzinflate + $decompressed = @gzinflate($gz_data); + if ($decompressed !== false) { + return $decompressed; + } + + // Fallback for all above failing, not expected, but included for + // debugging and preventing regressions and to track stats + $decompressed = @gzinflate(substr($gz_data, 2)); + if ($decompressed !== false) { + return $decompressed; + } + + return false; + } +} diff --git a/includes/vendor/rmccue/requests/src/Response.php b/includes/vendor/rmccue/requests/src/Response.php new file mode 100644 index 000000000..86a0438ba --- /dev/null +++ b/includes/vendor/rmccue/requests/src/Response.php @@ -0,0 +1,165 @@ +headers = new Headers(); + $this->cookies = new Jar(); + } + + /** + * Is the response a redirect? + * + * @return boolean True if redirect (3xx status), false if not. + */ + public function is_redirect() { + $code = $this->status_code; + return in_array($code, [300, 301, 302, 303, 307], true) || $code > 307 && $code < 400; + } + + /** + * Throws an exception if the request was not successful + * + * @param boolean $allow_redirects Set to false to throw on a 3xx as well + * + * @throws \WpOrg\Requests\Exception If `$allow_redirects` is false, and code is 3xx (`response.no_redirects`) + * @throws \WpOrg\Requests\Exception\Http On non-successful status code. Exception class corresponds to "Status" + code (e.g. {@see \WpOrg\Requests\Exception\Http\Status404}) + */ + public function throw_for_status($allow_redirects = true) { + if ($this->is_redirect()) { + if ($allow_redirects !== true) { + throw new Exception('Redirection not allowed', 'response.no_redirects', $this); + } + } elseif (!$this->success) { + $exception = Http::get_class($this->status_code); + throw new $exception(null, $this); + } + } + + /** + * JSON decode the response body. + * + * The method parameters are the same as those for the PHP native `json_decode()` function. + * + * @link https://php.net/json-decode + * + * @param bool|null $associative Optional. When `true`, JSON objects will be returned as associative arrays; + * When `false`, JSON objects will be returned as objects. + * When `null`, JSON objects will be returned as associative arrays + * or objects depending on whether `JSON_OBJECT_AS_ARRAY` is set in the flags. + * Defaults to `true` (in contrast to the PHP native default of `null`). + * @param int $depth Optional. Maximum nesting depth of the structure being decoded. + * Defaults to `512`. + * @param int $options Optional. Bitmask of JSON_BIGINT_AS_STRING, JSON_INVALID_UTF8_IGNORE, + * JSON_INVALID_UTF8_SUBSTITUTE, JSON_OBJECT_AS_ARRAY, JSON_THROW_ON_ERROR. + * Defaults to `0` (no options set). + * + * @return array + * + * @throws \WpOrg\Requests\Exception If `$this->body` is not valid json. + */ + public function decode_body($associative = true, $depth = 512, $options = 0) { + $data = json_decode($this->body, $associative, $depth, $options); + + if (json_last_error() !== JSON_ERROR_NONE) { + $last_error = json_last_error_msg(); + throw new Exception('Unable to parse JSON data: ' . $last_error, 'response.invalid', $this); + } + + return $data; + } +} diff --git a/includes/vendor/rmccue/requests/src/Response/Headers.php b/includes/vendor/rmccue/requests/src/Response/Headers.php new file mode 100644 index 000000000..b4d0fcf91 --- /dev/null +++ b/includes/vendor/rmccue/requests/src/Response/Headers.php @@ -0,0 +1,127 @@ +data[$offset])) { + return null; + } + + return $this->flatten($this->data[$offset]); + } + + /** + * Set the given item + * + * @param string $offset Item name + * @param string $value Item value + * + * @throws \WpOrg\Requests\Exception On attempting to use dictionary as list (`invalidset`) + */ + public function offsetSet($offset, $value) { + if ($offset === null) { + throw new Exception('Object is a dictionary, not a list', 'invalidset'); + } + + if (is_string($offset)) { + $offset = strtolower($offset); + } + + if (!isset($this->data[$offset])) { + $this->data[$offset] = []; + } + + $this->data[$offset][] = $value; + } + + /** + * Get all values for a given header + * + * @param string $offset Name of the header to retrieve. + * @return array|null Header values + * + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not valid as an array key. + */ + public function getValues($offset) { + if (!is_string($offset) && !is_int($offset)) { + throw InvalidArgument::create(1, '$offset', 'string|int', gettype($offset)); + } + + if (is_string($offset)) { + $offset = strtolower($offset); + } + + if (!isset($this->data[$offset])) { + return null; + } + + return $this->data[$offset]; + } + + /** + * Flattens a value into a string + * + * Converts an array into a string by imploding values with a comma, as per + * RFC2616's rules for folding headers. + * + * @param string|array $value Value to flatten + * @return string Flattened value + * + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string or an array. + */ + public function flatten($value) { + if (is_string($value)) { + return $value; + } + + if (is_array($value)) { + return implode(',', $value); + } + + throw InvalidArgument::create(1, '$value', 'string|array', gettype($value)); + } + + /** + * Get an iterator for the data + * + * Converts the internally stored values to a comma-separated string if there is more + * than one value for a key. + * + * @return \ArrayIterator + */ + public function getIterator() { + return new FilteredIterator($this->data, [$this, 'flatten']); + } +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Session.php b/includes/vendor/rmccue/requests/src/Session.php similarity index 50% rename from includes/vendor/rmccue/requests/library/Requests/Session.php rename to includes/vendor/rmccue/requests/src/Session.php index af14bbe41..000d2526d 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Session.php +++ b/includes/vendor/rmccue/requests/src/Session.php @@ -2,10 +2,17 @@ /** * Session handler for persistent requests and default parameters * - * @package Requests - * @subpackage Session Handler + * @package Requests\SessionHandler */ +namespace WpOrg\Requests; + +use WpOrg\Requests\Cookie\Jar; +use WpOrg\Requests\Exception\InvalidArgument; +use WpOrg\Requests\Iri; +use WpOrg\Requests\Requests; +use WpOrg\Requests\Utility\InputValidator; + /** * Session handler for persistent requests and default parameters * @@ -14,23 +21,24 @@ * with all subrequests resolved from this. Base options can be set (including * a shared cookie jar), then overridden for individual requests. * - * @package Requests - * @subpackage Session Handler + * @package Requests\SessionHandler */ -class Requests_Session { +class Session { /** * Base URL for requests * * URLs will be made absolute using this as the base + * * @var string|null */ public $url = null; /** * Base headers for requests + * * @var array */ - public $headers = array(); + public $headers = []; /** * Base data for requests @@ -40,7 +48,7 @@ class Requests_Session { * * @var array */ - public $data = array(); + public $data = []; /** * Base options for requests @@ -53,36 +61,57 @@ class Requests_Session { * * @var array */ - public $options = array(); + public $options = []; /** * Create a new session * - * @param string|null $url Base URL for requests + * @param string|Stringable|null $url Base URL for requests * @param array $headers Default headers for requests * @param array $data Default data for requests * @param array $options Default options for requests + * + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $url argument is not a string, Stringable or null. + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $headers argument is not an array. + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $data argument is not an array. + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array. */ - public function __construct($url = null, $headers = array(), $data = array(), $options = array()) { - $this->url = $url; + public function __construct($url = null, $headers = [], $data = [], $options = []) { + if ($url !== null && InputValidator::is_string_or_stringable($url) === false) { + throw InvalidArgument::create(1, '$url', 'string|Stringable|null', gettype($url)); + } + + if (is_array($headers) === false) { + throw InvalidArgument::create(2, '$headers', 'array', gettype($headers)); + } + + if (is_array($data) === false) { + throw InvalidArgument::create(3, '$data', 'array', gettype($data)); + } + + if (is_array($options) === false) { + throw InvalidArgument::create(4, '$options', 'array', gettype($options)); + } + + $this->url = $url; $this->headers = $headers; - $this->data = $data; + $this->data = $data; $this->options = $options; if (empty($this->options['cookies'])) { - $this->options['cookies'] = new Requests_Cookie_Jar(); + $this->options['cookies'] = new Jar(); } } /** * Get a property's value * - * @param string $key Property key + * @param string $name Property name. * @return mixed|null Property value, null if none found */ - public function __get($key) { - if (isset($this->options[$key])) { - return $this->options[$key]; + public function __get($name) { + if (isset($this->options[$name])) { + return $this->options[$name]; } return null; @@ -91,93 +120,91 @@ public function __get($key) { /** * Set a property's value * - * @param string $key Property key + * @param string $name Property name. * @param mixed $value Property value */ - public function __set($key, $value) { - $this->options[$key] = $value; + public function __set($name, $value) { + $this->options[$name] = $value; } /** * Remove a property's value * - * @param string $key Property key + * @param string $name Property name. */ - public function __isset($key) { - return isset($this->options[$key]); + public function __isset($name) { + return isset($this->options[$name]); } /** * Remove a property's value * - * @param string $key Property key + * @param string $name Property name. */ - public function __unset($key) { - if (isset($this->options[$key])) { - unset($this->options[$key]); - } + public function __unset($name) { + unset($this->options[$name]); } /**#@+ - * @see request() + * @see \WpOrg\Requests\Session::request() * @param string $url * @param array $headers * @param array $options - * @return Requests_Response + * @return \WpOrg\Requests\Response */ /** * Send a GET request */ - public function get($url, $headers = array(), $options = array()) { + public function get($url, $headers = [], $options = []) { return $this->request($url, $headers, null, Requests::GET, $options); } /** * Send a HEAD request */ - public function head($url, $headers = array(), $options = array()) { + public function head($url, $headers = [], $options = []) { return $this->request($url, $headers, null, Requests::HEAD, $options); } /** * Send a DELETE request */ - public function delete($url, $headers = array(), $options = array()) { + public function delete($url, $headers = [], $options = []) { return $this->request($url, $headers, null, Requests::DELETE, $options); } /**#@-*/ /**#@+ - * @see request() + * @see \WpOrg\Requests\Session::request() * @param string $url * @param array $headers * @param array $data * @param array $options - * @return Requests_Response + * @return \WpOrg\Requests\Response */ /** * Send a POST request */ - public function post($url, $headers = array(), $data = array(), $options = array()) { + public function post($url, $headers = [], $data = [], $options = []) { return $this->request($url, $headers, $data, Requests::POST, $options); } /** * Send a PUT request */ - public function put($url, $headers = array(), $data = array(), $options = array()) { + public function put($url, $headers = [], $data = [], $options = []) { return $this->request($url, $headers, $data, Requests::PUT, $options); } /** * Send a PATCH request * - * Note: Unlike {@see post} and {@see put}, `$headers` is required, as the - * specification recommends that should send an ETag + * Note: Unlike {@see \WpOrg\Requests\Session::post()} and {@see \WpOrg\Requests\Session::put()}, + * `$headers` is required, as the specification recommends that should send an ETag * * @link https://tools.ietf.org/html/rfc5789 */ - public function patch($url, $headers, $data = array(), $options = array()) { + public function patch($url, $headers, $data = [], $options = []) { return $this->request($url, $headers, $data, Requests::PATCH, $options); } /**#@-*/ @@ -188,18 +215,18 @@ public function patch($url, $headers, $data = array(), $options = array()) { * This method initiates a request and sends it via a transport before * parsing. * - * @see Requests::request() - * - * @throws Requests_Exception On invalid URLs (`nonhttp`) + * @see \WpOrg\Requests\Requests::request() * * @param string $url URL to request * @param array $headers Extra headers to send with the request * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests - * @param string $type HTTP request type (use Requests constants) - * @param array $options Options for the request (see {@see Requests::request}) - * @return Requests_Response + * @param string $type HTTP request type (use \WpOrg\Requests\Requests constants) + * @param array $options Options for the request (see {@see \WpOrg\Requests\Requests::request()}) + * @return \WpOrg\Requests\Response + * + * @throws \WpOrg\Requests\Exception On invalid URLs (`nonhttp`) */ - public function request($url, $headers = array(), $data = array(), $type = Requests::GET, $options = array()) { + public function request($url, $headers = [], $data = [], $type = Requests::GET, $options = []) { $request = $this->merge_request(compact('url', 'headers', 'data', 'options')); return Requests::request($request['url'], $request['headers'], $request['data'], $type, $request['options']); @@ -208,13 +235,24 @@ public function request($url, $headers = array(), $data = array(), $type = Reque /** * Send multiple HTTP requests simultaneously * - * @see Requests::request_multiple() + * @see \WpOrg\Requests\Requests::request_multiple() + * + * @param array $requests Requests data (see {@see \WpOrg\Requests\Requests::request_multiple()}) + * @param array $options Global and default options (see {@see \WpOrg\Requests\Requests::request()}) + * @return array Responses (either \WpOrg\Requests\Response or a \WpOrg\Requests\Exception object) * - * @param array $requests Requests data (see {@see Requests::request_multiple}) - * @param array $options Global and default options (see {@see Requests::request}) - * @return array Responses (either Requests_Response or a Requests_Exception object) + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $requests argument is not an array or iterable object with array access. + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array. */ - public function request_multiple($requests, $options = array()) { + public function request_multiple($requests, $options = []) { + if (InputValidator::has_array_access($requests) === false || InputValidator::is_iterable($requests) === false) { + throw InvalidArgument::create(1, '$requests', 'array|ArrayAccess&Traversable', gettype($requests)); + } + + if (is_array($options) === false) { + throw InvalidArgument::create(2, '$options', 'array', gettype($options)); + } + foreach ($requests as $key => $request) { $requests[$key] = $this->merge_request($request, false); } @@ -230,31 +268,31 @@ public function request_multiple($requests, $options = array()) { /** * Merge a request's data with the default data * - * @param array $request Request data (same form as {@see request_multiple}) + * @param array $request Request data (same form as {@see \WpOrg\Requests\Session::request_multiple()}) * @param boolean $merge_options Should we merge options as well? * @return array Request data */ protected function merge_request($request, $merge_options = true) { if ($this->url !== null) { - $request['url'] = Requests_IRI::absolutize($this->url, $request['url']); + $request['url'] = Iri::absolutize($this->url, $request['url']); $request['url'] = $request['url']->uri; } if (empty($request['headers'])) { - $request['headers'] = array(); + $request['headers'] = []; } + $request['headers'] = array_merge($this->headers, $request['headers']); if (empty($request['data'])) { if (is_array($this->data)) { $request['data'] = $this->data; } - } - elseif (is_array($request['data']) && is_array($this->data)) { + } elseif (is_array($request['data']) && is_array($this->data)) { $request['data'] = array_merge($this->data, $request['data']); } - if ($merge_options !== false) { + if ($merge_options === true) { $request['options'] = array_merge($this->options, $request['options']); // Disallow forcing the type, as that's a per request setting diff --git a/includes/vendor/rmccue/requests/library/Requests/SSL.php b/includes/vendor/rmccue/requests/src/Ssl.php similarity index 54% rename from includes/vendor/rmccue/requests/library/Requests/SSL.php rename to includes/vendor/rmccue/requests/src/Ssl.php index 2b0376853..99da11d8f 100644 --- a/includes/vendor/rmccue/requests/library/Requests/SSL.php +++ b/includes/vendor/rmccue/requests/src/Ssl.php @@ -2,45 +2,49 @@ /** * SSL utilities for Requests * - * @package Requests - * @subpackage Utilities + * @package Requests\Utilities */ +namespace WpOrg\Requests; + +use WpOrg\Requests\Exception\InvalidArgument; +use WpOrg\Requests\Utility\InputValidator; + /** * SSL utilities for Requests * * Collection of utilities for working with and verifying SSL certificates. * - * @package Requests - * @subpackage Utilities + * @package Requests\Utilities */ -class Requests_SSL { +final class Ssl { /** * Verify the certificate against common name and subject alternative names * * Unfortunately, PHP doesn't check the certificate against the alternative * names, leading things like 'https://www.github.com/' to be invalid. - * Instead * - * @see https://tools.ietf.org/html/rfc2818#section-3.1 RFC2818, Section 3.1 + * @link https://tools.ietf.org/html/rfc2818#section-3.1 RFC2818, Section 3.1 * - * @throws Requests_Exception On not obtaining a match for the host (`fsockopen.ssl.no_match`) - * @param string $host Host name to verify against + * @param string|Stringable $host Host name to verify against * @param array $cert Certificate data from openssl_x509_parse() * @return bool + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $host argument is not a string or a stringable object. + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $cert argument is not an array or array accessible. */ public static function verify_certificate($host, $cert) { - // Calculate the valid wildcard match if the host is not an IP address - $parts = explode('.', $host); - if (ip2long($host) === false) { - $parts[0] = '*'; + if (InputValidator::is_string_or_stringable($host) === false) { + throw InvalidArgument::create(1, '$host', 'string|Stringable', gettype($host)); + } + + if (InputValidator::has_array_access($cert) === false) { + throw InvalidArgument::create(2, '$cert', 'array|ArrayAccess', gettype($cert)); } - $wildcard = implode('.', $parts); $has_dns_alt = false; // Check the subjectAltName - if (!empty($cert['extensions']) && !empty($cert['extensions']['subjectAltName'])) { + if (!empty($cert['extensions']['subjectAltName'])) { $altnames = explode(',', $cert['extensions']['subjectAltName']); foreach ($altnames as $altname) { $altname = trim($altname); @@ -58,15 +62,17 @@ public static function verify_certificate($host, $cert) { return true; } } + + if ($has_dns_alt === true) { + return false; + } } // Fall back to checking the common name if we didn't get any dNSName // alt names, as per RFC2818 - if (!$has_dns_alt && !empty($cert['subject']['CN'])) { + if (!empty($cert['subject']['CN'])) { // Check for a match - if (self::match_domain($host, $cert['subject']['CN']) === true) { - return true; - } + return (self::match_domain($host, $cert['subject']['CN']) === true); } return false; @@ -85,11 +91,29 @@ public static function verify_certificate($host, $cert) { * character to be the full first component; that is, with the exclusion of * the third rule. * - * @param string $reference Reference dNSName + * @param string|Stringable $reference Reference dNSName * @return boolean Is the name valid? + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string or a stringable object. */ public static function verify_reference_name($reference) { + if (InputValidator::is_string_or_stringable($reference) === false) { + throw InvalidArgument::create(1, '$reference', 'string|Stringable', gettype($reference)); + } + + if ($reference === '') { + return false; + } + + if (preg_match('`\s`', $reference) > 0) { + // Whitespace detected. This can never be a dNSName. + return false; + } + $parts = explode('.', $reference); + if ($parts !== array_filter($parts)) { + // DNSName cannot contain two dots next to each other. + return false; + } // Check the first part of the name $first = array_shift($parts); @@ -120,33 +144,39 @@ public static function verify_reference_name($reference) { /** * Match a hostname against a dNSName reference * - * @param string $host Requested host - * @param string $reference dNSName to match against + * @param string|Stringable $host Requested host + * @param string|Stringable $reference dNSName to match against * @return boolean Does the domain match? + * @throws \WpOrg\Requests\Exception\InvalidArgument When either of the passed arguments is not a string or a stringable object. */ public static function match_domain($host, $reference) { - // Check if the reference is blacklisted first + if (InputValidator::is_string_or_stringable($host) === false) { + throw InvalidArgument::create(1, '$host', 'string|Stringable', gettype($host)); + } + + // Check if the reference is blocklisted first if (self::verify_reference_name($reference) !== true) { return false; } // Check for a direct match - if ($host === $reference) { + if ((string) $host === (string) $reference) { return true; } // Calculate the valid wildcard match if the host is not an IP address - // Also validates that the host has 3 parts or more, as per Firefox's - // ruleset. + // Also validates that the host has 3 parts or more, as per Firefox's ruleset, + // as a wildcard reference is only allowed with 3 parts or more, so the + // comparison will never match if host doesn't contain 3 parts or more as well. if (ip2long($host) === false) { - $parts = explode('.', $host); + $parts = explode('.', $host); $parts[0] = '*'; $wildcard = implode('.', $parts); - if ($wildcard === $reference) { + if ($wildcard === (string) $reference) { return true; } } return false; } -} \ No newline at end of file +} diff --git a/includes/vendor/rmccue/requests/src/Transport.php b/includes/vendor/rmccue/requests/src/Transport.php new file mode 100644 index 000000000..f2e1c6ed7 --- /dev/null +++ b/includes/vendor/rmccue/requests/src/Transport.php @@ -0,0 +1,45 @@ + $capabilities Optional. Associative array of capabilities to test against, i.e. `['' => true]`. + * @return bool Whether the transport can be used. + */ + public static function test($capabilities = []); +} diff --git a/includes/vendor/rmccue/requests/library/Requests/Transport/cURL.php b/includes/vendor/rmccue/requests/src/Transport/Curl.php similarity index 55% rename from includes/vendor/rmccue/requests/library/Requests/Transport/cURL.php rename to includes/vendor/rmccue/requests/src/Transport/Curl.php index 4429edb64..7316987b5 100644 --- a/includes/vendor/rmccue/requests/library/Requests/Transport/cURL.php +++ b/includes/vendor/rmccue/requests/src/Transport/Curl.php @@ -2,17 +2,27 @@ /** * cURL HTTP transport * - * @package Requests - * @subpackage Transport + * @package Requests\Transport */ +namespace WpOrg\Requests\Transport; + +use RecursiveArrayIterator; +use RecursiveIteratorIterator; +use WpOrg\Requests\Capability; +use WpOrg\Requests\Exception; +use WpOrg\Requests\Exception\InvalidArgument; +use WpOrg\Requests\Exception\Transport\Curl as CurlException; +use WpOrg\Requests\Requests; +use WpOrg\Requests\Transport; +use WpOrg\Requests\Utility\InputValidator; + /** * cURL HTTP transport * - * @package Requests - * @subpackage Transport + * @package Requests\Transport */ -class Requests_Transport_cURL implements Requests_Transport { +final class Curl implements Transport { const CURL_7_10_5 = 0x070A05; const CURL_7_16_2 = 0x071002; @@ -33,76 +43,80 @@ class Requests_Transport_cURL implements Requests_Transport { /** * Information on the current request * - * @var array cURL information array, see {@see https://secure.php.net/curl_getinfo} + * @var array cURL information array, see {@link https://www.php.net/curl_getinfo} */ public $info; /** - * Version string + * cURL version number * - * @var long + * @var int */ public $version; /** * cURL handle * - * @var resource + * @var resource|\CurlHandle Resource in PHP < 8.0, Instance of CurlHandle in PHP >= 8.0. */ - protected $handle; + private $handle; /** * Hook dispatcher instance * - * @var Requests_Hooks + * @var \WpOrg\Requests\Hooks */ - protected $hooks; + private $hooks; /** * Have we finished the headers yet? * * @var boolean */ - protected $done_headers = false; + private $done_headers = false; /** * If streaming to a file, keep the file pointer * * @var resource */ - protected $stream_handle; + private $stream_handle; /** * How many bytes are in the response body? * * @var int */ - protected $response_bytes; + private $response_bytes; /** * What's the maximum number of bytes we should keep? * * @var int|bool Byte count, or false if no limit. */ - protected $response_byte_limit; + private $response_byte_limit; /** * Constructor */ public function __construct() { - $curl = curl_version(); + $curl = curl_version(); $this->version = $curl['version_number']; - $this->handle = curl_init(); + $this->handle = curl_init(); curl_setopt($this->handle, CURLOPT_HEADER, false); curl_setopt($this->handle, CURLOPT_RETURNTRANSFER, 1); if ($this->version >= self::CURL_7_10_5) { curl_setopt($this->handle, CURLOPT_ENCODING, ''); } + if (defined('CURLOPT_PROTOCOLS')) { + // phpcs:ignore PHPCompatibility.Constants.NewConstants.curlopt_protocolsFound curl_setopt($this->handle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); } + if (defined('CURLOPT_REDIR_PROTOCOLS')) { + // phpcs:ignore PHPCompatibility.Constants.NewConstants.curlopt_redir_protocolsFound curl_setopt($this->handle, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); } } @@ -119,27 +133,56 @@ public function __destruct() { /** * Perform a request * - * @throws Requests_Exception On a cURL error (`curlerror`) - * - * @param string $url URL to request + * @param string|Stringable $url URL to request * @param array $headers Associative array of request headers * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD - * @param array $options Request options, see {@see Requests::response()} for documentation + * @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation * @return string Raw HTTP result + * + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $url argument is not a string or Stringable. + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $headers argument is not an array. + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $data parameter is not an array or string. + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array. + * @throws \WpOrg\Requests\Exception On a cURL error (`curlerror`) */ - public function request($url, $headers = array(), $data = array(), $options = array()) { + public function request($url, $headers = [], $data = [], $options = []) { + if (InputValidator::is_string_or_stringable($url) === false) { + throw InvalidArgument::create(1, '$url', 'string|Stringable', gettype($url)); + } + + if (is_array($headers) === false) { + throw InvalidArgument::create(2, '$headers', 'array', gettype($headers)); + } + + if (!is_array($data) && !is_string($data)) { + if ($data === null) { + $data = ''; + } else { + throw InvalidArgument::create(3, '$data', 'array|string', gettype($data)); + } + } + + if (is_array($options) === false) { + throw InvalidArgument::create(4, '$options', 'array', gettype($options)); + } + $this->hooks = $options['hooks']; $this->setup_handle($url, $headers, $data, $options); - $options['hooks']->dispatch('curl.before_send', array(&$this->handle)); + $options['hooks']->dispatch('curl.before_send', [&$this->handle]); if ($options['filename'] !== false) { - $this->stream_handle = fopen($options['filename'], 'wb'); + // phpcs:ignore WordPress.PHP.NoSilencedErrors -- Silenced the PHP native warning in favour of throwing an exception. + $this->stream_handle = @fopen($options['filename'], 'wb'); + if ($this->stream_handle === false) { + $error = error_get_last(); + throw new Exception($error['message'], 'fopen'); + } } - $this->response_data = ''; - $this->response_bytes = 0; + $this->response_data = ''; + $this->response_bytes = 0; $this->response_byte_limit = false; if ($options['max_bytes'] !== false) { $this->response_byte_limit = $options['max_bytes']; @@ -149,8 +192,7 @@ public function request($url, $headers = array(), $data = array(), $options = ar if ($options['verify'] === false) { curl_setopt($this->handle, CURLOPT_SSL_VERIFYHOST, 0); curl_setopt($this->handle, CURLOPT_SSL_VERIFYPEER, 0); - } - elseif (is_string($options['verify'])) { + } elseif (is_string($options['verify'])) { curl_setopt($this->handle, CURLOPT_CAINFO, $options['verify']); } } @@ -162,13 +204,13 @@ public function request($url, $headers = array(), $data = array(), $options = ar curl_exec($this->handle); $response = $this->response_data; - $options['hooks']->dispatch('curl.after_send', array()); + $options['hooks']->dispatch('curl.after_send', []); - if (curl_errno($this->handle) === 23 || curl_errno($this->handle) === 61) { + if (curl_errno($this->handle) === CURLE_WRITE_ERROR || curl_errno($this->handle) === CURLE_BAD_CONTENT_ENCODING) { // Reset encoding and try again curl_setopt($this->handle, CURLOPT_ENCODING, 'none'); - $this->response_data = ''; + $this->response_data = ''; $this->response_bytes = 0; curl_exec($this->handle); $response = $this->response_data; @@ -177,7 +219,7 @@ public function request($url, $headers = array(), $data = array(), $options = ar $this->process_response($response, $options); // Need to remove the $this reference from the curl handle. - // Otherwise Requests_Transport_cURL wont be garbage collected and the curl_close() will never be called. + // Otherwise \WpOrg\Requests\Transport\Curl won't be garbage collected and the curl_close() will never be called. curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, null); curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, null); @@ -189,40 +231,51 @@ public function request($url, $headers = array(), $data = array(), $options = ar * * @param array $requests Request data * @param array $options Global options - * @return array Array of Requests_Response objects (may contain Requests_Exception or string responses as well) + * @return array Array of \WpOrg\Requests\Response objects (may contain \WpOrg\Requests\Exception or string responses as well) + * + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $requests argument is not an array or iterable object with array access. + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array. */ public function request_multiple($requests, $options) { // If you're not requesting, we can't get any responses ¯\_(ツ)_/¯ if (empty($requests)) { - return array(); + return []; + } + + if (InputValidator::has_array_access($requests) === false || InputValidator::is_iterable($requests) === false) { + throw InvalidArgument::create(1, '$requests', 'array|ArrayAccess&Traversable', gettype($requests)); + } + + if (is_array($options) === false) { + throw InvalidArgument::create(2, '$options', 'array', gettype($options)); } $multihandle = curl_multi_init(); - $subrequests = array(); - $subhandles = array(); + $subrequests = []; + $subhandles = []; $class = get_class($this); foreach ($requests as $id => $request) { $subrequests[$id] = new $class(); - $subhandles[$id] = $subrequests[$id]->get_subrequest_handle($request['url'], $request['headers'], $request['data'], $request['options']); - $request['options']['hooks']->dispatch('curl.before_multi_add', array(&$subhandles[$id])); + $subhandles[$id] = $subrequests[$id]->get_subrequest_handle($request['url'], $request['headers'], $request['data'], $request['options']); + $request['options']['hooks']->dispatch('curl.before_multi_add', [&$subhandles[$id]]); curl_multi_add_handle($multihandle, $subhandles[$id]); } - $completed = 0; - $responses = array(); + $completed = 0; + $responses = []; + $subrequestcount = count($subrequests); - $request['options']['hooks']->dispatch('curl.before_multi_exec', array(&$multihandle)); + $request['options']['hooks']->dispatch('curl.before_multi_exec', [&$multihandle]); do { - $active = false; + $active = 0; do { $status = curl_multi_exec($multihandle, $active); - } - while ($status === CURLM_CALL_MULTI_PERFORM); + } while ($status === CURLM_CALL_MULTI_PERFORM); - $to_process = array(); + $to_process = []; // Read the information as needed while ($done = curl_multi_info_read($multihandle)) { @@ -235,36 +288,35 @@ public function request_multiple($requests, $options) { // Parse the finished requests before we start getting the new ones foreach ($to_process as $key => $done) { $options = $requests[$key]['options']; - if (CURLE_OK !== $done['result']) { + if ($done['result'] !== CURLE_OK) { //get error string for handle. - $reason = curl_error($done['handle']); - $exception = new Requests_Exception_Transport_cURL( - $reason, - Requests_Exception_Transport_cURL::EASY, - $done['handle'], - $done['result'] - ); + $reason = curl_error($done['handle']); + $exception = new CurlException( + $reason, + CurlException::EASY, + $done['handle'], + $done['result'] + ); $responses[$key] = $exception; - $options['hooks']->dispatch('transport.internal.parse_error', array(&$responses[$key], $requests[$key])); - } - else { + $options['hooks']->dispatch('transport.internal.parse_error', [&$responses[$key], $requests[$key]]); + } else { $responses[$key] = $subrequests[$key]->process_response($subrequests[$key]->response_data, $options); - $options['hooks']->dispatch('transport.internal.parse_response', array(&$responses[$key], $requests[$key])); + $options['hooks']->dispatch('transport.internal.parse_response', [&$responses[$key], $requests[$key]]); } curl_multi_remove_handle($multihandle, $done['handle']); curl_close($done['handle']); if (!is_string($responses[$key])) { - $options['hooks']->dispatch('multiple.request.complete', array(&$responses[$key], $key)); + $options['hooks']->dispatch('multiple.request.complete', [&$responses[$key], $key]); } + $completed++; } - } - while ($active || $completed < count($subrequests)); + } while ($active || $completed < $subrequestcount); - $request['options']['hooks']->dispatch('curl.after_multi_exec', array(&$multihandle)); + $request['options']['hooks']->dispatch('curl.after_multi_exec', [&$multihandle]); curl_multi_close($multihandle); @@ -277,8 +329,8 @@ public function request_multiple($requests, $options) { * @param string $url URL to request * @param array $headers Associative array of request headers * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD - * @param array $options Request options, see {@see Requests::response()} for documentation - * @return resource Subrequest's cURL handle + * @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation + * @return resource|\CurlHandle Subrequest's cURL handle */ public function &get_subrequest_handle($url, $headers, $data, $options) { $this->setup_handle($url, $headers, $data, $options); @@ -287,12 +339,13 @@ public function &get_subrequest_handle($url, $headers, $data, $options) { $this->stream_handle = fopen($options['filename'], 'wb'); } - $this->response_data = ''; - $this->response_bytes = 0; + $this->response_data = ''; + $this->response_bytes = 0; $this->response_byte_limit = false; if ($options['max_bytes'] !== false) { $this->response_byte_limit = $options['max_bytes']; } + $this->hooks = $options['hooks']; return $this->handle; @@ -304,27 +357,41 @@ public function &get_subrequest_handle($url, $headers, $data, $options) { * @param string $url URL to request * @param array $headers Associative array of request headers * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD - * @param array $options Request options, see {@see Requests::response()} for documentation + * @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation */ - protected function setup_handle($url, $headers, $data, $options) { - $options['hooks']->dispatch('curl.before_request', array(&$this->handle)); + private function setup_handle($url, $headers, $data, $options) { + $options['hooks']->dispatch('curl.before_request', [&$this->handle]); // Force closing the connection for old versions of cURL (<7.22). - if ( ! isset( $headers['Connection'] ) ) { + if (!isset($headers['Connection'])) { $headers['Connection'] = 'close'; } + /** + * Add "Expect" header. + * + * By default, cURL adds a "Expect: 100-Continue" to most requests. This header can + * add as much as a second to the time it takes for cURL to perform a request. To + * prevent this, we need to set an empty "Expect" header. To match the behaviour of + * Guzzle, we'll add the empty header to requests that are smaller than 1 MB and use + * HTTP/1.1. + * + * https://curl.se/mail/lib-2017-07/0013.html + */ + if (!isset($headers['Expect']) && $options['protocol_version'] === 1.1) { + $headers['Expect'] = $this->get_expect_header($data); + } + $headers = Requests::flatten($headers); if (!empty($data)) { $data_format = $options['data_format']; if ($data_format === 'query') { - $url = self::format_get($url, $data); + $url = self::format_get($url, $data); $data = ''; - } - elseif (!is_string($data)) { - $data = http_build_query($data, null, '&'); + } elseif (!is_string($data)) { + $data = http_build_query($data, '', '&'); } } @@ -361,33 +428,33 @@ protected function setup_handle($url, $headers, $data, $options) { if (is_int($timeout) || $this->version < self::CURL_7_16_2) { curl_setopt($this->handle, CURLOPT_TIMEOUT, ceil($timeout)); - } - else { + } else { + // phpcs:ignore PHPCompatibility.Constants.NewConstants.curlopt_timeout_msFound curl_setopt($this->handle, CURLOPT_TIMEOUT_MS, round($timeout * 1000)); } if (is_int($options['connect_timeout']) || $this->version < self::CURL_7_16_2) { curl_setopt($this->handle, CURLOPT_CONNECTTIMEOUT, ceil($options['connect_timeout'])); - } - else { + } else { + // phpcs:ignore PHPCompatibility.Constants.NewConstants.curlopt_connecttimeout_msFound curl_setopt($this->handle, CURLOPT_CONNECTTIMEOUT_MS, round($options['connect_timeout'] * 1000)); } + curl_setopt($this->handle, CURLOPT_URL, $url); - curl_setopt($this->handle, CURLOPT_REFERER, $url); curl_setopt($this->handle, CURLOPT_USERAGENT, $options['useragent']); if (!empty($headers)) { curl_setopt($this->handle, CURLOPT_HTTPHEADER, $headers); } + if ($options['protocol_version'] === 1.1) { curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); - } - else { + } else { curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); } - if (true === $options['blocking']) { - curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, array(&$this, 'stream_headers')); - curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, array(&$this, 'stream_body')); + if ($options['blocking'] === true) { + curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, [$this, 'stream_headers']); + curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, [$this, 'stream_body']); curl_setopt($this->handle, CURLOPT_BUFFERSIZE, Requests::BUFFER_SIZE); } } @@ -397,19 +464,20 @@ protected function setup_handle($url, $headers, $data, $options) { * * @param string $response Response data from the body * @param array $options Request options - * @return string HTTP response data including headers + * @return string|false HTTP response data including headers. False if non-blocking. + * @throws \WpOrg\Requests\Exception If the request resulted in a cURL error. */ public function process_response($response, $options) { if ($options['blocking'] === false) { $fake_headers = ''; - $options['hooks']->dispatch('curl.after_request', array(&$fake_headers)); + $options['hooks']->dispatch('curl.after_request', [&$fake_headers]); return false; } - if ($options['filename'] !== false) { + + if ($options['filename'] !== false && $this->stream_handle) { fclose($this->stream_handle); $this->headers = trim($this->headers); - } - else { + } else { $this->headers .= $response; } @@ -419,18 +487,19 @@ public function process_response($response, $options) { curl_errno($this->handle), curl_error($this->handle) ); - throw new Requests_Exception($error, 'curlerror', $this->handle); + throw new Exception($error, 'curlerror', $this->handle); } + $this->info = curl_getinfo($this->handle); - $options['hooks']->dispatch('curl.after_request', array(&$this->headers, &$this->info)); + $options['hooks']->dispatch('curl.after_request', [&$this->headers, &$this->info]); return $this->headers; } /** * Collect the headers as they are received * - * @param resource $handle cURL resource + * @param resource|\CurlHandle $handle cURL handle * @param string $headers Header string * @return integer Length of provided header */ @@ -439,14 +508,16 @@ public function stream_headers($handle, $headers) { // interim responses, such as a 100 Continue. We don't need that. // (We may want to keep this somewhere just in case) if ($this->done_headers) { - $this->headers = ''; + $this->headers = ''; $this->done_headers = false; } + $this->headers .= $headers; if ($headers === "\r\n") { $this->done_headers = true; } + return strlen($headers); } @@ -455,12 +526,12 @@ public function stream_headers($handle, $headers) { * * @since 1.6.1 * - * @param resource $handle cURL resource + * @param resource|\CurlHandle $handle cURL handle * @param string $data Body data * @return integer Length of provided data */ public function stream_body($handle, $data) { - $this->hooks->dispatch('request.progress', array($data, $this->response_bytes, $this->response_byte_limit)); + $this->hooks->dispatch('request.progress', [$data, $this->response_bytes, $this->response_byte_limit]); $data_length = strlen($data); // Are we limiting the response size? @@ -473,14 +544,13 @@ public function stream_body($handle, $data) { if (($this->response_bytes + $data_length) > $this->response_byte_limit) { // Limit the length $limited_length = ($this->response_byte_limit - $this->response_bytes); - $data = substr($data, 0, $limited_length); + $data = substr($data, 0, $limited_length); } } if ($this->stream_handle) { fwrite($this->stream_handle, $data); - } - else { + } else { $this->response_data .= $data; } @@ -491,46 +561,49 @@ public function stream_body($handle, $data) { /** * Format a URL given GET data * - * @param string $url - * @param array|object $data Data to build query using, see {@see https://secure.php.net/http_build_query} + * @param string $url Original URL. + * @param array|object $data Data to build query using, see {@link https://www.php.net/http_build_query} * @return string URL with data */ - protected static function format_get($url, $data) { + private static function format_get($url, $data) { if (!empty($data)) { + $query = ''; $url_parts = parse_url($url); if (empty($url_parts['query'])) { - $query = $url_parts['query'] = ''; - } - else { + $url_parts['query'] = ''; + } else { $query = $url_parts['query']; } - $query .= '&' . http_build_query($data, null, '&'); - $query = trim($query, '&'); + $query .= '&' . http_build_query($data, '', '&'); + $query = trim($query, '&'); if (empty($url_parts['query'])) { $url .= '?' . $query; - } - else { + } else { $url = str_replace($url_parts['query'], $query, $url); } } + return $url; } /** - * Whether this transport is valid + * Self-test whether the transport can be used. + * + * The available capabilities to test for can be found in {@see \WpOrg\Requests\Capability}. * * @codeCoverageIgnore - * @return boolean True if the transport is valid, false otherwise. + * @param array $capabilities Optional. Associative array of capabilities to test against, i.e. `['' => true]`. + * @return bool Whether the transport can be used. */ - public static function test($capabilities = array()) { + public static function test($capabilities = []) { if (!function_exists('curl_init') || !function_exists('curl_exec')) { return false; } // If needed, check that our installed curl version supports SSL - if (isset($capabilities['ssl']) && $capabilities['ssl']) { + if (isset($capabilities[Capability::SSL]) && $capabilities[Capability::SSL]) { $curl_version = curl_version(); if (!(CURL_VERSION_SSL & $curl_version['features'])) { return false; @@ -539,4 +612,29 @@ public static function test($capabilities = array()) { return true; } + + /** + * Get the correct "Expect" header for the given request data. + * + * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD. + * @return string The "Expect" header. + */ + private function get_expect_header($data) { + if (!is_array($data)) { + return strlen((string) $data) >= 1048576 ? '100-Continue' : ''; + } + + $bytesize = 0; + $iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($data)); + + foreach ($iterator as $datum) { + $bytesize += strlen((string) $datum); + + if ($bytesize >= 1048576) { + return '100-Continue'; + } + } + + return ''; + } } diff --git a/includes/vendor/rmccue/requests/src/Transport/Fsockopen.php b/includes/vendor/rmccue/requests/src/Transport/Fsockopen.php new file mode 100644 index 000000000..6bd82a32f --- /dev/null +++ b/includes/vendor/rmccue/requests/src/Transport/Fsockopen.php @@ -0,0 +1,518 @@ +dispatch('fsockopen.before_request'); + + $url_parts = parse_url($url); + if (empty($url_parts)) { + throw new Exception('Invalid URL.', 'invalidurl', $url); + } + + $host = $url_parts['host']; + $context = stream_context_create(); + $verifyname = false; + $case_insensitive_headers = new CaseInsensitiveDictionary($headers); + + // HTTPS support + if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https') { + $remote_socket = 'ssl://' . $host; + if (!isset($url_parts['port'])) { + $url_parts['port'] = Port::HTTPS; + } + + $context_options = [ + 'verify_peer' => true, + 'capture_peer_cert' => true, + ]; + $verifyname = true; + + // SNI, if enabled (OpenSSL >=0.9.8j) + // phpcs:ignore PHPCompatibility.Constants.NewConstants.openssl_tlsext_server_nameFound + if (defined('OPENSSL_TLSEXT_SERVER_NAME') && OPENSSL_TLSEXT_SERVER_NAME) { + $context_options['SNI_enabled'] = true; + if (isset($options['verifyname']) && $options['verifyname'] === false) { + $context_options['SNI_enabled'] = false; + } + } + + if (isset($options['verify'])) { + if ($options['verify'] === false) { + $context_options['verify_peer'] = false; + $context_options['verify_peer_name'] = false; + $verifyname = false; + } elseif (is_string($options['verify'])) { + $context_options['cafile'] = $options['verify']; + } + } + + if (isset($options['verifyname']) && $options['verifyname'] === false) { + $context_options['verify_peer_name'] = false; + $verifyname = false; + } + + // Handle the PHP 8.4 deprecation (PHP 9.0 removal) of the function signature we use for stream_context_set_option(). + // Ref: https://wiki.php.net/rfc/deprecate_functions_with_overloaded_signatures#stream_context_set_option + if (function_exists('stream_context_set_options')) { + // PHP 8.3+. + stream_context_set_options($context, ['ssl' => $context_options]); + } else { + // PHP < 8.3. + stream_context_set_option($context, ['ssl' => $context_options]); + } + } else { + $remote_socket = 'tcp://' . $host; + } + + $this->max_bytes = $options['max_bytes']; + + if (!isset($url_parts['port'])) { + $url_parts['port'] = Port::HTTP; + } + + $remote_socket .= ':' . $url_parts['port']; + + // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler + set_error_handler([$this, 'connect_error_handler'], E_WARNING | E_NOTICE); + + $options['hooks']->dispatch('fsockopen.remote_socket', [&$remote_socket]); + + $socket = stream_socket_client($remote_socket, $errno, $errstr, ceil($options['connect_timeout']), STREAM_CLIENT_CONNECT, $context); + + restore_error_handler(); + + if ($verifyname && !$this->verify_certificate_from_context($host, $context)) { + throw new Exception('SSL certificate did not match the requested domain name', 'ssl.no_match'); + } + + if (!$socket) { + if ($errno === 0) { + // Connection issue + throw new Exception(rtrim($this->connect_error), 'fsockopen.connect_error'); + } + + throw new Exception($errstr, 'fsockopenerror', null, $errno); + } + + $data_format = $options['data_format']; + + if ($data_format === 'query') { + $path = self::format_get($url_parts, $data); + $data = ''; + } else { + $path = self::format_get($url_parts, []); + } + + $options['hooks']->dispatch('fsockopen.remote_host_path', [&$path, $url]); + + $request_body = ''; + $out = sprintf("%s %s HTTP/%.1F\r\n", $options['type'], $path, $options['protocol_version']); + + if ($options['type'] !== Requests::TRACE) { + if (is_array($data)) { + $request_body = http_build_query($data, '', '&'); + } else { + $request_body = $data; + } + + // Always include Content-length on POST requests to prevent + // 411 errors from some servers when the body is empty. + if (!empty($data) || $options['type'] === Requests::POST) { + if (!isset($case_insensitive_headers['Content-Length'])) { + $headers['Content-Length'] = strlen($request_body); + } + + if (!isset($case_insensitive_headers['Content-Type'])) { + $headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; + } + } + } + + if (!isset($case_insensitive_headers['Host'])) { + $out .= sprintf('Host: %s', $url_parts['host']); + $scheme_lower = strtolower($url_parts['scheme']); + + if (($scheme_lower === 'http' && $url_parts['port'] !== Port::HTTP) || ($scheme_lower === 'https' && $url_parts['port'] !== Port::HTTPS)) { + $out .= ':' . $url_parts['port']; + } + + $out .= "\r\n"; + } + + if (!isset($case_insensitive_headers['User-Agent'])) { + $out .= sprintf("User-Agent: %s\r\n", $options['useragent']); + } + + $accept_encoding = $this->accept_encoding(); + if (!isset($case_insensitive_headers['Accept-Encoding']) && !empty($accept_encoding)) { + $out .= sprintf("Accept-Encoding: %s\r\n", $accept_encoding); + } + + $headers = Requests::flatten($headers); + + if (!empty($headers)) { + $out .= implode("\r\n", $headers) . "\r\n"; + } + + $options['hooks']->dispatch('fsockopen.after_headers', [&$out]); + + if (substr($out, -2) !== "\r\n") { + $out .= "\r\n"; + } + + if (!isset($case_insensitive_headers['Connection'])) { + $out .= "Connection: Close\r\n"; + } + + $out .= "\r\n" . $request_body; + + $options['hooks']->dispatch('fsockopen.before_send', [&$out]); + + fwrite($socket, $out); + $options['hooks']->dispatch('fsockopen.after_send', [$out]); + + if (!$options['blocking']) { + fclose($socket); + $fake_headers = ''; + $options['hooks']->dispatch('fsockopen.after_request', [&$fake_headers]); + return ''; + } + + $timeout_sec = (int) floor($options['timeout']); + if ($timeout_sec === $options['timeout']) { + $timeout_msec = 0; + } else { + $timeout_msec = self::SECOND_IN_MICROSECONDS * $options['timeout'] % self::SECOND_IN_MICROSECONDS; + } + + stream_set_timeout($socket, $timeout_sec, $timeout_msec); + + $response = ''; + $body = ''; + $headers = ''; + $this->info = stream_get_meta_data($socket); + $size = 0; + $doingbody = false; + $download = false; + if ($options['filename']) { + // phpcs:ignore WordPress.PHP.NoSilencedErrors -- Silenced the PHP native warning in favour of throwing an exception. + $download = @fopen($options['filename'], 'wb'); + if ($download === false) { + $error = error_get_last(); + throw new Exception($error['message'], 'fopen'); + } + } + + while (!feof($socket)) { + $this->info = stream_get_meta_data($socket); + if ($this->info['timed_out']) { + throw new Exception('fsocket timed out', 'timeout'); + } + + $block = fread($socket, Requests::BUFFER_SIZE); + if (!$doingbody) { + $response .= $block; + if (strpos($response, "\r\n\r\n")) { + list($headers, $block) = explode("\r\n\r\n", $response, 2); + $doingbody = true; + } + } + + // Are we in body mode now? + if ($doingbody) { + $options['hooks']->dispatch('request.progress', [$block, $size, $this->max_bytes]); + $data_length = strlen($block); + if ($this->max_bytes) { + // Have we already hit a limit? + if ($size === $this->max_bytes) { + continue; + } + + if (($size + $data_length) > $this->max_bytes) { + // Limit the length + $limited_length = ($this->max_bytes - $size); + $block = substr($block, 0, $limited_length); + } + } + + $size += strlen($block); + if ($download) { + fwrite($download, $block); + } else { + $body .= $block; + } + } + } + + $this->headers = $headers; + + if ($download) { + fclose($download); + } else { + $this->headers .= "\r\n\r\n" . $body; + } + + fclose($socket); + + $options['hooks']->dispatch('fsockopen.after_request', [&$this->headers, &$this->info]); + return $this->headers; + } + + /** + * Send multiple requests simultaneously + * + * @param array $requests Request data (array of 'url', 'headers', 'data', 'options') as per {@see \WpOrg\Requests\Transport::request()} + * @param array $options Global options, see {@see \WpOrg\Requests\Requests::response()} for documentation + * @return array Array of \WpOrg\Requests\Response objects (may contain \WpOrg\Requests\Exception or string responses as well) + * + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $requests argument is not an array or iterable object with array access. + * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array. + */ + public function request_multiple($requests, $options) { + // If you're not requesting, we can't get any responses ¯\_(ツ)_/¯ + if (empty($requests)) { + return []; + } + + if (InputValidator::has_array_access($requests) === false || InputValidator::is_iterable($requests) === false) { + throw InvalidArgument::create(1, '$requests', 'array|ArrayAccess&Traversable', gettype($requests)); + } + + if (is_array($options) === false) { + throw InvalidArgument::create(2, '$options', 'array', gettype($options)); + } + + $responses = []; + $class = get_class($this); + foreach ($requests as $id => $request) { + try { + $handler = new $class(); + $responses[$id] = $handler->request($request['url'], $request['headers'], $request['data'], $request['options']); + + $request['options']['hooks']->dispatch('transport.internal.parse_response', [&$responses[$id], $request]); + } catch (Exception $e) { + $responses[$id] = $e; + } + + if (!is_string($responses[$id])) { + $request['options']['hooks']->dispatch('multiple.request.complete', [&$responses[$id], $id]); + } + } + + return $responses; + } + + /** + * Retrieve the encodings we can accept + * + * @return string Accept-Encoding header value + */ + private static function accept_encoding() { + $type = []; + if (function_exists('gzinflate')) { + $type[] = 'deflate;q=1.0'; + } + + if (function_exists('gzuncompress')) { + $type[] = 'compress;q=0.5'; + } + + $type[] = 'gzip;q=0.5'; + + return implode(', ', $type); + } + + /** + * Format a URL given GET data + * + * @param array $url_parts Array of URL parts as received from {@link https://www.php.net/parse_url} + * @param array|object $data Data to build query using, see {@link https://www.php.net/http_build_query} + * @return string URL with data + */ + private static function format_get($url_parts, $data) { + if (!empty($data)) { + if (empty($url_parts['query'])) { + $url_parts['query'] = ''; + } + + $url_parts['query'] .= '&' . http_build_query($data, '', '&'); + $url_parts['query'] = trim($url_parts['query'], '&'); + } + + if (isset($url_parts['path'])) { + if (isset($url_parts['query'])) { + $get = $url_parts['path'] . '?' . $url_parts['query']; + } else { + $get = $url_parts['path']; + } + } else { + $get = '/'; + } + + return $get; + } + + /** + * Error handler for stream_socket_client() + * + * @param int $errno Error number (e.g. E_WARNING) + * @param string $errstr Error message + */ + public function connect_error_handler($errno, $errstr) { + // Double-check we can handle it + if (($errno & E_WARNING) === 0 && ($errno & E_NOTICE) === 0) { + // Return false to indicate the default error handler should engage + return false; + } + + $this->connect_error .= $errstr . "\n"; + return true; + } + + /** + * Verify the certificate against common name and subject alternative names + * + * Unfortunately, PHP doesn't check the certificate against the alternative + * names, leading things like 'https://www.github.com/' to be invalid. + * Instead + * + * @link https://tools.ietf.org/html/rfc2818#section-3.1 RFC2818, Section 3.1 + * + * @param string $host Host name to verify against + * @param resource $context Stream context + * @return bool + * + * @throws \WpOrg\Requests\Exception On failure to connect via TLS (`fsockopen.ssl.connect_error`) + * @throws \WpOrg\Requests\Exception On not obtaining a match for the host (`fsockopen.ssl.no_match`) + */ + public function verify_certificate_from_context($host, $context) { + $meta = stream_context_get_options($context); + + // If we don't have SSL options, then we couldn't make the connection at + // all + if (empty($meta) || empty($meta['ssl']) || empty($meta['ssl']['peer_certificate'])) { + throw new Exception(rtrim($this->connect_error), 'ssl.connect_error'); + } + + $cert = openssl_x509_parse($meta['ssl']['peer_certificate']); + + return Ssl::verify_certificate($host, $cert); + } + + /** + * Self-test whether the transport can be used. + * + * The available capabilities to test for can be found in {@see \WpOrg\Requests\Capability}. + * + * @codeCoverageIgnore + * @param array $capabilities Optional. Associative array of capabilities to test against, i.e. `['' => true]`. + * @return bool Whether the transport can be used. + */ + public static function test($capabilities = []) { + if (!function_exists('fsockopen')) { + return false; + } + + // If needed, check that streams support SSL + if (isset($capabilities[Capability::SSL]) && $capabilities[Capability::SSL]) { + if (!extension_loaded('openssl') || !function_exists('openssl_x509_parse')) { + return false; + } + } + + return true; + } +} diff --git a/includes/vendor/rmccue/requests/src/Utility/CaseInsensitiveDictionary.php b/includes/vendor/rmccue/requests/src/Utility/CaseInsensitiveDictionary.php new file mode 100644 index 000000000..0e1a914cd --- /dev/null +++ b/includes/vendor/rmccue/requests/src/Utility/CaseInsensitiveDictionary.php @@ -0,0 +1,127 @@ + $value) { + $this->offsetSet($offset, $value); + } + } + + /** + * Check if the given item exists + * + * @param string $offset Item key + * @return boolean Does the item exist? + */ + #[ReturnTypeWillChange] + public function offsetExists($offset) { + if (is_string($offset)) { + $offset = strtolower($offset); + } + + return isset($this->data[$offset]); + } + + /** + * Get the value for the item + * + * @param string $offset Item key + * @return string|null Item value (null if the item key doesn't exist) + */ + #[ReturnTypeWillChange] + public function offsetGet($offset) { + if (is_string($offset)) { + $offset = strtolower($offset); + } + + if (!isset($this->data[$offset])) { + return null; + } + + return $this->data[$offset]; + } + + /** + * Set the given item + * + * @param string $offset Item name + * @param string $value Item value + * + * @throws \WpOrg\Requests\Exception On attempting to use dictionary as list (`invalidset`) + */ + #[ReturnTypeWillChange] + public function offsetSet($offset, $value) { + if ($offset === null) { + throw new Exception('Object is a dictionary, not a list', 'invalidset'); + } + + if (is_string($offset)) { + $offset = strtolower($offset); + } + + $this->data[$offset] = $value; + } + + /** + * Unset the given header + * + * @param string $offset The key for the item to unset. + */ + #[ReturnTypeWillChange] + public function offsetUnset($offset) { + if (is_string($offset)) { + $offset = strtolower($offset); + } + + unset($this->data[$offset]); + } + + /** + * Get an iterator for the data + * + * @return \ArrayIterator + */ + #[ReturnTypeWillChange] + public function getIterator() { + return new ArrayIterator($this->data); + } + + /** + * Get the headers as an array + * + * @return array Header data + */ + public function getAll() { + return $this->data; + } +} diff --git a/includes/vendor/rmccue/requests/src/Utility/FilteredIterator.php b/includes/vendor/rmccue/requests/src/Utility/FilteredIterator.php new file mode 100644 index 000000000..4865966c4 --- /dev/null +++ b/includes/vendor/rmccue/requests/src/Utility/FilteredIterator.php @@ -0,0 +1,97 @@ +callback = $callback; + } + } + + /** + * Prevent unserialization of the object for security reasons. + * + * @phpcs:disable PHPCompatibility.FunctionNameRestrictions.NewMagicMethods.__unserializeFound + * + * @param array $data Restored array of data originally serialized. + * + * @return void + */ + #[ReturnTypeWillChange] + public function __unserialize($data) {} + // phpcs:enable + + /** + * Perform reinitialization tasks. + * + * Prevents a callback from being injected during unserialization of an object. + * + * @return void + */ + public function __wakeup() { + unset($this->callback); + } + + /** + * Get the current item's value after filtering + * + * @return string + */ + #[ReturnTypeWillChange] + public function current() { + $value = parent::current(); + + if (is_callable($this->callback)) { + $value = call_user_func($this->callback, $value); + } + + return $value; + } + + /** + * Prevent creating a PHP value from a stored representation of the object for security reasons. + * + * @param string $data The serialized string. + * + * @return void + */ + #[ReturnTypeWillChange] + public function unserialize($data) {} +} diff --git a/includes/vendor/rmccue/requests/src/Utility/InputValidator.php b/includes/vendor/rmccue/requests/src/Utility/InputValidator.php new file mode 100644 index 000000000..7c10d61a4 --- /dev/null +++ b/includes/vendor/rmccue/requests/src/Utility/InputValidator.php @@ -0,0 +1,109 @@ + [ '_attributes' => ['house'=>'Hogwarts'], '_value' => 'Harry Potter' - ] + ], + 'Good movie' => [ + '_attributes' => ['category' => 'Action'], + '_value' => 300, + ], ]; $result = ArrayToXml::convert($array); @@ -116,11 +118,74 @@ This code will result in: Harry Potter + 300 ``` *Note, that the value of the `_value` field must be a string. [(More)](https://github.com/spatie/array-to-xml/issues/75#issuecomment-413726065)* +### Adding comments + +You can use a key named `_comment` to add a comment to a node. The exact placement depends on where you put the key in your array. You can also add multiple keys *starting with* `_comment` to add multiple comments. + +```php +$array = [ + 'Good guy' => [ + '_comment' => 'Our hero', + 'name' => 'Luke Skywalker', + 'weapon' => 'Lightsaber' + ], + 'Bad guy' => [ + 'name' => 'Sauron', + 'weapon' => 'Evil Eye', + '_comment' => 'Finally gone', + ], + 'Another guy' => [ + '_comment' => 'The GOAT', + 'name' => 'John Wick', + '_comment2' => 'famous for', + 'weapon' => 'Pencil', + '_comment_other' => 'His dog needs an entry', + ]; + 'The survivor' => [ + '_attributes' => ['house'=>'Hogwarts'], + '_value' => 'Harry Potter', + '_comment' => 'He made it', + ] +]; + +$result = ArrayToXml::convert($array); +``` + +This code will result in: + +```xml + + + + + Luke Skywalker + Lightsaber + + + Sauron + Evil Eye + + + + + John Wick + + Pencil + + + Harry Potter + +``` + +> [!NOTE] +> A comment will be omitted if the value is an empty string "" or `null`. + ### Using reserved characters It is also possible to wrap the value of a node into a CDATA section. This allows you to use reserved characters. @@ -166,7 +231,8 @@ If your input contains something that cannot be parsed a `DOMException` will be You could specify specific values in for: - encoding as the fourth argument (string) - version as the fifth argument (string) - - standalone as sixth argument (boolean) + - DOM properties as the sixth argument (array) + - standalone as seventh argument (boolean) ```php $result = ArrayToXml::convert($array, [], true, 'UTF-8', '1.1', [], true); @@ -241,6 +307,58 @@ This will result in: ``` +### Using Closure values +The package can use Closure values: + +```php +$users = [ + [ + 'name' => 'one', + 'age' => 10, + ], + [ + 'name' => 'two', + 'age' => 12, + ], +]; + +$array = [ + 'users' => function () use ($users) { + $new_users = []; + foreach ($users as $user) { + $new_users[] = array_merge( + $user, + [ + 'double_age' => $user['age'] * 2, + ] + ); + } + + return $new_users; + }, +]; + +ArrayToXml::convert($array) +``` + +This will result in: + +```xml + + + + one + 10 + 20 + + + two + 12 + 24 + + +``` + ### Handling numeric keys The package can also can handle numeric keys: @@ -330,6 +448,44 @@ A custom key contains three, colon-separated parts: "__custom:[custom-tag]:[uniq - [unique-string] - A unique string that avoids overwriting of duplicate keys in PHP arrays. +a colon character can be included within the custom-tag portion by escaping it with a backslash: + +```php +$array = [ + '__custom:ns\\:custom-key:1' => [ + 'name' => 'Vladimir', + 'nickname' => 'greeflas', + ], + '__custom:ns\\:custom-key:2' => [ + 'name' => 'Marina', + 'nickname' => 'estacet', + 'tags' => [ + '__custom:ns\\:tag:1' => 'first-tag', + '__custom:ns\\:tag:2' => 'second-tag', + ] + ], +]; +``` +This will result in: + +```xml + + + + Vladimir + greeflas + + + Marina + estacet + + first-tag + second-tag + + + +``` + ### Setting DOMDocument properties To set properties of the internal DOMDocument object just pass an array consisting of keys and values. For a full list of valid properties consult https://www.php.net/manual/en/class.domdocument.php. @@ -441,23 +597,43 @@ This will result in: soap:value ``` +### Adding processing instructions + +Call `$arrayToXml->addProcessingInstruction($target, $data)` method on ArrayToXml object to prepend a processing instruction before the root element. + +Example: + +```php +$arrayToXml = new ArrayToXml($array); +$arrayToXml->addProcessingInstruction('xml-stylesheet', 'type="text/xsl" href="base.xsl"'); +$result = $arrayToXml->toXml(); +``` + +This will result in: + +```xml + + +Luke SkywalkerLightsaberSauronEvil Eye +``` + ## Testing ```bash vendor/bin/phpunit ``` -### Changelog +## Changelog -Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. +Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. ## Contributing -Please see [CONTRIBUTING](CONTRIBUTING.md) for details. +Please see [CONTRIBUTING](https://github.com/spatie/.github/blob/main/CONTRIBUTING.md) for details. -## Security +## Security Vulnerabilities -If you discover any security related issues, please email freek@spatie.be instead of using the issue tracker. +Please review [our security policy](../../security/policy) on how to report security vulnerabilities. ## Postcardware diff --git a/includes/vendor/spatie/array-to-xml/src/ArrayToXml.php b/includes/vendor/spatie/array-to-xml/src/ArrayToXml.php index 616c2422c..04197b07b 100644 --- a/includes/vendor/spatie/array-to-xml/src/ArrayToXml.php +++ b/includes/vendor/spatie/array-to-xml/src/ArrayToXml.php @@ -2,6 +2,7 @@ namespace Spatie\ArrayToXml; +use Closure; use DOMDocument; use DOMElement; use DOMException; @@ -9,24 +10,29 @@ class ArrayToXml { - protected $document; + protected DOMDocument $document; + protected DOMElement $rootNode; - protected $replaceSpacesByUnderScoresInKeyNames = true; + protected bool $replaceSpacesByUnderScoresInKeyNames = true; - protected $addXmlDeclaration = true; + protected bool $addXmlDeclaration = true; - protected $numericTagNamePrefix = 'numeric_'; + protected string $numericTagNamePrefix = 'numeric_'; + + protected array $options = ['convertNullToXsiNil' => false, 'convertBoolToString' => false]; public function __construct( array $array, - $rootElement = '', - $replaceSpacesByUnderScoresInKeyNames = true, - $xmlEncoding = null, - $xmlVersion = '1.0', - $domProperties = [], - $xmlStandalone = null + string | array $rootElement = '', + bool $replaceSpacesByUnderScoresInKeyNames = true, + string | null $xmlEncoding = null, + string $xmlVersion = '1.0', + array $domProperties = [], + bool | null $xmlStandalone = null, + bool $addXmlDeclaration = true, + array | null $options = ['convertNullToXsiNil' => false, 'convertBoolToString' => false] ) { - $this->document = new DOMDocument($xmlVersion, $xmlEncoding); + $this->document = new DOMDocument($xmlVersion, $xmlEncoding ?? ''); if (! is_null($xmlStandalone)) { $this->document->xmlStandalone = $xmlStandalone; @@ -36,20 +42,24 @@ public function __construct( $this->setDomProperties($domProperties); } + $this->addXmlDeclaration = $addXmlDeclaration; + + $this->options = array_merge($this->options, $options); + $this->replaceSpacesByUnderScoresInKeyNames = $replaceSpacesByUnderScoresInKeyNames; - if ($this->isArrayAllKeySequential($array) && ! empty($array)) { + if (! empty($array) && $this->isArrayAllKeySequential($array)) { throw new DOMException('Invalid Character Error'); } - $root = $this->createRootElement($rootElement); + $this->rootNode = $this->createRootElement($rootElement); - $this->document->appendChild($root); + $this->document->appendChild($this->rootNode); - $this->convertElement($root, $array); + $this->convertElement($this->rootNode, $array); } - public function setNumericTagNamePrefix(string $prefix) + public function setNumericTagNamePrefix(string $prefix): void { $this->numericTagNamePrefix = $prefix; } @@ -58,11 +68,13 @@ public static function convert( array $array, $rootElement = '', bool $replaceSpacesByUnderScoresInKeyNames = true, - string $xmlEncoding = null, + ?string $xmlEncoding = null, string $xmlVersion = '1.0', array $domProperties = [], - bool $xmlStandalone = null - ) { + ?bool $xmlStandalone = null, + bool $addXmlDeclaration = true, + array $options = ['convertNullToXsiNil' => false] + ): string { $converter = new static( $array, $rootElement, @@ -70,19 +82,19 @@ public static function convert( $xmlEncoding, $xmlVersion, $domProperties, - $xmlStandalone + $xmlStandalone, + $addXmlDeclaration, + $options ); return $converter->toXml(); } - public function toXml(): string + public function toXml($options = 0): string { - if ($this->addXmlDeclaration === false) { - return $this->document->saveXml($this->document->documentElement); - } - - return $this->document->saveXML(); + return $this->addXmlDeclaration + ? $this->document->saveXML(options: $options) + : $this->document->saveXML($this->document->documentElement, $options); } public function toDom(): DOMDocument @@ -90,16 +102,16 @@ public function toDom(): DOMDocument return $this->document; } - protected function ensureValidDomProperties(array $domProperties) + protected function ensureValidDomProperties(array $domProperties): void { foreach ($domProperties as $key => $value) { if (! property_exists($this->document, $key)) { - throw new Exception($key.' is not a valid property of DOMDocument'); + throw new Exception("{$key} is not a valid property of DOMDocument"); } } } - public function setDomProperties(array $domProperties) + public function setDomProperties(array $domProperties): self { $this->ensureValidDomProperties($domProperties); @@ -110,7 +122,7 @@ public function setDomProperties(array $domProperties) return $this; } - public function prettify() + public function prettify(): self { $this->document->preserveWhiteSpace = false; $this->document->formatOutput = true; @@ -118,19 +130,36 @@ public function prettify() return $this; } - public function dropXmlDeclaration() + public function dropXmlDeclaration(): self { $this->addXmlDeclaration = false; return $this; } - private function convertElement(DOMElement $element, $value) + public function addProcessingInstruction(string $target, string $data): self + { + $elements = $this->document->getElementsByTagName('*'); + + $rootElement = $elements->count() > 0 ? $elements->item(0) : null; + + $processingInstruction = $this->document->createProcessingInstruction($target, $data); + + $this->document->insertBefore($processingInstruction, $rootElement); + + return $this; + } + + protected function convertElement(DOMElement $element, mixed $value): void { + if ($value instanceof Closure) { + $value = $value(); + } + $sequential = $this->isArrayAllKeySequential($value); if (! is_array($value)) { - $value = htmlspecialchars($value); + $value = htmlspecialchars($value ?? ''); $value = $this->removeControlCharacters($value); @@ -143,18 +172,22 @@ private function convertElement(DOMElement $element, $value) if (! $sequential) { if (($key === '_attributes') || ($key === '@attributes')) { $this->addAttributes($element, $data); - } elseif ((($key === '_value') || ($key === '@value')) && is_string($data)) { + } elseif ((($key === '_value') || ($key === '@value')) && is_scalar($data)) { $element->nodeValue = htmlspecialchars($data); - } elseif ((($key === '_cdata') || ($key === '@cdata')) && is_string($data)) { + } elseif ((($key === '_cdata') || ($key === '@cdata')) && is_scalar($data)) { $element->appendChild($this->document->createCDATASection($data)); - } elseif ((($key === '_mixed') || ($key === '@mixed')) && is_string($data)) { + } elseif ((($key === '_mixed') || ($key === '@mixed')) && is_scalar($data)) { $fragment = $this->document->createDocumentFragment(); $fragment->appendXML($data); $element->appendChild($fragment); } elseif ($key === '__numeric') { $this->addNumericNode($element, $data); - } elseif (substr($key, 0, 9) === '__custom:') { - $this->addNode($element, explode(':', $key)[1], $data); + } elseif (str_starts_with($key, '__custom:')) { + $this->addNode($element, str_replace('\:', ':', preg_split('/(?appendChild(new \DOMComment($data)); + } } else { $this->addNode($element, $key, $data); } @@ -166,25 +199,51 @@ private function convertElement(DOMElement $element, $value) } } - protected function addNumericNode(DOMElement $element, $value) + protected function addNumericNode(DOMElement $element, mixed $value): void { foreach ($value as $key => $item) { $this->convertElement($element, [$this->numericTagNamePrefix.$key => $item]); } } - protected function addNode(DOMElement $element, $key, $value) + protected function addNode(DOMElement $element, string $key, mixed $value): void { if ($this->replaceSpacesByUnderScoresInKeyNames) { $key = str_replace(' ', '_', $key); } $child = $this->document->createElement($key); + + $this->addNodeTypeAttribute($child, $value); + $element->appendChild($child); + + $value = $this->convertNodeValue($child, $value); + $this->convertElement($child, $value); } - protected function addCollectionNode(DOMElement $element, $value) + protected function convertNodeValue(DOMElement $element, mixed $value): mixed + { + if ($this->options['convertBoolToString'] && is_bool($value)) { + $value = $value ? 'true' : 'false'; + } + + return $value; + } + + protected function addNodeTypeAttribute(DOMElement $element, mixed $value): void + { + if ($this->options['convertNullToXsiNil'] && is_null($value)) { + if (! $this->rootNode->hasAttribute('xmlns:xsi')) { + $this->rootNode->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); + } + + $element->setAttribute('xsi:nil', 'true'); + } + } + + protected function addCollectionNode(DOMElement $element, mixed $value): void { if ($element->childNodes->length === 0 && $element->attributes->length === 0) { $this->convertElement($element, $value); @@ -197,7 +256,7 @@ protected function addCollectionNode(DOMElement $element, $value) $this->convertElement($child, $value); } - protected function addSequentialNode(DOMElement $element, $value) + protected function addSequentialNode(DOMElement $element, mixed $value): void { if (empty($element->nodeValue) && ! is_numeric($element->nodeValue)) { $element->nodeValue = htmlspecialchars($value); @@ -205,12 +264,12 @@ protected function addSequentialNode(DOMElement $element, $value) return; } - $child = new DOMElement($element->tagName); + $child = $this->document->createElement($element->tagName); $child->nodeValue = htmlspecialchars($value); $element->parentNode->appendChild($child); } - protected function isArrayAllKeySequential($value) + protected function isArrayAllKeySequential(array | string | null $value): bool { if (! is_array($value)) { return false; @@ -227,14 +286,14 @@ protected function isArrayAllKeySequential($value) return array_unique(array_map('is_int', array_keys($value))) === [true]; } - protected function addAttributes(DOMElement $element, array $data) + protected function addAttributes(DOMElement $element, array $data): void { foreach ($data as $attrKey => $attrVal) { - $element->setAttribute($attrKey, $attrVal); + $element->setAttribute($attrKey, $attrVal ?? ''); } } - protected function createRootElement($rootElement): DOMElement + protected function createRootElement(string|array $rootElement): DOMElement { if (is_string($rootElement)) { $rootElementName = $rootElement ?: 'root'; @@ -251,7 +310,7 @@ protected function createRootElement($rootElement): DOMElement continue; } - $this->addAttributes($element, $rootElement[$key]); + $this->addAttributes($element, $value); } return $element; diff --git a/includes/vendor/symfony/polyfill-intl-idn/Idn.php b/includes/vendor/symfony/polyfill-intl-idn/Idn.php index fee3026df..334f8ee70 100644 --- a/includes/vendor/symfony/polyfill-intl-idn/Idn.php +++ b/includes/vendor/symfony/polyfill-intl-idn/Idn.php @@ -11,8 +11,6 @@ namespace Symfony\Polyfill\Intl\Idn; -use Exception; -use Normalizer; use Symfony\Polyfill\Intl\Idn\Resources\unidata\DisallowedRanges; use Symfony\Polyfill\Intl\Idn\Resources\unidata\Regex; @@ -147,7 +145,7 @@ final class Idn */ public static function idn_to_ascii($domainName, $options = self::IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = []) { - if (\PHP_VERSION_ID >= 70200 && self::INTL_IDNA_VARIANT_2003 === $variant) { + if (self::INTL_IDNA_VARIANT_2003 === $variant) { @trigger_error('idn_to_ascii(): INTL_IDNA_VARIANT_2003 is deprecated', \E_USER_DEPRECATED); } @@ -167,7 +165,7 @@ public static function idn_to_ascii($domainName, $options = self::IDNA_DEFAULT, if (1 === preg_match('/[^\x00-\x7F]/', $label)) { try { $label = 'xn--'.self::punycodeEncode($label); - } catch (Exception $e) { + } catch (\Exception $e) { $info->errors |= self::ERROR_PUNYCODE; } @@ -200,7 +198,7 @@ public static function idn_to_ascii($domainName, $options = self::IDNA_DEFAULT, */ public static function idn_to_utf8($domainName, $options = self::IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = []) { - if (\PHP_VERSION_ID >= 70200 && self::INTL_IDNA_VARIANT_2003 === $variant) { + if (self::INTL_IDNA_VARIANT_2003 === $variant) { @trigger_error('idn_to_utf8(): INTL_IDNA_VARIANT_2003 is deprecated', \E_USER_DEPRECATED); } @@ -282,10 +280,6 @@ private static function mapCodePoints($input, array $options, Info $info) switch ($data['status']) { case 'disallowed': - $info->errors |= self::ERROR_DISALLOWED; - - // no break. - case 'valid': $str .= mb_chr($codePoint, 'utf-8'); @@ -296,7 +290,7 @@ private static function mapCodePoints($input, array $options, Info $info) break; case 'mapped': - $str .= $data['mapping']; + $str .= $transitional && 0x1E9E === $codePoint ? 'ss' : $data['mapping']; break; @@ -335,8 +329,8 @@ private static function process($domain, array $options, Info $info) $domain = self::mapCodePoints($domain, $options, $info); // Step 2. Normalize the domain name string to Unicode Normalization Form C. - if (!Normalizer::isNormalized($domain, Normalizer::FORM_C)) { - $domain = Normalizer::normalize($domain, Normalizer::FORM_C); + if (!\Normalizer::isNormalized($domain, \Normalizer::FORM_C)) { + $domain = \Normalizer::normalize($domain, \Normalizer::FORM_C); } // Step 3. Break the string into labels at U+002E (.) FULL STOP. @@ -348,9 +342,21 @@ private static function process($domain, array $options, Info $info) $validationOptions = $options; if ('xn--' === substr($label, 0, 4)) { + // Step 4.1. If the label contains any non-ASCII code point (i.e., a code point greater than U+007F), + // record that there was an error, and continue with the next label. + if (preg_match('/[^\x00-\x7F]/', $label)) { + $info->errors |= self::ERROR_PUNYCODE; + + continue; + } + + // Step 4.2. Attempt to convert the rest of the label to Unicode according to Punycode [RFC3492]. If + // that conversion fails, record that there was an error, and continue + // with the next label. Otherwise replace the original label in the string by the results of the + // conversion. try { $label = self::punycodeDecode(substr($label, 4)); - } catch (Exception $e) { + } catch (\Exception $e) { $info->errors |= self::ERROR_PUNYCODE; continue; @@ -496,7 +502,7 @@ private static function validateLabel($label, Info $info, array $options, $canBe } // Step 1. The label must be in Unicode Normalization Form C. - if (!Normalizer::isNormalized($label, Normalizer::FORM_C)) { + if (!\Normalizer::isNormalized($label, \Normalizer::FORM_C)) { $info->errors |= self::ERROR_INVALID_ACE_LABEL; } @@ -518,6 +524,8 @@ private static function validateLabel($label, Info $info, array $options, $canBe if ('-' === substr($label, -1, 1)) { $info->errors |= self::ERROR_TRAILING_HYPHEN; } + } elseif ('xn--' === substr($label, 0, 4)) { + $info->errors |= self::ERROR_PUNYCODE; } // Step 4. The label must not contain a U+002E (.) FULL STOP. @@ -583,7 +591,7 @@ private static function punycodeDecode($input) for ($j = 0; $j < $b; ++$j) { if ($bytes[$j] > 0x7F) { - throw new Exception('Invalid input'); + throw new \Exception('Invalid input'); } $output[$out++] = $input[$j]; @@ -599,17 +607,17 @@ private static function punycodeDecode($input) for ($k = self::BASE; /* no condition */; $k += self::BASE) { if ($in >= $inputLength) { - throw new Exception('Invalid input'); + throw new \Exception('Invalid input'); } $digit = self::$basicToDigit[$bytes[$in++] & 0xFF]; if ($digit < 0) { - throw new Exception('Invalid input'); + throw new \Exception('Invalid input'); } if ($digit > intdiv(self::MAX_INT - $i, $w)) { - throw new Exception('Integer overflow'); + throw new \Exception('Integer overflow'); } $i += $digit * $w; @@ -629,7 +637,7 @@ private static function punycodeDecode($input) $baseMinusT = self::BASE - $t; if ($w > intdiv(self::MAX_INT, $baseMinusT)) { - throw new Exception('Integer overflow'); + throw new \Exception('Integer overflow'); } $w *= $baseMinusT; @@ -639,7 +647,7 @@ private static function punycodeDecode($input) $bias = self::adaptBias($i - $oldi, $outPlusOne, 0 === $oldi); if (intdiv($i, $outPlusOne) > self::MAX_INT - $n) { - throw new Exception('Integer overflow'); + throw new \Exception('Integer overflow'); } $n += intdiv($i, $outPlusOne); @@ -694,7 +702,7 @@ private static function punycodeEncode($input) } if ($m - $n > intdiv(self::MAX_INT - $delta, $h + 1)) { - throw new Exception('Integer overflow'); + throw new \Exception('Integer overflow'); } $delta += ($m - $n) * ($h + 1); @@ -702,7 +710,7 @@ private static function punycodeEncode($input) foreach ($iter as $codePoint) { if ($codePoint < $n && 0 === ++$delta) { - throw new Exception('Integer overflow'); + throw new \Exception('Integer overflow'); } if ($codePoint === $n) { @@ -723,7 +731,7 @@ private static function punycodeEncode($input) $qMinusT = $q - $t; $baseMinusT = self::BASE - $t; - $output .= self::encodeDigit($t + ($qMinusT) % ($baseMinusT), false); + $output .= self::encodeDigit($t + $qMinusT % $baseMinusT, false); ++$out; $q = intdiv($qMinusT, $baseMinusT); } diff --git a/includes/vendor/symfony/polyfill-intl-idn/LICENSE b/includes/vendor/symfony/polyfill-intl-idn/LICENSE index 03c5e2577..fd0a0626a 100644 --- a/includes/vendor/symfony/polyfill-intl-idn/LICENSE +++ b/includes/vendor/symfony/polyfill-intl-idn/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018-2019 Fabien Potencier and Trevor Rowbotham +Copyright (c) 2018-present Fabien Potencier and Trevor Rowbotham 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/includes/vendor/symfony/polyfill-intl-idn/README.md b/includes/vendor/symfony/polyfill-intl-idn/README.md index 2e75f2e52..cae551705 100644 --- a/includes/vendor/symfony/polyfill-intl-idn/README.md +++ b/includes/vendor/symfony/polyfill-intl-idn/README.md @@ -4,7 +4,7 @@ Symfony Polyfill / Intl: Idn This component provides [`idn_to_ascii`](https://php.net/idn-to-ascii) and [`idn_to_utf8`](https://php.net/idn-to-utf8) functions to users who run php versions without the [Intl](https://php.net/intl) extension. More information can be found in the -[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). License ======= diff --git a/includes/vendor/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php b/includes/vendor/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php index 5bb70e48a..d285acd13 100644 --- a/includes/vendor/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php +++ b/includes/vendor/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php @@ -1,5 +1,14 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace Symfony\Polyfill\Intl\Idn\Resources\unidata; /** diff --git a/includes/vendor/symfony/polyfill-intl-idn/Resources/unidata/Regex.php b/includes/vendor/symfony/polyfill-intl-idn/Resources/unidata/Regex.php index c4b9778e5..3c6af0c13 100644 --- a/includes/vendor/symfony/polyfill-intl-idn/Resources/unidata/Regex.php +++ b/includes/vendor/symfony/polyfill-intl-idn/Resources/unidata/Regex.php @@ -1,5 +1,14 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace Symfony\Polyfill\Intl\Idn\Resources\unidata; /** @@ -7,18 +16,18 @@ */ final class Regex { - public const COMBINING_MARK = '/^[\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{0903}\x{093A}\x{093B}\x{093C}\x{093E}-\x{0940}\x{0941}-\x{0948}\x{0949}-\x{094C}\x{094D}\x{094E}-\x{094F}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{0982}-\x{0983}\x{09BC}\x{09BE}-\x{09C0}\x{09C1}-\x{09C4}\x{09C7}-\x{09C8}\x{09CB}-\x{09CC}\x{09CD}\x{09D7}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A03}\x{0A3C}\x{0A3E}-\x{0A40}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0A83}\x{0ABC}\x{0ABE}-\x{0AC0}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0AC9}\x{0ACB}-\x{0ACC}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B02}-\x{0B03}\x{0B3C}\x{0B3E}\x{0B3F}\x{0B40}\x{0B41}-\x{0B44}\x{0B47}-\x{0B48}\x{0B4B}-\x{0B4C}\x{0B4D}\x{0B55}-\x{0B56}\x{0B57}\x{0B62}-\x{0B63}\x{0B82}\x{0BBE}-\x{0BBF}\x{0BC0}\x{0BC1}-\x{0BC2}\x{0BC6}-\x{0BC8}\x{0BCA}-\x{0BCC}\x{0BCD}\x{0BD7}\x{0C00}\x{0C01}-\x{0C03}\x{0C04}\x{0C3E}-\x{0C40}\x{0C41}-\x{0C44}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0C82}-\x{0C83}\x{0CBC}\x{0CBE}\x{0CBF}\x{0CC0}-\x{0CC4}\x{0CC6}\x{0CC7}-\x{0CC8}\x{0CCA}-\x{0CCB}\x{0CCC}-\x{0CCD}\x{0CD5}-\x{0CD6}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D02}-\x{0D03}\x{0D3B}-\x{0D3C}\x{0D3E}-\x{0D40}\x{0D41}-\x{0D44}\x{0D46}-\x{0D48}\x{0D4A}-\x{0D4C}\x{0D4D}\x{0D57}\x{0D62}-\x{0D63}\x{0D81}\x{0D82}-\x{0D83}\x{0DCA}\x{0DCF}-\x{0DD1}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0DD8}-\x{0DDF}\x{0DF2}-\x{0DF3}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3E}-\x{0F3F}\x{0F71}-\x{0F7E}\x{0F7F}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102B}-\x{102C}\x{102D}-\x{1030}\x{1031}\x{1032}-\x{1037}\x{1038}\x{1039}-\x{103A}\x{103B}-\x{103C}\x{103D}-\x{103E}\x{1056}-\x{1057}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1062}-\x{1064}\x{1067}-\x{106D}\x{1071}-\x{1074}\x{1082}\x{1083}-\x{1084}\x{1085}-\x{1086}\x{1087}-\x{108C}\x{108D}\x{108F}\x{109A}-\x{109C}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B6}\x{17B7}-\x{17BD}\x{17BE}-\x{17C5}\x{17C6}\x{17C7}-\x{17C8}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1923}-\x{1926}\x{1927}-\x{1928}\x{1929}-\x{192B}\x{1930}-\x{1931}\x{1932}\x{1933}-\x{1938}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A19}-\x{1A1A}\x{1A1B}\x{1A55}\x{1A56}\x{1A57}\x{1A58}-\x{1A5E}\x{1A60}\x{1A61}\x{1A62}\x{1A63}-\x{1A64}\x{1A65}-\x{1A6C}\x{1A6D}-\x{1A72}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B04}\x{1B34}\x{1B35}\x{1B36}-\x{1B3A}\x{1B3B}\x{1B3C}\x{1B3D}-\x{1B41}\x{1B42}\x{1B43}-\x{1B44}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1B82}\x{1BA1}\x{1BA2}-\x{1BA5}\x{1BA6}-\x{1BA7}\x{1BA8}-\x{1BA9}\x{1BAA}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE7}\x{1BE8}-\x{1BE9}\x{1BEA}-\x{1BEC}\x{1BED}\x{1BEE}\x{1BEF}-\x{1BF1}\x{1BF2}-\x{1BF3}\x{1C24}-\x{1C2B}\x{1C2C}-\x{1C33}\x{1C34}-\x{1C35}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE1}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF7}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{302E}-\x{302F}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A823}-\x{A824}\x{A825}-\x{A826}\x{A827}\x{A82C}\x{A880}-\x{A881}\x{A8B4}-\x{A8C3}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A952}-\x{A953}\x{A980}-\x{A982}\x{A983}\x{A9B3}\x{A9B4}-\x{A9B5}\x{A9B6}-\x{A9B9}\x{A9BA}-\x{A9BB}\x{A9BC}-\x{A9BD}\x{A9BE}-\x{A9C0}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA2F}-\x{AA30}\x{AA31}-\x{AA32}\x{AA33}-\x{AA34}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA4D}\x{AA7B}\x{AA7C}\x{AA7D}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEB}\x{AAEC}-\x{AAED}\x{AAEE}-\x{AAEF}\x{AAF5}\x{AAF6}\x{ABE3}-\x{ABE4}\x{ABE5}\x{ABE6}-\x{ABE7}\x{ABE8}\x{ABE9}-\x{ABEA}\x{ABEC}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11000}\x{11001}\x{11002}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{11082}\x{110B0}-\x{110B2}\x{110B3}-\x{110B6}\x{110B7}-\x{110B8}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112C}\x{1112D}-\x{11134}\x{11145}-\x{11146}\x{11173}\x{11180}-\x{11181}\x{11182}\x{111B3}-\x{111B5}\x{111B6}-\x{111BE}\x{111BF}-\x{111C0}\x{111C9}-\x{111CC}\x{111CE}\x{111CF}\x{1122C}-\x{1122E}\x{1122F}-\x{11231}\x{11232}-\x{11233}\x{11234}\x{11235}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E0}-\x{112E2}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{11302}-\x{11303}\x{1133B}-\x{1133C}\x{1133E}-\x{1133F}\x{11340}\x{11341}-\x{11344}\x{11347}-\x{11348}\x{1134B}-\x{1134D}\x{11357}\x{11362}-\x{11363}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11435}-\x{11437}\x{11438}-\x{1143F}\x{11440}-\x{11441}\x{11442}-\x{11444}\x{11445}\x{11446}\x{1145E}\x{114B0}-\x{114B2}\x{114B3}-\x{114B8}\x{114B9}\x{114BA}\x{114BB}-\x{114BE}\x{114BF}-\x{114C0}\x{114C1}\x{114C2}-\x{114C3}\x{115AF}-\x{115B1}\x{115B2}-\x{115B5}\x{115B8}-\x{115BB}\x{115BC}-\x{115BD}\x{115BE}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11630}-\x{11632}\x{11633}-\x{1163A}\x{1163B}-\x{1163C}\x{1163D}\x{1163E}\x{1163F}-\x{11640}\x{116AB}\x{116AC}\x{116AD}\x{116AE}-\x{116AF}\x{116B0}-\x{116B5}\x{116B6}\x{116B7}\x{1171D}-\x{1171F}\x{11720}-\x{11721}\x{11722}-\x{11725}\x{11726}\x{11727}-\x{1172B}\x{1182C}-\x{1182E}\x{1182F}-\x{11837}\x{11838}\x{11839}-\x{1183A}\x{11930}-\x{11935}\x{11937}-\x{11938}\x{1193B}-\x{1193C}\x{1193D}\x{1193E}\x{11940}\x{11942}\x{11943}\x{119D1}-\x{119D3}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119DC}-\x{119DF}\x{119E0}\x{119E4}\x{11A01}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A39}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A57}-\x{11A58}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A97}\x{11A98}-\x{11A99}\x{11C2F}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C3E}\x{11C3F}\x{11C92}-\x{11CA7}\x{11CA9}\x{11CAA}-\x{11CB0}\x{11CB1}\x{11CB2}-\x{11CB3}\x{11CB4}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D8A}-\x{11D8E}\x{11D90}-\x{11D91}\x{11D93}-\x{11D94}\x{11D95}\x{11D96}\x{11D97}\x{11EF3}-\x{11EF4}\x{11EF5}-\x{11EF6}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F51}-\x{16F87}\x{16F8F}-\x{16F92}\x{16FE4}\x{16FF0}-\x{16FF1}\x{1BC9D}-\x{1BC9E}\x{1D165}-\x{1D166}\x{1D167}-\x{1D169}\x{1D16D}-\x{1D172}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{E0100}-\x{E01EF}]/u'; + const COMBINING_MARK = '/^[\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{0903}\x{093A}\x{093B}\x{093C}\x{093E}-\x{0940}\x{0941}-\x{0948}\x{0949}-\x{094C}\x{094D}\x{094E}-\x{094F}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{0982}-\x{0983}\x{09BC}\x{09BE}-\x{09C0}\x{09C1}-\x{09C4}\x{09C7}-\x{09C8}\x{09CB}-\x{09CC}\x{09CD}\x{09D7}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A03}\x{0A3C}\x{0A3E}-\x{0A40}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0A83}\x{0ABC}\x{0ABE}-\x{0AC0}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0AC9}\x{0ACB}-\x{0ACC}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B02}-\x{0B03}\x{0B3C}\x{0B3E}\x{0B3F}\x{0B40}\x{0B41}-\x{0B44}\x{0B47}-\x{0B48}\x{0B4B}-\x{0B4C}\x{0B4D}\x{0B55}-\x{0B56}\x{0B57}\x{0B62}-\x{0B63}\x{0B82}\x{0BBE}-\x{0BBF}\x{0BC0}\x{0BC1}-\x{0BC2}\x{0BC6}-\x{0BC8}\x{0BCA}-\x{0BCC}\x{0BCD}\x{0BD7}\x{0C00}\x{0C01}-\x{0C03}\x{0C04}\x{0C3E}-\x{0C40}\x{0C41}-\x{0C44}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0C82}-\x{0C83}\x{0CBC}\x{0CBE}\x{0CBF}\x{0CC0}-\x{0CC4}\x{0CC6}\x{0CC7}-\x{0CC8}\x{0CCA}-\x{0CCB}\x{0CCC}-\x{0CCD}\x{0CD5}-\x{0CD6}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D02}-\x{0D03}\x{0D3B}-\x{0D3C}\x{0D3E}-\x{0D40}\x{0D41}-\x{0D44}\x{0D46}-\x{0D48}\x{0D4A}-\x{0D4C}\x{0D4D}\x{0D57}\x{0D62}-\x{0D63}\x{0D81}\x{0D82}-\x{0D83}\x{0DCA}\x{0DCF}-\x{0DD1}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0DD8}-\x{0DDF}\x{0DF2}-\x{0DF3}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3E}-\x{0F3F}\x{0F71}-\x{0F7E}\x{0F7F}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102B}-\x{102C}\x{102D}-\x{1030}\x{1031}\x{1032}-\x{1037}\x{1038}\x{1039}-\x{103A}\x{103B}-\x{103C}\x{103D}-\x{103E}\x{1056}-\x{1057}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1062}-\x{1064}\x{1067}-\x{106D}\x{1071}-\x{1074}\x{1082}\x{1083}-\x{1084}\x{1085}-\x{1086}\x{1087}-\x{108C}\x{108D}\x{108F}\x{109A}-\x{109C}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B6}\x{17B7}-\x{17BD}\x{17BE}-\x{17C5}\x{17C6}\x{17C7}-\x{17C8}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1923}-\x{1926}\x{1927}-\x{1928}\x{1929}-\x{192B}\x{1930}-\x{1931}\x{1932}\x{1933}-\x{1938}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A19}-\x{1A1A}\x{1A1B}\x{1A55}\x{1A56}\x{1A57}\x{1A58}-\x{1A5E}\x{1A60}\x{1A61}\x{1A62}\x{1A63}-\x{1A64}\x{1A65}-\x{1A6C}\x{1A6D}-\x{1A72}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B04}\x{1B34}\x{1B35}\x{1B36}-\x{1B3A}\x{1B3B}\x{1B3C}\x{1B3D}-\x{1B41}\x{1B42}\x{1B43}-\x{1B44}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1B82}\x{1BA1}\x{1BA2}-\x{1BA5}\x{1BA6}-\x{1BA7}\x{1BA8}-\x{1BA9}\x{1BAA}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE7}\x{1BE8}-\x{1BE9}\x{1BEA}-\x{1BEC}\x{1BED}\x{1BEE}\x{1BEF}-\x{1BF1}\x{1BF2}-\x{1BF3}\x{1C24}-\x{1C2B}\x{1C2C}-\x{1C33}\x{1C34}-\x{1C35}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE1}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF7}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{302E}-\x{302F}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A823}-\x{A824}\x{A825}-\x{A826}\x{A827}\x{A82C}\x{A880}-\x{A881}\x{A8B4}-\x{A8C3}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A952}-\x{A953}\x{A980}-\x{A982}\x{A983}\x{A9B3}\x{A9B4}-\x{A9B5}\x{A9B6}-\x{A9B9}\x{A9BA}-\x{A9BB}\x{A9BC}-\x{A9BD}\x{A9BE}-\x{A9C0}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA2F}-\x{AA30}\x{AA31}-\x{AA32}\x{AA33}-\x{AA34}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA4D}\x{AA7B}\x{AA7C}\x{AA7D}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEB}\x{AAEC}-\x{AAED}\x{AAEE}-\x{AAEF}\x{AAF5}\x{AAF6}\x{ABE3}-\x{ABE4}\x{ABE5}\x{ABE6}-\x{ABE7}\x{ABE8}\x{ABE9}-\x{ABEA}\x{ABEC}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11000}\x{11001}\x{11002}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{11082}\x{110B0}-\x{110B2}\x{110B3}-\x{110B6}\x{110B7}-\x{110B8}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112C}\x{1112D}-\x{11134}\x{11145}-\x{11146}\x{11173}\x{11180}-\x{11181}\x{11182}\x{111B3}-\x{111B5}\x{111B6}-\x{111BE}\x{111BF}-\x{111C0}\x{111C9}-\x{111CC}\x{111CE}\x{111CF}\x{1122C}-\x{1122E}\x{1122F}-\x{11231}\x{11232}-\x{11233}\x{11234}\x{11235}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E0}-\x{112E2}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{11302}-\x{11303}\x{1133B}-\x{1133C}\x{1133E}-\x{1133F}\x{11340}\x{11341}-\x{11344}\x{11347}-\x{11348}\x{1134B}-\x{1134D}\x{11357}\x{11362}-\x{11363}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11435}-\x{11437}\x{11438}-\x{1143F}\x{11440}-\x{11441}\x{11442}-\x{11444}\x{11445}\x{11446}\x{1145E}\x{114B0}-\x{114B2}\x{114B3}-\x{114B8}\x{114B9}\x{114BA}\x{114BB}-\x{114BE}\x{114BF}-\x{114C0}\x{114C1}\x{114C2}-\x{114C3}\x{115AF}-\x{115B1}\x{115B2}-\x{115B5}\x{115B8}-\x{115BB}\x{115BC}-\x{115BD}\x{115BE}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11630}-\x{11632}\x{11633}-\x{1163A}\x{1163B}-\x{1163C}\x{1163D}\x{1163E}\x{1163F}-\x{11640}\x{116AB}\x{116AC}\x{116AD}\x{116AE}-\x{116AF}\x{116B0}-\x{116B5}\x{116B6}\x{116B7}\x{1171D}-\x{1171F}\x{11720}-\x{11721}\x{11722}-\x{11725}\x{11726}\x{11727}-\x{1172B}\x{1182C}-\x{1182E}\x{1182F}-\x{11837}\x{11838}\x{11839}-\x{1183A}\x{11930}-\x{11935}\x{11937}-\x{11938}\x{1193B}-\x{1193C}\x{1193D}\x{1193E}\x{11940}\x{11942}\x{11943}\x{119D1}-\x{119D3}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119DC}-\x{119DF}\x{119E0}\x{119E4}\x{11A01}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A39}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A57}-\x{11A58}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A97}\x{11A98}-\x{11A99}\x{11C2F}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C3E}\x{11C3F}\x{11C92}-\x{11CA7}\x{11CA9}\x{11CAA}-\x{11CB0}\x{11CB1}\x{11CB2}-\x{11CB3}\x{11CB4}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D8A}-\x{11D8E}\x{11D90}-\x{11D91}\x{11D93}-\x{11D94}\x{11D95}\x{11D96}\x{11D97}\x{11EF3}-\x{11EF4}\x{11EF5}-\x{11EF6}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F51}-\x{16F87}\x{16F8F}-\x{16F92}\x{16FE4}\x{16FF0}-\x{16FF1}\x{1BC9D}-\x{1BC9E}\x{1D165}-\x{1D166}\x{1D167}-\x{1D169}\x{1D16D}-\x{1D172}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{E0100}-\x{E01EF}]/u'; - public const RTL_LABEL = '/[\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06DD}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08E2}\x{200F}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}]/u'; + const RTL_LABEL = '/[\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06DD}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08E2}\x{200F}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}]/u'; - public const BIDI_STEP_1_LTR = '/^[^\x{0000}-\x{0008}\x{0009}\x{000A}\x{000B}\x{000C}\x{000D}\x{000E}-\x{001B}\x{001C}-\x{001E}\x{001F}\x{0020}\x{0021}-\x{0022}\x{0023}\x{0024}\x{0025}\x{0026}-\x{0027}\x{0028}\x{0029}\x{002A}\x{002B}\x{002C}\x{002D}\x{002E}-\x{002F}\x{0030}-\x{0039}\x{003A}\x{003B}\x{003C}-\x{003E}\x{003F}-\x{0040}\x{005B}\x{005C}\x{005D}\x{005E}\x{005F}\x{0060}\x{007B}\x{007C}\x{007D}\x{007E}\x{007F}-\x{0084}\x{0085}\x{0086}-\x{009F}\x{00A0}\x{00A1}\x{00A2}-\x{00A5}\x{00A6}\x{00A7}\x{00A8}\x{00A9}\x{00AB}\x{00AC}\x{00AD}\x{00AE}\x{00AF}\x{00B0}\x{00B1}\x{00B2}-\x{00B3}\x{00B4}\x{00B6}-\x{00B7}\x{00B8}\x{00B9}\x{00BB}\x{00BC}-\x{00BE}\x{00BF}\x{00D7}\x{00F7}\x{02B9}-\x{02BA}\x{02C2}-\x{02C5}\x{02C6}-\x{02CF}\x{02D2}-\x{02DF}\x{02E5}-\x{02EB}\x{02EC}\x{02ED}\x{02EF}-\x{02FF}\x{0300}-\x{036F}\x{0374}\x{0375}\x{037E}\x{0384}-\x{0385}\x{0387}\x{03F6}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{058A}\x{058D}-\x{058E}\x{058F}\x{0590}\x{0591}-\x{05BD}\x{05BE}\x{05BF}\x{05C0}\x{05C1}-\x{05C2}\x{05C3}\x{05C4}-\x{05C5}\x{05C6}\x{05C7}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0606}-\x{0607}\x{0608}\x{0609}-\x{060A}\x{060B}\x{060C}\x{060D}\x{060E}-\x{060F}\x{0610}-\x{061A}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{064B}-\x{065F}\x{0660}-\x{0669}\x{066A}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0670}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06D6}-\x{06DC}\x{06DD}\x{06DE}\x{06DF}-\x{06E4}\x{06E5}-\x{06E6}\x{06E7}-\x{06E8}\x{06E9}\x{06EA}-\x{06ED}\x{06EE}-\x{06EF}\x{06F0}-\x{06F9}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0711}\x{0712}-\x{072F}\x{0730}-\x{074A}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07A6}-\x{07B0}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07EB}-\x{07F3}\x{07F4}-\x{07F5}\x{07F6}\x{07F7}-\x{07F9}\x{07FA}\x{07FB}-\x{07FC}\x{07FD}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{0816}-\x{0819}\x{081A}\x{081B}-\x{0823}\x{0824}\x{0825}-\x{0827}\x{0828}\x{0829}-\x{082D}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{0859}-\x{085B}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08D3}-\x{08E1}\x{08E2}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09F2}-\x{09F3}\x{09FB}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AF1}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0BF3}-\x{0BF8}\x{0BF9}\x{0BFA}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C78}-\x{0C7E}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E3F}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3A}\x{0F3B}\x{0F3C}\x{0F3D}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1390}-\x{1399}\x{1400}\x{1680}\x{169B}\x{169C}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DB}\x{17DD}\x{17F0}-\x{17F9}\x{1800}-\x{1805}\x{1806}\x{1807}-\x{180A}\x{180B}-\x{180D}\x{180E}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1940}\x{1944}-\x{1945}\x{19DE}-\x{19FF}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{1FBD}\x{1FBF}-\x{1FC1}\x{1FCD}-\x{1FCF}\x{1FDD}-\x{1FDF}\x{1FED}-\x{1FEF}\x{1FFD}-\x{1FFE}\x{2000}-\x{200A}\x{200B}-\x{200D}\x{200F}\x{2010}-\x{2015}\x{2016}-\x{2017}\x{2018}\x{2019}\x{201A}\x{201B}-\x{201C}\x{201D}\x{201E}\x{201F}\x{2020}-\x{2027}\x{2028}\x{2029}\x{202A}\x{202B}\x{202C}\x{202D}\x{202E}\x{202F}\x{2030}-\x{2034}\x{2035}-\x{2038}\x{2039}\x{203A}\x{203B}-\x{203E}\x{203F}-\x{2040}\x{2041}-\x{2043}\x{2044}\x{2045}\x{2046}\x{2047}-\x{2051}\x{2052}\x{2053}\x{2054}\x{2055}-\x{205E}\x{205F}\x{2060}-\x{2064}\x{2065}\x{2066}\x{2067}\x{2068}\x{2069}\x{206A}-\x{206F}\x{2070}\x{2074}-\x{2079}\x{207A}-\x{207B}\x{207C}\x{207D}\x{207E}\x{2080}-\x{2089}\x{208A}-\x{208B}\x{208C}\x{208D}\x{208E}\x{20A0}-\x{20BF}\x{20C0}-\x{20CF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2100}-\x{2101}\x{2103}-\x{2106}\x{2108}-\x{2109}\x{2114}\x{2116}-\x{2117}\x{2118}\x{211E}-\x{2123}\x{2125}\x{2127}\x{2129}\x{212E}\x{213A}-\x{213B}\x{2140}-\x{2144}\x{214A}\x{214B}\x{214C}-\x{214D}\x{2150}-\x{215F}\x{2189}\x{218A}-\x{218B}\x{2190}-\x{2194}\x{2195}-\x{2199}\x{219A}-\x{219B}\x{219C}-\x{219F}\x{21A0}\x{21A1}-\x{21A2}\x{21A3}\x{21A4}-\x{21A5}\x{21A6}\x{21A7}-\x{21AD}\x{21AE}\x{21AF}-\x{21CD}\x{21CE}-\x{21CF}\x{21D0}-\x{21D1}\x{21D2}\x{21D3}\x{21D4}\x{21D5}-\x{21F3}\x{21F4}-\x{2211}\x{2212}\x{2213}\x{2214}-\x{22FF}\x{2300}-\x{2307}\x{2308}\x{2309}\x{230A}\x{230B}\x{230C}-\x{231F}\x{2320}-\x{2321}\x{2322}-\x{2328}\x{2329}\x{232A}\x{232B}-\x{2335}\x{237B}\x{237C}\x{237D}-\x{2394}\x{2396}-\x{239A}\x{239B}-\x{23B3}\x{23B4}-\x{23DB}\x{23DC}-\x{23E1}\x{23E2}-\x{2426}\x{2440}-\x{244A}\x{2460}-\x{2487}\x{2488}-\x{249B}\x{24EA}-\x{24FF}\x{2500}-\x{25B6}\x{25B7}\x{25B8}-\x{25C0}\x{25C1}\x{25C2}-\x{25F7}\x{25F8}-\x{25FF}\x{2600}-\x{266E}\x{266F}\x{2670}-\x{26AB}\x{26AD}-\x{2767}\x{2768}\x{2769}\x{276A}\x{276B}\x{276C}\x{276D}\x{276E}\x{276F}\x{2770}\x{2771}\x{2772}\x{2773}\x{2774}\x{2775}\x{2776}-\x{2793}\x{2794}-\x{27BF}\x{27C0}-\x{27C4}\x{27C5}\x{27C6}\x{27C7}-\x{27E5}\x{27E6}\x{27E7}\x{27E8}\x{27E9}\x{27EA}\x{27EB}\x{27EC}\x{27ED}\x{27EE}\x{27EF}\x{27F0}-\x{27FF}\x{2900}-\x{2982}\x{2983}\x{2984}\x{2985}\x{2986}\x{2987}\x{2988}\x{2989}\x{298A}\x{298B}\x{298C}\x{298D}\x{298E}\x{298F}\x{2990}\x{2991}\x{2992}\x{2993}\x{2994}\x{2995}\x{2996}\x{2997}\x{2998}\x{2999}-\x{29D7}\x{29D8}\x{29D9}\x{29DA}\x{29DB}\x{29DC}-\x{29FB}\x{29FC}\x{29FD}\x{29FE}-\x{2AFF}\x{2B00}-\x{2B2F}\x{2B30}-\x{2B44}\x{2B45}-\x{2B46}\x{2B47}-\x{2B4C}\x{2B4D}-\x{2B73}\x{2B76}-\x{2B95}\x{2B97}-\x{2BFF}\x{2CE5}-\x{2CEA}\x{2CEF}-\x{2CF1}\x{2CF9}-\x{2CFC}\x{2CFD}\x{2CFE}-\x{2CFF}\x{2D7F}\x{2DE0}-\x{2DFF}\x{2E00}-\x{2E01}\x{2E02}\x{2E03}\x{2E04}\x{2E05}\x{2E06}-\x{2E08}\x{2E09}\x{2E0A}\x{2E0B}\x{2E0C}\x{2E0D}\x{2E0E}-\x{2E16}\x{2E17}\x{2E18}-\x{2E19}\x{2E1A}\x{2E1B}\x{2E1C}\x{2E1D}\x{2E1E}-\x{2E1F}\x{2E20}\x{2E21}\x{2E22}\x{2E23}\x{2E24}\x{2E25}\x{2E26}\x{2E27}\x{2E28}\x{2E29}\x{2E2A}-\x{2E2E}\x{2E2F}\x{2E30}-\x{2E39}\x{2E3A}-\x{2E3B}\x{2E3C}-\x{2E3F}\x{2E40}\x{2E41}\x{2E42}\x{2E43}-\x{2E4F}\x{2E50}-\x{2E51}\x{2E52}\x{2E80}-\x{2E99}\x{2E9B}-\x{2EF3}\x{2F00}-\x{2FD5}\x{2FF0}-\x{2FFB}\x{3000}\x{3001}-\x{3003}\x{3004}\x{3008}\x{3009}\x{300A}\x{300B}\x{300C}\x{300D}\x{300E}\x{300F}\x{3010}\x{3011}\x{3012}-\x{3013}\x{3014}\x{3015}\x{3016}\x{3017}\x{3018}\x{3019}\x{301A}\x{301B}\x{301C}\x{301D}\x{301E}-\x{301F}\x{3020}\x{302A}-\x{302D}\x{3030}\x{3036}-\x{3037}\x{303D}\x{303E}-\x{303F}\x{3099}-\x{309A}\x{309B}-\x{309C}\x{30A0}\x{30FB}\x{31C0}-\x{31E3}\x{321D}-\x{321E}\x{3250}\x{3251}-\x{325F}\x{327C}-\x{327E}\x{32B1}-\x{32BF}\x{32CC}-\x{32CF}\x{3377}-\x{337A}\x{33DE}-\x{33DF}\x{33FF}\x{4DC0}-\x{4DFF}\x{A490}-\x{A4C6}\x{A60D}-\x{A60F}\x{A66F}\x{A670}-\x{A672}\x{A673}\x{A674}-\x{A67D}\x{A67E}\x{A67F}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A700}-\x{A716}\x{A717}-\x{A71F}\x{A720}-\x{A721}\x{A788}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A828}-\x{A82B}\x{A82C}\x{A838}\x{A839}\x{A874}-\x{A877}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{AB6A}-\x{AB6B}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1D}\x{FB1E}\x{FB1F}-\x{FB28}\x{FB29}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD3E}\x{FD3F}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDD0}-\x{FDEF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFD}\x{FDFE}-\x{FDFF}\x{FE00}-\x{FE0F}\x{FE10}-\x{FE16}\x{FE17}\x{FE18}\x{FE19}\x{FE20}-\x{FE2F}\x{FE30}\x{FE31}-\x{FE32}\x{FE33}-\x{FE34}\x{FE35}\x{FE36}\x{FE37}\x{FE38}\x{FE39}\x{FE3A}\x{FE3B}\x{FE3C}\x{FE3D}\x{FE3E}\x{FE3F}\x{FE40}\x{FE41}\x{FE42}\x{FE43}\x{FE44}\x{FE45}-\x{FE46}\x{FE47}\x{FE48}\x{FE49}-\x{FE4C}\x{FE4D}-\x{FE4F}\x{FE50}\x{FE51}\x{FE52}\x{FE54}\x{FE55}\x{FE56}-\x{FE57}\x{FE58}\x{FE59}\x{FE5A}\x{FE5B}\x{FE5C}\x{FE5D}\x{FE5E}\x{FE5F}\x{FE60}-\x{FE61}\x{FE62}\x{FE63}\x{FE64}-\x{FE66}\x{FE68}\x{FE69}\x{FE6A}\x{FE6B}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FEFF}\x{FF01}-\x{FF02}\x{FF03}\x{FF04}\x{FF05}\x{FF06}-\x{FF07}\x{FF08}\x{FF09}\x{FF0A}\x{FF0B}\x{FF0C}\x{FF0D}\x{FF0E}-\x{FF0F}\x{FF10}-\x{FF19}\x{FF1A}\x{FF1B}\x{FF1C}-\x{FF1E}\x{FF1F}-\x{FF20}\x{FF3B}\x{FF3C}\x{FF3D}\x{FF3E}\x{FF3F}\x{FF40}\x{FF5B}\x{FF5C}\x{FF5D}\x{FF5E}\x{FF5F}\x{FF60}\x{FF61}\x{FF62}\x{FF63}\x{FF64}-\x{FF65}\x{FFE0}-\x{FFE1}\x{FFE2}\x{FFE3}\x{FFE4}\x{FFE5}-\x{FFE6}\x{FFE8}\x{FFE9}-\x{FFEC}\x{FFED}-\x{FFEE}\x{FFF0}-\x{FFF8}\x{FFF9}-\x{FFFB}\x{FFFC}-\x{FFFD}\x{FFFE}-\x{FFFF}\x{10101}\x{10140}-\x{10174}\x{10175}-\x{10178}\x{10179}-\x{10189}\x{1018A}-\x{1018B}\x{1018C}\x{10190}-\x{1019C}\x{101A0}\x{101FD}\x{102E0}\x{102E1}-\x{102FB}\x{10376}-\x{1037A}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{1091F}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A01}-\x{10A03}\x{10A04}\x{10A05}-\x{10A06}\x{10A07}-\x{10A0B}\x{10A0C}-\x{10A0F}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A38}-\x{10A3A}\x{10A3B}-\x{10A3E}\x{10A3F}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE5}-\x{10AE6}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B39}-\x{10B3F}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D24}-\x{10D27}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAB}-\x{10EAC}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F46}-\x{10F50}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{11001}\x{11038}-\x{11046}\x{11052}-\x{11065}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{11660}-\x{1166C}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{11FD5}-\x{11FDC}\x{11FDD}-\x{11FE0}\x{11FE1}-\x{11FF1}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE2}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D200}-\x{1D241}\x{1D242}-\x{1D244}\x{1D245}\x{1D300}-\x{1D356}\x{1D6DB}\x{1D715}\x{1D74F}\x{1D789}\x{1D7C3}\x{1D7CE}-\x{1D7FF}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E2FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D0}-\x{1E8D6}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E944}-\x{1E94A}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF0}-\x{1EEF1}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F000}-\x{1F02B}\x{1F030}-\x{1F093}\x{1F0A0}-\x{1F0AE}\x{1F0B1}-\x{1F0BF}\x{1F0C1}-\x{1F0CF}\x{1F0D1}-\x{1F0F5}\x{1F100}-\x{1F10A}\x{1F10B}-\x{1F10C}\x{1F10D}-\x{1F10F}\x{1F12F}\x{1F16A}-\x{1F16F}\x{1F1AD}\x{1F260}-\x{1F265}\x{1F300}-\x{1F3FA}\x{1F3FB}-\x{1F3FF}\x{1F400}-\x{1F6D7}\x{1F6E0}-\x{1F6EC}\x{1F6F0}-\x{1F6FC}\x{1F700}-\x{1F773}\x{1F780}-\x{1F7D8}\x{1F7E0}-\x{1F7EB}\x{1F800}-\x{1F80B}\x{1F810}-\x{1F847}\x{1F850}-\x{1F859}\x{1F860}-\x{1F887}\x{1F890}-\x{1F8AD}\x{1F8B0}-\x{1F8B1}\x{1F900}-\x{1F978}\x{1F97A}-\x{1F9CB}\x{1F9CD}-\x{1FA53}\x{1FA60}-\x{1FA6D}\x{1FA70}-\x{1FA74}\x{1FA78}-\x{1FA7A}\x{1FA80}-\x{1FA86}\x{1FA90}-\x{1FAA8}\x{1FAB0}-\x{1FAB6}\x{1FAC0}-\x{1FAC2}\x{1FAD0}-\x{1FAD6}\x{1FB00}-\x{1FB92}\x{1FB94}-\x{1FBCA}\x{1FBF0}-\x{1FBF9}\x{1FFFE}-\x{1FFFF}\x{2FFFE}-\x{2FFFF}\x{3FFFE}-\x{3FFFF}\x{4FFFE}-\x{4FFFF}\x{5FFFE}-\x{5FFFF}\x{6FFFE}-\x{6FFFF}\x{7FFFE}-\x{7FFFF}\x{8FFFE}-\x{8FFFF}\x{9FFFE}-\x{9FFFF}\x{AFFFE}-\x{AFFFF}\x{BFFFE}-\x{BFFFF}\x{CFFFE}-\x{CFFFF}\x{DFFFE}-\x{E0000}\x{E0001}\x{E0002}-\x{E001F}\x{E0020}-\x{E007F}\x{E0080}-\x{E00FF}\x{E0100}-\x{E01EF}\x{E01F0}-\x{E0FFF}\x{EFFFE}-\x{EFFFF}\x{FFFFE}-\x{FFFFF}\x{10FFFE}-\x{10FFFF}]/u'; - public const BIDI_STEP_1_RTL = '/^[\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{200F}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}]/u'; - public const BIDI_STEP_2 = '/[^\x{0000}-\x{0008}\x{000E}-\x{001B}\x{0021}-\x{0022}\x{0023}\x{0024}\x{0025}\x{0026}-\x{0027}\x{0028}\x{0029}\x{002A}\x{002B}\x{002C}\x{002D}\x{002E}-\x{002F}\x{0030}-\x{0039}\x{003A}\x{003B}\x{003C}-\x{003E}\x{003F}-\x{0040}\x{005B}\x{005C}\x{005D}\x{005E}\x{005F}\x{0060}\x{007B}\x{007C}\x{007D}\x{007E}\x{007F}-\x{0084}\x{0086}-\x{009F}\x{00A0}\x{00A1}\x{00A2}-\x{00A5}\x{00A6}\x{00A7}\x{00A8}\x{00A9}\x{00AB}\x{00AC}\x{00AD}\x{00AE}\x{00AF}\x{00B0}\x{00B1}\x{00B2}-\x{00B3}\x{00B4}\x{00B6}-\x{00B7}\x{00B8}\x{00B9}\x{00BB}\x{00BC}-\x{00BE}\x{00BF}\x{00D7}\x{00F7}\x{02B9}-\x{02BA}\x{02C2}-\x{02C5}\x{02C6}-\x{02CF}\x{02D2}-\x{02DF}\x{02E5}-\x{02EB}\x{02EC}\x{02ED}\x{02EF}-\x{02FF}\x{0300}-\x{036F}\x{0374}\x{0375}\x{037E}\x{0384}-\x{0385}\x{0387}\x{03F6}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{058A}\x{058D}-\x{058E}\x{058F}\x{0590}\x{0591}-\x{05BD}\x{05BE}\x{05BF}\x{05C0}\x{05C1}-\x{05C2}\x{05C3}\x{05C4}-\x{05C5}\x{05C6}\x{05C7}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0606}-\x{0607}\x{0608}\x{0609}-\x{060A}\x{060B}\x{060C}\x{060D}\x{060E}-\x{060F}\x{0610}-\x{061A}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{064B}-\x{065F}\x{0660}-\x{0669}\x{066A}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0670}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06D6}-\x{06DC}\x{06DD}\x{06DE}\x{06DF}-\x{06E4}\x{06E5}-\x{06E6}\x{06E7}-\x{06E8}\x{06E9}\x{06EA}-\x{06ED}\x{06EE}-\x{06EF}\x{06F0}-\x{06F9}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0711}\x{0712}-\x{072F}\x{0730}-\x{074A}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07A6}-\x{07B0}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07EB}-\x{07F3}\x{07F4}-\x{07F5}\x{07F6}\x{07F7}-\x{07F9}\x{07FA}\x{07FB}-\x{07FC}\x{07FD}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{0816}-\x{0819}\x{081A}\x{081B}-\x{0823}\x{0824}\x{0825}-\x{0827}\x{0828}\x{0829}-\x{082D}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{0859}-\x{085B}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08D3}-\x{08E1}\x{08E2}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09F2}-\x{09F3}\x{09FB}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AF1}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0BF3}-\x{0BF8}\x{0BF9}\x{0BFA}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C78}-\x{0C7E}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E3F}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3A}\x{0F3B}\x{0F3C}\x{0F3D}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1390}-\x{1399}\x{1400}\x{169B}\x{169C}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DB}\x{17DD}\x{17F0}-\x{17F9}\x{1800}-\x{1805}\x{1806}\x{1807}-\x{180A}\x{180B}-\x{180D}\x{180E}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1940}\x{1944}-\x{1945}\x{19DE}-\x{19FF}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{1FBD}\x{1FBF}-\x{1FC1}\x{1FCD}-\x{1FCF}\x{1FDD}-\x{1FDF}\x{1FED}-\x{1FEF}\x{1FFD}-\x{1FFE}\x{200B}-\x{200D}\x{200F}\x{2010}-\x{2015}\x{2016}-\x{2017}\x{2018}\x{2019}\x{201A}\x{201B}-\x{201C}\x{201D}\x{201E}\x{201F}\x{2020}-\x{2027}\x{202F}\x{2030}-\x{2034}\x{2035}-\x{2038}\x{2039}\x{203A}\x{203B}-\x{203E}\x{203F}-\x{2040}\x{2041}-\x{2043}\x{2044}\x{2045}\x{2046}\x{2047}-\x{2051}\x{2052}\x{2053}\x{2054}\x{2055}-\x{205E}\x{2060}-\x{2064}\x{2065}\x{206A}-\x{206F}\x{2070}\x{2074}-\x{2079}\x{207A}-\x{207B}\x{207C}\x{207D}\x{207E}\x{2080}-\x{2089}\x{208A}-\x{208B}\x{208C}\x{208D}\x{208E}\x{20A0}-\x{20BF}\x{20C0}-\x{20CF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2100}-\x{2101}\x{2103}-\x{2106}\x{2108}-\x{2109}\x{2114}\x{2116}-\x{2117}\x{2118}\x{211E}-\x{2123}\x{2125}\x{2127}\x{2129}\x{212E}\x{213A}-\x{213B}\x{2140}-\x{2144}\x{214A}\x{214B}\x{214C}-\x{214D}\x{2150}-\x{215F}\x{2189}\x{218A}-\x{218B}\x{2190}-\x{2194}\x{2195}-\x{2199}\x{219A}-\x{219B}\x{219C}-\x{219F}\x{21A0}\x{21A1}-\x{21A2}\x{21A3}\x{21A4}-\x{21A5}\x{21A6}\x{21A7}-\x{21AD}\x{21AE}\x{21AF}-\x{21CD}\x{21CE}-\x{21CF}\x{21D0}-\x{21D1}\x{21D2}\x{21D3}\x{21D4}\x{21D5}-\x{21F3}\x{21F4}-\x{2211}\x{2212}\x{2213}\x{2214}-\x{22FF}\x{2300}-\x{2307}\x{2308}\x{2309}\x{230A}\x{230B}\x{230C}-\x{231F}\x{2320}-\x{2321}\x{2322}-\x{2328}\x{2329}\x{232A}\x{232B}-\x{2335}\x{237B}\x{237C}\x{237D}-\x{2394}\x{2396}-\x{239A}\x{239B}-\x{23B3}\x{23B4}-\x{23DB}\x{23DC}-\x{23E1}\x{23E2}-\x{2426}\x{2440}-\x{244A}\x{2460}-\x{2487}\x{2488}-\x{249B}\x{24EA}-\x{24FF}\x{2500}-\x{25B6}\x{25B7}\x{25B8}-\x{25C0}\x{25C1}\x{25C2}-\x{25F7}\x{25F8}-\x{25FF}\x{2600}-\x{266E}\x{266F}\x{2670}-\x{26AB}\x{26AD}-\x{2767}\x{2768}\x{2769}\x{276A}\x{276B}\x{276C}\x{276D}\x{276E}\x{276F}\x{2770}\x{2771}\x{2772}\x{2773}\x{2774}\x{2775}\x{2776}-\x{2793}\x{2794}-\x{27BF}\x{27C0}-\x{27C4}\x{27C5}\x{27C6}\x{27C7}-\x{27E5}\x{27E6}\x{27E7}\x{27E8}\x{27E9}\x{27EA}\x{27EB}\x{27EC}\x{27ED}\x{27EE}\x{27EF}\x{27F0}-\x{27FF}\x{2900}-\x{2982}\x{2983}\x{2984}\x{2985}\x{2986}\x{2987}\x{2988}\x{2989}\x{298A}\x{298B}\x{298C}\x{298D}\x{298E}\x{298F}\x{2990}\x{2991}\x{2992}\x{2993}\x{2994}\x{2995}\x{2996}\x{2997}\x{2998}\x{2999}-\x{29D7}\x{29D8}\x{29D9}\x{29DA}\x{29DB}\x{29DC}-\x{29FB}\x{29FC}\x{29FD}\x{29FE}-\x{2AFF}\x{2B00}-\x{2B2F}\x{2B30}-\x{2B44}\x{2B45}-\x{2B46}\x{2B47}-\x{2B4C}\x{2B4D}-\x{2B73}\x{2B76}-\x{2B95}\x{2B97}-\x{2BFF}\x{2CE5}-\x{2CEA}\x{2CEF}-\x{2CF1}\x{2CF9}-\x{2CFC}\x{2CFD}\x{2CFE}-\x{2CFF}\x{2D7F}\x{2DE0}-\x{2DFF}\x{2E00}-\x{2E01}\x{2E02}\x{2E03}\x{2E04}\x{2E05}\x{2E06}-\x{2E08}\x{2E09}\x{2E0A}\x{2E0B}\x{2E0C}\x{2E0D}\x{2E0E}-\x{2E16}\x{2E17}\x{2E18}-\x{2E19}\x{2E1A}\x{2E1B}\x{2E1C}\x{2E1D}\x{2E1E}-\x{2E1F}\x{2E20}\x{2E21}\x{2E22}\x{2E23}\x{2E24}\x{2E25}\x{2E26}\x{2E27}\x{2E28}\x{2E29}\x{2E2A}-\x{2E2E}\x{2E2F}\x{2E30}-\x{2E39}\x{2E3A}-\x{2E3B}\x{2E3C}-\x{2E3F}\x{2E40}\x{2E41}\x{2E42}\x{2E43}-\x{2E4F}\x{2E50}-\x{2E51}\x{2E52}\x{2E80}-\x{2E99}\x{2E9B}-\x{2EF3}\x{2F00}-\x{2FD5}\x{2FF0}-\x{2FFB}\x{3001}-\x{3003}\x{3004}\x{3008}\x{3009}\x{300A}\x{300B}\x{300C}\x{300D}\x{300E}\x{300F}\x{3010}\x{3011}\x{3012}-\x{3013}\x{3014}\x{3015}\x{3016}\x{3017}\x{3018}\x{3019}\x{301A}\x{301B}\x{301C}\x{301D}\x{301E}-\x{301F}\x{3020}\x{302A}-\x{302D}\x{3030}\x{3036}-\x{3037}\x{303D}\x{303E}-\x{303F}\x{3099}-\x{309A}\x{309B}-\x{309C}\x{30A0}\x{30FB}\x{31C0}-\x{31E3}\x{321D}-\x{321E}\x{3250}\x{3251}-\x{325F}\x{327C}-\x{327E}\x{32B1}-\x{32BF}\x{32CC}-\x{32CF}\x{3377}-\x{337A}\x{33DE}-\x{33DF}\x{33FF}\x{4DC0}-\x{4DFF}\x{A490}-\x{A4C6}\x{A60D}-\x{A60F}\x{A66F}\x{A670}-\x{A672}\x{A673}\x{A674}-\x{A67D}\x{A67E}\x{A67F}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A700}-\x{A716}\x{A717}-\x{A71F}\x{A720}-\x{A721}\x{A788}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A828}-\x{A82B}\x{A82C}\x{A838}\x{A839}\x{A874}-\x{A877}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{AB6A}-\x{AB6B}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1D}\x{FB1E}\x{FB1F}-\x{FB28}\x{FB29}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD3E}\x{FD3F}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDD0}-\x{FDEF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFD}\x{FDFE}-\x{FDFF}\x{FE00}-\x{FE0F}\x{FE10}-\x{FE16}\x{FE17}\x{FE18}\x{FE19}\x{FE20}-\x{FE2F}\x{FE30}\x{FE31}-\x{FE32}\x{FE33}-\x{FE34}\x{FE35}\x{FE36}\x{FE37}\x{FE38}\x{FE39}\x{FE3A}\x{FE3B}\x{FE3C}\x{FE3D}\x{FE3E}\x{FE3F}\x{FE40}\x{FE41}\x{FE42}\x{FE43}\x{FE44}\x{FE45}-\x{FE46}\x{FE47}\x{FE48}\x{FE49}-\x{FE4C}\x{FE4D}-\x{FE4F}\x{FE50}\x{FE51}\x{FE52}\x{FE54}\x{FE55}\x{FE56}-\x{FE57}\x{FE58}\x{FE59}\x{FE5A}\x{FE5B}\x{FE5C}\x{FE5D}\x{FE5E}\x{FE5F}\x{FE60}-\x{FE61}\x{FE62}\x{FE63}\x{FE64}-\x{FE66}\x{FE68}\x{FE69}\x{FE6A}\x{FE6B}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FEFF}\x{FF01}-\x{FF02}\x{FF03}\x{FF04}\x{FF05}\x{FF06}-\x{FF07}\x{FF08}\x{FF09}\x{FF0A}\x{FF0B}\x{FF0C}\x{FF0D}\x{FF0E}-\x{FF0F}\x{FF10}-\x{FF19}\x{FF1A}\x{FF1B}\x{FF1C}-\x{FF1E}\x{FF1F}-\x{FF20}\x{FF3B}\x{FF3C}\x{FF3D}\x{FF3E}\x{FF3F}\x{FF40}\x{FF5B}\x{FF5C}\x{FF5D}\x{FF5E}\x{FF5F}\x{FF60}\x{FF61}\x{FF62}\x{FF63}\x{FF64}-\x{FF65}\x{FFE0}-\x{FFE1}\x{FFE2}\x{FFE3}\x{FFE4}\x{FFE5}-\x{FFE6}\x{FFE8}\x{FFE9}-\x{FFEC}\x{FFED}-\x{FFEE}\x{FFF0}-\x{FFF8}\x{FFF9}-\x{FFFB}\x{FFFC}-\x{FFFD}\x{FFFE}-\x{FFFF}\x{10101}\x{10140}-\x{10174}\x{10175}-\x{10178}\x{10179}-\x{10189}\x{1018A}-\x{1018B}\x{1018C}\x{10190}-\x{1019C}\x{101A0}\x{101FD}\x{102E0}\x{102E1}-\x{102FB}\x{10376}-\x{1037A}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{1091F}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A01}-\x{10A03}\x{10A04}\x{10A05}-\x{10A06}\x{10A07}-\x{10A0B}\x{10A0C}-\x{10A0F}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A38}-\x{10A3A}\x{10A3B}-\x{10A3E}\x{10A3F}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE5}-\x{10AE6}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B39}-\x{10B3F}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D24}-\x{10D27}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAB}-\x{10EAC}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F46}-\x{10F50}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{11001}\x{11038}-\x{11046}\x{11052}-\x{11065}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{11660}-\x{1166C}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{11FD5}-\x{11FDC}\x{11FDD}-\x{11FE0}\x{11FE1}-\x{11FF1}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE2}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D200}-\x{1D241}\x{1D242}-\x{1D244}\x{1D245}\x{1D300}-\x{1D356}\x{1D6DB}\x{1D715}\x{1D74F}\x{1D789}\x{1D7C3}\x{1D7CE}-\x{1D7FF}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E2FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D0}-\x{1E8D6}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E944}-\x{1E94A}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF0}-\x{1EEF1}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F000}-\x{1F02B}\x{1F030}-\x{1F093}\x{1F0A0}-\x{1F0AE}\x{1F0B1}-\x{1F0BF}\x{1F0C1}-\x{1F0CF}\x{1F0D1}-\x{1F0F5}\x{1F100}-\x{1F10A}\x{1F10B}-\x{1F10C}\x{1F10D}-\x{1F10F}\x{1F12F}\x{1F16A}-\x{1F16F}\x{1F1AD}\x{1F260}-\x{1F265}\x{1F300}-\x{1F3FA}\x{1F3FB}-\x{1F3FF}\x{1F400}-\x{1F6D7}\x{1F6E0}-\x{1F6EC}\x{1F6F0}-\x{1F6FC}\x{1F700}-\x{1F773}\x{1F780}-\x{1F7D8}\x{1F7E0}-\x{1F7EB}\x{1F800}-\x{1F80B}\x{1F810}-\x{1F847}\x{1F850}-\x{1F859}\x{1F860}-\x{1F887}\x{1F890}-\x{1F8AD}\x{1F8B0}-\x{1F8B1}\x{1F900}-\x{1F978}\x{1F97A}-\x{1F9CB}\x{1F9CD}-\x{1FA53}\x{1FA60}-\x{1FA6D}\x{1FA70}-\x{1FA74}\x{1FA78}-\x{1FA7A}\x{1FA80}-\x{1FA86}\x{1FA90}-\x{1FAA8}\x{1FAB0}-\x{1FAB6}\x{1FAC0}-\x{1FAC2}\x{1FAD0}-\x{1FAD6}\x{1FB00}-\x{1FB92}\x{1FB94}-\x{1FBCA}\x{1FBF0}-\x{1FBF9}\x{1FFFE}-\x{1FFFF}\x{2FFFE}-\x{2FFFF}\x{3FFFE}-\x{3FFFF}\x{4FFFE}-\x{4FFFF}\x{5FFFE}-\x{5FFFF}\x{6FFFE}-\x{6FFFF}\x{7FFFE}-\x{7FFFF}\x{8FFFE}-\x{8FFFF}\x{9FFFE}-\x{9FFFF}\x{AFFFE}-\x{AFFFF}\x{BFFFE}-\x{BFFFF}\x{CFFFE}-\x{CFFFF}\x{DFFFE}-\x{E0000}\x{E0001}\x{E0002}-\x{E001F}\x{E0020}-\x{E007F}\x{E0080}-\x{E00FF}\x{E0100}-\x{E01EF}\x{E01F0}-\x{E0FFF}\x{EFFFE}-\x{EFFFF}\x{FFFFE}-\x{FFFFF}\x{10FFFE}-\x{10FFFF}]/u'; - public const BIDI_STEP_3 = '/[\x{0030}-\x{0039}\x{00B2}-\x{00B3}\x{00B9}\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06DD}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06F0}-\x{06F9}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08E2}\x{200F}\x{2070}\x{2074}-\x{2079}\x{2080}-\x{2089}\x{2488}-\x{249B}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FF10}-\x{FF19}\x{102E1}-\x{102FB}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1D7CE}-\x{1D7FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F100}-\x{1F10A}\x{1FBF0}-\x{1FBF9}][\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1D167}-\x{1D169}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{E0100}-\x{E01EF}]*$/u'; - public const BIDI_STEP_4_AN = '/[\x{0600}-\x{0605}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{06DD}\x{08E2}\x{10D30}-\x{10D39}\x{10E60}-\x{10E7E}]/u'; - public const BIDI_STEP_4_EN = '/[\x{0030}-\x{0039}\x{00B2}-\x{00B3}\x{00B9}\x{06F0}-\x{06F9}\x{2070}\x{2074}-\x{2079}\x{2080}-\x{2089}\x{2488}-\x{249B}\x{FF10}-\x{FF19}\x{102E1}-\x{102FB}\x{1D7CE}-\x{1D7FF}\x{1F100}-\x{1F10A}\x{1FBF0}-\x{1FBF9}]/u'; - public const BIDI_STEP_5 = '/[\x{0009}\x{000A}\x{000B}\x{000C}\x{000D}\x{001C}-\x{001E}\x{001F}\x{0020}\x{0085}\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06DD}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08E2}\x{1680}\x{2000}-\x{200A}\x{200F}\x{2028}\x{2029}\x{202A}\x{202B}\x{202C}\x{202D}\x{202E}\x{205F}\x{2066}\x{2067}\x{2068}\x{2069}\x{3000}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}]/u'; - public const BIDI_STEP_6 = '/[^\x{0000}-\x{0008}\x{0009}\x{000A}\x{000B}\x{000C}\x{000D}\x{000E}-\x{001B}\x{001C}-\x{001E}\x{001F}\x{0020}\x{0021}-\x{0022}\x{0023}\x{0024}\x{0025}\x{0026}-\x{0027}\x{0028}\x{0029}\x{002A}\x{002B}\x{002C}\x{002D}\x{002E}-\x{002F}\x{003A}\x{003B}\x{003C}-\x{003E}\x{003F}-\x{0040}\x{005B}\x{005C}\x{005D}\x{005E}\x{005F}\x{0060}\x{007B}\x{007C}\x{007D}\x{007E}\x{007F}-\x{0084}\x{0085}\x{0086}-\x{009F}\x{00A0}\x{00A1}\x{00A2}-\x{00A5}\x{00A6}\x{00A7}\x{00A8}\x{00A9}\x{00AB}\x{00AC}\x{00AD}\x{00AE}\x{00AF}\x{00B0}\x{00B1}\x{00B4}\x{00B6}-\x{00B7}\x{00B8}\x{00BB}\x{00BC}-\x{00BE}\x{00BF}\x{00D7}\x{00F7}\x{02B9}-\x{02BA}\x{02C2}-\x{02C5}\x{02C6}-\x{02CF}\x{02D2}-\x{02DF}\x{02E5}-\x{02EB}\x{02EC}\x{02ED}\x{02EF}-\x{02FF}\x{0300}-\x{036F}\x{0374}\x{0375}\x{037E}\x{0384}-\x{0385}\x{0387}\x{03F6}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{058A}\x{058D}-\x{058E}\x{058F}\x{0590}\x{0591}-\x{05BD}\x{05BE}\x{05BF}\x{05C0}\x{05C1}-\x{05C2}\x{05C3}\x{05C4}-\x{05C5}\x{05C6}\x{05C7}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0606}-\x{0607}\x{0608}\x{0609}-\x{060A}\x{060B}\x{060C}\x{060D}\x{060E}-\x{060F}\x{0610}-\x{061A}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{064B}-\x{065F}\x{0660}-\x{0669}\x{066A}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0670}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06D6}-\x{06DC}\x{06DD}\x{06DE}\x{06DF}-\x{06E4}\x{06E5}-\x{06E6}\x{06E7}-\x{06E8}\x{06E9}\x{06EA}-\x{06ED}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0711}\x{0712}-\x{072F}\x{0730}-\x{074A}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07A6}-\x{07B0}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07EB}-\x{07F3}\x{07F4}-\x{07F5}\x{07F6}\x{07F7}-\x{07F9}\x{07FA}\x{07FB}-\x{07FC}\x{07FD}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{0816}-\x{0819}\x{081A}\x{081B}-\x{0823}\x{0824}\x{0825}-\x{0827}\x{0828}\x{0829}-\x{082D}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{0859}-\x{085B}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08D3}-\x{08E1}\x{08E2}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09F2}-\x{09F3}\x{09FB}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AF1}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0BF3}-\x{0BF8}\x{0BF9}\x{0BFA}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C78}-\x{0C7E}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E3F}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3A}\x{0F3B}\x{0F3C}\x{0F3D}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1390}-\x{1399}\x{1400}\x{1680}\x{169B}\x{169C}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DB}\x{17DD}\x{17F0}-\x{17F9}\x{1800}-\x{1805}\x{1806}\x{1807}-\x{180A}\x{180B}-\x{180D}\x{180E}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1940}\x{1944}-\x{1945}\x{19DE}-\x{19FF}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{1FBD}\x{1FBF}-\x{1FC1}\x{1FCD}-\x{1FCF}\x{1FDD}-\x{1FDF}\x{1FED}-\x{1FEF}\x{1FFD}-\x{1FFE}\x{2000}-\x{200A}\x{200B}-\x{200D}\x{200F}\x{2010}-\x{2015}\x{2016}-\x{2017}\x{2018}\x{2019}\x{201A}\x{201B}-\x{201C}\x{201D}\x{201E}\x{201F}\x{2020}-\x{2027}\x{2028}\x{2029}\x{202A}\x{202B}\x{202C}\x{202D}\x{202E}\x{202F}\x{2030}-\x{2034}\x{2035}-\x{2038}\x{2039}\x{203A}\x{203B}-\x{203E}\x{203F}-\x{2040}\x{2041}-\x{2043}\x{2044}\x{2045}\x{2046}\x{2047}-\x{2051}\x{2052}\x{2053}\x{2054}\x{2055}-\x{205E}\x{205F}\x{2060}-\x{2064}\x{2065}\x{2066}\x{2067}\x{2068}\x{2069}\x{206A}-\x{206F}\x{207A}-\x{207B}\x{207C}\x{207D}\x{207E}\x{208A}-\x{208B}\x{208C}\x{208D}\x{208E}\x{20A0}-\x{20BF}\x{20C0}-\x{20CF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2100}-\x{2101}\x{2103}-\x{2106}\x{2108}-\x{2109}\x{2114}\x{2116}-\x{2117}\x{2118}\x{211E}-\x{2123}\x{2125}\x{2127}\x{2129}\x{212E}\x{213A}-\x{213B}\x{2140}-\x{2144}\x{214A}\x{214B}\x{214C}-\x{214D}\x{2150}-\x{215F}\x{2189}\x{218A}-\x{218B}\x{2190}-\x{2194}\x{2195}-\x{2199}\x{219A}-\x{219B}\x{219C}-\x{219F}\x{21A0}\x{21A1}-\x{21A2}\x{21A3}\x{21A4}-\x{21A5}\x{21A6}\x{21A7}-\x{21AD}\x{21AE}\x{21AF}-\x{21CD}\x{21CE}-\x{21CF}\x{21D0}-\x{21D1}\x{21D2}\x{21D3}\x{21D4}\x{21D5}-\x{21F3}\x{21F4}-\x{2211}\x{2212}\x{2213}\x{2214}-\x{22FF}\x{2300}-\x{2307}\x{2308}\x{2309}\x{230A}\x{230B}\x{230C}-\x{231F}\x{2320}-\x{2321}\x{2322}-\x{2328}\x{2329}\x{232A}\x{232B}-\x{2335}\x{237B}\x{237C}\x{237D}-\x{2394}\x{2396}-\x{239A}\x{239B}-\x{23B3}\x{23B4}-\x{23DB}\x{23DC}-\x{23E1}\x{23E2}-\x{2426}\x{2440}-\x{244A}\x{2460}-\x{2487}\x{24EA}-\x{24FF}\x{2500}-\x{25B6}\x{25B7}\x{25B8}-\x{25C0}\x{25C1}\x{25C2}-\x{25F7}\x{25F8}-\x{25FF}\x{2600}-\x{266E}\x{266F}\x{2670}-\x{26AB}\x{26AD}-\x{2767}\x{2768}\x{2769}\x{276A}\x{276B}\x{276C}\x{276D}\x{276E}\x{276F}\x{2770}\x{2771}\x{2772}\x{2773}\x{2774}\x{2775}\x{2776}-\x{2793}\x{2794}-\x{27BF}\x{27C0}-\x{27C4}\x{27C5}\x{27C6}\x{27C7}-\x{27E5}\x{27E6}\x{27E7}\x{27E8}\x{27E9}\x{27EA}\x{27EB}\x{27EC}\x{27ED}\x{27EE}\x{27EF}\x{27F0}-\x{27FF}\x{2900}-\x{2982}\x{2983}\x{2984}\x{2985}\x{2986}\x{2987}\x{2988}\x{2989}\x{298A}\x{298B}\x{298C}\x{298D}\x{298E}\x{298F}\x{2990}\x{2991}\x{2992}\x{2993}\x{2994}\x{2995}\x{2996}\x{2997}\x{2998}\x{2999}-\x{29D7}\x{29D8}\x{29D9}\x{29DA}\x{29DB}\x{29DC}-\x{29FB}\x{29FC}\x{29FD}\x{29FE}-\x{2AFF}\x{2B00}-\x{2B2F}\x{2B30}-\x{2B44}\x{2B45}-\x{2B46}\x{2B47}-\x{2B4C}\x{2B4D}-\x{2B73}\x{2B76}-\x{2B95}\x{2B97}-\x{2BFF}\x{2CE5}-\x{2CEA}\x{2CEF}-\x{2CF1}\x{2CF9}-\x{2CFC}\x{2CFD}\x{2CFE}-\x{2CFF}\x{2D7F}\x{2DE0}-\x{2DFF}\x{2E00}-\x{2E01}\x{2E02}\x{2E03}\x{2E04}\x{2E05}\x{2E06}-\x{2E08}\x{2E09}\x{2E0A}\x{2E0B}\x{2E0C}\x{2E0D}\x{2E0E}-\x{2E16}\x{2E17}\x{2E18}-\x{2E19}\x{2E1A}\x{2E1B}\x{2E1C}\x{2E1D}\x{2E1E}-\x{2E1F}\x{2E20}\x{2E21}\x{2E22}\x{2E23}\x{2E24}\x{2E25}\x{2E26}\x{2E27}\x{2E28}\x{2E29}\x{2E2A}-\x{2E2E}\x{2E2F}\x{2E30}-\x{2E39}\x{2E3A}-\x{2E3B}\x{2E3C}-\x{2E3F}\x{2E40}\x{2E41}\x{2E42}\x{2E43}-\x{2E4F}\x{2E50}-\x{2E51}\x{2E52}\x{2E80}-\x{2E99}\x{2E9B}-\x{2EF3}\x{2F00}-\x{2FD5}\x{2FF0}-\x{2FFB}\x{3000}\x{3001}-\x{3003}\x{3004}\x{3008}\x{3009}\x{300A}\x{300B}\x{300C}\x{300D}\x{300E}\x{300F}\x{3010}\x{3011}\x{3012}-\x{3013}\x{3014}\x{3015}\x{3016}\x{3017}\x{3018}\x{3019}\x{301A}\x{301B}\x{301C}\x{301D}\x{301E}-\x{301F}\x{3020}\x{302A}-\x{302D}\x{3030}\x{3036}-\x{3037}\x{303D}\x{303E}-\x{303F}\x{3099}-\x{309A}\x{309B}-\x{309C}\x{30A0}\x{30FB}\x{31C0}-\x{31E3}\x{321D}-\x{321E}\x{3250}\x{3251}-\x{325F}\x{327C}-\x{327E}\x{32B1}-\x{32BF}\x{32CC}-\x{32CF}\x{3377}-\x{337A}\x{33DE}-\x{33DF}\x{33FF}\x{4DC0}-\x{4DFF}\x{A490}-\x{A4C6}\x{A60D}-\x{A60F}\x{A66F}\x{A670}-\x{A672}\x{A673}\x{A674}-\x{A67D}\x{A67E}\x{A67F}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A700}-\x{A716}\x{A717}-\x{A71F}\x{A720}-\x{A721}\x{A788}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A828}-\x{A82B}\x{A82C}\x{A838}\x{A839}\x{A874}-\x{A877}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{AB6A}-\x{AB6B}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1D}\x{FB1E}\x{FB1F}-\x{FB28}\x{FB29}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD3E}\x{FD3F}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDD0}-\x{FDEF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFD}\x{FDFE}-\x{FDFF}\x{FE00}-\x{FE0F}\x{FE10}-\x{FE16}\x{FE17}\x{FE18}\x{FE19}\x{FE20}-\x{FE2F}\x{FE30}\x{FE31}-\x{FE32}\x{FE33}-\x{FE34}\x{FE35}\x{FE36}\x{FE37}\x{FE38}\x{FE39}\x{FE3A}\x{FE3B}\x{FE3C}\x{FE3D}\x{FE3E}\x{FE3F}\x{FE40}\x{FE41}\x{FE42}\x{FE43}\x{FE44}\x{FE45}-\x{FE46}\x{FE47}\x{FE48}\x{FE49}-\x{FE4C}\x{FE4D}-\x{FE4F}\x{FE50}\x{FE51}\x{FE52}\x{FE54}\x{FE55}\x{FE56}-\x{FE57}\x{FE58}\x{FE59}\x{FE5A}\x{FE5B}\x{FE5C}\x{FE5D}\x{FE5E}\x{FE5F}\x{FE60}-\x{FE61}\x{FE62}\x{FE63}\x{FE64}-\x{FE66}\x{FE68}\x{FE69}\x{FE6A}\x{FE6B}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FEFF}\x{FF01}-\x{FF02}\x{FF03}\x{FF04}\x{FF05}\x{FF06}-\x{FF07}\x{FF08}\x{FF09}\x{FF0A}\x{FF0B}\x{FF0C}\x{FF0D}\x{FF0E}-\x{FF0F}\x{FF1A}\x{FF1B}\x{FF1C}-\x{FF1E}\x{FF1F}-\x{FF20}\x{FF3B}\x{FF3C}\x{FF3D}\x{FF3E}\x{FF3F}\x{FF40}\x{FF5B}\x{FF5C}\x{FF5D}\x{FF5E}\x{FF5F}\x{FF60}\x{FF61}\x{FF62}\x{FF63}\x{FF64}-\x{FF65}\x{FFE0}-\x{FFE1}\x{FFE2}\x{FFE3}\x{FFE4}\x{FFE5}-\x{FFE6}\x{FFE8}\x{FFE9}-\x{FFEC}\x{FFED}-\x{FFEE}\x{FFF0}-\x{FFF8}\x{FFF9}-\x{FFFB}\x{FFFC}-\x{FFFD}\x{FFFE}-\x{FFFF}\x{10101}\x{10140}-\x{10174}\x{10175}-\x{10178}\x{10179}-\x{10189}\x{1018A}-\x{1018B}\x{1018C}\x{10190}-\x{1019C}\x{101A0}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{1091F}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A01}-\x{10A03}\x{10A04}\x{10A05}-\x{10A06}\x{10A07}-\x{10A0B}\x{10A0C}-\x{10A0F}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A38}-\x{10A3A}\x{10A3B}-\x{10A3E}\x{10A3F}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE5}-\x{10AE6}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B39}-\x{10B3F}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D24}-\x{10D27}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAB}-\x{10EAC}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F46}-\x{10F50}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{11001}\x{11038}-\x{11046}\x{11052}-\x{11065}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{11660}-\x{1166C}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{11FD5}-\x{11FDC}\x{11FDD}-\x{11FE0}\x{11FE1}-\x{11FF1}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE2}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D200}-\x{1D241}\x{1D242}-\x{1D244}\x{1D245}\x{1D300}-\x{1D356}\x{1D6DB}\x{1D715}\x{1D74F}\x{1D789}\x{1D7C3}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E2FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D0}-\x{1E8D6}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E944}-\x{1E94A}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF0}-\x{1EEF1}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F000}-\x{1F02B}\x{1F030}-\x{1F093}\x{1F0A0}-\x{1F0AE}\x{1F0B1}-\x{1F0BF}\x{1F0C1}-\x{1F0CF}\x{1F0D1}-\x{1F0F5}\x{1F10B}-\x{1F10C}\x{1F10D}-\x{1F10F}\x{1F12F}\x{1F16A}-\x{1F16F}\x{1F1AD}\x{1F260}-\x{1F265}\x{1F300}-\x{1F3FA}\x{1F3FB}-\x{1F3FF}\x{1F400}-\x{1F6D7}\x{1F6E0}-\x{1F6EC}\x{1F6F0}-\x{1F6FC}\x{1F700}-\x{1F773}\x{1F780}-\x{1F7D8}\x{1F7E0}-\x{1F7EB}\x{1F800}-\x{1F80B}\x{1F810}-\x{1F847}\x{1F850}-\x{1F859}\x{1F860}-\x{1F887}\x{1F890}-\x{1F8AD}\x{1F8B0}-\x{1F8B1}\x{1F900}-\x{1F978}\x{1F97A}-\x{1F9CB}\x{1F9CD}-\x{1FA53}\x{1FA60}-\x{1FA6D}\x{1FA70}-\x{1FA74}\x{1FA78}-\x{1FA7A}\x{1FA80}-\x{1FA86}\x{1FA90}-\x{1FAA8}\x{1FAB0}-\x{1FAB6}\x{1FAC0}-\x{1FAC2}\x{1FAD0}-\x{1FAD6}\x{1FB00}-\x{1FB92}\x{1FB94}-\x{1FBCA}\x{1FFFE}-\x{1FFFF}\x{2FFFE}-\x{2FFFF}\x{3FFFE}-\x{3FFFF}\x{4FFFE}-\x{4FFFF}\x{5FFFE}-\x{5FFFF}\x{6FFFE}-\x{6FFFF}\x{7FFFE}-\x{7FFFF}\x{8FFFE}-\x{8FFFF}\x{9FFFE}-\x{9FFFF}\x{AFFFE}-\x{AFFFF}\x{BFFFE}-\x{BFFFF}\x{CFFFE}-\x{CFFFF}\x{DFFFE}-\x{E0000}\x{E0001}\x{E0002}-\x{E001F}\x{E0020}-\x{E007F}\x{E0080}-\x{E00FF}\x{E0100}-\x{E01EF}\x{E01F0}-\x{E0FFF}\x{EFFFE}-\x{EFFFF}\x{FFFFE}-\x{FFFFF}\x{10FFFE}-\x{10FFFF}][\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1D167}-\x{1D169}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{E0100}-\x{E01EF}]*$/u'; + const BIDI_STEP_1_LTR = '/^[^\x{0000}-\x{0008}\x{0009}\x{000A}\x{000B}\x{000C}\x{000D}\x{000E}-\x{001B}\x{001C}-\x{001E}\x{001F}\x{0020}\x{0021}-\x{0022}\x{0023}\x{0024}\x{0025}\x{0026}-\x{0027}\x{0028}\x{0029}\x{002A}\x{002B}\x{002C}\x{002D}\x{002E}-\x{002F}\x{0030}-\x{0039}\x{003A}\x{003B}\x{003C}-\x{003E}\x{003F}-\x{0040}\x{005B}\x{005C}\x{005D}\x{005E}\x{005F}\x{0060}\x{007B}\x{007C}\x{007D}\x{007E}\x{007F}-\x{0084}\x{0085}\x{0086}-\x{009F}\x{00A0}\x{00A1}\x{00A2}-\x{00A5}\x{00A6}\x{00A7}\x{00A8}\x{00A9}\x{00AB}\x{00AC}\x{00AD}\x{00AE}\x{00AF}\x{00B0}\x{00B1}\x{00B2}-\x{00B3}\x{00B4}\x{00B6}-\x{00B7}\x{00B8}\x{00B9}\x{00BB}\x{00BC}-\x{00BE}\x{00BF}\x{00D7}\x{00F7}\x{02B9}-\x{02BA}\x{02C2}-\x{02C5}\x{02C6}-\x{02CF}\x{02D2}-\x{02DF}\x{02E5}-\x{02EB}\x{02EC}\x{02ED}\x{02EF}-\x{02FF}\x{0300}-\x{036F}\x{0374}\x{0375}\x{037E}\x{0384}-\x{0385}\x{0387}\x{03F6}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{058A}\x{058D}-\x{058E}\x{058F}\x{0590}\x{0591}-\x{05BD}\x{05BE}\x{05BF}\x{05C0}\x{05C1}-\x{05C2}\x{05C3}\x{05C4}-\x{05C5}\x{05C6}\x{05C7}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0606}-\x{0607}\x{0608}\x{0609}-\x{060A}\x{060B}\x{060C}\x{060D}\x{060E}-\x{060F}\x{0610}-\x{061A}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{064B}-\x{065F}\x{0660}-\x{0669}\x{066A}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0670}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06D6}-\x{06DC}\x{06DD}\x{06DE}\x{06DF}-\x{06E4}\x{06E5}-\x{06E6}\x{06E7}-\x{06E8}\x{06E9}\x{06EA}-\x{06ED}\x{06EE}-\x{06EF}\x{06F0}-\x{06F9}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0711}\x{0712}-\x{072F}\x{0730}-\x{074A}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07A6}-\x{07B0}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07EB}-\x{07F3}\x{07F4}-\x{07F5}\x{07F6}\x{07F7}-\x{07F9}\x{07FA}\x{07FB}-\x{07FC}\x{07FD}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{0816}-\x{0819}\x{081A}\x{081B}-\x{0823}\x{0824}\x{0825}-\x{0827}\x{0828}\x{0829}-\x{082D}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{0859}-\x{085B}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08D3}-\x{08E1}\x{08E2}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09F2}-\x{09F3}\x{09FB}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AF1}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0BF3}-\x{0BF8}\x{0BF9}\x{0BFA}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C78}-\x{0C7E}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E3F}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3A}\x{0F3B}\x{0F3C}\x{0F3D}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1390}-\x{1399}\x{1400}\x{1680}\x{169B}\x{169C}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DB}\x{17DD}\x{17F0}-\x{17F9}\x{1800}-\x{1805}\x{1806}\x{1807}-\x{180A}\x{180B}-\x{180D}\x{180E}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1940}\x{1944}-\x{1945}\x{19DE}-\x{19FF}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{1FBD}\x{1FBF}-\x{1FC1}\x{1FCD}-\x{1FCF}\x{1FDD}-\x{1FDF}\x{1FED}-\x{1FEF}\x{1FFD}-\x{1FFE}\x{2000}-\x{200A}\x{200B}-\x{200D}\x{200F}\x{2010}-\x{2015}\x{2016}-\x{2017}\x{2018}\x{2019}\x{201A}\x{201B}-\x{201C}\x{201D}\x{201E}\x{201F}\x{2020}-\x{2027}\x{2028}\x{2029}\x{202A}\x{202B}\x{202C}\x{202D}\x{202E}\x{202F}\x{2030}-\x{2034}\x{2035}-\x{2038}\x{2039}\x{203A}\x{203B}-\x{203E}\x{203F}-\x{2040}\x{2041}-\x{2043}\x{2044}\x{2045}\x{2046}\x{2047}-\x{2051}\x{2052}\x{2053}\x{2054}\x{2055}-\x{205E}\x{205F}\x{2060}-\x{2064}\x{2065}\x{2066}\x{2067}\x{2068}\x{2069}\x{206A}-\x{206F}\x{2070}\x{2074}-\x{2079}\x{207A}-\x{207B}\x{207C}\x{207D}\x{207E}\x{2080}-\x{2089}\x{208A}-\x{208B}\x{208C}\x{208D}\x{208E}\x{20A0}-\x{20BF}\x{20C0}-\x{20CF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2100}-\x{2101}\x{2103}-\x{2106}\x{2108}-\x{2109}\x{2114}\x{2116}-\x{2117}\x{2118}\x{211E}-\x{2123}\x{2125}\x{2127}\x{2129}\x{212E}\x{213A}-\x{213B}\x{2140}-\x{2144}\x{214A}\x{214B}\x{214C}-\x{214D}\x{2150}-\x{215F}\x{2189}\x{218A}-\x{218B}\x{2190}-\x{2194}\x{2195}-\x{2199}\x{219A}-\x{219B}\x{219C}-\x{219F}\x{21A0}\x{21A1}-\x{21A2}\x{21A3}\x{21A4}-\x{21A5}\x{21A6}\x{21A7}-\x{21AD}\x{21AE}\x{21AF}-\x{21CD}\x{21CE}-\x{21CF}\x{21D0}-\x{21D1}\x{21D2}\x{21D3}\x{21D4}\x{21D5}-\x{21F3}\x{21F4}-\x{2211}\x{2212}\x{2213}\x{2214}-\x{22FF}\x{2300}-\x{2307}\x{2308}\x{2309}\x{230A}\x{230B}\x{230C}-\x{231F}\x{2320}-\x{2321}\x{2322}-\x{2328}\x{2329}\x{232A}\x{232B}-\x{2335}\x{237B}\x{237C}\x{237D}-\x{2394}\x{2396}-\x{239A}\x{239B}-\x{23B3}\x{23B4}-\x{23DB}\x{23DC}-\x{23E1}\x{23E2}-\x{2426}\x{2440}-\x{244A}\x{2460}-\x{2487}\x{2488}-\x{249B}\x{24EA}-\x{24FF}\x{2500}-\x{25B6}\x{25B7}\x{25B8}-\x{25C0}\x{25C1}\x{25C2}-\x{25F7}\x{25F8}-\x{25FF}\x{2600}-\x{266E}\x{266F}\x{2670}-\x{26AB}\x{26AD}-\x{2767}\x{2768}\x{2769}\x{276A}\x{276B}\x{276C}\x{276D}\x{276E}\x{276F}\x{2770}\x{2771}\x{2772}\x{2773}\x{2774}\x{2775}\x{2776}-\x{2793}\x{2794}-\x{27BF}\x{27C0}-\x{27C4}\x{27C5}\x{27C6}\x{27C7}-\x{27E5}\x{27E6}\x{27E7}\x{27E8}\x{27E9}\x{27EA}\x{27EB}\x{27EC}\x{27ED}\x{27EE}\x{27EF}\x{27F0}-\x{27FF}\x{2900}-\x{2982}\x{2983}\x{2984}\x{2985}\x{2986}\x{2987}\x{2988}\x{2989}\x{298A}\x{298B}\x{298C}\x{298D}\x{298E}\x{298F}\x{2990}\x{2991}\x{2992}\x{2993}\x{2994}\x{2995}\x{2996}\x{2997}\x{2998}\x{2999}-\x{29D7}\x{29D8}\x{29D9}\x{29DA}\x{29DB}\x{29DC}-\x{29FB}\x{29FC}\x{29FD}\x{29FE}-\x{2AFF}\x{2B00}-\x{2B2F}\x{2B30}-\x{2B44}\x{2B45}-\x{2B46}\x{2B47}-\x{2B4C}\x{2B4D}-\x{2B73}\x{2B76}-\x{2B95}\x{2B97}-\x{2BFF}\x{2CE5}-\x{2CEA}\x{2CEF}-\x{2CF1}\x{2CF9}-\x{2CFC}\x{2CFD}\x{2CFE}-\x{2CFF}\x{2D7F}\x{2DE0}-\x{2DFF}\x{2E00}-\x{2E01}\x{2E02}\x{2E03}\x{2E04}\x{2E05}\x{2E06}-\x{2E08}\x{2E09}\x{2E0A}\x{2E0B}\x{2E0C}\x{2E0D}\x{2E0E}-\x{2E16}\x{2E17}\x{2E18}-\x{2E19}\x{2E1A}\x{2E1B}\x{2E1C}\x{2E1D}\x{2E1E}-\x{2E1F}\x{2E20}\x{2E21}\x{2E22}\x{2E23}\x{2E24}\x{2E25}\x{2E26}\x{2E27}\x{2E28}\x{2E29}\x{2E2A}-\x{2E2E}\x{2E2F}\x{2E30}-\x{2E39}\x{2E3A}-\x{2E3B}\x{2E3C}-\x{2E3F}\x{2E40}\x{2E41}\x{2E42}\x{2E43}-\x{2E4F}\x{2E50}-\x{2E51}\x{2E52}\x{2E80}-\x{2E99}\x{2E9B}-\x{2EF3}\x{2F00}-\x{2FD5}\x{2FF0}-\x{2FFB}\x{3000}\x{3001}-\x{3003}\x{3004}\x{3008}\x{3009}\x{300A}\x{300B}\x{300C}\x{300D}\x{300E}\x{300F}\x{3010}\x{3011}\x{3012}-\x{3013}\x{3014}\x{3015}\x{3016}\x{3017}\x{3018}\x{3019}\x{301A}\x{301B}\x{301C}\x{301D}\x{301E}-\x{301F}\x{3020}\x{302A}-\x{302D}\x{3030}\x{3036}-\x{3037}\x{303D}\x{303E}-\x{303F}\x{3099}-\x{309A}\x{309B}-\x{309C}\x{30A0}\x{30FB}\x{31C0}-\x{31E3}\x{321D}-\x{321E}\x{3250}\x{3251}-\x{325F}\x{327C}-\x{327E}\x{32B1}-\x{32BF}\x{32CC}-\x{32CF}\x{3377}-\x{337A}\x{33DE}-\x{33DF}\x{33FF}\x{4DC0}-\x{4DFF}\x{A490}-\x{A4C6}\x{A60D}-\x{A60F}\x{A66F}\x{A670}-\x{A672}\x{A673}\x{A674}-\x{A67D}\x{A67E}\x{A67F}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A700}-\x{A716}\x{A717}-\x{A71F}\x{A720}-\x{A721}\x{A788}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A828}-\x{A82B}\x{A82C}\x{A838}\x{A839}\x{A874}-\x{A877}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{AB6A}-\x{AB6B}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1D}\x{FB1E}\x{FB1F}-\x{FB28}\x{FB29}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD3E}\x{FD3F}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDD0}-\x{FDEF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFD}\x{FDFE}-\x{FDFF}\x{FE00}-\x{FE0F}\x{FE10}-\x{FE16}\x{FE17}\x{FE18}\x{FE19}\x{FE20}-\x{FE2F}\x{FE30}\x{FE31}-\x{FE32}\x{FE33}-\x{FE34}\x{FE35}\x{FE36}\x{FE37}\x{FE38}\x{FE39}\x{FE3A}\x{FE3B}\x{FE3C}\x{FE3D}\x{FE3E}\x{FE3F}\x{FE40}\x{FE41}\x{FE42}\x{FE43}\x{FE44}\x{FE45}-\x{FE46}\x{FE47}\x{FE48}\x{FE49}-\x{FE4C}\x{FE4D}-\x{FE4F}\x{FE50}\x{FE51}\x{FE52}\x{FE54}\x{FE55}\x{FE56}-\x{FE57}\x{FE58}\x{FE59}\x{FE5A}\x{FE5B}\x{FE5C}\x{FE5D}\x{FE5E}\x{FE5F}\x{FE60}-\x{FE61}\x{FE62}\x{FE63}\x{FE64}-\x{FE66}\x{FE68}\x{FE69}\x{FE6A}\x{FE6B}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FEFF}\x{FF01}-\x{FF02}\x{FF03}\x{FF04}\x{FF05}\x{FF06}-\x{FF07}\x{FF08}\x{FF09}\x{FF0A}\x{FF0B}\x{FF0C}\x{FF0D}\x{FF0E}-\x{FF0F}\x{FF10}-\x{FF19}\x{FF1A}\x{FF1B}\x{FF1C}-\x{FF1E}\x{FF1F}-\x{FF20}\x{FF3B}\x{FF3C}\x{FF3D}\x{FF3E}\x{FF3F}\x{FF40}\x{FF5B}\x{FF5C}\x{FF5D}\x{FF5E}\x{FF5F}\x{FF60}\x{FF61}\x{FF62}\x{FF63}\x{FF64}-\x{FF65}\x{FFE0}-\x{FFE1}\x{FFE2}\x{FFE3}\x{FFE4}\x{FFE5}-\x{FFE6}\x{FFE8}\x{FFE9}-\x{FFEC}\x{FFED}-\x{FFEE}\x{FFF0}-\x{FFF8}\x{FFF9}-\x{FFFB}\x{FFFC}-\x{FFFD}\x{FFFE}-\x{FFFF}\x{10101}\x{10140}-\x{10174}\x{10175}-\x{10178}\x{10179}-\x{10189}\x{1018A}-\x{1018B}\x{1018C}\x{10190}-\x{1019C}\x{101A0}\x{101FD}\x{102E0}\x{102E1}-\x{102FB}\x{10376}-\x{1037A}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{1091F}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A01}-\x{10A03}\x{10A04}\x{10A05}-\x{10A06}\x{10A07}-\x{10A0B}\x{10A0C}-\x{10A0F}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A38}-\x{10A3A}\x{10A3B}-\x{10A3E}\x{10A3F}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE5}-\x{10AE6}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B39}-\x{10B3F}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D24}-\x{10D27}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAB}-\x{10EAC}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F46}-\x{10F50}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{11001}\x{11038}-\x{11046}\x{11052}-\x{11065}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{11660}-\x{1166C}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{11FD5}-\x{11FDC}\x{11FDD}-\x{11FE0}\x{11FE1}-\x{11FF1}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE2}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D200}-\x{1D241}\x{1D242}-\x{1D244}\x{1D245}\x{1D300}-\x{1D356}\x{1D6DB}\x{1D715}\x{1D74F}\x{1D789}\x{1D7C3}\x{1D7CE}-\x{1D7FF}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E2FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D0}-\x{1E8D6}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E944}-\x{1E94A}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF0}-\x{1EEF1}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F000}-\x{1F02B}\x{1F030}-\x{1F093}\x{1F0A0}-\x{1F0AE}\x{1F0B1}-\x{1F0BF}\x{1F0C1}-\x{1F0CF}\x{1F0D1}-\x{1F0F5}\x{1F100}-\x{1F10A}\x{1F10B}-\x{1F10C}\x{1F10D}-\x{1F10F}\x{1F12F}\x{1F16A}-\x{1F16F}\x{1F1AD}\x{1F260}-\x{1F265}\x{1F300}-\x{1F3FA}\x{1F3FB}-\x{1F3FF}\x{1F400}-\x{1F6D7}\x{1F6E0}-\x{1F6EC}\x{1F6F0}-\x{1F6FC}\x{1F700}-\x{1F773}\x{1F780}-\x{1F7D8}\x{1F7E0}-\x{1F7EB}\x{1F800}-\x{1F80B}\x{1F810}-\x{1F847}\x{1F850}-\x{1F859}\x{1F860}-\x{1F887}\x{1F890}-\x{1F8AD}\x{1F8B0}-\x{1F8B1}\x{1F900}-\x{1F978}\x{1F97A}-\x{1F9CB}\x{1F9CD}-\x{1FA53}\x{1FA60}-\x{1FA6D}\x{1FA70}-\x{1FA74}\x{1FA78}-\x{1FA7A}\x{1FA80}-\x{1FA86}\x{1FA90}-\x{1FAA8}\x{1FAB0}-\x{1FAB6}\x{1FAC0}-\x{1FAC2}\x{1FAD0}-\x{1FAD6}\x{1FB00}-\x{1FB92}\x{1FB94}-\x{1FBCA}\x{1FBF0}-\x{1FBF9}\x{1FFFE}-\x{1FFFF}\x{2FFFE}-\x{2FFFF}\x{3FFFE}-\x{3FFFF}\x{4FFFE}-\x{4FFFF}\x{5FFFE}-\x{5FFFF}\x{6FFFE}-\x{6FFFF}\x{7FFFE}-\x{7FFFF}\x{8FFFE}-\x{8FFFF}\x{9FFFE}-\x{9FFFF}\x{AFFFE}-\x{AFFFF}\x{BFFFE}-\x{BFFFF}\x{CFFFE}-\x{CFFFF}\x{DFFFE}-\x{E0000}\x{E0001}\x{E0002}-\x{E001F}\x{E0020}-\x{E007F}\x{E0080}-\x{E00FF}\x{E0100}-\x{E01EF}\x{E01F0}-\x{E0FFF}\x{EFFFE}-\x{EFFFF}\x{FFFFE}-\x{FFFFF}\x{10FFFE}-\x{10FFFF}]/u'; + const BIDI_STEP_1_RTL = '/^[\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{200F}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}]/u'; + const BIDI_STEP_2 = '/[^\x{0000}-\x{0008}\x{000E}-\x{001B}\x{0021}-\x{0022}\x{0023}\x{0024}\x{0025}\x{0026}-\x{0027}\x{0028}\x{0029}\x{002A}\x{002B}\x{002C}\x{002D}\x{002E}-\x{002F}\x{0030}-\x{0039}\x{003A}\x{003B}\x{003C}-\x{003E}\x{003F}-\x{0040}\x{005B}\x{005C}\x{005D}\x{005E}\x{005F}\x{0060}\x{007B}\x{007C}\x{007D}\x{007E}\x{007F}-\x{0084}\x{0086}-\x{009F}\x{00A0}\x{00A1}\x{00A2}-\x{00A5}\x{00A6}\x{00A7}\x{00A8}\x{00A9}\x{00AB}\x{00AC}\x{00AD}\x{00AE}\x{00AF}\x{00B0}\x{00B1}\x{00B2}-\x{00B3}\x{00B4}\x{00B6}-\x{00B7}\x{00B8}\x{00B9}\x{00BB}\x{00BC}-\x{00BE}\x{00BF}\x{00D7}\x{00F7}\x{02B9}-\x{02BA}\x{02C2}-\x{02C5}\x{02C6}-\x{02CF}\x{02D2}-\x{02DF}\x{02E5}-\x{02EB}\x{02EC}\x{02ED}\x{02EF}-\x{02FF}\x{0300}-\x{036F}\x{0374}\x{0375}\x{037E}\x{0384}-\x{0385}\x{0387}\x{03F6}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{058A}\x{058D}-\x{058E}\x{058F}\x{0590}\x{0591}-\x{05BD}\x{05BE}\x{05BF}\x{05C0}\x{05C1}-\x{05C2}\x{05C3}\x{05C4}-\x{05C5}\x{05C6}\x{05C7}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0606}-\x{0607}\x{0608}\x{0609}-\x{060A}\x{060B}\x{060C}\x{060D}\x{060E}-\x{060F}\x{0610}-\x{061A}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{064B}-\x{065F}\x{0660}-\x{0669}\x{066A}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0670}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06D6}-\x{06DC}\x{06DD}\x{06DE}\x{06DF}-\x{06E4}\x{06E5}-\x{06E6}\x{06E7}-\x{06E8}\x{06E9}\x{06EA}-\x{06ED}\x{06EE}-\x{06EF}\x{06F0}-\x{06F9}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0711}\x{0712}-\x{072F}\x{0730}-\x{074A}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07A6}-\x{07B0}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07EB}-\x{07F3}\x{07F4}-\x{07F5}\x{07F6}\x{07F7}-\x{07F9}\x{07FA}\x{07FB}-\x{07FC}\x{07FD}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{0816}-\x{0819}\x{081A}\x{081B}-\x{0823}\x{0824}\x{0825}-\x{0827}\x{0828}\x{0829}-\x{082D}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{0859}-\x{085B}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08D3}-\x{08E1}\x{08E2}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09F2}-\x{09F3}\x{09FB}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AF1}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0BF3}-\x{0BF8}\x{0BF9}\x{0BFA}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C78}-\x{0C7E}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E3F}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3A}\x{0F3B}\x{0F3C}\x{0F3D}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1390}-\x{1399}\x{1400}\x{169B}\x{169C}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DB}\x{17DD}\x{17F0}-\x{17F9}\x{1800}-\x{1805}\x{1806}\x{1807}-\x{180A}\x{180B}-\x{180D}\x{180E}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1940}\x{1944}-\x{1945}\x{19DE}-\x{19FF}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{1FBD}\x{1FBF}-\x{1FC1}\x{1FCD}-\x{1FCF}\x{1FDD}-\x{1FDF}\x{1FED}-\x{1FEF}\x{1FFD}-\x{1FFE}\x{200B}-\x{200D}\x{200F}\x{2010}-\x{2015}\x{2016}-\x{2017}\x{2018}\x{2019}\x{201A}\x{201B}-\x{201C}\x{201D}\x{201E}\x{201F}\x{2020}-\x{2027}\x{202F}\x{2030}-\x{2034}\x{2035}-\x{2038}\x{2039}\x{203A}\x{203B}-\x{203E}\x{203F}-\x{2040}\x{2041}-\x{2043}\x{2044}\x{2045}\x{2046}\x{2047}-\x{2051}\x{2052}\x{2053}\x{2054}\x{2055}-\x{205E}\x{2060}-\x{2064}\x{2065}\x{206A}-\x{206F}\x{2070}\x{2074}-\x{2079}\x{207A}-\x{207B}\x{207C}\x{207D}\x{207E}\x{2080}-\x{2089}\x{208A}-\x{208B}\x{208C}\x{208D}\x{208E}\x{20A0}-\x{20BF}\x{20C0}-\x{20CF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2100}-\x{2101}\x{2103}-\x{2106}\x{2108}-\x{2109}\x{2114}\x{2116}-\x{2117}\x{2118}\x{211E}-\x{2123}\x{2125}\x{2127}\x{2129}\x{212E}\x{213A}-\x{213B}\x{2140}-\x{2144}\x{214A}\x{214B}\x{214C}-\x{214D}\x{2150}-\x{215F}\x{2189}\x{218A}-\x{218B}\x{2190}-\x{2194}\x{2195}-\x{2199}\x{219A}-\x{219B}\x{219C}-\x{219F}\x{21A0}\x{21A1}-\x{21A2}\x{21A3}\x{21A4}-\x{21A5}\x{21A6}\x{21A7}-\x{21AD}\x{21AE}\x{21AF}-\x{21CD}\x{21CE}-\x{21CF}\x{21D0}-\x{21D1}\x{21D2}\x{21D3}\x{21D4}\x{21D5}-\x{21F3}\x{21F4}-\x{2211}\x{2212}\x{2213}\x{2214}-\x{22FF}\x{2300}-\x{2307}\x{2308}\x{2309}\x{230A}\x{230B}\x{230C}-\x{231F}\x{2320}-\x{2321}\x{2322}-\x{2328}\x{2329}\x{232A}\x{232B}-\x{2335}\x{237B}\x{237C}\x{237D}-\x{2394}\x{2396}-\x{239A}\x{239B}-\x{23B3}\x{23B4}-\x{23DB}\x{23DC}-\x{23E1}\x{23E2}-\x{2426}\x{2440}-\x{244A}\x{2460}-\x{2487}\x{2488}-\x{249B}\x{24EA}-\x{24FF}\x{2500}-\x{25B6}\x{25B7}\x{25B8}-\x{25C0}\x{25C1}\x{25C2}-\x{25F7}\x{25F8}-\x{25FF}\x{2600}-\x{266E}\x{266F}\x{2670}-\x{26AB}\x{26AD}-\x{2767}\x{2768}\x{2769}\x{276A}\x{276B}\x{276C}\x{276D}\x{276E}\x{276F}\x{2770}\x{2771}\x{2772}\x{2773}\x{2774}\x{2775}\x{2776}-\x{2793}\x{2794}-\x{27BF}\x{27C0}-\x{27C4}\x{27C5}\x{27C6}\x{27C7}-\x{27E5}\x{27E6}\x{27E7}\x{27E8}\x{27E9}\x{27EA}\x{27EB}\x{27EC}\x{27ED}\x{27EE}\x{27EF}\x{27F0}-\x{27FF}\x{2900}-\x{2982}\x{2983}\x{2984}\x{2985}\x{2986}\x{2987}\x{2988}\x{2989}\x{298A}\x{298B}\x{298C}\x{298D}\x{298E}\x{298F}\x{2990}\x{2991}\x{2992}\x{2993}\x{2994}\x{2995}\x{2996}\x{2997}\x{2998}\x{2999}-\x{29D7}\x{29D8}\x{29D9}\x{29DA}\x{29DB}\x{29DC}-\x{29FB}\x{29FC}\x{29FD}\x{29FE}-\x{2AFF}\x{2B00}-\x{2B2F}\x{2B30}-\x{2B44}\x{2B45}-\x{2B46}\x{2B47}-\x{2B4C}\x{2B4D}-\x{2B73}\x{2B76}-\x{2B95}\x{2B97}-\x{2BFF}\x{2CE5}-\x{2CEA}\x{2CEF}-\x{2CF1}\x{2CF9}-\x{2CFC}\x{2CFD}\x{2CFE}-\x{2CFF}\x{2D7F}\x{2DE0}-\x{2DFF}\x{2E00}-\x{2E01}\x{2E02}\x{2E03}\x{2E04}\x{2E05}\x{2E06}-\x{2E08}\x{2E09}\x{2E0A}\x{2E0B}\x{2E0C}\x{2E0D}\x{2E0E}-\x{2E16}\x{2E17}\x{2E18}-\x{2E19}\x{2E1A}\x{2E1B}\x{2E1C}\x{2E1D}\x{2E1E}-\x{2E1F}\x{2E20}\x{2E21}\x{2E22}\x{2E23}\x{2E24}\x{2E25}\x{2E26}\x{2E27}\x{2E28}\x{2E29}\x{2E2A}-\x{2E2E}\x{2E2F}\x{2E30}-\x{2E39}\x{2E3A}-\x{2E3B}\x{2E3C}-\x{2E3F}\x{2E40}\x{2E41}\x{2E42}\x{2E43}-\x{2E4F}\x{2E50}-\x{2E51}\x{2E52}\x{2E80}-\x{2E99}\x{2E9B}-\x{2EF3}\x{2F00}-\x{2FD5}\x{2FF0}-\x{2FFB}\x{3001}-\x{3003}\x{3004}\x{3008}\x{3009}\x{300A}\x{300B}\x{300C}\x{300D}\x{300E}\x{300F}\x{3010}\x{3011}\x{3012}-\x{3013}\x{3014}\x{3015}\x{3016}\x{3017}\x{3018}\x{3019}\x{301A}\x{301B}\x{301C}\x{301D}\x{301E}-\x{301F}\x{3020}\x{302A}-\x{302D}\x{3030}\x{3036}-\x{3037}\x{303D}\x{303E}-\x{303F}\x{3099}-\x{309A}\x{309B}-\x{309C}\x{30A0}\x{30FB}\x{31C0}-\x{31E3}\x{321D}-\x{321E}\x{3250}\x{3251}-\x{325F}\x{327C}-\x{327E}\x{32B1}-\x{32BF}\x{32CC}-\x{32CF}\x{3377}-\x{337A}\x{33DE}-\x{33DF}\x{33FF}\x{4DC0}-\x{4DFF}\x{A490}-\x{A4C6}\x{A60D}-\x{A60F}\x{A66F}\x{A670}-\x{A672}\x{A673}\x{A674}-\x{A67D}\x{A67E}\x{A67F}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A700}-\x{A716}\x{A717}-\x{A71F}\x{A720}-\x{A721}\x{A788}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A828}-\x{A82B}\x{A82C}\x{A838}\x{A839}\x{A874}-\x{A877}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{AB6A}-\x{AB6B}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1D}\x{FB1E}\x{FB1F}-\x{FB28}\x{FB29}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD3E}\x{FD3F}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDD0}-\x{FDEF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFD}\x{FDFE}-\x{FDFF}\x{FE00}-\x{FE0F}\x{FE10}-\x{FE16}\x{FE17}\x{FE18}\x{FE19}\x{FE20}-\x{FE2F}\x{FE30}\x{FE31}-\x{FE32}\x{FE33}-\x{FE34}\x{FE35}\x{FE36}\x{FE37}\x{FE38}\x{FE39}\x{FE3A}\x{FE3B}\x{FE3C}\x{FE3D}\x{FE3E}\x{FE3F}\x{FE40}\x{FE41}\x{FE42}\x{FE43}\x{FE44}\x{FE45}-\x{FE46}\x{FE47}\x{FE48}\x{FE49}-\x{FE4C}\x{FE4D}-\x{FE4F}\x{FE50}\x{FE51}\x{FE52}\x{FE54}\x{FE55}\x{FE56}-\x{FE57}\x{FE58}\x{FE59}\x{FE5A}\x{FE5B}\x{FE5C}\x{FE5D}\x{FE5E}\x{FE5F}\x{FE60}-\x{FE61}\x{FE62}\x{FE63}\x{FE64}-\x{FE66}\x{FE68}\x{FE69}\x{FE6A}\x{FE6B}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FEFF}\x{FF01}-\x{FF02}\x{FF03}\x{FF04}\x{FF05}\x{FF06}-\x{FF07}\x{FF08}\x{FF09}\x{FF0A}\x{FF0B}\x{FF0C}\x{FF0D}\x{FF0E}-\x{FF0F}\x{FF10}-\x{FF19}\x{FF1A}\x{FF1B}\x{FF1C}-\x{FF1E}\x{FF1F}-\x{FF20}\x{FF3B}\x{FF3C}\x{FF3D}\x{FF3E}\x{FF3F}\x{FF40}\x{FF5B}\x{FF5C}\x{FF5D}\x{FF5E}\x{FF5F}\x{FF60}\x{FF61}\x{FF62}\x{FF63}\x{FF64}-\x{FF65}\x{FFE0}-\x{FFE1}\x{FFE2}\x{FFE3}\x{FFE4}\x{FFE5}-\x{FFE6}\x{FFE8}\x{FFE9}-\x{FFEC}\x{FFED}-\x{FFEE}\x{FFF0}-\x{FFF8}\x{FFF9}-\x{FFFB}\x{FFFC}-\x{FFFD}\x{FFFE}-\x{FFFF}\x{10101}\x{10140}-\x{10174}\x{10175}-\x{10178}\x{10179}-\x{10189}\x{1018A}-\x{1018B}\x{1018C}\x{10190}-\x{1019C}\x{101A0}\x{101FD}\x{102E0}\x{102E1}-\x{102FB}\x{10376}-\x{1037A}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{1091F}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A01}-\x{10A03}\x{10A04}\x{10A05}-\x{10A06}\x{10A07}-\x{10A0B}\x{10A0C}-\x{10A0F}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A38}-\x{10A3A}\x{10A3B}-\x{10A3E}\x{10A3F}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE5}-\x{10AE6}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B39}-\x{10B3F}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D24}-\x{10D27}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAB}-\x{10EAC}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F46}-\x{10F50}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{11001}\x{11038}-\x{11046}\x{11052}-\x{11065}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{11660}-\x{1166C}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{11FD5}-\x{11FDC}\x{11FDD}-\x{11FE0}\x{11FE1}-\x{11FF1}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE2}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D200}-\x{1D241}\x{1D242}-\x{1D244}\x{1D245}\x{1D300}-\x{1D356}\x{1D6DB}\x{1D715}\x{1D74F}\x{1D789}\x{1D7C3}\x{1D7CE}-\x{1D7FF}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E2FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D0}-\x{1E8D6}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E944}-\x{1E94A}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF0}-\x{1EEF1}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F000}-\x{1F02B}\x{1F030}-\x{1F093}\x{1F0A0}-\x{1F0AE}\x{1F0B1}-\x{1F0BF}\x{1F0C1}-\x{1F0CF}\x{1F0D1}-\x{1F0F5}\x{1F100}-\x{1F10A}\x{1F10B}-\x{1F10C}\x{1F10D}-\x{1F10F}\x{1F12F}\x{1F16A}-\x{1F16F}\x{1F1AD}\x{1F260}-\x{1F265}\x{1F300}-\x{1F3FA}\x{1F3FB}-\x{1F3FF}\x{1F400}-\x{1F6D7}\x{1F6E0}-\x{1F6EC}\x{1F6F0}-\x{1F6FC}\x{1F700}-\x{1F773}\x{1F780}-\x{1F7D8}\x{1F7E0}-\x{1F7EB}\x{1F800}-\x{1F80B}\x{1F810}-\x{1F847}\x{1F850}-\x{1F859}\x{1F860}-\x{1F887}\x{1F890}-\x{1F8AD}\x{1F8B0}-\x{1F8B1}\x{1F900}-\x{1F978}\x{1F97A}-\x{1F9CB}\x{1F9CD}-\x{1FA53}\x{1FA60}-\x{1FA6D}\x{1FA70}-\x{1FA74}\x{1FA78}-\x{1FA7A}\x{1FA80}-\x{1FA86}\x{1FA90}-\x{1FAA8}\x{1FAB0}-\x{1FAB6}\x{1FAC0}-\x{1FAC2}\x{1FAD0}-\x{1FAD6}\x{1FB00}-\x{1FB92}\x{1FB94}-\x{1FBCA}\x{1FBF0}-\x{1FBF9}\x{1FFFE}-\x{1FFFF}\x{2FFFE}-\x{2FFFF}\x{3FFFE}-\x{3FFFF}\x{4FFFE}-\x{4FFFF}\x{5FFFE}-\x{5FFFF}\x{6FFFE}-\x{6FFFF}\x{7FFFE}-\x{7FFFF}\x{8FFFE}-\x{8FFFF}\x{9FFFE}-\x{9FFFF}\x{AFFFE}-\x{AFFFF}\x{BFFFE}-\x{BFFFF}\x{CFFFE}-\x{CFFFF}\x{DFFFE}-\x{E0000}\x{E0001}\x{E0002}-\x{E001F}\x{E0020}-\x{E007F}\x{E0080}-\x{E00FF}\x{E0100}-\x{E01EF}\x{E01F0}-\x{E0FFF}\x{EFFFE}-\x{EFFFF}\x{FFFFE}-\x{FFFFF}\x{10FFFE}-\x{10FFFF}]/u'; + const BIDI_STEP_3 = '/[\x{0030}-\x{0039}\x{00B2}-\x{00B3}\x{00B9}\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06DD}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06F0}-\x{06F9}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08E2}\x{200F}\x{2070}\x{2074}-\x{2079}\x{2080}-\x{2089}\x{2488}-\x{249B}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FF10}-\x{FF19}\x{102E1}-\x{102FB}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1D7CE}-\x{1D7FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F100}-\x{1F10A}\x{1FBF0}-\x{1FBF9}][\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1D167}-\x{1D169}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{E0100}-\x{E01EF}]*$/u'; + const BIDI_STEP_4_AN = '/[\x{0600}-\x{0605}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{06DD}\x{08E2}\x{10D30}-\x{10D39}\x{10E60}-\x{10E7E}]/u'; + const BIDI_STEP_4_EN = '/[\x{0030}-\x{0039}\x{00B2}-\x{00B3}\x{00B9}\x{06F0}-\x{06F9}\x{2070}\x{2074}-\x{2079}\x{2080}-\x{2089}\x{2488}-\x{249B}\x{FF10}-\x{FF19}\x{102E1}-\x{102FB}\x{1D7CE}-\x{1D7FF}\x{1F100}-\x{1F10A}\x{1FBF0}-\x{1FBF9}]/u'; + const BIDI_STEP_5 = '/[\x{0009}\x{000A}\x{000B}\x{000C}\x{000D}\x{001C}-\x{001E}\x{001F}\x{0020}\x{0085}\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06DD}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08E2}\x{1680}\x{2000}-\x{200A}\x{200F}\x{2028}\x{2029}\x{202A}\x{202B}\x{202C}\x{202D}\x{202E}\x{205F}\x{2066}\x{2067}\x{2068}\x{2069}\x{3000}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}]/u'; + const BIDI_STEP_6 = '/[^\x{0000}-\x{0008}\x{0009}\x{000A}\x{000B}\x{000C}\x{000D}\x{000E}-\x{001B}\x{001C}-\x{001E}\x{001F}\x{0020}\x{0021}-\x{0022}\x{0023}\x{0024}\x{0025}\x{0026}-\x{0027}\x{0028}\x{0029}\x{002A}\x{002B}\x{002C}\x{002D}\x{002E}-\x{002F}\x{003A}\x{003B}\x{003C}-\x{003E}\x{003F}-\x{0040}\x{005B}\x{005C}\x{005D}\x{005E}\x{005F}\x{0060}\x{007B}\x{007C}\x{007D}\x{007E}\x{007F}-\x{0084}\x{0085}\x{0086}-\x{009F}\x{00A0}\x{00A1}\x{00A2}-\x{00A5}\x{00A6}\x{00A7}\x{00A8}\x{00A9}\x{00AB}\x{00AC}\x{00AD}\x{00AE}\x{00AF}\x{00B0}\x{00B1}\x{00B4}\x{00B6}-\x{00B7}\x{00B8}\x{00BB}\x{00BC}-\x{00BE}\x{00BF}\x{00D7}\x{00F7}\x{02B9}-\x{02BA}\x{02C2}-\x{02C5}\x{02C6}-\x{02CF}\x{02D2}-\x{02DF}\x{02E5}-\x{02EB}\x{02EC}\x{02ED}\x{02EF}-\x{02FF}\x{0300}-\x{036F}\x{0374}\x{0375}\x{037E}\x{0384}-\x{0385}\x{0387}\x{03F6}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{058A}\x{058D}-\x{058E}\x{058F}\x{0590}\x{0591}-\x{05BD}\x{05BE}\x{05BF}\x{05C0}\x{05C1}-\x{05C2}\x{05C3}\x{05C4}-\x{05C5}\x{05C6}\x{05C7}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0606}-\x{0607}\x{0608}\x{0609}-\x{060A}\x{060B}\x{060C}\x{060D}\x{060E}-\x{060F}\x{0610}-\x{061A}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{064B}-\x{065F}\x{0660}-\x{0669}\x{066A}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0670}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06D6}-\x{06DC}\x{06DD}\x{06DE}\x{06DF}-\x{06E4}\x{06E5}-\x{06E6}\x{06E7}-\x{06E8}\x{06E9}\x{06EA}-\x{06ED}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0711}\x{0712}-\x{072F}\x{0730}-\x{074A}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07A6}-\x{07B0}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07EB}-\x{07F3}\x{07F4}-\x{07F5}\x{07F6}\x{07F7}-\x{07F9}\x{07FA}\x{07FB}-\x{07FC}\x{07FD}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{0816}-\x{0819}\x{081A}\x{081B}-\x{0823}\x{0824}\x{0825}-\x{0827}\x{0828}\x{0829}-\x{082D}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{0859}-\x{085B}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08D3}-\x{08E1}\x{08E2}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09F2}-\x{09F3}\x{09FB}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AF1}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0BF3}-\x{0BF8}\x{0BF9}\x{0BFA}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C78}-\x{0C7E}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E3F}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3A}\x{0F3B}\x{0F3C}\x{0F3D}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1390}-\x{1399}\x{1400}\x{1680}\x{169B}\x{169C}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DB}\x{17DD}\x{17F0}-\x{17F9}\x{1800}-\x{1805}\x{1806}\x{1807}-\x{180A}\x{180B}-\x{180D}\x{180E}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1940}\x{1944}-\x{1945}\x{19DE}-\x{19FF}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{1FBD}\x{1FBF}-\x{1FC1}\x{1FCD}-\x{1FCF}\x{1FDD}-\x{1FDF}\x{1FED}-\x{1FEF}\x{1FFD}-\x{1FFE}\x{2000}-\x{200A}\x{200B}-\x{200D}\x{200F}\x{2010}-\x{2015}\x{2016}-\x{2017}\x{2018}\x{2019}\x{201A}\x{201B}-\x{201C}\x{201D}\x{201E}\x{201F}\x{2020}-\x{2027}\x{2028}\x{2029}\x{202A}\x{202B}\x{202C}\x{202D}\x{202E}\x{202F}\x{2030}-\x{2034}\x{2035}-\x{2038}\x{2039}\x{203A}\x{203B}-\x{203E}\x{203F}-\x{2040}\x{2041}-\x{2043}\x{2044}\x{2045}\x{2046}\x{2047}-\x{2051}\x{2052}\x{2053}\x{2054}\x{2055}-\x{205E}\x{205F}\x{2060}-\x{2064}\x{2065}\x{2066}\x{2067}\x{2068}\x{2069}\x{206A}-\x{206F}\x{207A}-\x{207B}\x{207C}\x{207D}\x{207E}\x{208A}-\x{208B}\x{208C}\x{208D}\x{208E}\x{20A0}-\x{20BF}\x{20C0}-\x{20CF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2100}-\x{2101}\x{2103}-\x{2106}\x{2108}-\x{2109}\x{2114}\x{2116}-\x{2117}\x{2118}\x{211E}-\x{2123}\x{2125}\x{2127}\x{2129}\x{212E}\x{213A}-\x{213B}\x{2140}-\x{2144}\x{214A}\x{214B}\x{214C}-\x{214D}\x{2150}-\x{215F}\x{2189}\x{218A}-\x{218B}\x{2190}-\x{2194}\x{2195}-\x{2199}\x{219A}-\x{219B}\x{219C}-\x{219F}\x{21A0}\x{21A1}-\x{21A2}\x{21A3}\x{21A4}-\x{21A5}\x{21A6}\x{21A7}-\x{21AD}\x{21AE}\x{21AF}-\x{21CD}\x{21CE}-\x{21CF}\x{21D0}-\x{21D1}\x{21D2}\x{21D3}\x{21D4}\x{21D5}-\x{21F3}\x{21F4}-\x{2211}\x{2212}\x{2213}\x{2214}-\x{22FF}\x{2300}-\x{2307}\x{2308}\x{2309}\x{230A}\x{230B}\x{230C}-\x{231F}\x{2320}-\x{2321}\x{2322}-\x{2328}\x{2329}\x{232A}\x{232B}-\x{2335}\x{237B}\x{237C}\x{237D}-\x{2394}\x{2396}-\x{239A}\x{239B}-\x{23B3}\x{23B4}-\x{23DB}\x{23DC}-\x{23E1}\x{23E2}-\x{2426}\x{2440}-\x{244A}\x{2460}-\x{2487}\x{24EA}-\x{24FF}\x{2500}-\x{25B6}\x{25B7}\x{25B8}-\x{25C0}\x{25C1}\x{25C2}-\x{25F7}\x{25F8}-\x{25FF}\x{2600}-\x{266E}\x{266F}\x{2670}-\x{26AB}\x{26AD}-\x{2767}\x{2768}\x{2769}\x{276A}\x{276B}\x{276C}\x{276D}\x{276E}\x{276F}\x{2770}\x{2771}\x{2772}\x{2773}\x{2774}\x{2775}\x{2776}-\x{2793}\x{2794}-\x{27BF}\x{27C0}-\x{27C4}\x{27C5}\x{27C6}\x{27C7}-\x{27E5}\x{27E6}\x{27E7}\x{27E8}\x{27E9}\x{27EA}\x{27EB}\x{27EC}\x{27ED}\x{27EE}\x{27EF}\x{27F0}-\x{27FF}\x{2900}-\x{2982}\x{2983}\x{2984}\x{2985}\x{2986}\x{2987}\x{2988}\x{2989}\x{298A}\x{298B}\x{298C}\x{298D}\x{298E}\x{298F}\x{2990}\x{2991}\x{2992}\x{2993}\x{2994}\x{2995}\x{2996}\x{2997}\x{2998}\x{2999}-\x{29D7}\x{29D8}\x{29D9}\x{29DA}\x{29DB}\x{29DC}-\x{29FB}\x{29FC}\x{29FD}\x{29FE}-\x{2AFF}\x{2B00}-\x{2B2F}\x{2B30}-\x{2B44}\x{2B45}-\x{2B46}\x{2B47}-\x{2B4C}\x{2B4D}-\x{2B73}\x{2B76}-\x{2B95}\x{2B97}-\x{2BFF}\x{2CE5}-\x{2CEA}\x{2CEF}-\x{2CF1}\x{2CF9}-\x{2CFC}\x{2CFD}\x{2CFE}-\x{2CFF}\x{2D7F}\x{2DE0}-\x{2DFF}\x{2E00}-\x{2E01}\x{2E02}\x{2E03}\x{2E04}\x{2E05}\x{2E06}-\x{2E08}\x{2E09}\x{2E0A}\x{2E0B}\x{2E0C}\x{2E0D}\x{2E0E}-\x{2E16}\x{2E17}\x{2E18}-\x{2E19}\x{2E1A}\x{2E1B}\x{2E1C}\x{2E1D}\x{2E1E}-\x{2E1F}\x{2E20}\x{2E21}\x{2E22}\x{2E23}\x{2E24}\x{2E25}\x{2E26}\x{2E27}\x{2E28}\x{2E29}\x{2E2A}-\x{2E2E}\x{2E2F}\x{2E30}-\x{2E39}\x{2E3A}-\x{2E3B}\x{2E3C}-\x{2E3F}\x{2E40}\x{2E41}\x{2E42}\x{2E43}-\x{2E4F}\x{2E50}-\x{2E51}\x{2E52}\x{2E80}-\x{2E99}\x{2E9B}-\x{2EF3}\x{2F00}-\x{2FD5}\x{2FF0}-\x{2FFB}\x{3000}\x{3001}-\x{3003}\x{3004}\x{3008}\x{3009}\x{300A}\x{300B}\x{300C}\x{300D}\x{300E}\x{300F}\x{3010}\x{3011}\x{3012}-\x{3013}\x{3014}\x{3015}\x{3016}\x{3017}\x{3018}\x{3019}\x{301A}\x{301B}\x{301C}\x{301D}\x{301E}-\x{301F}\x{3020}\x{302A}-\x{302D}\x{3030}\x{3036}-\x{3037}\x{303D}\x{303E}-\x{303F}\x{3099}-\x{309A}\x{309B}-\x{309C}\x{30A0}\x{30FB}\x{31C0}-\x{31E3}\x{321D}-\x{321E}\x{3250}\x{3251}-\x{325F}\x{327C}-\x{327E}\x{32B1}-\x{32BF}\x{32CC}-\x{32CF}\x{3377}-\x{337A}\x{33DE}-\x{33DF}\x{33FF}\x{4DC0}-\x{4DFF}\x{A490}-\x{A4C6}\x{A60D}-\x{A60F}\x{A66F}\x{A670}-\x{A672}\x{A673}\x{A674}-\x{A67D}\x{A67E}\x{A67F}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A700}-\x{A716}\x{A717}-\x{A71F}\x{A720}-\x{A721}\x{A788}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A828}-\x{A82B}\x{A82C}\x{A838}\x{A839}\x{A874}-\x{A877}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{AB6A}-\x{AB6B}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1D}\x{FB1E}\x{FB1F}-\x{FB28}\x{FB29}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD3E}\x{FD3F}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDD0}-\x{FDEF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFD}\x{FDFE}-\x{FDFF}\x{FE00}-\x{FE0F}\x{FE10}-\x{FE16}\x{FE17}\x{FE18}\x{FE19}\x{FE20}-\x{FE2F}\x{FE30}\x{FE31}-\x{FE32}\x{FE33}-\x{FE34}\x{FE35}\x{FE36}\x{FE37}\x{FE38}\x{FE39}\x{FE3A}\x{FE3B}\x{FE3C}\x{FE3D}\x{FE3E}\x{FE3F}\x{FE40}\x{FE41}\x{FE42}\x{FE43}\x{FE44}\x{FE45}-\x{FE46}\x{FE47}\x{FE48}\x{FE49}-\x{FE4C}\x{FE4D}-\x{FE4F}\x{FE50}\x{FE51}\x{FE52}\x{FE54}\x{FE55}\x{FE56}-\x{FE57}\x{FE58}\x{FE59}\x{FE5A}\x{FE5B}\x{FE5C}\x{FE5D}\x{FE5E}\x{FE5F}\x{FE60}-\x{FE61}\x{FE62}\x{FE63}\x{FE64}-\x{FE66}\x{FE68}\x{FE69}\x{FE6A}\x{FE6B}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FEFF}\x{FF01}-\x{FF02}\x{FF03}\x{FF04}\x{FF05}\x{FF06}-\x{FF07}\x{FF08}\x{FF09}\x{FF0A}\x{FF0B}\x{FF0C}\x{FF0D}\x{FF0E}-\x{FF0F}\x{FF1A}\x{FF1B}\x{FF1C}-\x{FF1E}\x{FF1F}-\x{FF20}\x{FF3B}\x{FF3C}\x{FF3D}\x{FF3E}\x{FF3F}\x{FF40}\x{FF5B}\x{FF5C}\x{FF5D}\x{FF5E}\x{FF5F}\x{FF60}\x{FF61}\x{FF62}\x{FF63}\x{FF64}-\x{FF65}\x{FFE0}-\x{FFE1}\x{FFE2}\x{FFE3}\x{FFE4}\x{FFE5}-\x{FFE6}\x{FFE8}\x{FFE9}-\x{FFEC}\x{FFED}-\x{FFEE}\x{FFF0}-\x{FFF8}\x{FFF9}-\x{FFFB}\x{FFFC}-\x{FFFD}\x{FFFE}-\x{FFFF}\x{10101}\x{10140}-\x{10174}\x{10175}-\x{10178}\x{10179}-\x{10189}\x{1018A}-\x{1018B}\x{1018C}\x{10190}-\x{1019C}\x{101A0}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{1091F}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A01}-\x{10A03}\x{10A04}\x{10A05}-\x{10A06}\x{10A07}-\x{10A0B}\x{10A0C}-\x{10A0F}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A38}-\x{10A3A}\x{10A3B}-\x{10A3E}\x{10A3F}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE5}-\x{10AE6}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B39}-\x{10B3F}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D24}-\x{10D27}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAB}-\x{10EAC}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F46}-\x{10F50}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{11001}\x{11038}-\x{11046}\x{11052}-\x{11065}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{11660}-\x{1166C}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{11FD5}-\x{11FDC}\x{11FDD}-\x{11FE0}\x{11FE1}-\x{11FF1}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE2}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D200}-\x{1D241}\x{1D242}-\x{1D244}\x{1D245}\x{1D300}-\x{1D356}\x{1D6DB}\x{1D715}\x{1D74F}\x{1D789}\x{1D7C3}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E2FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D0}-\x{1E8D6}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E944}-\x{1E94A}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF0}-\x{1EEF1}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F000}-\x{1F02B}\x{1F030}-\x{1F093}\x{1F0A0}-\x{1F0AE}\x{1F0B1}-\x{1F0BF}\x{1F0C1}-\x{1F0CF}\x{1F0D1}-\x{1F0F5}\x{1F10B}-\x{1F10C}\x{1F10D}-\x{1F10F}\x{1F12F}\x{1F16A}-\x{1F16F}\x{1F1AD}\x{1F260}-\x{1F265}\x{1F300}-\x{1F3FA}\x{1F3FB}-\x{1F3FF}\x{1F400}-\x{1F6D7}\x{1F6E0}-\x{1F6EC}\x{1F6F0}-\x{1F6FC}\x{1F700}-\x{1F773}\x{1F780}-\x{1F7D8}\x{1F7E0}-\x{1F7EB}\x{1F800}-\x{1F80B}\x{1F810}-\x{1F847}\x{1F850}-\x{1F859}\x{1F860}-\x{1F887}\x{1F890}-\x{1F8AD}\x{1F8B0}-\x{1F8B1}\x{1F900}-\x{1F978}\x{1F97A}-\x{1F9CB}\x{1F9CD}-\x{1FA53}\x{1FA60}-\x{1FA6D}\x{1FA70}-\x{1FA74}\x{1FA78}-\x{1FA7A}\x{1FA80}-\x{1FA86}\x{1FA90}-\x{1FAA8}\x{1FAB0}-\x{1FAB6}\x{1FAC0}-\x{1FAC2}\x{1FAD0}-\x{1FAD6}\x{1FB00}-\x{1FB92}\x{1FB94}-\x{1FBCA}\x{1FFFE}-\x{1FFFF}\x{2FFFE}-\x{2FFFF}\x{3FFFE}-\x{3FFFF}\x{4FFFE}-\x{4FFFF}\x{5FFFE}-\x{5FFFF}\x{6FFFE}-\x{6FFFF}\x{7FFFE}-\x{7FFFF}\x{8FFFE}-\x{8FFFF}\x{9FFFE}-\x{9FFFF}\x{AFFFE}-\x{AFFFF}\x{BFFFE}-\x{BFFFF}\x{CFFFE}-\x{CFFFF}\x{DFFFE}-\x{E0000}\x{E0001}\x{E0002}-\x{E001F}\x{E0020}-\x{E007F}\x{E0080}-\x{E00FF}\x{E0100}-\x{E01EF}\x{E01F0}-\x{E0FFF}\x{EFFFE}-\x{EFFFF}\x{FFFFE}-\x{FFFFF}\x{10FFFE}-\x{10FFFF}][\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1D167}-\x{1D169}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{E0100}-\x{E01EF}]*$/u'; - public const ZWNJ = '/([\x{A872}\x{10ACD}\x{10AD7}\x{10D00}\x{10FCB}\x{0620}\x{0626}\x{0628}\x{062A}-\x{062E}\x{0633}-\x{063F}\x{0641}-\x{0647}\x{0649}-\x{064A}\x{066E}-\x{066F}\x{0678}-\x{0687}\x{069A}-\x{06BF}\x{06C1}-\x{06C2}\x{06CC}\x{06CE}\x{06D0}-\x{06D1}\x{06FA}-\x{06FC}\x{06FF}\x{0712}-\x{0714}\x{071A}-\x{071D}\x{071F}-\x{0727}\x{0729}\x{072B}\x{072D}-\x{072E}\x{074E}-\x{0758}\x{075C}-\x{076A}\x{076D}-\x{0770}\x{0772}\x{0775}-\x{0777}\x{077A}-\x{077F}\x{07CA}-\x{07EA}\x{0841}-\x{0845}\x{0848}\x{084A}-\x{0853}\x{0855}\x{0860}\x{0862}-\x{0865}\x{0868}\x{08A0}-\x{08A9}\x{08AF}-\x{08B0}\x{08B3}-\x{08B4}\x{08B6}-\x{08B8}\x{08BA}-\x{08C7}\x{1807}\x{1820}-\x{1842}\x{1843}\x{1844}-\x{1878}\x{1887}-\x{18A8}\x{18AA}\x{A840}-\x{A871}\x{10AC0}-\x{10AC4}\x{10AD3}-\x{10AD6}\x{10AD8}-\x{10ADC}\x{10ADE}-\x{10AE0}\x{10AEB}-\x{10AEE}\x{10B80}\x{10B82}\x{10B86}-\x{10B88}\x{10B8A}-\x{10B8B}\x{10B8D}\x{10B90}\x{10BAD}-\x{10BAE}\x{10D01}-\x{10D21}\x{10D23}\x{10F30}-\x{10F32}\x{10F34}-\x{10F44}\x{10F51}-\x{10F53}\x{10FB0}\x{10FB2}-\x{10FB3}\x{10FB8}\x{10FBB}-\x{10FBC}\x{10FBE}-\x{10FBF}\x{10FC1}\x{10FC4}\x{10FCA}\x{1E900}-\x{1E943}][\x{00AD}\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{061C}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{070F}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CBF}\x{0CC6}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{200B}\x{200E}-\x{200F}\x{202A}-\x{202E}\x{2060}-\x{2064}\x{206A}-\x{206F}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{FEFF}\x{FFF9}-\x{FFFB}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C3F}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{13430}-\x{13438}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{1E94B}\x{E0001}\x{E0020}-\x{E007F}\x{E0100}-\x{E01EF}]*\x{200C}[\x{00AD}\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{061C}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{070F}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CBF}\x{0CC6}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{200B}\x{200E}-\x{200F}\x{202A}-\x{202E}\x{2060}-\x{2064}\x{206A}-\x{206F}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{FEFF}\x{FFF9}-\x{FFFB}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C3F}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{13430}-\x{13438}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{1E94B}\x{E0001}\x{E0020}-\x{E007F}\x{E0100}-\x{E01EF}]*)[\x{0622}-\x{0625}\x{0627}\x{0629}\x{062F}-\x{0632}\x{0648}\x{0671}-\x{0673}\x{0675}-\x{0677}\x{0688}-\x{0699}\x{06C0}\x{06C3}-\x{06CB}\x{06CD}\x{06CF}\x{06D2}-\x{06D3}\x{06D5}\x{06EE}-\x{06EF}\x{0710}\x{0715}-\x{0719}\x{071E}\x{0728}\x{072A}\x{072C}\x{072F}\x{074D}\x{0759}-\x{075B}\x{076B}-\x{076C}\x{0771}\x{0773}-\x{0774}\x{0778}-\x{0779}\x{0840}\x{0846}-\x{0847}\x{0849}\x{0854}\x{0856}-\x{0858}\x{0867}\x{0869}-\x{086A}\x{08AA}-\x{08AC}\x{08AE}\x{08B1}-\x{08B2}\x{08B9}\x{10AC5}\x{10AC7}\x{10AC9}-\x{10ACA}\x{10ACE}-\x{10AD2}\x{10ADD}\x{10AE1}\x{10AE4}\x{10AEF}\x{10B81}\x{10B83}-\x{10B85}\x{10B89}\x{10B8C}\x{10B8E}-\x{10B8F}\x{10B91}\x{10BA9}-\x{10BAC}\x{10D22}\x{10F33}\x{10F54}\x{10FB4}-\x{10FB6}\x{10FB9}-\x{10FBA}\x{10FBD}\x{10FC2}-\x{10FC3}\x{10FC9}\x{0620}\x{0626}\x{0628}\x{062A}-\x{062E}\x{0633}-\x{063F}\x{0641}-\x{0647}\x{0649}-\x{064A}\x{066E}-\x{066F}\x{0678}-\x{0687}\x{069A}-\x{06BF}\x{06C1}-\x{06C2}\x{06CC}\x{06CE}\x{06D0}-\x{06D1}\x{06FA}-\x{06FC}\x{06FF}\x{0712}-\x{0714}\x{071A}-\x{071D}\x{071F}-\x{0727}\x{0729}\x{072B}\x{072D}-\x{072E}\x{074E}-\x{0758}\x{075C}-\x{076A}\x{076D}-\x{0770}\x{0772}\x{0775}-\x{0777}\x{077A}-\x{077F}\x{07CA}-\x{07EA}\x{0841}-\x{0845}\x{0848}\x{084A}-\x{0853}\x{0855}\x{0860}\x{0862}-\x{0865}\x{0868}\x{08A0}-\x{08A9}\x{08AF}-\x{08B0}\x{08B3}-\x{08B4}\x{08B6}-\x{08B8}\x{08BA}-\x{08C7}\x{1807}\x{1820}-\x{1842}\x{1843}\x{1844}-\x{1878}\x{1887}-\x{18A8}\x{18AA}\x{A840}-\x{A871}\x{10AC0}-\x{10AC4}\x{10AD3}-\x{10AD6}\x{10AD8}-\x{10ADC}\x{10ADE}-\x{10AE0}\x{10AEB}-\x{10AEE}\x{10B80}\x{10B82}\x{10B86}-\x{10B88}\x{10B8A}-\x{10B8B}\x{10B8D}\x{10B90}\x{10BAD}-\x{10BAE}\x{10D01}-\x{10D21}\x{10D23}\x{10F30}-\x{10F32}\x{10F34}-\x{10F44}\x{10F51}-\x{10F53}\x{10FB0}\x{10FB2}-\x{10FB3}\x{10FB8}\x{10FBB}-\x{10FBC}\x{10FBE}-\x{10FBF}\x{10FC1}\x{10FC4}\x{10FCA}\x{1E900}-\x{1E943}]/u'; + const ZWNJ = '/([\x{A872}\x{10ACD}\x{10AD7}\x{10D00}\x{10FCB}\x{0620}\x{0626}\x{0628}\x{062A}-\x{062E}\x{0633}-\x{063F}\x{0641}-\x{0647}\x{0649}-\x{064A}\x{066E}-\x{066F}\x{0678}-\x{0687}\x{069A}-\x{06BF}\x{06C1}-\x{06C2}\x{06CC}\x{06CE}\x{06D0}-\x{06D1}\x{06FA}-\x{06FC}\x{06FF}\x{0712}-\x{0714}\x{071A}-\x{071D}\x{071F}-\x{0727}\x{0729}\x{072B}\x{072D}-\x{072E}\x{074E}-\x{0758}\x{075C}-\x{076A}\x{076D}-\x{0770}\x{0772}\x{0775}-\x{0777}\x{077A}-\x{077F}\x{07CA}-\x{07EA}\x{0841}-\x{0845}\x{0848}\x{084A}-\x{0853}\x{0855}\x{0860}\x{0862}-\x{0865}\x{0868}\x{08A0}-\x{08A9}\x{08AF}-\x{08B0}\x{08B3}-\x{08B4}\x{08B6}-\x{08B8}\x{08BA}-\x{08C7}\x{1807}\x{1820}-\x{1842}\x{1843}\x{1844}-\x{1878}\x{1887}-\x{18A8}\x{18AA}\x{A840}-\x{A871}\x{10AC0}-\x{10AC4}\x{10AD3}-\x{10AD6}\x{10AD8}-\x{10ADC}\x{10ADE}-\x{10AE0}\x{10AEB}-\x{10AEE}\x{10B80}\x{10B82}\x{10B86}-\x{10B88}\x{10B8A}-\x{10B8B}\x{10B8D}\x{10B90}\x{10BAD}-\x{10BAE}\x{10D01}-\x{10D21}\x{10D23}\x{10F30}-\x{10F32}\x{10F34}-\x{10F44}\x{10F51}-\x{10F53}\x{10FB0}\x{10FB2}-\x{10FB3}\x{10FB8}\x{10FBB}-\x{10FBC}\x{10FBE}-\x{10FBF}\x{10FC1}\x{10FC4}\x{10FCA}\x{1E900}-\x{1E943}][\x{00AD}\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{061C}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{070F}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CBF}\x{0CC6}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{200B}\x{200E}-\x{200F}\x{202A}-\x{202E}\x{2060}-\x{2064}\x{206A}-\x{206F}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{FEFF}\x{FFF9}-\x{FFFB}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C3F}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{13430}-\x{13438}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{1E94B}\x{E0001}\x{E0020}-\x{E007F}\x{E0100}-\x{E01EF}]*\x{200C}[\x{00AD}\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{061C}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{070F}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CBF}\x{0CC6}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{200B}\x{200E}-\x{200F}\x{202A}-\x{202E}\x{2060}-\x{2064}\x{206A}-\x{206F}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{FEFF}\x{FFF9}-\x{FFFB}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C3F}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{13430}-\x{13438}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{1E94B}\x{E0001}\x{E0020}-\x{E007F}\x{E0100}-\x{E01EF}]*)[\x{0622}-\x{0625}\x{0627}\x{0629}\x{062F}-\x{0632}\x{0648}\x{0671}-\x{0673}\x{0675}-\x{0677}\x{0688}-\x{0699}\x{06C0}\x{06C3}-\x{06CB}\x{06CD}\x{06CF}\x{06D2}-\x{06D3}\x{06D5}\x{06EE}-\x{06EF}\x{0710}\x{0715}-\x{0719}\x{071E}\x{0728}\x{072A}\x{072C}\x{072F}\x{074D}\x{0759}-\x{075B}\x{076B}-\x{076C}\x{0771}\x{0773}-\x{0774}\x{0778}-\x{0779}\x{0840}\x{0846}-\x{0847}\x{0849}\x{0854}\x{0856}-\x{0858}\x{0867}\x{0869}-\x{086A}\x{08AA}-\x{08AC}\x{08AE}\x{08B1}-\x{08B2}\x{08B9}\x{10AC5}\x{10AC7}\x{10AC9}-\x{10ACA}\x{10ACE}-\x{10AD2}\x{10ADD}\x{10AE1}\x{10AE4}\x{10AEF}\x{10B81}\x{10B83}-\x{10B85}\x{10B89}\x{10B8C}\x{10B8E}-\x{10B8F}\x{10B91}\x{10BA9}-\x{10BAC}\x{10D22}\x{10F33}\x{10F54}\x{10FB4}-\x{10FB6}\x{10FB9}-\x{10FBA}\x{10FBD}\x{10FC2}-\x{10FC3}\x{10FC9}\x{0620}\x{0626}\x{0628}\x{062A}-\x{062E}\x{0633}-\x{063F}\x{0641}-\x{0647}\x{0649}-\x{064A}\x{066E}-\x{066F}\x{0678}-\x{0687}\x{069A}-\x{06BF}\x{06C1}-\x{06C2}\x{06CC}\x{06CE}\x{06D0}-\x{06D1}\x{06FA}-\x{06FC}\x{06FF}\x{0712}-\x{0714}\x{071A}-\x{071D}\x{071F}-\x{0727}\x{0729}\x{072B}\x{072D}-\x{072E}\x{074E}-\x{0758}\x{075C}-\x{076A}\x{076D}-\x{0770}\x{0772}\x{0775}-\x{0777}\x{077A}-\x{077F}\x{07CA}-\x{07EA}\x{0841}-\x{0845}\x{0848}\x{084A}-\x{0853}\x{0855}\x{0860}\x{0862}-\x{0865}\x{0868}\x{08A0}-\x{08A9}\x{08AF}-\x{08B0}\x{08B3}-\x{08B4}\x{08B6}-\x{08B8}\x{08BA}-\x{08C7}\x{1807}\x{1820}-\x{1842}\x{1843}\x{1844}-\x{1878}\x{1887}-\x{18A8}\x{18AA}\x{A840}-\x{A871}\x{10AC0}-\x{10AC4}\x{10AD3}-\x{10AD6}\x{10AD8}-\x{10ADC}\x{10ADE}-\x{10AE0}\x{10AEB}-\x{10AEE}\x{10B80}\x{10B82}\x{10B86}-\x{10B88}\x{10B8A}-\x{10B8B}\x{10B8D}\x{10B90}\x{10BAD}-\x{10BAE}\x{10D01}-\x{10D21}\x{10D23}\x{10F30}-\x{10F32}\x{10F34}-\x{10F44}\x{10F51}-\x{10F53}\x{10FB0}\x{10FB2}-\x{10FB3}\x{10FB8}\x{10FBB}-\x{10FBC}\x{10FBE}-\x{10FBF}\x{10FC1}\x{10FC4}\x{10FCA}\x{1E900}-\x{1E943}]/u'; } diff --git a/includes/vendor/symfony/polyfill-intl-idn/bootstrap80.php b/includes/vendor/symfony/polyfill-intl-idn/bootstrap80.php index 6c2b72923..a62c2d69b 100644 --- a/includes/vendor/symfony/polyfill-intl-idn/bootstrap80.php +++ b/includes/vendor/symfony/polyfill-intl-idn/bootstrap80.php @@ -74,9 +74,6 @@ if (!defined('IDNA_NONTRANSITIONAL_TO_UNICODE')) { define('IDNA_NONTRANSITIONAL_TO_UNICODE', 32); } -if (!defined('INTL_IDNA_VARIANT_2003')) { - define('INTL_IDNA_VARIANT_2003', 0); -} if (!defined('INTL_IDNA_VARIANT_UTS46')) { define('INTL_IDNA_VARIANT_UTS46', 1); } @@ -121,8 +118,8 @@ } if (!function_exists('idn_to_ascii')) { - function idn_to_ascii(string $domain, int $flags = 0, int $variant = INTL_IDNA_VARIANT_UTS46, &$idna_info = null): string|false { return p\Idn::idn_to_ascii($domain, $flags, $variant, $idna_info); } + function idn_to_ascii(?string $domain, ?int $flags = IDNA_DEFAULT, ?int $variant = INTL_IDNA_VARIANT_UTS46, &$idna_info = null): string|false { return p\Idn::idn_to_ascii((string) $domain, (int) $flags, (int) $variant, $idna_info); } } if (!function_exists('idn_to_utf8')) { - function idn_to_utf8(string $domain, int $flags = 0, int $variant = INTL_IDNA_VARIANT_UTS46, &$idna_info = null): string|false { return p\Idn::idn_to_utf8($domain, $flags, $variant, $idna_info); } + function idn_to_utf8(?string $domain, ?int $flags = IDNA_DEFAULT, ?int $variant = INTL_IDNA_VARIANT_UTS46, &$idna_info = null): string|false { return p\Idn::idn_to_utf8((string) $domain, (int) $flags, (int) $variant, $idna_info); } } diff --git a/includes/vendor/symfony/polyfill-intl-idn/composer.json b/includes/vendor/symfony/polyfill-intl-idn/composer.json index 450d1e7b2..760debcd2 100644 --- a/includes/vendor/symfony/polyfill-intl-idn/composer.json +++ b/includes/vendor/symfony/polyfill-intl-idn/composer.json @@ -20,9 +20,8 @@ } ], "require": { - "php": ">=7.1", - "symfony/polyfill-intl-normalizer": "^1.10", - "symfony/polyfill-php72": "^1.10" + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" }, "autoload": { "psr-4": { "Symfony\\Polyfill\\Intl\\Idn\\": "" }, @@ -33,9 +32,6 @@ }, "minimum-stability": "dev", "extra": { - "branch-alias": { - "dev-main": "1.22-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" diff --git a/includes/vendor/symfony/polyfill-intl-normalizer/LICENSE b/includes/vendor/symfony/polyfill-intl-normalizer/LICENSE index 4cd8bdd30..6e3afce69 100644 --- a/includes/vendor/symfony/polyfill-intl-normalizer/LICENSE +++ b/includes/vendor/symfony/polyfill-intl-normalizer/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015-2019 Fabien Potencier +Copyright (c) 2015-present Fabien Potencier 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/includes/vendor/symfony/polyfill-intl-normalizer/Normalizer.php b/includes/vendor/symfony/polyfill-intl-normalizer/Normalizer.php index 4443c2322..81704ab37 100644 --- a/includes/vendor/symfony/polyfill-intl-normalizer/Normalizer.php +++ b/includes/vendor/symfony/polyfill-intl-normalizer/Normalizer.php @@ -90,7 +90,7 @@ public static function normalize(string $s, int $form = self::FORM_C) self::$cC = self::getData('combiningClass'); } - if (null !== $mbEncoding = (2 /* MB_OVERLOAD_STRING */ & (int) ini_get('mbstring.func_overload')) ? mb_internal_encoding() : null) { + if (null !== $mbEncoding = (2 /* MB_OVERLOAD_STRING */ & (int) \ini_get('mbstring.func_overload')) ? mb_internal_encoding() : null) { mb_internal_encoding('8bit'); } diff --git a/includes/vendor/symfony/polyfill-intl-normalizer/README.md b/includes/vendor/symfony/polyfill-intl-normalizer/README.md index 15060c5f1..b9b762e85 100644 --- a/includes/vendor/symfony/polyfill-intl-normalizer/README.md +++ b/includes/vendor/symfony/polyfill-intl-normalizer/README.md @@ -6,7 +6,7 @@ This component provides a fallback implementation for the by the [Intl](https://php.net/intl) extension. More information can be found in the -[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). License ======= diff --git a/includes/vendor/symfony/polyfill-intl-normalizer/bootstrap80.php b/includes/vendor/symfony/polyfill-intl-normalizer/bootstrap80.php index c9a29d7a9..e36d1a947 100644 --- a/includes/vendor/symfony/polyfill-intl-normalizer/bootstrap80.php +++ b/includes/vendor/symfony/polyfill-intl-normalizer/bootstrap80.php @@ -12,8 +12,8 @@ use Symfony\Polyfill\Intl\Normalizer as p; if (!function_exists('normalizer_is_normalized')) { - function normalizer_is_normalized(string $string, int $form = p\Normalizer::FORM_C): bool { return p\Normalizer::isNormalized($string, $form); } + function normalizer_is_normalized(?string $string, ?int $form = p\Normalizer::FORM_C): bool { return p\Normalizer::isNormalized((string) $string, (int) $form); } } if (!function_exists('normalizer_normalize')) { - function normalizer_normalize(string $string, int $form = p\Normalizer::FORM_C): string|false { return p\Normalizer::normalize($string, $form); } + function normalizer_normalize(?string $string, ?int $form = p\Normalizer::FORM_C): string|false { return p\Normalizer::normalize((string) $string, (int) $form); } } diff --git a/includes/vendor/symfony/polyfill-intl-normalizer/composer.json b/includes/vendor/symfony/polyfill-intl-normalizer/composer.json index 8f4cfb4dc..9bd04e887 100644 --- a/includes/vendor/symfony/polyfill-intl-normalizer/composer.json +++ b/includes/vendor/symfony/polyfill-intl-normalizer/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=7.1" + "php": ">=7.2" }, "autoload": { "psr-4": { "Symfony\\Polyfill\\Intl\\Normalizer\\": "" }, @@ -28,9 +28,6 @@ }, "minimum-stability": "dev", "extra": { - "branch-alias": { - "dev-main": "1.22-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" diff --git a/includes/vendor/symfony/polyfill-mbstring/LICENSE b/includes/vendor/symfony/polyfill-mbstring/LICENSE index 4cd8bdd30..6e3afce69 100644 --- a/includes/vendor/symfony/polyfill-mbstring/LICENSE +++ b/includes/vendor/symfony/polyfill-mbstring/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015-2019 Fabien Potencier +Copyright (c) 2015-present Fabien Potencier 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/includes/vendor/symfony/polyfill-mbstring/Mbstring.php b/includes/vendor/symfony/polyfill-mbstring/Mbstring.php index 15503bc9d..3d45c9d9a 100644 --- a/includes/vendor/symfony/polyfill-mbstring/Mbstring.php +++ b/includes/vendor/symfony/polyfill-mbstring/Mbstring.php @@ -48,6 +48,11 @@ * - mb_strstr - Finds first occurrence of a string within another * - mb_strwidth - Return width of string * - mb_substr_count - Count the number of substring occurrences + * - mb_ucfirst - Make a string's first character uppercase + * - mb_lcfirst - Make a string's first character lowercase + * - mb_trim - Strip whitespace (or other characters) from the beginning and end of a string + * - mb_ltrim - Strip whitespace (or other characters) from the beginning of a string + * - mb_rtrim - Strip whitespace (or other characters) from the end of a string * * Not implemented: * - mb_convert_kana - Convert "kana" one from another ("zen-kaku", "han-kaku" and more) @@ -67,19 +72,29 @@ */ final class Mbstring { - const MB_CASE_FOLD = PHP_INT_MAX; + public const MB_CASE_FOLD = \PHP_INT_MAX; - private static $encodingList = array('ASCII', 'UTF-8'); + private const SIMPLE_CASE_FOLD = [ + ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"], + ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'], + ]; + + private static $encodingList = ['ASCII', 'UTF-8']; private static $language = 'neutral'; private static $internalEncoding = 'UTF-8'; - private static $caseFold = array( - array('µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"), - array('μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'), - ); public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null) { - if (\is_array($fromEncoding) || false !== strpos($fromEncoding, ',')) { + if (\is_array($s)) { + $r = []; + foreach ($s as $str) { + $r[] = self::mb_convert_encoding($str, $toEncoding, $fromEncoding); + } + + return $r; + } + + if (\is_array($fromEncoding) || (null !== $fromEncoding && false !== strpos($fromEncoding, ','))) { $fromEncoding = self::mb_detect_encoding($s, $fromEncoding); } else { $fromEncoding = self::getEncoding($fromEncoding); @@ -104,24 +119,22 @@ public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null $s = iconv($fromEncoding, 'UTF-8//IGNORE', $s); } - return preg_replace_callback('/[\x80-\xFF]+/', array(__CLASS__, 'html_encoding_callback'), $s); + return preg_replace_callback('/[\x80-\xFF]+/', [__CLASS__, 'html_encoding_callback'], $s); } if ('HTML-ENTITIES' === $fromEncoding) { - $s = html_entity_decode($s, ENT_COMPAT, 'UTF-8'); + $s = html_entity_decode($s, \ENT_COMPAT, 'UTF-8'); $fromEncoding = 'UTF-8'; } return iconv($fromEncoding, $toEncoding.'//IGNORE', $s); } - public static function mb_convert_variables($toEncoding, $fromEncoding, &$a = null, &$b = null, &$c = null, &$d = null, &$e = null, &$f = null) + public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars) { - $vars = array(&$a, &$b, &$c, &$d, &$e, &$f); - $ok = true; array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) { - if (false === $v = Mbstring::mb_convert_encoding($v, $toEncoding, $fromEncoding)) { + if (false === $v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding)) { $ok = false; } }); @@ -136,23 +149,23 @@ public static function mb_decode_mimeheader($s) public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null) { - trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', E_USER_WARNING); + trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', \E_USER_WARNING); } public static function mb_decode_numericentity($s, $convmap, $encoding = null) { - if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) { - trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', E_USER_WARNING); + if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) { + trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING); return null; } - if (!\is_array($convmap) || !$convmap) { + if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) { return false; } if (null !== $encoding && !\is_scalar($encoding)) { - trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', E_USER_WARNING); + trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING); return ''; // Instead of null (cf. mb_encode_numericentity). } @@ -185,7 +198,7 @@ public static function mb_decode_numericentity($s, $convmap, $encoding = null) $c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1]; for ($i = 0; $i < $cnt; $i += 4) { if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) { - return Mbstring::mb_chr($c - $convmap[$i + 2]); + return self::mb_chr($c - $convmap[$i + 2]); } } @@ -201,24 +214,24 @@ public static function mb_decode_numericentity($s, $convmap, $encoding = null) public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false) { - if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) { - trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', E_USER_WARNING); + if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) { + trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING); return null; } - if (!\is_array($convmap) || !$convmap) { + if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) { return false; } if (null !== $encoding && !\is_scalar($encoding)) { - trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', E_USER_WARNING); + trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING); return null; // Instead of '' (cf. mb_decode_numericentity). } if (null !== $is_hex && !\is_scalar($is_hex)) { - trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', E_USER_WARNING); + trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', \E_USER_WARNING); return null; } @@ -239,7 +252,7 @@ public static function mb_encode_numericentity($s, $convmap, $encoding = null, $ $s = iconv($encoding, 'UTF-8//IGNORE', $s); } - static $ulenMask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4); + static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4]; $cnt = floor(\count($convmap) / 4) * 4; $i = 0; @@ -287,14 +300,14 @@ public static function mb_convert_case($s, $mode, $encoding = null) $s = iconv($encoding, 'UTF-8//IGNORE', $s); } - if (MB_CASE_TITLE == $mode) { + if (\MB_CASE_TITLE == $mode) { static $titleRegexp = null; if (null === $titleRegexp) { $titleRegexp = self::getData('titleCaseRegexp'); } - $s = preg_replace_callback($titleRegexp, array(__CLASS__, 'title_case'), $s); + $s = preg_replace_callback($titleRegexp, [__CLASS__, 'title_case'], $s); } else { - if (MB_CASE_UPPER == $mode) { + if (\MB_CASE_UPPER == $mode) { static $upper = null; if (null === $upper) { $upper = self::getData('upperCase'); @@ -302,7 +315,11 @@ public static function mb_convert_case($s, $mode, $encoding = null) $map = $upper; } else { if (self::MB_CASE_FOLD === $mode) { - $s = str_replace(self::$caseFold[0], self::$caseFold[1], $s); + static $caseFolding = null; + if (null === $caseFolding) { + $caseFolding = self::getData('caseFolding'); + } + $s = strtr($s, $caseFolding); } static $lower = null; @@ -312,7 +329,7 @@ public static function mb_convert_case($s, $mode, $encoding = null) $map = $lower; } - static $ulenMask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4); + static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4]; $i = 0; $len = \strlen($s); @@ -353,15 +370,19 @@ public static function mb_internal_encoding($encoding = null) return self::$internalEncoding; } - $encoding = self::getEncoding($encoding); + $normalizedEncoding = self::getEncoding($encoding); - if ('UTF-8' === $encoding || false !== @iconv($encoding, $encoding, ' ')) { - self::$internalEncoding = $encoding; + if ('UTF-8' === $normalizedEncoding || false !== @iconv($normalizedEncoding, $normalizedEncoding, ' ')) { + self::$internalEncoding = $normalizedEncoding; return true; } - return false; + if (80000 > \PHP_VERSION_ID) { + return false; + } + + throw new \ValueError(sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding)); } public static function mb_language($lang = null) @@ -370,20 +391,24 @@ public static function mb_language($lang = null) return self::$language; } - switch ($lang = strtolower($lang)) { + switch ($normalizedLang = strtolower($lang)) { case 'uni': case 'neutral': - self::$language = $lang; + self::$language = $normalizedLang; return true; } - return false; + if (80000 > \PHP_VERSION_ID) { + return false; + } + + throw new \ValueError(sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang)); } public static function mb_list_encodings() { - return array('UTF-8'); + return ['UTF-8']; } public static function mb_encoding_aliases($encoding) @@ -391,7 +416,7 @@ public static function mb_encoding_aliases($encoding) switch (strtoupper($encoding)) { case 'UTF8': case 'UTF-8': - return array('utf8'); + return ['utf8']; } return false; @@ -406,7 +431,20 @@ public static function mb_check_encoding($var = null, $encoding = null) $encoding = self::$internalEncoding; } - return self::mb_detect_encoding($var, array($encoding)) || false !== @iconv($encoding, $encoding, $var); + if (!\is_array($var)) { + return self::mb_detect_encoding($var, [$encoding]) || false !== @iconv($encoding, $encoding, $var); + } + + foreach ($var as $key => $value) { + if (!self::mb_check_encoding($key, $encoding)) { + return false; + } + if (!self::mb_check_encoding($value, $encoding)) { + return false; + } + } + + return true; } public static function mb_detect_encoding($str, $encodingList = null, $strict = false) @@ -493,9 +531,13 @@ public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = nu $needle = (string) $needle; if ('' === $needle) { - trigger_error(__METHOD__.': Empty delimiter', E_USER_WARNING); + if (80000 > \PHP_VERSION_ID) { + trigger_error(__METHOD__.': Empty delimiter', \E_USER_WARNING); - return false; + return false; + } + + return 0; } return iconv_strpos($haystack, $needle, $offset, $encoding); @@ -521,23 +563,29 @@ public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = n } } - $pos = iconv_strrpos($haystack, $needle, $encoding); + $pos = '' !== $needle || 80000 > \PHP_VERSION_ID + ? iconv_strrpos($haystack, $needle, $encoding) + : self::mb_strlen($haystack, $encoding); return false !== $pos ? $offset + $pos : false; } public static function mb_str_split($string, $split_length = 1, $encoding = null) { - if (null !== $string && !\is_scalar($string) && !(\is_object($string) && \method_exists($string, '__toString'))) { - trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', E_USER_WARNING); + if (null !== $string && !\is_scalar($string) && !(\is_object($string) && method_exists($string, '__toString'))) { + trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', \E_USER_WARNING); return null; } if (1 > $split_length = (int) $split_length) { - trigger_error('The length of each segment must be greater than zero', E_USER_WARNING); + if (80000 > \PHP_VERSION_ID) { + trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING); - return false; + return false; + } + + throw new \ValueError('Argument #2 ($length) must be greater than 0'); } if (null === $encoding) { @@ -552,10 +600,10 @@ public static function mb_str_split($string, $split_length = 1, $encoding = null } $rx .= '.{'.$split_length.'})/us'; - return preg_split($rx, $string, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + return preg_split($rx, $string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY); } - $result = array(); + $result = []; $length = mb_strlen($string, $encoding); for ($i = 0; $i < $length; $i += $split_length) { @@ -567,21 +615,30 @@ public static function mb_str_split($string, $split_length = 1, $encoding = null public static function mb_strtolower($s, $encoding = null) { - return self::mb_convert_case($s, MB_CASE_LOWER, $encoding); + return self::mb_convert_case($s, \MB_CASE_LOWER, $encoding); } public static function mb_strtoupper($s, $encoding = null) { - return self::mb_convert_case($s, MB_CASE_UPPER, $encoding); + return self::mb_convert_case($s, \MB_CASE_UPPER, $encoding); } public static function mb_substitute_character($c = null) { + if (null === $c) { + return 'none'; + } if (0 === strcasecmp($c, 'none')) { return true; } + if (80000 > \PHP_VERSION_ID) { + return false; + } + if (\is_int($c) || 'long' === $c || 'entity' === $c) { + return false; + } - return null !== $c ? false : 'none'; + throw new \ValueError('Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint'); } public static function mb_substr($s, $start, $length = null, $encoding = null) @@ -612,8 +669,10 @@ public static function mb_substr($s, $start, $length = null, $encoding = null) public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { - $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding); - $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding); + [$haystack, $needle] = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], [ + self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding), + self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding), + ]); return self::mb_strpos($haystack, $needle, $offset, $encoding); } @@ -629,10 +688,11 @@ public static function mb_strrchr($haystack, $needle, $part = false, $encoding = { $encoding = self::getEncoding($encoding); if ('CP850' === $encoding || 'ASCII' === $encoding) { - return strrchr($haystack, $needle, $part); + $pos = strrpos($haystack, $needle); + } else { + $needle = self::mb_substr($needle, 0, 1, $encoding); + $pos = iconv_strrpos($haystack, $needle, $encoding); } - $needle = self::mb_substr($needle, 0, 1, $encoding); - $pos = iconv_strrpos($haystack, $needle, $encoding); return self::getSubpart($pos, $part, $haystack, $encoding); } @@ -647,8 +707,11 @@ public static function mb_strrichr($haystack, $needle, $part = false, $encoding public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { - $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding); - $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding); + $haystack = self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding); + $needle = self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding); + + $haystack = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $haystack); + $needle = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $needle); return self::mb_strrpos($haystack, $needle, $offset, $encoding); } @@ -668,7 +731,7 @@ public static function mb_strstr($haystack, $needle, $part = false, $encoding = public static function mb_get_info($type = 'all') { - $info = array( + $info = [ 'internal_encoding' => self::$internalEncoding, 'http_output' => 'pass', 'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)', @@ -683,7 +746,7 @@ public static function mb_get_info($type = 'all') 'detect_order' => self::$encodingList, 'substitute_character' => 'none', 'strict_detection' => 'Off', - ); + ]; if ('all' === $type) { return $info; @@ -771,6 +834,69 @@ public static function mb_ord($s, $encoding = null) return $code; } + public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null): string + { + if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], true)) { + throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH'); + } + + if (null === $encoding) { + $encoding = self::mb_internal_encoding(); + } else { + self::assertEncoding($encoding, 'mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given'); + } + + if (self::mb_strlen($pad_string, $encoding) <= 0) { + throw new \ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string'); + } + + $paddingRequired = $length - self::mb_strlen($string, $encoding); + + if ($paddingRequired < 1) { + return $string; + } + + switch ($pad_type) { + case \STR_PAD_LEFT: + return self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding).$string; + case \STR_PAD_RIGHT: + return $string.self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding); + default: + $leftPaddingLength = floor($paddingRequired / 2); + $rightPaddingLength = $paddingRequired - $leftPaddingLength; + + return self::mb_substr(str_repeat($pad_string, $leftPaddingLength), 0, $leftPaddingLength, $encoding).$string.self::mb_substr(str_repeat($pad_string, $rightPaddingLength), 0, $rightPaddingLength, $encoding); + } + } + + public static function mb_ucfirst(string $string, ?string $encoding = null): string + { + if (null === $encoding) { + $encoding = self::mb_internal_encoding(); + } else { + self::assertEncoding($encoding, 'mb_ucfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given'); + } + + $firstChar = mb_substr($string, 0, 1, $encoding); + $firstChar = mb_convert_case($firstChar, \MB_CASE_TITLE, $encoding); + + return $firstChar.mb_substr($string, 1, null, $encoding); + } + + public static function mb_lcfirst(string $string, ?string $encoding = null): string + { + if (null === $encoding) { + $encoding = self::mb_internal_encoding(); + } else { + self::assertEncoding($encoding, 'mb_lcfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given'); + } + + $firstChar = mb_substr($string, 0, 1, $encoding); + $firstChar = mb_convert_case($firstChar, \MB_CASE_LOWER, $encoding); + + return $firstChar.mb_substr($string, 1, null, $encoding); + } + private static function getSubpart($pos, $part, $haystack, $encoding) { if (false === $pos) { @@ -787,7 +913,7 @@ private static function html_encoding_callback(array $m) { $i = 1; $entities = ''; - $m = unpack('C*', htmlentities($m[0], ENT_COMPAT, 'UTF-8')); + $m = unpack('C*', htmlentities($m[0], \ENT_COMPAT, 'UTF-8')); while (isset($m[$i])) { if (0x80 > $m[$i]) { @@ -810,7 +936,7 @@ private static function html_encoding_callback(array $m) private static function title_case(array $s) { - return self::mb_convert_case($s[1], MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], MB_CASE_LOWER, 'UTF-8'); + return self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8'); } private static function getData($file) @@ -844,4 +970,76 @@ private static function getEncoding($encoding) return $encoding; } + + public static function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string + { + return self::mb_internal_trim('{^[%s]+|[%1$s]+$}Du', $string, $characters, $encoding, __FUNCTION__); + } + + public static function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string + { + return self::mb_internal_trim('{^[%s]+}Du', $string, $characters, $encoding, __FUNCTION__); + } + + public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string + { + return self::mb_internal_trim('{[%s]+$}D', $string, $characters, $encoding, __FUNCTION__); + } + + private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function): string + { + if (null === $encoding) { + $encoding = self::mb_internal_encoding(); + } else { + self::assertEncoding($encoding, $function.'(): Argument #3 ($encoding) must be a valid encoding, "%s" given'); + } + + if ('' === $characters) { + return null === $encoding ? $string : self::mb_convert_encoding($string, $encoding); + } + + if ('UTF-8' === $encoding) { + $encoding = null; + if (!preg_match('//u', $string)) { + $string = @iconv('UTF-8', 'UTF-8//IGNORE', $string); + } + if (null !== $characters && !preg_match('//u', $characters)) { + $characters = @iconv('UTF-8', 'UTF-8//IGNORE', $characters); + } + } else { + $string = iconv($encoding, 'UTF-8//IGNORE', $string); + + if (null !== $characters) { + $characters = iconv($encoding, 'UTF-8//IGNORE', $characters); + } + } + + if (null === $characters) { + $characters = "\\0 \f\n\r\t\v\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}"; + } else { + $characters = preg_quote($characters); + } + + $string = preg_replace(sprintf($regex, $characters), '', $string); + + if (null === $encoding) { + return $string; + } + + return iconv('UTF-8', $encoding.'//IGNORE', $string); + } + + private static function assertEncoding(string $encoding, string $errorFormat): void + { + try { + $validEncoding = @self::mb_check_encoding('', $encoding); + } catch (\ValueError $e) { + throw new \ValueError(sprintf($errorFormat, $encoding)); + } + + // BC for PHP 7.3 and lower + if (!$validEncoding) { + throw new \ValueError(sprintf($errorFormat, $encoding)); + } + } } diff --git a/includes/vendor/symfony/polyfill-mbstring/README.md b/includes/vendor/symfony/polyfill-mbstring/README.md index 4efb599d8..478b40da2 100644 --- a/includes/vendor/symfony/polyfill-mbstring/README.md +++ b/includes/vendor/symfony/polyfill-mbstring/README.md @@ -5,7 +5,7 @@ This component provides a partial, native PHP implementation for the [Mbstring](https://php.net/mbstring) extension. More information can be found in the -[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). License ======= diff --git a/includes/vendor/symfony/polyfill-mbstring/Resources/unidata/caseFolding.php b/includes/vendor/symfony/polyfill-mbstring/Resources/unidata/caseFolding.php new file mode 100644 index 000000000..512bba0bf --- /dev/null +++ b/includes/vendor/symfony/polyfill-mbstring/Resources/unidata/caseFolding.php @@ -0,0 +1,119 @@ + 'i̇', + 'µ' => 'μ', + 'ſ' => 's', + 'ͅ' => 'ι', + 'ς' => 'σ', + 'ϐ' => 'β', + 'ϑ' => 'θ', + 'ϕ' => 'φ', + 'ϖ' => 'π', + 'ϰ' => 'κ', + 'ϱ' => 'ρ', + 'ϵ' => 'ε', + 'ẛ' => 'ṡ', + 'ι' => 'ι', + 'ß' => 'ss', + 'ʼn' => 'ʼn', + 'ǰ' => 'ǰ', + 'ΐ' => 'ΐ', + 'ΰ' => 'ΰ', + 'և' => 'եւ', + 'ẖ' => 'ẖ', + 'ẗ' => 'ẗ', + 'ẘ' => 'ẘ', + 'ẙ' => 'ẙ', + 'ẚ' => 'aʾ', + 'ẞ' => 'ss', + 'ὐ' => 'ὐ', + 'ὒ' => 'ὒ', + 'ὔ' => 'ὔ', + 'ὖ' => 'ὖ', + 'ᾀ' => 'ἀι', + 'ᾁ' => 'ἁι', + 'ᾂ' => 'ἂι', + 'ᾃ' => 'ἃι', + 'ᾄ' => 'ἄι', + 'ᾅ' => 'ἅι', + 'ᾆ' => 'ἆι', + 'ᾇ' => 'ἇι', + 'ᾈ' => 'ἀι', + 'ᾉ' => 'ἁι', + 'ᾊ' => 'ἂι', + 'ᾋ' => 'ἃι', + 'ᾌ' => 'ἄι', + 'ᾍ' => 'ἅι', + 'ᾎ' => 'ἆι', + 'ᾏ' => 'ἇι', + 'ᾐ' => 'ἠι', + 'ᾑ' => 'ἡι', + 'ᾒ' => 'ἢι', + 'ᾓ' => 'ἣι', + 'ᾔ' => 'ἤι', + 'ᾕ' => 'ἥι', + 'ᾖ' => 'ἦι', + 'ᾗ' => 'ἧι', + 'ᾘ' => 'ἠι', + 'ᾙ' => 'ἡι', + 'ᾚ' => 'ἢι', + 'ᾛ' => 'ἣι', + 'ᾜ' => 'ἤι', + 'ᾝ' => 'ἥι', + 'ᾞ' => 'ἦι', + 'ᾟ' => 'ἧι', + 'ᾠ' => 'ὠι', + 'ᾡ' => 'ὡι', + 'ᾢ' => 'ὢι', + 'ᾣ' => 'ὣι', + 'ᾤ' => 'ὤι', + 'ᾥ' => 'ὥι', + 'ᾦ' => 'ὦι', + 'ᾧ' => 'ὧι', + 'ᾨ' => 'ὠι', + 'ᾩ' => 'ὡι', + 'ᾪ' => 'ὢι', + 'ᾫ' => 'ὣι', + 'ᾬ' => 'ὤι', + 'ᾭ' => 'ὥι', + 'ᾮ' => 'ὦι', + 'ᾯ' => 'ὧι', + 'ᾲ' => 'ὰι', + 'ᾳ' => 'αι', + 'ᾴ' => 'άι', + 'ᾶ' => 'ᾶ', + 'ᾷ' => 'ᾶι', + 'ᾼ' => 'αι', + 'ῂ' => 'ὴι', + 'ῃ' => 'ηι', + 'ῄ' => 'ήι', + 'ῆ' => 'ῆ', + 'ῇ' => 'ῆι', + 'ῌ' => 'ηι', + 'ῒ' => 'ῒ', + 'ῖ' => 'ῖ', + 'ῗ' => 'ῗ', + 'ῢ' => 'ῢ', + 'ῤ' => 'ῤ', + 'ῦ' => 'ῦ', + 'ῧ' => 'ῧ', + 'ῲ' => 'ὼι', + 'ῳ' => 'ωι', + 'ῴ' => 'ώι', + 'ῶ' => 'ῶ', + 'ῷ' => 'ῶι', + 'ῼ' => 'ωι', + 'ff' => 'ff', + 'fi' => 'fi', + 'fl' => 'fl', + 'ffi' => 'ffi', + 'ffl' => 'ffl', + 'ſt' => 'st', + 'st' => 'st', + 'ﬓ' => 'մն', + 'ﬔ' => 'մե', + 'ﬕ' => 'մի', + 'ﬖ' => 'վն', + 'ﬗ' => 'մխ', +]; diff --git a/includes/vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php b/includes/vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php index e6fbfa64e..fac60b081 100644 --- a/includes/vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php +++ b/includes/vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php @@ -1,6 +1,6 @@ 'a', 'B' => 'b', 'C' => 'c', @@ -81,7 +81,7 @@ 'Ī' => 'ī', 'Ĭ' => 'ĭ', 'Į' => 'į', - 'İ' => 'i', + 'İ' => 'i̇', 'IJ' => 'ij', 'Ĵ' => 'ĵ', 'Ķ' => 'ķ', @@ -510,6 +510,138 @@ 'Ⴥ' => 'ⴥ', 'Ⴧ' => 'ⴧ', 'Ⴭ' => 'ⴭ', + 'Ꭰ' => 'ꭰ', + 'Ꭱ' => 'ꭱ', + 'Ꭲ' => 'ꭲ', + 'Ꭳ' => 'ꭳ', + 'Ꭴ' => 'ꭴ', + 'Ꭵ' => 'ꭵ', + 'Ꭶ' => 'ꭶ', + 'Ꭷ' => 'ꭷ', + 'Ꭸ' => 'ꭸ', + 'Ꭹ' => 'ꭹ', + 'Ꭺ' => 'ꭺ', + 'Ꭻ' => 'ꭻ', + 'Ꭼ' => 'ꭼ', + 'Ꭽ' => 'ꭽ', + 'Ꭾ' => 'ꭾ', + 'Ꭿ' => 'ꭿ', + 'Ꮀ' => 'ꮀ', + 'Ꮁ' => 'ꮁ', + 'Ꮂ' => 'ꮂ', + 'Ꮃ' => 'ꮃ', + 'Ꮄ' => 'ꮄ', + 'Ꮅ' => 'ꮅ', + 'Ꮆ' => 'ꮆ', + 'Ꮇ' => 'ꮇ', + 'Ꮈ' => 'ꮈ', + 'Ꮉ' => 'ꮉ', + 'Ꮊ' => 'ꮊ', + 'Ꮋ' => 'ꮋ', + 'Ꮌ' => 'ꮌ', + 'Ꮍ' => 'ꮍ', + 'Ꮎ' => 'ꮎ', + 'Ꮏ' => 'ꮏ', + 'Ꮐ' => 'ꮐ', + 'Ꮑ' => 'ꮑ', + 'Ꮒ' => 'ꮒ', + 'Ꮓ' => 'ꮓ', + 'Ꮔ' => 'ꮔ', + 'Ꮕ' => 'ꮕ', + 'Ꮖ' => 'ꮖ', + 'Ꮗ' => 'ꮗ', + 'Ꮘ' => 'ꮘ', + 'Ꮙ' => 'ꮙ', + 'Ꮚ' => 'ꮚ', + 'Ꮛ' => 'ꮛ', + 'Ꮜ' => 'ꮜ', + 'Ꮝ' => 'ꮝ', + 'Ꮞ' => 'ꮞ', + 'Ꮟ' => 'ꮟ', + 'Ꮠ' => 'ꮠ', + 'Ꮡ' => 'ꮡ', + 'Ꮢ' => 'ꮢ', + 'Ꮣ' => 'ꮣ', + 'Ꮤ' => 'ꮤ', + 'Ꮥ' => 'ꮥ', + 'Ꮦ' => 'ꮦ', + 'Ꮧ' => 'ꮧ', + 'Ꮨ' => 'ꮨ', + 'Ꮩ' => 'ꮩ', + 'Ꮪ' => 'ꮪ', + 'Ꮫ' => 'ꮫ', + 'Ꮬ' => 'ꮬ', + 'Ꮭ' => 'ꮭ', + 'Ꮮ' => 'ꮮ', + 'Ꮯ' => 'ꮯ', + 'Ꮰ' => 'ꮰ', + 'Ꮱ' => 'ꮱ', + 'Ꮲ' => 'ꮲ', + 'Ꮳ' => 'ꮳ', + 'Ꮴ' => 'ꮴ', + 'Ꮵ' => 'ꮵ', + 'Ꮶ' => 'ꮶ', + 'Ꮷ' => 'ꮷ', + 'Ꮸ' => 'ꮸ', + 'Ꮹ' => 'ꮹ', + 'Ꮺ' => 'ꮺ', + 'Ꮻ' => 'ꮻ', + 'Ꮼ' => 'ꮼ', + 'Ꮽ' => 'ꮽ', + 'Ꮾ' => 'ꮾ', + 'Ꮿ' => 'ꮿ', + 'Ᏸ' => 'ᏸ', + 'Ᏹ' => 'ᏹ', + 'Ᏺ' => 'ᏺ', + 'Ᏻ' => 'ᏻ', + 'Ᏼ' => 'ᏼ', + 'Ᏽ' => 'ᏽ', + 'Ა' => 'ა', + 'Ბ' => 'ბ', + 'Გ' => 'გ', + 'Დ' => 'დ', + 'Ე' => 'ე', + 'Ვ' => 'ვ', + 'Ზ' => 'ზ', + 'Თ' => 'თ', + 'Ი' => 'ი', + 'Კ' => 'კ', + 'Ლ' => 'ლ', + 'Მ' => 'მ', + 'Ნ' => 'ნ', + 'Ო' => 'ო', + 'Პ' => 'პ', + 'Ჟ' => 'ჟ', + 'Რ' => 'რ', + 'Ს' => 'ს', + 'Ტ' => 'ტ', + 'Უ' => 'უ', + 'Ფ' => 'ფ', + 'Ქ' => 'ქ', + 'Ღ' => 'ღ', + 'Ყ' => 'ყ', + 'Შ' => 'შ', + 'Ჩ' => 'ჩ', + 'Ც' => 'ც', + 'Ძ' => 'ძ', + 'Წ' => 'წ', + 'Ჭ' => 'ჭ', + 'Ხ' => 'ხ', + 'Ჯ' => 'ჯ', + 'Ჰ' => 'ჰ', + 'Ჱ' => 'ჱ', + 'Ჲ' => 'ჲ', + 'Ჳ' => 'ჳ', + 'Ჴ' => 'ჴ', + 'Ჵ' => 'ჵ', + 'Ჶ' => 'ჶ', + 'Ჷ' => 'ჷ', + 'Ჸ' => 'ჸ', + 'Ჹ' => 'ჹ', + 'Ჺ' => 'ჺ', + 'Ჽ' => 'ჽ', + 'Ჾ' => 'ჾ', + 'Ჿ' => 'ჿ', 'Ḁ' => 'ḁ', 'Ḃ' => 'ḃ', 'Ḅ' => 'ḅ', @@ -993,8 +1125,24 @@ 'Ɜ' => 'ɜ', 'Ɡ' => 'ɡ', 'Ɬ' => 'ɬ', + 'Ɪ' => 'ɪ', 'Ʞ' => 'ʞ', 'Ʇ' => 'ʇ', + 'Ʝ' => 'ʝ', + 'Ꭓ' => 'ꭓ', + 'Ꞵ' => 'ꞵ', + 'Ꞷ' => 'ꞷ', + 'Ꞹ' => 'ꞹ', + 'Ꞻ' => 'ꞻ', + 'Ꞽ' => 'ꞽ', + 'Ꞿ' => 'ꞿ', + 'Ꟃ' => 'ꟃ', + 'Ꞔ' => 'ꞔ', + 'Ʂ' => 'ʂ', + 'Ᶎ' => 'ᶎ', + 'Ꟈ' => 'ꟈ', + 'Ꟊ' => 'ꟊ', + 'Ꟶ' => 'ꟶ', 'A' => 'a', 'B' => 'b', 'C' => 'c', @@ -1061,6 +1209,93 @@ '𐐥' => '𐑍', '𐐦' => '𐑎', '𐐧' => '𐑏', + '𐒰' => '𐓘', + '𐒱' => '𐓙', + '𐒲' => '𐓚', + '𐒳' => '𐓛', + '𐒴' => '𐓜', + '𐒵' => '𐓝', + '𐒶' => '𐓞', + '𐒷' => '𐓟', + '𐒸' => '𐓠', + '𐒹' => '𐓡', + '𐒺' => '𐓢', + '𐒻' => '𐓣', + '𐒼' => '𐓤', + '𐒽' => '𐓥', + '𐒾' => '𐓦', + '𐒿' => '𐓧', + '𐓀' => '𐓨', + '𐓁' => '𐓩', + '𐓂' => '𐓪', + '𐓃' => '𐓫', + '𐓄' => '𐓬', + '𐓅' => '𐓭', + '𐓆' => '𐓮', + '𐓇' => '𐓯', + '𐓈' => '𐓰', + '𐓉' => '𐓱', + '𐓊' => '𐓲', + '𐓋' => '𐓳', + '𐓌' => '𐓴', + '𐓍' => '𐓵', + '𐓎' => '𐓶', + '𐓏' => '𐓷', + '𐓐' => '𐓸', + '𐓑' => '𐓹', + '𐓒' => '𐓺', + '𐓓' => '𐓻', + '𐲀' => '𐳀', + '𐲁' => '𐳁', + '𐲂' => '𐳂', + '𐲃' => '𐳃', + '𐲄' => '𐳄', + '𐲅' => '𐳅', + '𐲆' => '𐳆', + '𐲇' => '𐳇', + '𐲈' => '𐳈', + '𐲉' => '𐳉', + '𐲊' => '𐳊', + '𐲋' => '𐳋', + '𐲌' => '𐳌', + '𐲍' => '𐳍', + '𐲎' => '𐳎', + '𐲏' => '𐳏', + '𐲐' => '𐳐', + '𐲑' => '𐳑', + '𐲒' => '𐳒', + '𐲓' => '𐳓', + '𐲔' => '𐳔', + '𐲕' => '𐳕', + '𐲖' => '𐳖', + '𐲗' => '𐳗', + '𐲘' => '𐳘', + '𐲙' => '𐳙', + '𐲚' => '𐳚', + '𐲛' => '𐳛', + '𐲜' => '𐳜', + '𐲝' => '𐳝', + '𐲞' => '𐳞', + '𐲟' => '𐳟', + '𐲠' => '𐳠', + '𐲡' => '𐳡', + '𐲢' => '𐳢', + '𐲣' => '𐳣', + '𐲤' => '𐳤', + '𐲥' => '𐳥', + '𐲦' => '𐳦', + '𐲧' => '𐳧', + '𐲨' => '𐳨', + '𐲩' => '𐳩', + '𐲪' => '𐳪', + '𐲫' => '𐳫', + '𐲬' => '𐳬', + '𐲭' => '𐳭', + '𐲮' => '𐳮', + '𐲯' => '𐳯', + '𐲰' => '𐳰', + '𐲱' => '𐳱', + '𐲲' => '𐳲', '𑢠' => '𑣀', '𑢡' => '𑣁', '𑢢' => '𑣂', @@ -1093,4 +1328,70 @@ '𑢽' => '𑣝', '𑢾' => '𑣞', '𑢿' => '𑣟', + '𖹀' => '𖹠', + '𖹁' => '𖹡', + '𖹂' => '𖹢', + '𖹃' => '𖹣', + '𖹄' => '𖹤', + '𖹅' => '𖹥', + '𖹆' => '𖹦', + '𖹇' => '𖹧', + '𖹈' => '𖹨', + '𖹉' => '𖹩', + '𖹊' => '𖹪', + '𖹋' => '𖹫', + '𖹌' => '𖹬', + '𖹍' => '𖹭', + '𖹎' => '𖹮', + '𖹏' => '𖹯', + '𖹐' => '𖹰', + '𖹑' => '𖹱', + '𖹒' => '𖹲', + '𖹓' => '𖹳', + '𖹔' => '𖹴', + '𖹕' => '𖹵', + '𖹖' => '𖹶', + '𖹗' => '𖹷', + '𖹘' => '𖹸', + '𖹙' => '𖹹', + '𖹚' => '𖹺', + '𖹛' => '𖹻', + '𖹜' => '𖹼', + '𖹝' => '𖹽', + '𖹞' => '𖹾', + '𖹟' => '𖹿', + '𞤀' => '𞤢', + '𞤁' => '𞤣', + '𞤂' => '𞤤', + '𞤃' => '𞤥', + '𞤄' => '𞤦', + '𞤅' => '𞤧', + '𞤆' => '𞤨', + '𞤇' => '𞤩', + '𞤈' => '𞤪', + '𞤉' => '𞤫', + '𞤊' => '𞤬', + '𞤋' => '𞤭', + '𞤌' => '𞤮', + '𞤍' => '𞤯', + '𞤎' => '𞤰', + '𞤏' => '𞤱', + '𞤐' => '𞤲', + '𞤑' => '𞤳', + '𞤒' => '𞤴', + '𞤓' => '𞤵', + '𞤔' => '𞤶', + '𞤕' => '𞤷', + '𞤖' => '𞤸', + '𞤗' => '𞤹', + '𞤘' => '𞤺', + '𞤙' => '𞤻', + '𞤚' => '𞤼', + '𞤛' => '𞤽', + '𞤜' => '𞤾', + '𞤝' => '𞤿', + '𞤞' => '𞥀', + '𞤟' => '𞥁', + '𞤠' => '𞥂', + '𞤡' => '𞥃', ); diff --git a/includes/vendor/symfony/polyfill-mbstring/Resources/unidata/upperCase.php b/includes/vendor/symfony/polyfill-mbstring/Resources/unidata/upperCase.php index b8103b2e8..56b9cb852 100644 --- a/includes/vendor/symfony/polyfill-mbstring/Resources/unidata/upperCase.php +++ b/includes/vendor/symfony/polyfill-mbstring/Resources/unidata/upperCase.php @@ -1,6 +1,6 @@ 'A', 'b' => 'B', 'c' => 'C', @@ -225,6 +225,7 @@ 'ɦ' => 'Ɦ', 'ɨ' => 'Ɨ', 'ɩ' => 'Ɩ', + 'ɪ' => 'Ɪ', 'ɫ' => 'Ɫ', 'ɬ' => 'Ɬ', 'ɯ' => 'Ɯ', @@ -233,6 +234,7 @@ 'ɵ' => 'Ɵ', 'ɽ' => 'Ɽ', 'ʀ' => 'Ʀ', + 'ʂ' => 'Ʂ', 'ʃ' => 'Ʃ', 'ʇ' => 'Ʇ', 'ʈ' => 'Ʈ', @@ -241,6 +243,7 @@ 'ʋ' => 'Ʋ', 'ʌ' => 'Ʌ', 'ʒ' => 'Ʒ', + 'ʝ' => 'Ʝ', 'ʞ' => 'Ʞ', 'ͅ' => 'Ι', 'ͱ' => 'Ͱ', @@ -493,8 +496,70 @@ 'ք' => 'Ք', 'օ' => 'Օ', 'ֆ' => 'Ֆ', + 'ა' => 'Ა', + 'ბ' => 'Ბ', + 'გ' => 'Გ', + 'დ' => 'Დ', + 'ე' => 'Ე', + 'ვ' => 'Ვ', + 'ზ' => 'Ზ', + 'თ' => 'Თ', + 'ი' => 'Ი', + 'კ' => 'Კ', + 'ლ' => 'Ლ', + 'მ' => 'Მ', + 'ნ' => 'Ნ', + 'ო' => 'Ო', + 'პ' => 'Პ', + 'ჟ' => 'Ჟ', + 'რ' => 'Რ', + 'ს' => 'Ს', + 'ტ' => 'Ტ', + 'უ' => 'Უ', + 'ფ' => 'Ფ', + 'ქ' => 'Ქ', + 'ღ' => 'Ღ', + 'ყ' => 'Ყ', + 'შ' => 'Შ', + 'ჩ' => 'Ჩ', + 'ც' => 'Ც', + 'ძ' => 'Ძ', + 'წ' => 'Წ', + 'ჭ' => 'Ჭ', + 'ხ' => 'Ხ', + 'ჯ' => 'Ჯ', + 'ჰ' => 'Ჰ', + 'ჱ' => 'Ჱ', + 'ჲ' => 'Ჲ', + 'ჳ' => 'Ჳ', + 'ჴ' => 'Ჴ', + 'ჵ' => 'Ჵ', + 'ჶ' => 'Ჶ', + 'ჷ' => 'Ჷ', + 'ჸ' => 'Ჸ', + 'ჹ' => 'Ჹ', + 'ჺ' => 'Ჺ', + 'ჽ' => 'Ჽ', + 'ჾ' => 'Ჾ', + 'ჿ' => 'Ჿ', + 'ᏸ' => 'Ᏸ', + 'ᏹ' => 'Ᏹ', + 'ᏺ' => 'Ᏺ', + 'ᏻ' => 'Ᏻ', + 'ᏼ' => 'Ᏼ', + 'ᏽ' => 'Ᏽ', + 'ᲀ' => 'В', + 'ᲁ' => 'Д', + 'ᲂ' => 'О', + 'ᲃ' => 'С', + 'ᲄ' => 'Т', + 'ᲅ' => 'Т', + 'ᲆ' => 'Ъ', + 'ᲇ' => 'Ѣ', + 'ᲈ' => 'Ꙋ', 'ᵹ' => 'Ᵹ', 'ᵽ' => 'Ᵽ', + 'ᶎ' => 'Ᶎ', 'ḁ' => 'Ḁ', 'ḃ' => 'Ḃ', 'ḅ' => 'Ḅ', @@ -681,41 +746,41 @@ 'ύ' => 'Ύ', 'ὼ' => 'Ὼ', 'ώ' => 'Ώ', - 'ᾀ' => 'ᾈ', - 'ᾁ' => 'ᾉ', - 'ᾂ' => 'ᾊ', - 'ᾃ' => 'ᾋ', - 'ᾄ' => 'ᾌ', - 'ᾅ' => 'ᾍ', - 'ᾆ' => 'ᾎ', - 'ᾇ' => 'ᾏ', - 'ᾐ' => 'ᾘ', - 'ᾑ' => 'ᾙ', - 'ᾒ' => 'ᾚ', - 'ᾓ' => 'ᾛ', - 'ᾔ' => 'ᾜ', - 'ᾕ' => 'ᾝ', - 'ᾖ' => 'ᾞ', - 'ᾗ' => 'ᾟ', - 'ᾠ' => 'ᾨ', - 'ᾡ' => 'ᾩ', - 'ᾢ' => 'ᾪ', - 'ᾣ' => 'ᾫ', - 'ᾤ' => 'ᾬ', - 'ᾥ' => 'ᾭ', - 'ᾦ' => 'ᾮ', - 'ᾧ' => 'ᾯ', + 'ᾀ' => 'ἈΙ', + 'ᾁ' => 'ἉΙ', + 'ᾂ' => 'ἊΙ', + 'ᾃ' => 'ἋΙ', + 'ᾄ' => 'ἌΙ', + 'ᾅ' => 'ἍΙ', + 'ᾆ' => 'ἎΙ', + 'ᾇ' => 'ἏΙ', + 'ᾐ' => 'ἨΙ', + 'ᾑ' => 'ἩΙ', + 'ᾒ' => 'ἪΙ', + 'ᾓ' => 'ἫΙ', + 'ᾔ' => 'ἬΙ', + 'ᾕ' => 'ἭΙ', + 'ᾖ' => 'ἮΙ', + 'ᾗ' => 'ἯΙ', + 'ᾠ' => 'ὨΙ', + 'ᾡ' => 'ὩΙ', + 'ᾢ' => 'ὪΙ', + 'ᾣ' => 'ὫΙ', + 'ᾤ' => 'ὬΙ', + 'ᾥ' => 'ὭΙ', + 'ᾦ' => 'ὮΙ', + 'ᾧ' => 'ὯΙ', 'ᾰ' => 'Ᾰ', 'ᾱ' => 'Ᾱ', - 'ᾳ' => 'ᾼ', + 'ᾳ' => 'ΑΙ', 'ι' => 'Ι', - 'ῃ' => 'ῌ', + 'ῃ' => 'ΗΙ', 'ῐ' => 'Ῐ', 'ῑ' => 'Ῑ', 'ῠ' => 'Ῠ', 'ῡ' => 'Ῡ', 'ῥ' => 'Ῥ', - 'ῳ' => 'ῼ', + 'ῳ' => 'ΩΙ', 'ⅎ' => 'Ⅎ', 'ⅰ' => 'Ⅰ', 'ⅱ' => 'Ⅱ', @@ -993,6 +1058,7 @@ 'ꞌ' => 'Ꞌ', 'ꞑ' => 'Ꞑ', 'ꞓ' => 'Ꞓ', + 'ꞔ' => 'Ꞔ', 'ꞗ' => 'Ꞗ', 'ꞙ' => 'Ꞙ', 'ꞛ' => 'Ꞛ', @@ -1003,6 +1069,97 @@ 'ꞥ' => 'Ꞥ', 'ꞧ' => 'Ꞧ', 'ꞩ' => 'Ꞩ', + 'ꞵ' => 'Ꞵ', + 'ꞷ' => 'Ꞷ', + 'ꞹ' => 'Ꞹ', + 'ꞻ' => 'Ꞻ', + 'ꞽ' => 'Ꞽ', + 'ꞿ' => 'Ꞿ', + 'ꟃ' => 'Ꟃ', + 'ꟈ' => 'Ꟈ', + 'ꟊ' => 'Ꟊ', + 'ꟶ' => 'Ꟶ', + 'ꭓ' => 'Ꭓ', + 'ꭰ' => 'Ꭰ', + 'ꭱ' => 'Ꭱ', + 'ꭲ' => 'Ꭲ', + 'ꭳ' => 'Ꭳ', + 'ꭴ' => 'Ꭴ', + 'ꭵ' => 'Ꭵ', + 'ꭶ' => 'Ꭶ', + 'ꭷ' => 'Ꭷ', + 'ꭸ' => 'Ꭸ', + 'ꭹ' => 'Ꭹ', + 'ꭺ' => 'Ꭺ', + 'ꭻ' => 'Ꭻ', + 'ꭼ' => 'Ꭼ', + 'ꭽ' => 'Ꭽ', + 'ꭾ' => 'Ꭾ', + 'ꭿ' => 'Ꭿ', + 'ꮀ' => 'Ꮀ', + 'ꮁ' => 'Ꮁ', + 'ꮂ' => 'Ꮂ', + 'ꮃ' => 'Ꮃ', + 'ꮄ' => 'Ꮄ', + 'ꮅ' => 'Ꮅ', + 'ꮆ' => 'Ꮆ', + 'ꮇ' => 'Ꮇ', + 'ꮈ' => 'Ꮈ', + 'ꮉ' => 'Ꮉ', + 'ꮊ' => 'Ꮊ', + 'ꮋ' => 'Ꮋ', + 'ꮌ' => 'Ꮌ', + 'ꮍ' => 'Ꮍ', + 'ꮎ' => 'Ꮎ', + 'ꮏ' => 'Ꮏ', + 'ꮐ' => 'Ꮐ', + 'ꮑ' => 'Ꮑ', + 'ꮒ' => 'Ꮒ', + 'ꮓ' => 'Ꮓ', + 'ꮔ' => 'Ꮔ', + 'ꮕ' => 'Ꮕ', + 'ꮖ' => 'Ꮖ', + 'ꮗ' => 'Ꮗ', + 'ꮘ' => 'Ꮘ', + 'ꮙ' => 'Ꮙ', + 'ꮚ' => 'Ꮚ', + 'ꮛ' => 'Ꮛ', + 'ꮜ' => 'Ꮜ', + 'ꮝ' => 'Ꮝ', + 'ꮞ' => 'Ꮞ', + 'ꮟ' => 'Ꮟ', + 'ꮠ' => 'Ꮠ', + 'ꮡ' => 'Ꮡ', + 'ꮢ' => 'Ꮢ', + 'ꮣ' => 'Ꮣ', + 'ꮤ' => 'Ꮤ', + 'ꮥ' => 'Ꮥ', + 'ꮦ' => 'Ꮦ', + 'ꮧ' => 'Ꮧ', + 'ꮨ' => 'Ꮨ', + 'ꮩ' => 'Ꮩ', + 'ꮪ' => 'Ꮪ', + 'ꮫ' => 'Ꮫ', + 'ꮬ' => 'Ꮬ', + 'ꮭ' => 'Ꮭ', + 'ꮮ' => 'Ꮮ', + 'ꮯ' => 'Ꮯ', + 'ꮰ' => 'Ꮰ', + 'ꮱ' => 'Ꮱ', + 'ꮲ' => 'Ꮲ', + 'ꮳ' => 'Ꮳ', + 'ꮴ' => 'Ꮴ', + 'ꮵ' => 'Ꮵ', + 'ꮶ' => 'Ꮶ', + 'ꮷ' => 'Ꮷ', + 'ꮸ' => 'Ꮸ', + 'ꮹ' => 'Ꮹ', + 'ꮺ' => 'Ꮺ', + 'ꮻ' => 'Ꮻ', + 'ꮼ' => 'Ꮼ', + 'ꮽ' => 'Ꮽ', + 'ꮾ' => 'Ꮾ', + 'ꮿ' => 'Ꮿ', 'a' => 'A', 'b' => 'B', 'c' => 'C', @@ -1069,6 +1226,93 @@ '𐑍' => '𐐥', '𐑎' => '𐐦', '𐑏' => '𐐧', + '𐓘' => '𐒰', + '𐓙' => '𐒱', + '𐓚' => '𐒲', + '𐓛' => '𐒳', + '𐓜' => '𐒴', + '𐓝' => '𐒵', + '𐓞' => '𐒶', + '𐓟' => '𐒷', + '𐓠' => '𐒸', + '𐓡' => '𐒹', + '𐓢' => '𐒺', + '𐓣' => '𐒻', + '𐓤' => '𐒼', + '𐓥' => '𐒽', + '𐓦' => '𐒾', + '𐓧' => '𐒿', + '𐓨' => '𐓀', + '𐓩' => '𐓁', + '𐓪' => '𐓂', + '𐓫' => '𐓃', + '𐓬' => '𐓄', + '𐓭' => '𐓅', + '𐓮' => '𐓆', + '𐓯' => '𐓇', + '𐓰' => '𐓈', + '𐓱' => '𐓉', + '𐓲' => '𐓊', + '𐓳' => '𐓋', + '𐓴' => '𐓌', + '𐓵' => '𐓍', + '𐓶' => '𐓎', + '𐓷' => '𐓏', + '𐓸' => '𐓐', + '𐓹' => '𐓑', + '𐓺' => '𐓒', + '𐓻' => '𐓓', + '𐳀' => '𐲀', + '𐳁' => '𐲁', + '𐳂' => '𐲂', + '𐳃' => '𐲃', + '𐳄' => '𐲄', + '𐳅' => '𐲅', + '𐳆' => '𐲆', + '𐳇' => '𐲇', + '𐳈' => '𐲈', + '𐳉' => '𐲉', + '𐳊' => '𐲊', + '𐳋' => '𐲋', + '𐳌' => '𐲌', + '𐳍' => '𐲍', + '𐳎' => '𐲎', + '𐳏' => '𐲏', + '𐳐' => '𐲐', + '𐳑' => '𐲑', + '𐳒' => '𐲒', + '𐳓' => '𐲓', + '𐳔' => '𐲔', + '𐳕' => '𐲕', + '𐳖' => '𐲖', + '𐳗' => '𐲗', + '𐳘' => '𐲘', + '𐳙' => '𐲙', + '𐳚' => '𐲚', + '𐳛' => '𐲛', + '𐳜' => '𐲜', + '𐳝' => '𐲝', + '𐳞' => '𐲞', + '𐳟' => '𐲟', + '𐳠' => '𐲠', + '𐳡' => '𐲡', + '𐳢' => '𐲢', + '𐳣' => '𐲣', + '𐳤' => '𐲤', + '𐳥' => '𐲥', + '𐳦' => '𐲦', + '𐳧' => '𐲧', + '𐳨' => '𐲨', + '𐳩' => '𐲩', + '𐳪' => '𐲪', + '𐳫' => '𐲫', + '𐳬' => '𐲬', + '𐳭' => '𐲭', + '𐳮' => '𐲮', + '𐳯' => '𐲯', + '𐳰' => '𐲰', + '𐳱' => '𐲱', + '𐳲' => '𐲲', '𑣀' => '𑢠', '𑣁' => '𑢡', '𑣂' => '𑢢', @@ -1101,4 +1345,145 @@ '𑣝' => '𑢽', '𑣞' => '𑢾', '𑣟' => '𑢿', + '𖹠' => '𖹀', + '𖹡' => '𖹁', + '𖹢' => '𖹂', + '𖹣' => '𖹃', + '𖹤' => '𖹄', + '𖹥' => '𖹅', + '𖹦' => '𖹆', + '𖹧' => '𖹇', + '𖹨' => '𖹈', + '𖹩' => '𖹉', + '𖹪' => '𖹊', + '𖹫' => '𖹋', + '𖹬' => '𖹌', + '𖹭' => '𖹍', + '𖹮' => '𖹎', + '𖹯' => '𖹏', + '𖹰' => '𖹐', + '𖹱' => '𖹑', + '𖹲' => '𖹒', + '𖹳' => '𖹓', + '𖹴' => '𖹔', + '𖹵' => '𖹕', + '𖹶' => '𖹖', + '𖹷' => '𖹗', + '𖹸' => '𖹘', + '𖹹' => '𖹙', + '𖹺' => '𖹚', + '𖹻' => '𖹛', + '𖹼' => '𖹜', + '𖹽' => '𖹝', + '𖹾' => '𖹞', + '𖹿' => '𖹟', + '𞤢' => '𞤀', + '𞤣' => '𞤁', + '𞤤' => '𞤂', + '𞤥' => '𞤃', + '𞤦' => '𞤄', + '𞤧' => '𞤅', + '𞤨' => '𞤆', + '𞤩' => '𞤇', + '𞤪' => '𞤈', + '𞤫' => '𞤉', + '𞤬' => '𞤊', + '𞤭' => '𞤋', + '𞤮' => '𞤌', + '𞤯' => '𞤍', + '𞤰' => '𞤎', + '𞤱' => '𞤏', + '𞤲' => '𞤐', + '𞤳' => '𞤑', + '𞤴' => '𞤒', + '𞤵' => '𞤓', + '𞤶' => '𞤔', + '𞤷' => '𞤕', + '𞤸' => '𞤖', + '𞤹' => '𞤗', + '𞤺' => '𞤘', + '𞤻' => '𞤙', + '𞤼' => '𞤚', + '𞤽' => '𞤛', + '𞤾' => '𞤜', + '𞤿' => '𞤝', + '𞥀' => '𞤞', + '𞥁' => '𞤟', + '𞥂' => '𞤠', + '𞥃' => '𞤡', + 'ß' => 'SS', + 'ff' => 'FF', + 'fi' => 'FI', + 'fl' => 'FL', + 'ffi' => 'FFI', + 'ffl' => 'FFL', + 'ſt' => 'ST', + 'st' => 'ST', + 'և' => 'ԵՒ', + 'ﬓ' => 'ՄՆ', + 'ﬔ' => 'ՄԵ', + 'ﬕ' => 'ՄԻ', + 'ﬖ' => 'ՎՆ', + 'ﬗ' => 'ՄԽ', + 'ʼn' => 'ʼN', + 'ΐ' => 'Ϊ́', + 'ΰ' => 'Ϋ́', + 'ǰ' => 'J̌', + 'ẖ' => 'H̱', + 'ẗ' => 'T̈', + 'ẘ' => 'W̊', + 'ẙ' => 'Y̊', + 'ẚ' => 'Aʾ', + 'ὐ' => 'Υ̓', + 'ὒ' => 'Υ̓̀', + 'ὔ' => 'Υ̓́', + 'ὖ' => 'Υ̓͂', + 'ᾶ' => 'Α͂', + 'ῆ' => 'Η͂', + 'ῒ' => 'Ϊ̀', + 'ΐ' => 'Ϊ́', + 'ῖ' => 'Ι͂', + 'ῗ' => 'Ϊ͂', + 'ῢ' => 'Ϋ̀', + 'ΰ' => 'Ϋ́', + 'ῤ' => 'Ρ̓', + 'ῦ' => 'Υ͂', + 'ῧ' => 'Ϋ͂', + 'ῶ' => 'Ω͂', + 'ᾈ' => 'ἈΙ', + 'ᾉ' => 'ἉΙ', + 'ᾊ' => 'ἊΙ', + 'ᾋ' => 'ἋΙ', + 'ᾌ' => 'ἌΙ', + 'ᾍ' => 'ἍΙ', + 'ᾎ' => 'ἎΙ', + 'ᾏ' => 'ἏΙ', + 'ᾘ' => 'ἨΙ', + 'ᾙ' => 'ἩΙ', + 'ᾚ' => 'ἪΙ', + 'ᾛ' => 'ἫΙ', + 'ᾜ' => 'ἬΙ', + 'ᾝ' => 'ἭΙ', + 'ᾞ' => 'ἮΙ', + 'ᾟ' => 'ἯΙ', + 'ᾨ' => 'ὨΙ', + 'ᾩ' => 'ὩΙ', + 'ᾪ' => 'ὪΙ', + 'ᾫ' => 'ὫΙ', + 'ᾬ' => 'ὬΙ', + 'ᾭ' => 'ὭΙ', + 'ᾮ' => 'ὮΙ', + 'ᾯ' => 'ὯΙ', + 'ᾼ' => 'ΑΙ', + 'ῌ' => 'ΗΙ', + 'ῼ' => 'ΩΙ', + 'ᾲ' => 'ᾺΙ', + 'ᾴ' => 'ΆΙ', + 'ῂ' => 'ῊΙ', + 'ῄ' => 'ΉΙ', + 'ῲ' => 'ῺΙ', + 'ῴ' => 'ΏΙ', + 'ᾷ' => 'Α͂Ι', + 'ῇ' => 'Η͂Ι', + 'ῷ' => 'Ω͂Ι', ); diff --git a/includes/vendor/symfony/polyfill-mbstring/bootstrap.php b/includes/vendor/symfony/polyfill-mbstring/bootstrap.php index 8c8225c52..ff51ae079 100644 --- a/includes/vendor/symfony/polyfill-mbstring/bootstrap.php +++ b/includes/vendor/symfony/polyfill-mbstring/bootstrap.php @@ -11,54 +11,162 @@ use Symfony\Polyfill\Mbstring as p; -if (!defined('MB_CASE_UPPER')) { - define('MB_CASE_UPPER', 0); - define('MB_CASE_LOWER', 1); - define('MB_CASE_TITLE', 2); +if (\PHP_VERSION_ID >= 80000) { + return require __DIR__.'/bootstrap80.php'; } -if (!function_exists('mb_strlen')) { - function mb_convert_encoding($s, $to, $from = null) { return p\Mbstring::mb_convert_encoding($s, $to, $from); } - function mb_decode_mimeheader($s) { return p\Mbstring::mb_decode_mimeheader($s); } - function mb_encode_mimeheader($s, $charset = null, $transferEnc = null, $lf = null, $indent = null) { return p\Mbstring::mb_encode_mimeheader($s, $charset, $transferEnc, $lf, $indent); } - function mb_decode_numericentity($s, $convmap, $enc = null) { return p\Mbstring::mb_decode_numericentity($s, $convmap, $enc); } - function mb_encode_numericentity($s, $convmap, $enc = null, $is_hex = false) { return p\Mbstring::mb_encode_numericentity($s, $convmap, $enc, $is_hex); } - function mb_convert_case($s, $mode, $enc = null) { return p\Mbstring::mb_convert_case($s, $mode, $enc); } - function mb_internal_encoding($enc = null) { return p\Mbstring::mb_internal_encoding($enc); } - function mb_language($lang = null) { return p\Mbstring::mb_language($lang); } +if (!function_exists('mb_convert_encoding')) { + function mb_convert_encoding($string, $to_encoding, $from_encoding = null) { return p\Mbstring::mb_convert_encoding($string, $to_encoding, $from_encoding); } +} +if (!function_exists('mb_decode_mimeheader')) { + function mb_decode_mimeheader($string) { return p\Mbstring::mb_decode_mimeheader($string); } +} +if (!function_exists('mb_encode_mimeheader')) { + function mb_encode_mimeheader($string, $charset = null, $transfer_encoding = null, $newline = "\r\n", $indent = 0) { return p\Mbstring::mb_encode_mimeheader($string, $charset, $transfer_encoding, $newline, $indent); } +} +if (!function_exists('mb_decode_numericentity')) { + function mb_decode_numericentity($string, $map, $encoding = null) { return p\Mbstring::mb_decode_numericentity($string, $map, $encoding); } +} +if (!function_exists('mb_encode_numericentity')) { + function mb_encode_numericentity($string, $map, $encoding = null, $hex = false) { return p\Mbstring::mb_encode_numericentity($string, $map, $encoding, $hex); } +} +if (!function_exists('mb_convert_case')) { + function mb_convert_case($string, $mode, $encoding = null) { return p\Mbstring::mb_convert_case($string, $mode, $encoding); } +} +if (!function_exists('mb_internal_encoding')) { + function mb_internal_encoding($encoding = null) { return p\Mbstring::mb_internal_encoding($encoding); } +} +if (!function_exists('mb_language')) { + function mb_language($language = null) { return p\Mbstring::mb_language($language); } +} +if (!function_exists('mb_list_encodings')) { function mb_list_encodings() { return p\Mbstring::mb_list_encodings(); } +} +if (!function_exists('mb_encoding_aliases')) { function mb_encoding_aliases($encoding) { return p\Mbstring::mb_encoding_aliases($encoding); } - function mb_check_encoding($var = null, $encoding = null) { return p\Mbstring::mb_check_encoding($var, $encoding); } - function mb_detect_encoding($str, $encodingList = null, $strict = false) { return p\Mbstring::mb_detect_encoding($str, $encodingList, $strict); } - function mb_detect_order($encodingList = null) { return p\Mbstring::mb_detect_order($encodingList); } - function mb_parse_str($s, &$result = array()) { parse_str($s, $result); } - function mb_strlen($s, $enc = null) { return p\Mbstring::mb_strlen($s, $enc); } - function mb_strpos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_strpos($s, $needle, $offset, $enc); } - function mb_strtolower($s, $enc = null) { return p\Mbstring::mb_strtolower($s, $enc); } - function mb_strtoupper($s, $enc = null) { return p\Mbstring::mb_strtoupper($s, $enc); } - function mb_substitute_character($char = null) { return p\Mbstring::mb_substitute_character($char); } - function mb_substr($s, $start, $length = 2147483647, $enc = null) { return p\Mbstring::mb_substr($s, $start, $length, $enc); } - function mb_stripos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_stripos($s, $needle, $offset, $enc); } - function mb_stristr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_stristr($s, $needle, $part, $enc); } - function mb_strrchr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_strrchr($s, $needle, $part, $enc); } - function mb_strrichr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_strrichr($s, $needle, $part, $enc); } - function mb_strripos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_strripos($s, $needle, $offset, $enc); } - function mb_strrpos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_strrpos($s, $needle, $offset, $enc); } - function mb_strstr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_strstr($s, $needle, $part, $enc); } +} +if (!function_exists('mb_check_encoding')) { + function mb_check_encoding($value = null, $encoding = null) { return p\Mbstring::mb_check_encoding($value, $encoding); } +} +if (!function_exists('mb_detect_encoding')) { + function mb_detect_encoding($string, $encodings = null, $strict = false) { return p\Mbstring::mb_detect_encoding($string, $encodings, $strict); } +} +if (!function_exists('mb_detect_order')) { + function mb_detect_order($encoding = null) { return p\Mbstring::mb_detect_order($encoding); } +} +if (!function_exists('mb_parse_str')) { + function mb_parse_str($string, &$result = []) { parse_str($string, $result); return (bool) $result; } +} +if (!function_exists('mb_strlen')) { + function mb_strlen($string, $encoding = null) { return p\Mbstring::mb_strlen($string, $encoding); } +} +if (!function_exists('mb_strpos')) { + function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strpos($haystack, $needle, $offset, $encoding); } +} +if (!function_exists('mb_strtolower')) { + function mb_strtolower($string, $encoding = null) { return p\Mbstring::mb_strtolower($string, $encoding); } +} +if (!function_exists('mb_strtoupper')) { + function mb_strtoupper($string, $encoding = null) { return p\Mbstring::mb_strtoupper($string, $encoding); } +} +if (!function_exists('mb_substitute_character')) { + function mb_substitute_character($substitute_character = null) { return p\Mbstring::mb_substitute_character($substitute_character); } +} +if (!function_exists('mb_substr')) { + function mb_substr($string, $start, $length = 2147483647, $encoding = null) { return p\Mbstring::mb_substr($string, $start, $length, $encoding); } +} +if (!function_exists('mb_stripos')) { + function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_stripos($haystack, $needle, $offset, $encoding); } +} +if (!function_exists('mb_stristr')) { + function mb_stristr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_stristr($haystack, $needle, $before_needle, $encoding); } +} +if (!function_exists('mb_strrchr')) { + function mb_strrchr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrchr($haystack, $needle, $before_needle, $encoding); } +} +if (!function_exists('mb_strrichr')) { + function mb_strrichr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrichr($haystack, $needle, $before_needle, $encoding); } +} +if (!function_exists('mb_strripos')) { + function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strripos($haystack, $needle, $offset, $encoding); } +} +if (!function_exists('mb_strrpos')) { + function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strrpos($haystack, $needle, $offset, $encoding); } +} +if (!function_exists('mb_strstr')) { + function mb_strstr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strstr($haystack, $needle, $before_needle, $encoding); } +} +if (!function_exists('mb_get_info')) { function mb_get_info($type = 'all') { return p\Mbstring::mb_get_info($type); } - function mb_http_output($enc = null) { return p\Mbstring::mb_http_output($enc); } - function mb_strwidth($s, $enc = null) { return p\Mbstring::mb_strwidth($s, $enc); } - function mb_substr_count($haystack, $needle, $enc = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $enc); } - function mb_output_handler($contents, $status) { return p\Mbstring::mb_output_handler($contents, $status); } - function mb_http_input($type = '') { return p\Mbstring::mb_http_input($type); } - function mb_convert_variables($toEncoding, $fromEncoding, &$a = null, &$b = null, &$c = null, &$d = null, &$e = null, &$f = null) { return p\Mbstring::mb_convert_variables($toEncoding, $fromEncoding, $a, $b, $c, $d, $e, $f); } } -if (!function_exists('mb_chr')) { - function mb_ord($s, $enc = null) { return p\Mbstring::mb_ord($s, $enc); } - function mb_chr($code, $enc = null) { return p\Mbstring::mb_chr($code, $enc); } - function mb_scrub($s, $enc = null) { $enc = null === $enc ? mb_internal_encoding() : $enc; return mb_convert_encoding($s, $enc, $enc); } +if (!function_exists('mb_http_output')) { + function mb_http_output($encoding = null) { return p\Mbstring::mb_http_output($encoding); } +} +if (!function_exists('mb_strwidth')) { + function mb_strwidth($string, $encoding = null) { return p\Mbstring::mb_strwidth($string, $encoding); } +} +if (!function_exists('mb_substr_count')) { + function mb_substr_count($haystack, $needle, $encoding = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $encoding); } +} +if (!function_exists('mb_output_handler')) { + function mb_output_handler($string, $status) { return p\Mbstring::mb_output_handler($string, $status); } +} +if (!function_exists('mb_http_input')) { + function mb_http_input($type = null) { return p\Mbstring::mb_http_input($type); } } +if (!function_exists('mb_convert_variables')) { + function mb_convert_variables($to_encoding, $from_encoding, &...$vars) { return p\Mbstring::mb_convert_variables($to_encoding, $from_encoding, ...$vars); } +} + +if (!function_exists('mb_ord')) { + function mb_ord($string, $encoding = null) { return p\Mbstring::mb_ord($string, $encoding); } +} +if (!function_exists('mb_chr')) { + function mb_chr($codepoint, $encoding = null) { return p\Mbstring::mb_chr($codepoint, $encoding); } +} +if (!function_exists('mb_scrub')) { + function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); } +} if (!function_exists('mb_str_split')) { - function mb_str_split($string, $split_length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $split_length, $encoding); } + function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $length, $encoding); } +} + +if (!function_exists('mb_str_pad')) { + function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); } +} + +if (!function_exists('mb_ucfirst')) { + function mb_ucfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); } +} + +if (!function_exists('mb_lcfirst')) { + function mb_lcfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); } +} + +if (!function_exists('mb_trim')) { + function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_trim($string, $characters, $encoding); } +} + +if (!function_exists('mb_ltrim')) { + function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_ltrim($string, $characters, $encoding); } +} + +if (!function_exists('mb_rtrim')) { + function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_rtrim($string, $characters, $encoding); } +} + + +if (extension_loaded('mbstring')) { + return; +} + +if (!defined('MB_CASE_UPPER')) { + define('MB_CASE_UPPER', 0); +} +if (!defined('MB_CASE_LOWER')) { + define('MB_CASE_LOWER', 1); +} +if (!defined('MB_CASE_TITLE')) { + define('MB_CASE_TITLE', 2); } diff --git a/includes/vendor/symfony/polyfill-mbstring/bootstrap80.php b/includes/vendor/symfony/polyfill-mbstring/bootstrap80.php new file mode 100644 index 000000000..5be7d2018 --- /dev/null +++ b/includes/vendor/symfony/polyfill-mbstring/bootstrap80.php @@ -0,0 +1,167 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Mbstring as p; + +if (!function_exists('mb_convert_encoding')) { + function mb_convert_encoding(array|string|null $string, ?string $to_encoding, array|string|null $from_encoding = null): array|string|false { return p\Mbstring::mb_convert_encoding($string ?? '', (string) $to_encoding, $from_encoding); } +} +if (!function_exists('mb_decode_mimeheader')) { + function mb_decode_mimeheader(?string $string): string { return p\Mbstring::mb_decode_mimeheader((string) $string); } +} +if (!function_exists('mb_encode_mimeheader')) { + function mb_encode_mimeheader(?string $string, ?string $charset = null, ?string $transfer_encoding = null, ?string $newline = "\r\n", ?int $indent = 0): string { return p\Mbstring::mb_encode_mimeheader((string) $string, $charset, $transfer_encoding, (string) $newline, (int) $indent); } +} +if (!function_exists('mb_decode_numericentity')) { + function mb_decode_numericentity(?string $string, array $map, ?string $encoding = null): string { return p\Mbstring::mb_decode_numericentity((string) $string, $map, $encoding); } +} +if (!function_exists('mb_encode_numericentity')) { + function mb_encode_numericentity(?string $string, array $map, ?string $encoding = null, ?bool $hex = false): string { return p\Mbstring::mb_encode_numericentity((string) $string, $map, $encoding, (bool) $hex); } +} +if (!function_exists('mb_convert_case')) { + function mb_convert_case(?string $string, ?int $mode, ?string $encoding = null): string { return p\Mbstring::mb_convert_case((string) $string, (int) $mode, $encoding); } +} +if (!function_exists('mb_internal_encoding')) { + function mb_internal_encoding(?string $encoding = null): string|bool { return p\Mbstring::mb_internal_encoding($encoding); } +} +if (!function_exists('mb_language')) { + function mb_language(?string $language = null): string|bool { return p\Mbstring::mb_language($language); } +} +if (!function_exists('mb_list_encodings')) { + function mb_list_encodings(): array { return p\Mbstring::mb_list_encodings(); } +} +if (!function_exists('mb_encoding_aliases')) { + function mb_encoding_aliases(?string $encoding): array { return p\Mbstring::mb_encoding_aliases((string) $encoding); } +} +if (!function_exists('mb_check_encoding')) { + function mb_check_encoding(array|string|null $value = null, ?string $encoding = null): bool { return p\Mbstring::mb_check_encoding($value, $encoding); } +} +if (!function_exists('mb_detect_encoding')) { + function mb_detect_encoding(?string $string, array|string|null $encodings = null, ?bool $strict = false): string|false { return p\Mbstring::mb_detect_encoding((string) $string, $encodings, (bool) $strict); } +} +if (!function_exists('mb_detect_order')) { + function mb_detect_order(array|string|null $encoding = null): array|bool { return p\Mbstring::mb_detect_order($encoding); } +} +if (!function_exists('mb_parse_str')) { + function mb_parse_str(?string $string, &$result = []): bool { parse_str((string) $string, $result); return (bool) $result; } +} +if (!function_exists('mb_strlen')) { + function mb_strlen(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strlen((string) $string, $encoding); } +} +if (!function_exists('mb_strpos')) { + function mb_strpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strpos((string) $haystack, (string) $needle, (int) $offset, $encoding); } +} +if (!function_exists('mb_strtolower')) { + function mb_strtolower(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtolower((string) $string, $encoding); } +} +if (!function_exists('mb_strtoupper')) { + function mb_strtoupper(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtoupper((string) $string, $encoding); } +} +if (!function_exists('mb_substitute_character')) { + function mb_substitute_character(string|int|null $substitute_character = null): string|int|bool { return p\Mbstring::mb_substitute_character($substitute_character); } +} +if (!function_exists('mb_substr')) { + function mb_substr(?string $string, ?int $start, ?int $length = null, ?string $encoding = null): string { return p\Mbstring::mb_substr((string) $string, (int) $start, $length, $encoding); } +} +if (!function_exists('mb_stripos')) { + function mb_stripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_stripos((string) $haystack, (string) $needle, (int) $offset, $encoding); } +} +if (!function_exists('mb_stristr')) { + function mb_stristr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_stristr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } +} +if (!function_exists('mb_strrchr')) { + function mb_strrchr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrchr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } +} +if (!function_exists('mb_strrichr')) { + function mb_strrichr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrichr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } +} +if (!function_exists('mb_strripos')) { + function mb_strripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strripos((string) $haystack, (string) $needle, (int) $offset, $encoding); } +} +if (!function_exists('mb_strrpos')) { + function mb_strrpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strrpos((string) $haystack, (string) $needle, (int) $offset, $encoding); } +} +if (!function_exists('mb_strstr')) { + function mb_strstr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strstr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } +} +if (!function_exists('mb_get_info')) { + function mb_get_info(?string $type = 'all'): array|string|int|false|null { return p\Mbstring::mb_get_info((string) $type); } +} +if (!function_exists('mb_http_output')) { + function mb_http_output(?string $encoding = null): string|bool { return p\Mbstring::mb_http_output($encoding); } +} +if (!function_exists('mb_strwidth')) { + function mb_strwidth(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strwidth((string) $string, $encoding); } +} +if (!function_exists('mb_substr_count')) { + function mb_substr_count(?string $haystack, ?string $needle, ?string $encoding = null): int { return p\Mbstring::mb_substr_count((string) $haystack, (string) $needle, $encoding); } +} +if (!function_exists('mb_output_handler')) { + function mb_output_handler(?string $string, ?int $status): string { return p\Mbstring::mb_output_handler((string) $string, (int) $status); } +} +if (!function_exists('mb_http_input')) { + function mb_http_input(?string $type = null): array|string|false { return p\Mbstring::mb_http_input($type); } +} + +if (!function_exists('mb_convert_variables')) { + function mb_convert_variables(?string $to_encoding, array|string|null $from_encoding, mixed &$var, mixed &...$vars): string|false { return p\Mbstring::mb_convert_variables((string) $to_encoding, $from_encoding ?? '', $var, ...$vars); } +} + +if (!function_exists('mb_ord')) { + function mb_ord(?string $string, ?string $encoding = null): int|false { return p\Mbstring::mb_ord((string) $string, $encoding); } +} +if (!function_exists('mb_chr')) { + function mb_chr(?int $codepoint, ?string $encoding = null): string|false { return p\Mbstring::mb_chr((int) $codepoint, $encoding); } +} +if (!function_exists('mb_scrub')) { + function mb_scrub(?string $string, ?string $encoding = null): string { $encoding ??= mb_internal_encoding(); return mb_convert_encoding((string) $string, $encoding, $encoding); } +} +if (!function_exists('mb_str_split')) { + function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = null): array { return p\Mbstring::mb_str_split((string) $string, (int) $length, $encoding); } +} + +if (!function_exists('mb_str_pad')) { + function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); } +} + +if (!function_exists('mb_ucfirst')) { + function mb_ucfirst($string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); } +} + +if (!function_exists('mb_lcfirst')) { + function mb_lcfirst($string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); } +} + +if (!function_exists('mb_trim')) { + function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_trim($string, $characters, $encoding); } +} + +if (!function_exists('mb_ltrim')) { + function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_ltrim($string, $characters, $encoding); } +} + +if (!function_exists('mb_rtrim')) { + function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_rtrim($string, $characters, $encoding); } +} + +if (extension_loaded('mbstring')) { + return; +} + +if (!defined('MB_CASE_UPPER')) { + define('MB_CASE_UPPER', 0); +} +if (!defined('MB_CASE_LOWER')) { + define('MB_CASE_LOWER', 1); +} +if (!defined('MB_CASE_TITLE')) { + define('MB_CASE_TITLE', 2); +} diff --git a/includes/vendor/symfony/polyfill-mbstring/composer.json b/includes/vendor/symfony/polyfill-mbstring/composer.json index 02b8896f7..4ed241a33 100644 --- a/includes/vendor/symfony/polyfill-mbstring/composer.json +++ b/includes/vendor/symfony/polyfill-mbstring/composer.json @@ -16,7 +16,10 @@ } ], "require": { - "php": ">=5.3.3" + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" }, "autoload": { "psr-4": { "Symfony\\Polyfill\\Mbstring\\": "" }, @@ -27,8 +30,9 @@ }, "minimum-stability": "dev", "extra": { - "branch-alias": { - "dev-master": "1.15-dev" + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } } } diff --git a/includes/vendor/symfony/polyfill-php72/LICENSE b/includes/vendor/symfony/polyfill-php72/LICENSE deleted file mode 100644 index 4cd8bdd30..000000000 --- a/includes/vendor/symfony/polyfill-php72/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2015-2019 Fabien Potencier - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished -to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/includes/vendor/symfony/polyfill-php72/Php72.php b/includes/vendor/symfony/polyfill-php72/Php72.php deleted file mode 100644 index 2b706d42b..000000000 --- a/includes/vendor/symfony/polyfill-php72/Php72.php +++ /dev/null @@ -1,217 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Polyfill\Php72; - -/** - * @author Nicolas Grekas - * @author Dariusz Rumiński - * - * @internal - */ -final class Php72 -{ - private static $hashMask; - - public static function utf8_encode($s) - { - $s .= $s; - $len = \strlen($s); - - for ($i = $len >> 1, $j = 0; $i < $len; ++$i, ++$j) { - switch (true) { - case $s[$i] < "\x80": $s[$j] = $s[$i]; break; - case $s[$i] < "\xC0": $s[$j] = "\xC2"; $s[++$j] = $s[$i]; break; - default: $s[$j] = "\xC3"; $s[++$j] = \chr(\ord($s[$i]) - 64); break; - } - } - - return substr($s, 0, $j); - } - - public static function utf8_decode($s) - { - $s = (string) $s; - $len = \strlen($s); - - for ($i = 0, $j = 0; $i < $len; ++$i, ++$j) { - switch ($s[$i] & "\xF0") { - case "\xC0": - case "\xD0": - $c = (\ord($s[$i] & "\x1F") << 6) | \ord($s[++$i] & "\x3F"); - $s[$j] = $c < 256 ? \chr($c) : '?'; - break; - - case "\xF0": - ++$i; - // no break - - case "\xE0": - $s[$j] = '?'; - $i += 2; - break; - - default: - $s[$j] = $s[$i]; - } - } - - return substr($s, 0, $j); - } - - public static function php_os_family() - { - if ('\\' === \DIRECTORY_SEPARATOR) { - return 'Windows'; - } - - $map = [ - 'Darwin' => 'Darwin', - 'DragonFly' => 'BSD', - 'FreeBSD' => 'BSD', - 'NetBSD' => 'BSD', - 'OpenBSD' => 'BSD', - 'Linux' => 'Linux', - 'SunOS' => 'Solaris', - ]; - - return isset($map[\PHP_OS]) ? $map[\PHP_OS] : 'Unknown'; - } - - public static function spl_object_id($object) - { - if (null === self::$hashMask) { - self::initHashMask(); - } - if (null === $hash = spl_object_hash($object)) { - return; - } - - // On 32-bit systems, PHP_INT_SIZE is 4, - return self::$hashMask ^ hexdec(substr($hash, 16 - (\PHP_INT_SIZE * 2 - 1), (\PHP_INT_SIZE * 2 - 1))); - } - - public static function sapi_windows_vt100_support($stream, $enable = null) - { - if (!\is_resource($stream)) { - trigger_error('sapi_windows_vt100_support() expects parameter 1 to be resource, '.\gettype($stream).' given', \E_USER_WARNING); - - return false; - } - - $meta = stream_get_meta_data($stream); - - if ('STDIO' !== $meta['stream_type']) { - trigger_error('sapi_windows_vt100_support() was not able to analyze the specified stream', \E_USER_WARNING); - - return false; - } - - // We cannot actually disable vt100 support if it is set - if (false === $enable || !self::stream_isatty($stream)) { - return false; - } - - // The native function does not apply to stdin - $meta = array_map('strtolower', $meta); - $stdin = 'php://stdin' === $meta['uri'] || 'php://fd/0' === $meta['uri']; - - return !$stdin - && (false !== getenv('ANSICON') - || 'ON' === getenv('ConEmuANSI') - || 'xterm' === getenv('TERM') - || 'Hyper' === getenv('TERM_PROGRAM')); - } - - public static function stream_isatty($stream) - { - if (!\is_resource($stream)) { - trigger_error('stream_isatty() expects parameter 1 to be resource, '.\gettype($stream).' given', \E_USER_WARNING); - - return false; - } - - if ('\\' === \DIRECTORY_SEPARATOR) { - $stat = @fstat($stream); - // Check if formatted mode is S_IFCHR - return $stat ? 0020000 === ($stat['mode'] & 0170000) : false; - } - - return \function_exists('posix_isatty') && @posix_isatty($stream); - } - - private static function initHashMask() - { - $obj = (object) []; - self::$hashMask = -1; - - // check if we are nested in an output buffering handler to prevent a fatal error with ob_start() below - $obFuncs = ['ob_clean', 'ob_end_clean', 'ob_flush', 'ob_end_flush', 'ob_get_contents', 'ob_get_flush']; - foreach (debug_backtrace(\PHP_VERSION_ID >= 50400 ? \DEBUG_BACKTRACE_IGNORE_ARGS : false) as $frame) { - if (isset($frame['function'][0]) && !isset($frame['class']) && 'o' === $frame['function'][0] && \in_array($frame['function'], $obFuncs)) { - $frame['line'] = 0; - break; - } - } - if (!empty($frame['line'])) { - ob_start(); - debug_zval_dump($obj); - self::$hashMask = (int) substr(ob_get_clean(), 17); - } - - self::$hashMask ^= hexdec(substr(spl_object_hash($obj), 16 - (\PHP_INT_SIZE * 2 - 1), (\PHP_INT_SIZE * 2 - 1))); - } - - public static function mb_chr($code, $encoding = null) - { - if (0x80 > $code %= 0x200000) { - $s = \chr($code); - } elseif (0x800 > $code) { - $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F); - } elseif (0x10000 > $code) { - $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); - } else { - $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); - } - - if ('UTF-8' !== $encoding) { - $s = mb_convert_encoding($s, $encoding, 'UTF-8'); - } - - return $s; - } - - public static function mb_ord($s, $encoding = null) - { - if (null === $encoding) { - $s = mb_convert_encoding($s, 'UTF-8'); - } elseif ('UTF-8' !== $encoding) { - $s = mb_convert_encoding($s, 'UTF-8', $encoding); - } - - if (1 === \strlen($s)) { - return \ord($s); - } - - $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0; - if (0xF0 <= $code) { - return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80; - } - if (0xE0 <= $code) { - return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80; - } - if (0xC0 <= $code) { - return (($code - 0xC0) << 6) + $s[2] - 0x80; - } - - return $code; - } -} diff --git a/includes/vendor/symfony/polyfill-php72/README.md b/includes/vendor/symfony/polyfill-php72/README.md deleted file mode 100644 index 59dec8a23..000000000 --- a/includes/vendor/symfony/polyfill-php72/README.md +++ /dev/null @@ -1,28 +0,0 @@ -Symfony Polyfill / Php72 -======================== - -This component provides functions added to PHP 7.2 core: - -- [`spl_object_id`](https://php.net/spl_object_id) -- [`stream_isatty`](https://php.net/stream_isatty) - -On Windows only: - -- [`sapi_windows_vt100_support`](https://php.net/sapi_windows_vt100_support) - -Moved to core since 7.2 (was in the optional XML extension earlier): - -- [`utf8_encode`](https://php.net/utf8_encode) -- [`utf8_decode`](https://php.net/utf8_decode) - -Also, it provides constants added to PHP 7.2: -- [`PHP_FLOAT_*`](https://php.net/reserved.constants#constant.php-float-dig) -- [`PHP_OS_FAMILY`](https://php.net/reserved.constants#constant.php-os-family) - -More information can be found in the -[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). - -License -======= - -This library is released under the [MIT license](LICENSE). diff --git a/includes/vendor/symfony/polyfill-php72/bootstrap.php b/includes/vendor/symfony/polyfill-php72/bootstrap.php deleted file mode 100644 index b5c92d4c7..000000000 --- a/includes/vendor/symfony/polyfill-php72/bootstrap.php +++ /dev/null @@ -1,57 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -use Symfony\Polyfill\Php72 as p; - -if (\PHP_VERSION_ID >= 70200) { - return; -} - -if (!defined('PHP_FLOAT_DIG')) { - define('PHP_FLOAT_DIG', 15); -} -if (!defined('PHP_FLOAT_EPSILON')) { - define('PHP_FLOAT_EPSILON', 2.2204460492503E-16); -} -if (!defined('PHP_FLOAT_MIN')) { - define('PHP_FLOAT_MIN', 2.2250738585072E-308); -} -if (!defined('PHP_FLOAT_MAX')) { - define('PHP_FLOAT_MAX', 1.7976931348623157E+308); -} -if (!defined('PHP_OS_FAMILY')) { - define('PHP_OS_FAMILY', p\Php72::php_os_family()); -} - -if ('\\' === \DIRECTORY_SEPARATOR && !function_exists('sapi_windows_vt100_support')) { - function sapi_windows_vt100_support($stream, $enable = null) { return p\Php72::sapi_windows_vt100_support($stream, $enable); } -} -if (!function_exists('stream_isatty')) { - function stream_isatty($stream) { return p\Php72::stream_isatty($stream); } -} -if (!function_exists('utf8_encode')) { - function utf8_encode($string) { return p\Php72::utf8_encode($string); } -} -if (!function_exists('utf8_decode')) { - function utf8_decode($string) { return p\Php72::utf8_decode($string); } -} -if (!function_exists('spl_object_id')) { - function spl_object_id($object) { return p\Php72::spl_object_id($object); } -} -if (!function_exists('mb_ord')) { - function mb_ord($string, $encoding = null) { return p\Php72::mb_ord($string, $encoding); } -} -if (!function_exists('mb_chr')) { - function mb_chr($codepoint, $encoding = null) { return p\Php72::mb_chr($codepoint, $encoding); } -} -if (!function_exists('mb_scrub')) { - function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); } -} diff --git a/includes/vendor/symfony/polyfill-php72/composer.json b/includes/vendor/symfony/polyfill-php72/composer.json deleted file mode 100644 index 7946892c3..000000000 --- a/includes/vendor/symfony/polyfill-php72/composer.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "symfony/polyfill-php72", - "type": "library", - "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", - "keywords": ["polyfill", "shim", "compatibility", "portable"], - "homepage": "https://symfony.com", - "license": "MIT", - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "require": { - "php": ">=7.1" - }, - "autoload": { - "psr-4": { "Symfony\\Polyfill\\Php72\\": "" }, - "files": [ "bootstrap.php" ] - }, - "minimum-stability": "dev", - "extra": { - "branch-alias": { - "dev-main": "1.22-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - } -} diff --git a/includes/version.php b/includes/version.php index baa1a78d4..9af59b7dd 100644 --- a/includes/version.php +++ b/includes/version.php @@ -9,7 +9,7 @@ * MAJOR.MINOR.PATCH-SOMETHING (1.8.1-donotuse) * */ -define( 'YOURLS_VERSION', '1.8.3-dev' ); +define( 'YOURLS_VERSION', '1.10.4-dev' ); /** * YOURLS DB version. Increments when changes are made to the DB schema, to trigger a DB update @@ -17,4 +17,4 @@ * Must be a string of an integer. * */ -define( 'YOURLS_DB_VERSION', '506' ); +define( 'YOURLS_DB_VERSION', '507' ); diff --git a/js/common.js b/js/common.js index 65f5b6d99..5850a8b15 100644 --- a/js/common.js +++ b/js/common.js @@ -55,7 +55,7 @@ function logout() { // Begin the spinning animation & disable a button function add_loading(el) { - $(el).attr("disabled", "disabled").addClass('disabled').addClass('loading'); + $(el).attr("disabled", "disabled").addClass('disabled').addClass('loading').attr("aria-disabled", "true"); } // End spinning animation @@ -65,7 +65,7 @@ function end_loading(el) { // Un-disable an element function end_disable(el) { - $(el).removeAttr("disabled").removeClass('disabled'); + $(el).removeAttr("disabled").removeClass('disabled').removeAttr("aria-disabled"); } // Trim long string @@ -165,4 +165,4 @@ function get_protocol_slashes_and_rest( url ) { } else { return { protocol: '', slashes: '', rest: url };; } -} \ No newline at end of file +} diff --git a/js/insert.js b/js/insert.js index 8298f7fe2..1f373d6cb 100644 --- a/js/insert.js +++ b/js/insert.js @@ -35,10 +35,11 @@ function add_link() { return; } var keyword = $("#add-keyword").val(); + var nextid = parseInt($('#main_table tbody tr[id^="id-"]').length) + 1; add_loading("#add-button"); $.getJSON( ajaxurl, - {action:'add', url: newurl, keyword: keyword, nonce: nonce}, + {action:'add', url: newurl, keyword: keyword, nonce: nonce, rowid: nextid}, function(data){ if(data.status == 'success') { $('#main_table tbody').prepend( data.html ).trigger("update"); @@ -89,34 +90,65 @@ function edit_link_display(id) { // Delete a link function remove_link(id) { - if( $('#delete-button-'+id).hasClass('disabled') ) { - return false; - } - if (!confirm('Really delete?')) { - return; - } - var keyword = $('#keyword_'+id).val(); - var nonce = get_var_from_query( $('#delete-button-'+id).attr('href'), 'nonce' ); - $.getJSON( - ajaxurl, - { action: "delete", keyword: keyword, nonce: nonce, id: id }, - function(data){ - if (data.success == 1) { - $("#id-" + id).fadeOut(function(){ - $(this).remove(); - if( $('#main_table tbody tr').length == 1 ) { - $('#nourl_found').css('display', ''); - } - - zebra_table(); - }); - decrement_counter(); - decrease_total_clicks( id ); - } else { - alert('something wrong happened while deleting :/'); - } - } - ); + if( $('#delete-button-'+id).hasClass('disabled') ) { + return false; + } + var dialog = $('#delete-confirm-dialog')[0]; + dialog.showModal(); + + $('#delete-confirm-dialog input[name="keyword_id"]').val(id); + var keyword = trim_long_string( $('#keyword-'+id+' > a').text() ); + $('#delete-confirm-dialog span[name="short_url"]').text(keyword); + var title = trim_long_string( $('#url-'+id+' > a').attr('title') ); + $('#delete-confirm-dialog span[name="title"]').text(title); + var url = trim_long_string( $('#url-'+id+' > a').attr('href') ); + $('#delete-confirm-dialog span[name="url"]').text(url); + + // Listen for dialog close event (handles Escape key) + $(dialog).one('close', function() { + if (document.activeElement) { + document.activeElement.blur(); + } + }); + + // Show dialog, don't follow link + return false; +} + +function remove_link_confirmed(id) { + var id = $('#delete-confirm-dialog input[name="keyword_id"]').val(); + var keyword = $('#keyword_'+id).val(); + var nonce = get_var_from_query( $('#delete-button-'+id).attr('href'), 'nonce' ); + $.getJSON( + ajaxurl, + { action: "delete", keyword: keyword, nonce: nonce, id: id }, + function(data){ + if (data.success == 1) { + $("#id-" + id).fadeOut(function(){ + $(this).remove(); + if( $('#main_table tbody tr').length == 1 ) { + $('#nourl_found').css('display', ''); + } + + zebra_table(); + }); + decrement_counter(); + decrease_total_clicks( id ); + } else { + feedback('something wrong happened while deleting!' , 'fail'); + } + $('#delete-confirm-dialog')[0].close(); + } + ); +} + +function remove_link_canceled() { + $('#delete-confirm-dialog')[0].close(); + + // Force blur on all interactive elements to restore action buttons opacity + if (document.activeElement) { + document.activeElement.blur(); + } } // Redirect to stat page @@ -229,4 +261,3 @@ function split_search_text_before_search() { $('#filter_form input[name=search_protocol]').val( search.protocol ); $('#filter_form input[name=search_slashes]').val( search.slashes ); } - diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 0c61fbc4c..95a9546ce 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,44 +1,52 @@ - - - - ./tests/tests - - - - - ajax - - - - + bootstrap="tests/bootstrap.php" + colors="true" + displayDetailsOnTestsThatTriggerDeprecations="true" + displayDetailsOnTestsThatTriggerErrors="true" + displayDetailsOnTestsThatTriggerNotices="true" + displayDetailsOnTestsThatTriggerWarnings="true" + displayDetailsOnPhpunitDeprecations="true" + > + + ./includes - - ./includes/vendors - - - - - - - - - - - - - - - - - - + + + ./includes/vendors + + + + + ./tests/tests + ./tests/tests/auth/AbstractLoginTestCase.php + ./tests/tests/auth/LoginAssertionTrait.php + + + + + ajax + + + + + + + + + + + + + + + + + diff --git a/readme.html b/readme.html index dcce73020..4fc1fd296 100644 --- a/readme.html +++ b/readme.html @@ -273,7 +273,7 @@

    YOURLS: Your Own YOURLS is made by awesome people.

    -

    Keep up to date: read the official YOURLS Blog.

    +

    Keep up to date: read the official YOURLS Blog.

    @@ -288,7 +288,7 @@

    YOURLS: Your Own Point your browser to http://your-own-domain-here.com/admin/

  • Install Guides

    -

    The wiki is full of important information. Regarding installation, you'll find help for Apache, IIS and Nginx.

    +

    The documentation on docs.yourls.org is full of important information. Regarding installation, you'll find help for Apache and Nginx.

    You will also find numerous unofficial installation guides on Awesome YOURLS, a curated list of resources.

    Upgrade

    @@ -371,7 +371,7 @@

    YOURLS: Your Own
  • You can install YOURLS behind a firewall or a proxy: see Proxy Support
  • File includes/Config/Config.php contains a few more undocumented but self explanatory and commented settings. Add them to your own config.php if you know what you're doing.
  • -
  • There are numerous tips and guides on the Wiki, be sure to read them.
  • +
  • There are numerous tips and guides on the Documentation, be sure to read them.
@@ -504,7 +504,7 @@

YOURLS: Your Own

Sample return in XML format for the expand action

@@ -531,10 +531,11 @@

YOURLS: Your Own

Server requirements and recommendations

    -
  1. We recommend PHP 7.4 or above
  2. +
  3. PHP 8.1 or above is required
  4. You will need at least MYSQL 5
  5. A web server with mod_rewrite enabled
    - Note: YOURLS can also run on Nginx, IIS and Cherokee
  6. + Note: YOURLS can also run on Nginx, + Cherokee and more !
  7. HTTPS support
  8. PHP CURL extension installed if you plan on playing with the API
@@ -556,8 +557,8 @@

YOURLS: Your Own

Getting a short domain name for your YOURLS install

  • Unless you plan on making it public and as popular as bit.ly, any shared hosting will be fine. Ozh runs all his YOURLS instance on Dreamhost and it works just great.
  • -
  • Domainr is a fun search tool that might inspire and help you
  • -
  • Aim for exotic top-level domains (.in, .im, .li ...), they're often cheap and a lot are still available. Gandi is a pretty comprehensive registrar, for instance.
  • +
  • Domainr is a fun search tool that might inspire and help you. TLD List has each and every existing top level domain.
  • +
  • Aim for exotic top-level domains (.in, .im, .li, .xyz ...), they're often cheap and a lot are still available.

YOURLS needs its own .htaccess

@@ -603,7 +604,7 @@

YOURLS: Your Own

Feedback, feature requests and bug reporting

  1. Please don't get in touch directly by mail or Twitter. Please.
  2. -
  3. Read all the wiki documents.
  4. +
  5. Read all the documentation.
  6. Search in all the issues, open and closed.
  7. Eventually raise a new issue. To do so, please read the contribute guidelines. Thanks!
@@ -621,7 +622,7 @@

YOURLS: Your Own

Resources

  • The official YOURLS blog, for news, hints and showcase.
  • -
  • The wiki: basic and advanced documentation, plugins, tips and more
  • +
  • The documentations: basic and advanced documentation, plugins, tips and more
  • Awesome YOURLS is a curated list of YOURLS resources, plugins, translations, guides and third-party tools.
diff --git a/sample-public-front-page.txt b/sample-public-front-page.txt index 7bc9b0e7e..3497bc933 100644 --- a/sample-public-front-page.txt +++ b/sample-public-front-page.txt @@ -3,7 +3,7 @@ /* * This is an example file for a public interface and a bookmarklet. It * is provided so you can build from it and customize to suit your needs. - * It's not really part of the project. Don't submit feature requests + * It's not really part of the project. Don't submit feature requests * about this file. It's _your_ job to make it what you need it to be :) * * Rename to .php @@ -27,19 +27,19 @@ if ( isset( $_REQUEST['url'] ) && $_REQUEST['url'] != 'http://' ) { // Create short URL, receive array $return with various information $return = yourls_add_new_link( $url, $keyword, $title ); - + $shorturl = isset( $return['shorturl'] ) ? $return['shorturl'] : ''; $message = isset( $return['message'] ) ? $return['message'] : ''; $title = isset( $return['title'] ) ? $return['title'] : ''; $status = isset( $return['status'] ) ? $return['status'] : ''; - + // Stop here if bookmarklet with a JSON callback function ("instant" bookmarklets) if( isset( $_GET['jsonp'] ) && $_GET['jsonp'] == 'yourls' ) { $short = $return['shorturl'] ? $return['shorturl'] : ''; $message = "Short URL (Ctrl+C to copy)"; header('Content-type: application/json'); echo yourls_apply_filter( 'bookmarklet_jsonp', "yourls_callback({'short_url':'$short','message':'$message'});" ); - + die(); } } @@ -60,11 +60,11 @@ if ( isset( $_REQUEST['url'] ) && $_REQUEST['url'] != 'http://' ) { if( isset( $message ) ) { echo "

$message

"; } - + if( $status == 'success' ) { // Include the Copy box and the Quick Share box yourls_share_box( $url, $shorturl, $title, $text ); - + // Initialize clipboard -- requires js/share.js and js/clipboard.min.js to be properly loaded in the echo "\n"; } @@ -73,7 +73,7 @@ if ( isset( $_REQUEST['url'] ) && $_REQUEST['url'] != 'http://' ) { } else { $site = YOURLS_SITE; - + // Display the form echo <<Enter a new URL to shorten

@@ -82,7 +82,7 @@ if ( isset( $_REQUEST['url'] ) && $_REQUEST['url'] != 'http://' ) {

- + HTML; } @@ -99,9 +99,9 @@ HTML; Custom -Popup +Popup -Custom Popup +Custom Popup

@@ -112,4 +112,4 @@ HTML; tests/data/config/yourls-tests-config-sample.php` to `/tests/yourls-tests-config.php` and edit it to match your setup. +0. Install PHPUnit. + ```bash + composer -d tests/ install + ``` +1. Create an empty MySQL database and user. **Do not use an exisiting database** or you will lose data, guaranteed. +3. Copy `tests/data/config/yourls-tests-config-sample.php` to `/tests/yourls-tests-config.php` and edit it to match your setup. + ```bash + cp tests/data/config/yourls-tests-config-sample.php tests/yourls-tests-config.php + ``` 4. In YOURLS root directory, you can now run the shell command: -```bash -$ phpunit -``` + ```bash + composer -d tests/ run test -- --configuration=../phpunit.xml.dist .. + ``` Hopefully you should see something like the following appear: ``` YOURLS installed, starting PHPUnit -PHPUnit 7.5.20 by Sebastian Bergmann and contributors. +PHPUnit by Sebastian Bergmann and contributors. -Runtime: PHP 7.4.3 -Configuration: D:\home\planetozh\ozh.in\phpunit.xml.dist +Configuration: ...\phpunit.xml.dist ............................................................... 63 / 519 ( 12%) ............................................................... 126 / 519 ( 24%) @@ -50,7 +52,5 @@ You can elect to run only selected groups of tests, eg: $ phpunit --group formatting ``` -See each `@group` directive in selected tests. - PHPUnit supports both `phpunit.xml` and `phpunit.xml.dist`, where `phpunit.xml` has higher priority: if you want to specify your own settings, copy `phpunit.xml.dist` to `phpunit.xml` and edit that file. diff --git a/tests/bootstrap.php b/tests/bootstrap.php index c4320a587..d4da057f2 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -11,16 +11,17 @@ $yourls_locale, $yourls_l10n, $yourls_locale_formats, // used by L10N API $yourls_allowedentitynames, $yourls_allowedprotocols; // used by KSES -require_once dirname( __FILE__ ) . '/includes/utils.php'; -require_once dirname( __FILE__ ) . '/includes/install.php'; +require_once __DIR__ . '/includes/utils.php'; +require_once __DIR__ . '/includes/install.php'; // Include relevant config file define('YOURLS_CONFIGFILE', yut_find_config()); +echo "Using config file: " . YOURLS_CONFIGFILE . "\n"; require_once YOURLS_CONFIGFILE; // Bootstrap YOURLS require_once YOURLS_ABSPATH . '/includes/vendor/autoload.php'; -define('YOURLS_TESTDATA_DIR', dirname( __FILE__ ) . '/data'); +define('YOURLS_TESTDATA_DIR', __DIR__ . '/data'); define('YOURLS_LANG_DIR', YOURLS_TESTDATA_DIR.'/pomo'); define('YOURLS_PLUGINDIR', YOURLS_TESTDATA_DIR.'/plugins'); define('YOURLS_PAGEDIR', YOURLS_TESTDATA_DIR.'/pages'); @@ -37,7 +38,6 @@ $init->load_plugins = false; // do not attempt to load (no DB yet to store data), but do send the 'plugins_loaded' action (some code depend on it) $init->get_all_options = false; $init->check_new_version = false; -$init->include_install_upgrade_funcs = true; new \YOURLS\Config\Init($init); // All set -- install @@ -48,4 +48,20 @@ yourls_load_plugins(); // At this point, tests will start + +// Simplify yourls_die() when running unit tests +yourls_add_action( 'pre_yourls_die', function($params) { + printf("\n\nCalling yourls_die(). %s : %s (%s)\n\n", $params[1], $params[0], $params[2]); + echo "Last 10 Backtrace:\n"; + $trace = debug_backtrace(); + foreach( array_slice($trace, 0, 10) as $t ) { + printf("** %s:%d %s() with args\n%s\n", $t['file'], $t['line'], $t['function'], var_export($t['args'], true)); + } + + die(1); +} ); + echo "YOURLS installed, starting PHPUnit\n\n"; + +require_once __DIR__ . "/tests/auth/AbstractLoginTestCase.php"; +require_once __DIR__ . "/tests/auth/LoginAssertionTrait.php"; diff --git a/tests/composer.lock b/tests/composer.lock new file mode 100644 index 000000000..5f50e7ca1 --- /dev/null +++ b/tests/composer.lock @@ -0,0 +1,1707 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "9fcd71b761cb2ca79908f32b4f52bfd1", + "packages": [ + { + "name": "myclabs/deep-copy", + "version": "1.13.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "024473a478be9df5fdaca2c793f2232fe788e414" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414", + "reference": "024473a478be9df5fdaca2c793f2232fe788e414", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "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", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-02-12T12:17:51+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.4.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" + }, + "time": "2024-12-30T11:07:19+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "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", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "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.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "11.0.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/14d63fbcca18457e49c6f8bebaa91a87e8e188d7", + "reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.4.0", + "php": ">=8.2", + "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-text-template": "^4.0.1", + "sebastian/code-unit-reverse-lookup": "^4.0.1", + "sebastian/complexity": "^4.0.1", + "sebastian/environment": "^7.2.0", + "sebastian/lines-of-code": "^3.0.1", + "sebastian/version": "^5.0.2", + "theseer/tokenizer": "^1.2.3" + }, + "require-dev": { + "phpunit/phpunit": "^11.5.2" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "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/11.0.9" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-25T13:26:39+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "5.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/118cfaaa8bc5aef3287bf315b6060b1174754af6", + "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-08-27T05:02:59+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "5.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^11.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:07:44+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:08:43+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "7.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:09:35+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "11.5.10", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "d5df2b32d729562ff8db634678d71085ee579006" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d5df2b32d729562ff8db634678d71085ee579006", + "reference": "d5df2b32d729562ff8db634678d71085ee579006", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.0", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=8.2", + "phpunit/php-code-coverage": "^11.0.8", + "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-invoker": "^5.0.1", + "phpunit/php-text-template": "^4.0.1", + "phpunit/php-timer": "^7.0.1", + "sebastian/cli-parser": "^3.0.2", + "sebastian/code-unit": "^3.0.2", + "sebastian/comparator": "^6.3.0", + "sebastian/diff": "^6.0.2", + "sebastian/environment": "^7.2.0", + "sebastian/exporter": "^6.3.0", + "sebastian/global-state": "^7.0.2", + "sebastian/object-enumerator": "^6.0.1", + "sebastian/type": "^5.1.0", + "sebastian/version": "^5.0.2", + "staabm/side-effects-detector": "^1.0.5" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.5-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.10" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2025-02-25T06:11:48+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:41:36+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "ee88b0cdbe74cf8dd3b54940ff17643c0d6543ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/ee88b0cdbe74cf8dd3b54940ff17643c0d6543ca", + "reference": "ee88b0cdbe74cf8dd3b54940ff17643c0d6543ca", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "security": "https://github.com/sebastianbergmann/code-unit/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-12-12T09:59:06+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:45:54+00:00" + }, + { + "name": "sebastian/comparator", + "version": "6.3.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "d4e47a769525c4dd38cea90e5dcd435ddbbc7115" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/d4e47a769525c4dd38cea90e5dcd435ddbbc7115", + "reference": "d4e47a769525c4dd38cea90e5dcd435ddbbc7115", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/diff": "^6.0", + "sebastian/exporter": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.4" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-01-06T10:28:19+00:00" + }, + { + "name": "sebastian/complexity", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:49:50+00:00" + }, + { + "name": "sebastian/diff", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:53:05+00:00" + }, + { + "name": "sebastian/environment", + "version": "7.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5", + "reference": "855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "https://github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/7.2.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:54:44+00:00" + }, + { + "name": "sebastian/exporter", + "version": "6.3.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/3473f61172093b2da7de1fb5782e1f24cc036dc3", + "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-12-05T09:17:50+00:00" + }, + { + "name": "sebastian/global-state", + "version": "7.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:57:36+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:58:38+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "6.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:00:13+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:01:32+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "694d156164372abbd149a4b85ccda2e4670c0e16" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/694d156164372abbd149a4b85ccda2e4670c0e16", + "reference": "694d156164372abbd149a4b85ccda2e4670c0e16", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:10:34+00:00" + }, + { + "name": "sebastian/type", + "version": "5.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "461b9c5da241511a2a0e8f240814fb23ce5c0aac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/461b9c5da241511a2a0e8f240814fb23ce5c0aac", + "reference": "461b9c5da241511a2a0e8f240814fb23ce5c0aac", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/5.1.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-09-17T13:12:04+00:00" + }, + { + "name": "sebastian/version", + "version": "5.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/5.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-10-09T05:16:32+00:00" + }, + { + "name": "staabm/side-effects-detector", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + }, + "funding": [ + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2024-10-20T05:08:20+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "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.3" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:36:25+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": false, + "prefer-lowest": false, + "platform": {}, + "platform-dev": {}, + "plugin-api-version": "2.6.0" +} diff --git a/tests/data/auth/config-test-auth.php b/tests/data/auth/config-test-auth.php index aad741ce2..7b89a2275 100644 --- a/tests/data/auth/config-test-auth.php +++ b/tests/data/auth/config-test-auth.php @@ -8,5 +8,6 @@ 'quote1' => '"ahah"', 'quote2' => "'ahah'", 'utf8fun' => 'أنا أحب النقانق', - ); + 's[p]e(c)i{a}!@#$%^&*-=l<>,/?' => 'password', + ); diff --git a/tests/data/auth/empty.php b/tests/data/auth/empty.php new file mode 100644 index 000000000..e69de29bb diff --git a/tests/data/auth/nopassword.php b/tests/data/auth/nopassword.php new file mode 100644 index 000000000..c4f377508 --- /dev/null +++ b/tests/data/auth/nopassword.php @@ -0,0 +1,3 @@ + $password, +]; diff --git a/tests/data/config/yourls-tests-config-ci.php b/tests/data/config/yourls-tests-config-ci.php index ef7ad7d79..1dcd2564f 100644 --- a/tests/data/config/yourls-tests-config-ci.php +++ b/tests/data/config/yourls-tests-config-ci.php @@ -30,15 +30,17 @@ define('YOURLS_DEBUG', true); $yourls_reserved_URL = array( - 'porn', 'sex', 'nigger', 'fuck', 'cunt', 'dick', + 'porn', 'sex', 'nigger', 'fuck', 'cunt', 'dick', ); $yourls_user_passwords = array( - 'yourls' => 'secret-ci-test', - 'clear' => 'somepassword', - 'md5' => 'md5:12373:e52e4488f79a740bd341f229e3c163c8', // password: '3cd6944201fa7bbc5e0fe852e36b1096' with md5 and salt - 'phpass' => 'phpass:!2a!08!T1ptMlBSxu7g3odpbUXgd.9wbKvg8k7cJt.HbwSqUNrlLPudWnf/6', // password: '3cd6944201fa7bbc5e0fe852e36b1096' with PHPass - 'phpass2' => 'phpass:$2a$08$gt2bnpfUyuCX3hrp0RPOieFR1RwBnLsMzpq/NvPXwCdV3LqI3RGYi', // password: also '3cd6944201fa7bbc5e0fe852e36b1096' but without YOURLS internal char substitution + 'yourls' => 'secret-ci-test', + 'clear' => 'somepassword', + 'md5' => 'md5:12373:e52e4488f79a740bd341f229e3c163c8', // password: '3cd6944201fa7bbc5e0fe852e36b1096' with md5 and salt + 'phpass' => 'phpass:!2a!08!T1ptMlBSxu7g3odpbUXgd.9wbKvg8k7cJt.HbwSqUNrlLPudWnf/6', // password: '3cd6944201fa7bbc5e0fe852e36b1096' with old PHPass library + 'phpass2' => 'phpass:$2a$08$gt2bnpfUyuCX3hrp0RPOieFR1RwBnLsMzpq/NvPXwCdV3LqI3RGYi', // password: also '3cd6944201fa7bbc5e0fe852e36b1096' with old PHPass lib but without YOURLS internal char substitution + 'phpass3' => 'phpass:!2y!10!.FjK.vQR0JVivkMwckiiIesFUFhtMxX/f9pes.i/ccp/W0IuUSxPW', // password: also '3cd6944201fa7bbc5e0fe852e36b1096' hashed with password_hash + 'phpass4' => 'phpass:$2y$10$KPP/sv7pv0JL2GwcixNBfuXRPElC4KxQUgetqBfCboB.q30yKwKG6', // password: also '3cd6944201fa7bbc5e0fe852e36b1096' hashed with password_hash but without YOURLS internal char substitution '1994' => '@$*', 'special' => 'lol .\+*?[^]$(){}=!<>|:-/', 'quote1' => '"ahah"', diff --git a/tests/data/config/yourls-tests-config-sample.php b/tests/data/config/yourls-tests-config-sample.php index b1eb7563b..213c907e5 100644 --- a/tests/data/config/yourls-tests-config-sample.php +++ b/tests/data/config/yourls-tests-config-sample.php @@ -1,6 +1,6 @@ 'secret-ci-test', - 'clear' => 'somepassword', - 'md5' => 'md5:12373:e52e4488f79a740bd341f229e3c163c8', // password: '3cd6944201fa7bbc5e0fe852e36b1096' with md5 and salt - 'phpass' => 'phpass:!2a!08!T1ptMlBSxu7g3odpbUXgd.9wbKvg8k7cJt.HbwSqUNrlLPudWnf/6', // password: '3cd6944201fa7bbc5e0fe852e36b1096' with PHPass - 'phpass2' => 'phpass:$2a$08$gt2bnpfUyuCX3hrp0RPOieFR1RwBnLsMzpq/NvPXwCdV3LqI3RGYi', // password: also '3cd6944201fa7bbc5e0fe852e36b1096' but without YOURLS internal char substitution + 'yourls' => 'secret-ci-test', + 'clear' => 'somepassword', + 'md5' => 'md5:12373:e52e4488f79a740bd341f229e3c163c8', // password: '3cd6944201fa7bbc5e0fe852e36b1096' with md5 and salt + 'phpass' => 'phpass:!2a!08!T1ptMlBSxu7g3odpbUXgd.9wbKvg8k7cJt.HbwSqUNrlLPudWnf/6', // password: '3cd6944201fa7bbc5e0fe852e36b1096' with old PHPass library + 'phpass2' => 'phpass:$2a$08$gt2bnpfUyuCX3hrp0RPOieFR1RwBnLsMzpq/NvPXwCdV3LqI3RGYi', // password: also '3cd6944201fa7bbc5e0fe852e36b1096' with old PHPass lib but without YOURLS internal char substitution + 'phpass3' => 'phpass:!2y!10!.FjK.vQR0JVivkMwckiiIesFUFhtMxX/f9pes.i/ccp/W0IuUSxPW', // password: also '3cd6944201fa7bbc5e0fe852e36b1096' hashed with password_hash + 'phpass4' => 'phpass:$2y$10$KPP/sv7pv0JL2GwcixNBfuXRPElC4KxQUgetqBfCboB.q30yKwKG6', // password: also '3cd6944201fa7bbc5e0fe852e36b1096' hashed with password_hash but without YOURLS internal char substitution '1994' => '@$*', 'special' => 'lol .\+*?[^]$(){}=!<>|:-/', 'quote1' => '"ahah"', diff --git a/tests/data/plugins/invalid-code/invalid_class_not_found.php b/tests/data/plugins/invalid-code/invalid_class_not_found.php new file mode 100644 index 000000000..0c5c5d011 --- /dev/null +++ b/tests/data/plugins/invalid-code/invalid_class_not_found.php @@ -0,0 +1,14 @@ + + Hello World + + + + + + diff --git a/tests/data/remote-pages/title1.html b/tests/data/remote-pages/title1.html new file mode 100644 index 000000000..a050b0509 --- /dev/null +++ b/tests/data/remote-pages/title1.html @@ -0,0 +1 @@ +How <strong>Will</strong> I Laugh Tomorrow <em>When I Can't Even Smile Today</em> diff --git a/tests/data/remote-pages/title2.html b/tests/data/remote-pages/title2.html new file mode 100644 index 000000000..3e2042a1d --- /dev/null +++ b/tests/data/remote-pages/title2.html @@ -0,0 +1 @@ +Twilight <bleh omg="wtf" >of</bleh> the <blah something>Thunder God diff --git a/tests/includes/install.php b/tests/includes/install.php index 41bcba17c..4dc609a66 100644 --- a/tests/includes/install.php +++ b/tests/includes/install.php @@ -8,18 +8,18 @@ function yut_install_yourls() { yut_drop_all_tables_if_local(); - if (!yourls_check_database_version()) { - die( sprintf( 'MySQL version too old. Version is: %s', yourls_get_database_version() ) ); - } + if (!yourls_check_database_version()) { + die( sprintf( 'MySQL version too old. Version is: %s', yourls_get_database_version() ) ); + } - if (!yourls_check_php_version()) { - die( sprintf( 'PHP version too old. Version is: %s', phpversion() ) ); - } + if (!yourls_check_php_version()) { + die( sprintf( 'PHP version too old. Version is: %s', phpversion() ) ); + } - $create = yourls_create_sql_tables(); - if (array() != $create['error']) { - die( sprintf( 'Could not run SQL. Error is: %s', implode( "\n\n", $create['error'] ) ) ); - } + $create = yourls_create_sql_tables(); + if (array() != $create['error']) { + die( sprintf( 'Could not run SQL. Error is: %s', implode( "\n\n", $create['error'] ) ) ); + } } @@ -44,7 +44,7 @@ function yut_find_config() { } } - die( sprintf( "ERROR: config file missing. Current directory: %s\n", dirname(__DIR__) ) ); + die( sprintf( "ERROR: YOURLS config file missing. Current directory: %s\n", dirname(__DIR__) ) ); } /** @@ -55,11 +55,11 @@ function yut_find_config() { * @return void */ function yut_drop_all_tables_if_local() { - if( !yut_is_local() ) - return; + if( !yut_is_local() ) + return; - // If not running in Travis environment, drop any tables from the selected database prior to starting tests + // If not running in Travis environment, drop any tables from the selected database prior to starting tests $tables = sprintf('%s,%s,%s', YOURLS_DB_TABLE_URL, YOURLS_DB_TABLE_OPTIONS, YOURLS_DB_TABLE_LOG); $sql = sprintf('DROP TABLE IF EXISTS %s', $tables); - yourls_get_db()->perform($sql); + yourls_get_db('write-drop_tables_if_local')->perform($sql); } diff --git a/tests/includes/utils.php b/tests/includes/utils.php index 2a4cbc4bc..28171f720 100644 --- a/tests/includes/utils.php +++ b/tests/includes/utils.php @@ -12,7 +12,7 @@ * @return string Random string */ function rand_str( $len=32 ) { - return substr( md5( uniqid( rand() ) ), 0, $len ); + return substr( md5( uniqid( rand() ) ), 0, $len ); } /** @@ -21,7 +21,7 @@ function rand_str( $len=32 ) { * @since 0.1 */ function yut_is_local() { - return ! defined( 'YOURLS_TESTS_CI' ) || YOURLS_TESTS_CI === false; + return ! defined( 'YOURLS_TESTS_CI' ) || YOURLS_TESTS_CI === false; } /** @@ -116,27 +116,27 @@ function yourls_ut_var_dump( ...$what ) { */ class Log_in_File { - public static $has_logged = false; + public static $has_logged = false; - public static function log( $what ) { - // Don't mess with Travis - if( !yut_is_local() ) - return; + public static function log( $what ) { + // Don't mess with Travis + if( !yut_is_local() ) + return; - if( ! self::$has_logged ) { - self::$has_logged = true; - self::start_log(); - } + if( ! self::$has_logged ) { + self::$has_logged = true; + self::start_log(); + } - ob_start(); - var_dump( $what ); - $what = ob_get_clean(); + ob_start(); + var_dump( $what ); + $what = ob_get_clean(); - error_log( $what."\n", 3, dirname( dirname( __FILE__ ) ) . '/log.txt' ); - } + error_log( $what."\n", 3, dirname( dirname( __FILE__ ) ) . '/log.txt' ); + } - public static function start_log() { - self::log( "---------------- START TESTS ----------------" ); - } + public static function start_log() { + self::log( "---------------- START TESTS ----------------" ); + } } diff --git a/tests/tests/OptionTest.php b/tests/tests/OptionTest.php new file mode 100644 index 000000000..7bc82644b --- /dev/null +++ b/tests/tests/OptionTest.php @@ -0,0 +1,135 @@ +assertFalse( yourls_get_option( 'doesnotexist' ) ); + $this->assertTrue( yourls_add_option( $key, $value ) ); + $this->assertEquals( $value, yourls_get_option( $key ) ); + $this->assertFalse( yourls_add_option( $key, $value ) ); // Already exists + $this->assertFalse( yourls_update_option( $key, $value ) ); // Value is the same + $this->assertTrue( yourls_update_option( $key, $value2 ) ); + $this->assertEquals( $value2, yourls_get_option( $key ) ); + + $this->assertFalse( yourls_add_option( $key, $value ) ); + $this->assertEquals( $value2, yourls_get_option( $key ) ); + $this->assertTrue( yourls_delete_option( $key ) ); + $this->assertFalse( yourls_get_option( $key ) ); + $this->assertFalse( yourls_delete_option( $key ) ); + + $this->assertTrue( yourls_update_option( $key2, $value2 ) ); + $this->assertEquals( $value2, yourls_get_option( $key2 ) ); + $this->assertTrue( yourls_delete_option( $key2 ) ); + $this->assertFalse( yourls_get_option( $key2 ) ); + } + + /** + * Check with array and objects + * + * @since 0.1 + */ + public function test_serialized_data() { + $key = rand_str(); + $value = array( 'foo' => true, 'bar' => true ); + + $this->assertTrue( yourls_add_option( $key, $value ) ); + $this->assertEquals( $value, yourls_get_option( $key ) ); + + $value = (object) $value; + $this->assertTrue( yourls_update_option( $key, $value ) ); + $this->assertEquals( $value, yourls_get_option( $key ) ); + $this->assertTrue( yourls_delete_option( $key ) ); + } + + /** + * Data provider of bad option names + */ + public static function bad_option_names(): \Iterator + { + yield array( '' ); + yield array( '0' ); + yield array( ' ' ); + yield array( 0 ); + yield array( false ); + yield array( null ); + } + + /** + * Check with bad option names + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\DataProvider('bad_option_names')] + public function test_bad_option_names($empty) { + $this->assertFalse( yourls_get_option( $empty ) ); + $this->assertFalse( yourls_add_option( $empty, '' ) ); + $this->assertFalse( yourls_update_option( $empty, '' ) ); + $this->assertFalse( yourls_delete_option( $empty ) ); + } + + function setUp(): void { + parent::setUp(); + $this->slash_1 = 'String with 1 slash \\'; + $this->slash_2 = 'String with 2 slashes \\\\'; + $this->slash_3 = 'String with 3 slashes \\\\\\'; + $this->slash_4 = 'String with 4 slashes \\\\\\\\'; + $this->slash_5 = 'String with 5 slashes \\\\\\\\\\'; + $this->slash_6 = 'String with 6 slashes \\\\\\\\\\\\'; + $this->slash_7 = 'String with 7 slashes \\\\\\\\\\\\\\'; + } + + /** + * Tests the model function that expects un-slashed data + * + * @since 0.1 + */ + function test_add_option() { + yourls_add_option( 'slash_test_1', $this->slash_1 ); + yourls_add_option( 'slash_test_2', $this->slash_2 ); + yourls_add_option( 'slash_test_3', $this->slash_3 ); + yourls_add_option( 'slash_test_4', $this->slash_4 ); + + $this->assertEquals( $this->slash_1, yourls_get_option( 'slash_test_1' ) ); + $this->assertEquals( $this->slash_2, yourls_get_option( 'slash_test_2' ) ); + $this->assertEquals( $this->slash_3, yourls_get_option( 'slash_test_3' ) ); + $this->assertEquals( $this->slash_4, yourls_get_option( 'slash_test_4' ) ); + } + + /** + * Tests the model function that expects un-slashed data + * + * @since 0.1 + */ + function test_update_option() { + yourls_add_option( 'slash_test_5', 'foo' ); + + yourls_update_option( 'slash_test_5', $this->slash_1 ); + $this->assertEquals( $this->slash_1, yourls_get_option( 'slash_test_5' ) ); + + yourls_update_option( 'slash_test_5', $this->slash_2 ); + $this->assertEquals( $this->slash_2, yourls_get_option( 'slash_test_5' ) ); + + yourls_update_option( 'slash_test_5', $this->slash_3 ); + $this->assertEquals( $this->slash_3, yourls_get_option( 'slash_test_5' ) ); + + yourls_update_option( 'slash_test_5', $this->slash_4 ); + $this->assertEquals( $this->slash_4, yourls_get_option( 'slash_test_5' ) ); + } +} diff --git a/tests/tests/api/FuncTest.php b/tests/tests/api/FuncTest.php new file mode 100644 index 000000000..bac61a401 --- /dev/null +++ b/tests/tests/api/FuncTest.php @@ -0,0 +1,36 @@ +assertTrue( is_callable( $function ) ); + $this->assertTrue( is_array( $function() ) ); + } + +} diff --git a/tests/tests/api/output.php b/tests/tests/api/OutputTest.php similarity index 76% rename from tests/tests/api/output.php rename to tests/tests/api/OutputTest.php index 8fce9e736..ad94bbc9b 100644 --- a/tests/tests/api/output.php +++ b/tests/tests/api/OutputTest.php @@ -3,10 +3,10 @@ /** * Main API Output tests (content and headers sent) * - * @group API * @since 0.1 */ -class API_Output_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('API')] +class OutputTest extends PHPUnit\Framework\TestCase { protected $header_content; @@ -43,22 +43,21 @@ public function get_status_header( $args ) { /** * Provide API output mode and the associated expected content-type header */ - public function API_type() { - return array( - array( 'xml', 'application/xml' ), - array( 'json', 'application/json' ), - array( 'jsonp', 'application/javascript' ), - array( 'simple', 'text/plain' ), - array( rand_str(), 'text/plain' ), - ); + public static function API_type(): \Iterator + { + yield array( 'xml', 'application/xml' ); + yield array( 'json', 'application/json' ); + yield array( 'jsonp', 'application/javascript' ); + yield array( 'simple', 'text/plain' ); + yield array( rand_str(), 'text/plain' ); } /** * Check that yourls_api_output selectively sends expected content-type headers * - * @dataProvider API_type * @since 0.1 */ + #[\PHPUnit\Framework\Attributes\DataProvider('API_type')] public function test_output_content_headers( $type, $expected_header ) { yourls_add_action( 'content_type_header', array( $this, 'get_content_header' ) ); yourls_add_action( 'status_header', array( $this, 'get_status_header' ) ); @@ -72,27 +71,24 @@ public function test_output_content_headers( $type, $expected_header ) { /** * Provide mocked API output and the expected status codes */ - public function status_code() { + public static function status_code(): \Iterator { $success_code = mt_rand( 1, 10 ); $error_code = mt_rand( 1, 10 ); $content_success = array( 'statusCode' => $success_code ); $content_error = array( 'errorCode' => $error_code ); $content_random = array( 'thereIsNoCode' => rand_str() ); - - return array( - array( $content_success, $success_code ), - array( $content_error, $error_code ), - array( $content_random, 200 ), - ); + yield array( $content_success, $success_code ); + yield array( $content_error, $error_code ); + yield array( $content_random, 200 ); } /** * Check that yourls_api_output status header * - * @dataProvider status_code * @since 0.1 */ + #[\PHPUnit\Framework\Attributes\DataProvider('status_code')] public function test_output_status_headers( $content, $expected_status ) { yourls_add_action( 'status_header', array( $this, 'get_status_header' ) ); diff --git a/tests/tests/api/funcs.php b/tests/tests/api/funcs.php deleted file mode 100644 index 980c99e67..000000000 --- a/tests/tests/api/funcs.php +++ /dev/null @@ -1,37 +0,0 @@ -assertTrue( is_callable( $function ) ); - $this->assertTrue( is_array( $function() ) ); - } - -} diff --git a/tests/tests/auth/AbstractLoginTestCase.php b/tests/tests/auth/AbstractLoginTestCase.php new file mode 100644 index 000000000..37155462e --- /dev/null +++ b/tests/tests/auth/AbstractLoginTestCase.php @@ -0,0 +1,21 @@ +backup_request = $_REQUEST; + $_REQUEST['nonce'] = yourls_create_nonce('admin_login'); + } + + protected function tearDown(): void { + $_REQUEST = $this->backup_request; + yourls_remove_all_actions('pre_yourls_die'); + } + +} diff --git a/tests/tests/auth/auth.php b/tests/tests/auth/AuthTest.php similarity index 73% rename from tests/tests/auth/auth.php rename to tests/tests/auth/AuthTest.php index b9c88f3c8..a59c19bbb 100644 --- a/tests/tests/auth/auth.php +++ b/tests/tests/auth/AuthTest.php @@ -2,10 +2,9 @@ /** * Auth functions other than login and logout - * - * @group auth */ -class Auth_Func_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('auth')] +class AuthTest extends PHPUnit\Framework\TestCase { protected static $random_password; @@ -80,24 +79,21 @@ public function test_has_phpass() { /** * Provide strings to hash */ - public function strings_to_hash() { - - return array( - array( rand_str() ), - array( 'lol .\+*?[^]$(){}=!<>|:-/' . "'" . '"' ), - array( 'أنا أحب النقانق' ), - array( '"double quotes"' ), - array( "'single quotes'" ), - array( '@$*' ), - array( 'أنا أحب النقانق' ), - ); + public static function strings_to_hash(): \Iterator + { + yield array( rand_str() ); + yield array( 'lol .\+*?[^]$(){}=!<>|:-/' . "'" . '"' ); + yield array( 'أنا أحب النقانق' ); + yield array( '"double quotes"' ); + yield array( "'single quotes'" ); + yield array( '@$*' ); + yield array( 'أنا أحب النقانق' ); } /** * Check that a hash can be verified - * - * @dataProvider strings_to_hash */ + #[\PHPUnit\Framework\Attributes\DataProvider('strings_to_hash')] public function test_hash_and_check( $string ) { $hash = yourls_phpass_hash( $string ); $this->assertTrue( yourls_phpass_check( $string, $hash ) ); @@ -122,7 +118,7 @@ public function test_valid_md5() { // Check that md5 hashed passwords match the password $this->assertTrue( yourls_check_password_hash( 'random_md5', self::$random_password ) ); - // Unknow user, existing password + // Unknown user, existing password $this->assertFalse( yourls_check_password_hash( rand_str(), self::$random_password ) ); // Known user, invalid password @@ -133,11 +129,11 @@ public function test_valid_md5() { * Check that valid login / phpass password is deemed valid */ public function test_valid_phpass() { - // Check that phppass hashed passwords match the password + // Check that phpass hashed passwords match the password $this->assertTrue( yourls_check_password_hash( 'random_phpass1', self::$random_password ) ); $this->assertTrue( yourls_check_password_hash( 'random_phpass2', self::$random_password ) ); - // unknow user, existing valid password + // unknown user, existing valid password $this->assertFalse( yourls_check_password_hash( rand_str(), self::$random_password ) ); // known users, invalid passwords @@ -173,7 +169,60 @@ public function test_hash_passwords_now() { } exec( YOURLS_PHP_BIN . ' -l ' . escapeshellarg( $config_file ), $output, $return ); - $this->assertEquals( 0, $return ); + $this->assertSame( 0, $return ); + } + + /** + * Check that encrypting un-writable file returns expected error + */ + public function test_hash_passwords_now_unwritable() { + // generate un-writable file + $file = YOURLS_TESTDATA_DIR . '/auth/unwritable.php'; + touch( $file ); + + if(yourls_is_windows()) { + exec( 'attrib +r ' . escapeshellarg( $file ) ); + } else { + chmod( $file, 0444 ); + } + + $this->assertSame('cannot write file', yourls_hash_passwords_now( $file ) ); + + // cleanup + if(yourls_is_windows()) { + exec( 'attrib -r ' . escapeshellarg( $file ) ); + } else { + chmod( $file, 0644 ); + } + unlink( $file ); + } + + /** + * Check that encrypting non-existent or unreadable file returns expected error + */ + public function test_hash_passwords_now_non_existent() { + $this->assertSame('cannot read file', yourls_hash_passwords_now( rand_str() ) ); + } + + /** + * Check that encrypting empty file returns expected error + */ + public function test_hash_passwords_now_empty() { + $this->assertSame('could not read file', yourls_hash_passwords_now( YOURLS_TESTDATA_DIR . '/auth/empty.php' ) ); + } + + /** + * Check that encrypting file with no passwords returns expected error + */ + public function test_hash_passwords_now_no_pwd() { + $this->assertSame('no password found', yourls_hash_passwords_now( YOURLS_TESTDATA_DIR . '/auth/nopassword.php' ) ); + } + + /** + * Check that encrypting file with incorrect content returns expected error + */ + public function test_hash_passwords_now_bad_content() { + $this->assertSame('preg_replace problem', yourls_hash_passwords_now( YOURLS_TESTDATA_DIR . '/auth/preg_replace_problem.php' ) ); } /** @@ -181,7 +230,7 @@ public function test_hash_passwords_now() { * * This test checks that encrypting the config file, with different kinds of pwd, results in a valid * PHP file as expected. It doesn't test that the different kinds of password get correctly hashed - * and can be correctly decyphered. This task is covered in test_hash_and_check() + * and can be correctly deciphered. This task is covered in test_hash_and_check() */ public function test_hash_passwords_special_chars_now() { @@ -201,7 +250,7 @@ public function test_hash_passwords_special_chars_now() { } exec( YOURLS_PHP_BIN . ' -l ' . escapeshellarg( $config_file ), $output, $return ); - $this->assertEquals( 0, $return ); + $this->assertSame( 0, $return ); } /** @@ -237,10 +286,12 @@ public function test_maybe_hash_passwords_no_clear_password() { /** * Check that we don't hash passwords in config file if user explicitly doesn't want it * - * Actually we're not testing this :-( + * (Note that we're checking with the filter, it can also be enforced with a constant) */ - public function zz_test_maybe_hash_passwords_YOURLS_NO_HASH_PASSWORD() { - // we're not testing anything because it currently relies on a defined constant + public function test_maybe_hash_passwords_YOURLS_NO_HASH_PASSWORD() { + yourls_add_filter('skip_password_hashing', 'yourls_return_true'); + $this->assertFalse( yourls_maybe_hash_passwords() ); + yourls_remove_filter('skip_password_hashing', 'yourls_return_true'); } /** @@ -256,6 +307,4 @@ public function test_maybe_hash_passwords_via_env() { putenv('YOURLS_PASSWORD'); } - - } diff --git a/tests/tests/auth/login_secure.php b/tests/tests/auth/LoginAPISecureTest.php similarity index 78% rename from tests/tests/auth/login_secure.php rename to tests/tests/auth/LoginAPISecureTest.php index 4b21ebef4..b0d5b958b 100644 --- a/tests/tests/auth/login_secure.php +++ b/tests/tests/auth/LoginAPISecureTest.php @@ -1,15 +1,15 @@ backup_request = $_REQUEST; - $_REQUEST['nonce'] = yourls_create_nonce('admin_login'); - } - - protected function tearDown(): void { - $_REQUEST = $this->backup_request; - yourls_remove_all_actions('pre_yourls_die'); - } - - /** - * Check that user, as submitted by REQUEST (see phpunit XML config file), is valid - * - * @since 0.1 - */ - public function test_login() { +trait LoginAssertionTrait +{ + /** + * Check that user, as submitted by REQUEST (see phpunit XML config file), is valid + * + * @since 0.1 + */ + public function test_login() { $pre_login = yourls_did_action( 'pre_login' ); $login = yourls_did_action( 'login' ); $login_failed = yourls_did_action( 'login_failed' ); - $this->assertTrue( yourls_is_valid_user() ); + $this->assertTrue( yourls_is_valid_user() ); - $this->assertEquals( $pre_login + 1, yourls_did_action( 'pre_login' ) ); - $this->assertEquals( $login + 1, yourls_did_action( 'login' ) ); - $this->assertEquals( $login_failed, yourls_did_action( 'login_failed' ) ); - } + $this->assertEquals( $pre_login + 1, yourls_did_action( 'pre_login' ) ); + $this->assertEquals( $login + 1, yourls_did_action( 'login' ) ); + $this->assertEquals( $login_failed, yourls_did_action( 'login_failed' ) ); + } /** * Check that auth is shuntable @@ -58,8 +42,8 @@ public function test_login_with_no_credential() { $this->assertNotTrue( yourls_is_valid_user() ); - $this->assertEquals( $login, yourls_did_action( 'login' ) ); - $this->assertEquals( $login_failed + 1, yourls_did_action( 'login_failed' ) ); + $this->assertEquals( $login, yourls_did_action( 'login' ) ); + $this->assertEquals( $login_failed + 1, yourls_did_action( 'login_failed' ) ); } /** @@ -74,8 +58,8 @@ public function test_login_with_empty_credential() { $this->assertNotTrue( yourls_is_valid_user() ); - $this->assertEquals( $login, yourls_did_action( 'login' ) ); - $this->assertEquals( $login_failed + 1, yourls_did_action( 'login_failed' ) ); + $this->assertEquals( $login, yourls_did_action( 'login' ) ); + $this->assertEquals( $login_failed + 1, yourls_did_action( 'login_failed' ) ); } /** @@ -89,7 +73,7 @@ public function test_login_with_random_credentials() { $login_failed = yourls_did_action( 'login_failed' ); // with "normal" logins, we simulate the login forms and the presence of a nonce - if (get_class($this) == 'Auth_Login_Normal_Tests') { + if (get_class($this) == 'LoginNormalTest') { $this->expectException(Exception::class); $this->expectExceptionMessage('I have died'); // intercept yourls_die() before it actually dies @@ -98,5 +82,4 @@ public function test_login_with_random_credentials() { $this->assertNotTrue( yourls_is_valid_user() ); } - } diff --git a/tests/tests/auth/login_cookie.php b/tests/tests/auth/LoginCookieTest.php similarity index 52% rename from tests/tests/auth/login_cookie.php rename to tests/tests/auth/LoginCookieTest.php index 7cba9e744..5c76a90a7 100644 --- a/tests/tests/auth/login_cookie.php +++ b/tests/tests/auth/LoginCookieTest.php @@ -2,24 +2,29 @@ /** * Login tests - via Cookies * - * @group auth - * @group login - * @group cookies * @since 0.1 */ -class Auth_Login_Cookie_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('auth')] +#[\PHPUnit\Framework\Attributes\Group('login')] +#[\PHPUnit\Framework\Attributes\Group('cookies')] +class LoginCookieTest extends PHPUnit\Framework\TestCase { protected $cookie; protected $request; + protected $backup_yourls_actions; protected function setUp(): void { $this->cookie = $_COOKIE; $this->request = $_REQUEST; + global $yourls_actions; + $this->backup_yourls_actions = $yourls_actions; } protected function tearDown(): void { $_COOKIE = $this->cookie; $_REQUEST = $this->request; + global $yourls_actions; + $yourls_actions = $this->backup_yourls_actions; } public static function setUpBeforeClass(): void { @@ -30,49 +35,53 @@ public static function tearDownAfterClass(): void { yourls_remove_filter( 'is_API', 'yourls_return_false' ); } - /** - * Check for valid cookie name - */ - public function test_cookie_name() { + /** + * Check for valid cookie name + */ + public function test_cookie_name() { $this->assertTrue( is_string(yourls_cookie_name()) ); } - /** - * Check for valid cookie value - */ - public function test_cookie_value() { + /** + * Check for valid cookie value + */ + public function test_cookie_value() { $this->assertTrue( is_string(yourls_cookie_value(rand_str())) ); } - /** - * Check for valid cookie life - */ - public function test_cookie_life() { + /** + * Check for valid cookie life + */ + public function test_cookie_life() { $this->assertTrue( is_int(yourls_get_cookie_life()) ); } - /** - * Test login with valid cookie - */ - public function test_login_valid_cookie() { + /** + * Test login with valid cookie - also check that cookie is set + */ + public function test_login_valid_cookie() { global $yourls_user_passwords; $random_user = array_rand($yourls_user_passwords); $_COOKIE[yourls_cookie_name()] = yourls_cookie_value( $random_user ); unset($_REQUEST); + $this->assertSame( 0, yourls_did_action('pre_setcookie') ); $this->assertTrue(yourls_check_auth_cookie()); $this->assertTrue(yourls_is_valid_user()); + $this->assertSame( 1, yourls_did_action('pre_setcookie') ); } - /** - * Test login with invalid cookie - */ - public function test_login_invalid_cookie() { + /** + * Test login with invalid cookie - also check that no cookie is set + */ + public function test_login_invalid_cookie() { $_COOKIE[yourls_cookie_name()] = yourls_cookie_value( rand_str() ); unset($_REQUEST); + $this->assertSame( 0, yourls_did_action('pre_setcookie') ); $this->assertFalse(yourls_check_auth_cookie()); $this->assertNotTrue(yourls_is_valid_user()); + $this->assertSame( 0, yourls_did_action('pre_setcookie') ); } } diff --git a/tests/tests/auth/LoginNormalTest.php b/tests/tests/auth/LoginNormalTest.php new file mode 100644 index 000000000..f3a579465 --- /dev/null +++ b/tests/tests/auth/LoginNormalTest.php @@ -0,0 +1,14 @@ +backup_get = $_GET; + $this->backup_request = $_REQUEST; + self::$user = false; + } + + protected function tearDown(): void { + $_GET = $this->backup_get; + $_REQUEST = $this->backup_request; + } + + public static function setUpBeforeClass(): void { + yourls_add_action( 'pre_setcookie', function ($in) { + self::$user = $in[0]; // $in[0] is the user ID passed to yourls_setcookie() + } ); + } + + public static function tearDownAfterClass(): void { + yourls_remove_all_actions('pre_setcookie'); + } + + /** + * Check logout procedure - phase 1 - we're logging in + */ + public function test_logout_user_is_logged_in() { + $_REQUEST['nonce'] = yourls_create_nonce('admin_login'); + $valid = yourls_is_valid_user(); + $this->assertTrue($valid); + $this->assertSame('yourls', self::$user); + } + + /** + * Check logout procedure - phase 2 - we're logging out and checking that cookie was reset + */ + #[\PHPUnit\Framework\Attributes\Depends('test_logout_user_is_logged_in')] + public function test_logout_user_logs_out() { + $_GET['action'] = 'logout'; + $_REQUEST['nonce'] = yourls_create_nonce('admin_logout', 'logout'); + $invalid = yourls_is_valid_user(); + $this->assertNotTrue( $invalid ); + $this->assertSame('', self::$user); + } + + /** + * Check logout procedure - phase 3 - check we can log in again + */ + #[\PHPUnit\Framework\Attributes\Depends('test_logout_user_logs_out')] + public function test_logout_user_is_logged_in_back() { + $_REQUEST['nonce'] = yourls_create_nonce('admin_login'); + $valid = yourls_is_valid_user(); + $this->assertTrue( $valid ); + $this->assertSame('yourls', self::$user); + } + +} diff --git a/tests/tests/auth/MiscAuthTest.php b/tests/tests/auth/MiscAuthTest.php new file mode 100644 index 000000000..a6acc672c --- /dev/null +++ b/tests/tests/auth/MiscAuthTest.php @@ -0,0 +1,41 @@ +assertIsBool(yourls_skip_password_hashing()); + } + + public function test_yourls_salt_return_string() { + $this->assertIsString(yourls_salt(rand_str())); + } + + public function test_yourls_hmac_algo_default() { + $this->assertContains(yourls_hmac_algo(), hash_hmac_algos()); + } + + public function test_yourls_hmac_algo_custom() { + // get random hash_hmac_algo + $rnd_algo = hash_hmac_algos()[mt_rand(0, count(hash_hmac_algos()) - 1)]; + yourls_add_filter('hmac_algo', function() use ($rnd_algo) { + return $rnd_algo; + } ); + + // make sure it's the one we set + $algo = yourls_hmac_algo(); + $this->assertSame($algo, $rnd_algo); + } + + public function test_yourls_hmac_algo_non_existent() { + $this->assertSame( 'sha256', yourls_hmac_algo('omgozh') ); + } + +} diff --git a/tests/tests/auth/NonceTest.php b/tests/tests/auth/NonceTest.php new file mode 100644 index 000000000..d293c3152 --- /dev/null +++ b/tests/tests/auth/NonceTest.php @@ -0,0 +1,103 @@ +assertTrue( is_int(yourls_get_cookie_life()) ); + } + + /** + * Check for valid tick + */ + public function test_tick() { + $this->assertTrue( is_float(yourls_tick()) ); + } + + /** + * Check nonce creation + */ + public function test_create_nonce() { + $this->assertTrue( is_string(yourls_create_nonce(rand_str(), rand_str())) ); + } + + /** + * Check nonce field creation and output + */ + public function test_create_nonce_field_echo() { + $action = rand_str(); + $name = rand_str(); + $user = rand_str(); + $field = yourls_nonce_field( $action, $name, $user, false ); + $this->assertTrue( is_string($field) ); + $this->expectOutputString( $field . "\n" ); + $field = yourls_nonce_field( $action, $name, $user, true ); + } + + /** + * Check nonce URL creation + */ + public function test_create_nonce_url() { + $url = yourls_nonce_url( rand_str(), rand_str(), rand_str(), rand_str() ); + $this->assertTrue( is_string($url) ); + } + + /** + * Test valid nonce + */ + public function test_valid_nonce() { + $action = rand_str(); + $user = rand_str(); + + // what nonce should be + $valid = yourls_create_nonce( $action, $user ); + + $this->assertTrue(yourls_verify_nonce($action, $valid, $user)); + } + + /** + * Test invalid nonce + */ + public function test_invalid_nonce() { + $this->expectException(Exception::class); + $this->expectExceptionMessage('I have died'); + + // intercept yourls_die() before it actually dies + yourls_add_action( 'pre_yourls_die', function() { throw new Exception( 'I have died' ); } ); + + // This should trigger yourls_die() + $this->assertTrue(yourls_verify_nonce(rand_str(), rand_str(), rand_str())); + } + + /** + * Check nonces are different for different actions & users + */ + public function test_nonce_different_for_different_actions_and_users() { + $action1 = rand_str(); + $action2 = rand_str(); + $user1 = rand_str(); + $user2 = rand_str(); + + $nonce_a1 = yourls_create_nonce($action1); + $nonce_a2 = yourls_create_nonce($action2); + $nonce_a1_u1 = yourls_create_nonce($action1, $user1); + $nonce_a1_u2 = yourls_create_nonce($action1, $user2); + + $this->assertNotEquals($nonce_a1, $nonce_a2); + $this->assertNotEquals($nonce_a1_u1, $nonce_a1_u2); + $this->assertNotEquals($nonce_a1, $nonce_a1_u1); + } + +} diff --git a/tests/tests/auth/login_redirection.php b/tests/tests/auth/RedirectionTest.php similarity index 65% rename from tests/tests/auth/login_redirection.php rename to tests/tests/auth/RedirectionTest.php index a64aa7152..7979e2e0c 100644 --- a/tests/tests/auth/login_redirection.php +++ b/tests/tests/auth/RedirectionTest.php @@ -4,10 +4,9 @@ * Login redirection * * Check that, when submitting correct credentials, we're redirected as expected - * - * @group auth */ -class Login_Redirection_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('auth')] +class RedirectionTest extends PHPUnit\Framework\TestCase { protected $backup_request; protected $backup_server; @@ -22,13 +21,13 @@ protected function tearDown(): void { $_SERVER = $this->backup_server; } - /** - * Check that authentication on a webpage triggers a redirection - */ - public function test_login() { + /** + * Check that authentication on a webpage triggers a redirection + */ + public function test_login() { $_REQUEST['nonce'] = yourls_create_nonce('admin_login'); $_SERVER['REQUEST_URI'] = '/'; - $this->assertSame( 3, yourls_is_valid_user() ); - } + $this->assertSame( 3, yourls_is_valid_user() ); + } } diff --git a/tests/tests/auth/signatures.php b/tests/tests/auth/SigTest.php similarity index 87% rename from tests/tests/auth/signatures.php rename to tests/tests/auth/SigTest.php index c3165c1ba..f06400faf 100644 --- a/tests/tests/auth/signatures.php +++ b/tests/tests/auth/SigTest.php @@ -2,11 +2,11 @@ /** * Tests with signatures * - * @group auth - * @group signatures * @since 0.1 */ -class Auth_Sig_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('auth')] +#[\PHPUnit\Framework\Attributes\Group('signatures')] +class SigTest extends PHPUnit\Framework\TestCase { protected $backup_request; @@ -114,29 +114,26 @@ public function test_signature_timestamp_hash() { /** * Provide valid and invalid timestamps as compared to current time and nonce life */ - public function timestamps() { + public static function timestamps(): \Iterator { $now = time(); $little_in_the_future = $now + ( YOURLS_NONCE_LIFE / 2 ); $little_in_the_past = $now - ( YOURLS_NONCE_LIFE / 2 ); $far_in_the_future = $now + ( YOURLS_NONCE_LIFE * 2 ); $far_in_the_past = $now - ( YOURLS_NONCE_LIFE * 2 ); - - return array( - array( 0, false ), - array( $now, true ), - array( $little_in_the_future, true ), - array( $little_in_the_past, true ), - array( $far_in_the_future, false ), - array( $far_in_the_past, false ), - ); + yield array( 0, false ); + yield array( $now, true ); + yield array( $little_in_the_future, true ); + yield array( $little_in_the_past, true ); + yield array( $far_in_the_future, false ); + yield array( $far_in_the_past, false ); } /** * Check that timestamps are correctly handled (too old = bad, too future = bad, ...) * * @since 0.1 - * @dataProvider timestamps */ + #[\PHPUnit\Framework\Attributes\DataProvider('timestamps')] public function test_check_timestamp( $timestamp, $is_valid ) { $this->assertSame(yourls_check_timestamp( $timestamp ), $is_valid ); } diff --git a/tests/tests/auth/login_normal.php b/tests/tests/auth/login_normal.php deleted file mode 100644 index 4a2bc4f37..000000000 --- a/tests/tests/auth/login_normal.php +++ /dev/null @@ -1,14 +0,0 @@ -backup_get = $_GET; - $this->backup_request = $_REQUEST; - } - - protected function tearDown(): void { - $_GET = $this->backup_get; - $_REQUEST = $this->backup_request; - } - - /** - * Check logout procedure - phase 1 - */ - public function test_logout_user_is_logged_in() { - $_REQUEST['nonce'] = yourls_create_nonce('admin_login'); - $valid = yourls_is_valid_user(); - $this->assertTrue($valid); - } - - /** - * Check logout procedure - phase 2 - * @depends test_logout_user_is_logged_in - */ - public function test_logout_user_logs_out() { - $_GET['action'] = 'logout'; - $invalid = yourls_is_valid_user(); - $this->assertNotTrue( $invalid ); - } - - /** - * Check logout procedure - phase 3 - * @depends test_logout_user_logs_out - */ - public function test_logout_user_is_logged_in_back() { - $_REQUEST['nonce'] = yourls_create_nonce('admin_login'); - $valid = yourls_is_valid_user(); - $this->assertTrue( $valid ); - } - -} diff --git a/tests/tests/auth/misc.php b/tests/tests/auth/misc.php deleted file mode 100644 index b753fe4fd..000000000 --- a/tests/tests/auth/misc.php +++ /dev/null @@ -1,14 +0,0 @@ -assertIsBool(yourls_skip_password_hashing()); - } - -} diff --git a/tests/tests/auth/nonces.php b/tests/tests/auth/nonces.php deleted file mode 100644 index 21dc9f428..000000000 --- a/tests/tests/auth/nonces.php +++ /dev/null @@ -1,80 +0,0 @@ -assertTrue( is_int(yourls_get_cookie_life()) ); - } - - /** - * Check for valid tick - */ - public function test_tick() { - $this->assertTrue( is_float(yourls_tick()) ); - } - - /** - * Check nonce creation - */ - public function test_create_nonce() { - $this->assertTrue( is_string(yourls_create_nonce(rand_str(), rand_str())) ); - } - - /** - * Check nonce field creation - */ - public function test_create_nonce_field() { - $field = yourls_nonce_field( rand_str(), rand_str(), rand_str(), false ); - $this->assertTrue( is_string($field) ); - } - - /** - * Check nonce URL creation - */ - public function test_create_nonce_url() { - $url = yourls_nonce_url( rand_str(), rand_str(), rand_str(), rand_str() ); - $this->assertTrue( is_string($url) ); - // $this->assertIsString($url); - } - - /** - * Test valid nonce - */ - public function test_valid_nonce() { - $action = rand_str(); - $user = rand_str(); - - // what nonce should be - $valid = yourls_create_nonce( $action, $user ); - - $this->assertTrue(yourls_verify_nonce($action, $valid, $user)); - } - - /** - * Test invalid nonce - */ - public function test_invalid_nonce() { - $this->expectException(Exception::class); - $this->expectExceptionMessage('I have died'); - - // intercept yourls_die() before it actually dies - yourls_add_action( 'pre_yourls_die', function() { throw new Exception( 'I have died' ); } ); - - // This should trigger yourls_die() - $this->assertTrue(yourls_verify_nonce(rand_str(), rand_str(), rand_str())); - } - -} diff --git a/tests/tests/db/DBGetTest.php b/tests/tests/db/DBGetTest.php new file mode 100644 index 000000000..0499a70a3 --- /dev/null +++ b/tests/tests/db/DBGetTest.php @@ -0,0 +1,91 @@ +ydb_copy = yourls_get_db('read-test_setup'); + yourls_set_db(null); + } + + /** + * Restore original $ydb + */ + public function tearDown(): void { + yourls_set_db($this->ydb_copy); + } + + public function test_get() { + $this->assertInstanceOf( '\YOURLS\Database\YDB', yourls_get_db('read-test_get') ); + } + + /** + * Provide valid context strings + */ + public static function valid_contexts(): \Iterator + { + yield array( 'read-do_something' ); + yield array( 'read-dothis' ); + yield array( 'write-do_something' ); + yield array( 'write-dothis' ); + } + + /** + * Check that properly formatted contexts trigger no notice + */ + #[\PHPUnit\Framework\Attributes\DataProvider('valid_contexts')] + public function test_get_with_valid_context($context) { + $db = yourls_get_db($context); + $this->assertInstanceOf( '\YOURLS\Database\YDB', $db ); + } + + /** + * Provide invalid context strings + */ + public static function invalid_contexts(): \Iterator + { + yield array( 'do_something' ); +// yield array( 'dothis' ); +// yield array( 'omg-do-it_already' ); +// yield array( 'read_something' ); +// yield array( 'write-SOME_THING' ); + } + + /** + * Check that improperly formatted contexts trigger a notice - yet the default DB is returned + */ + #[\PHPUnit\Framework\Attributes\DataProvider('invalid_contexts')] + public function test_get_with_invalid_context($context) { + set_error_handler(function($errno, $errstr) { + $this->assertEquals(E_USER_NOTICE, $errno); + $this->assertStringContainsString('Improperly formatted yourls_get_db() context', $errstr); + return true; // Prevent PHP's default error handler + }); + $db = yourls_get_db($context); + $this->assertInstanceOf( '\YOURLS\Database\YDB', $db ); + restore_error_handler(); + } + + /** + * Check that missing context triggers a notice - yet the default DB is returned + */ + public function test_get_with_empty_context() { + set_error_handler(function($errno, $errstr) { + $this->assertEquals(E_USER_NOTICE, $errno); + $this->assertStringContainsString('Undefined yourls_get_db() context', $errstr); + return true; // Prevent PHP's default error handler + }); + $db = yourls_get_db(); + $this->assertInstanceOf( '\YOURLS\Database\YDB', $db ); + restore_error_handler(); + } + +} diff --git a/tests/tests/db/DBSetTest.php b/tests/tests/db/DBSetTest.php new file mode 100644 index 000000000..06f28994f --- /dev/null +++ b/tests/tests/db/DBSetTest.php @@ -0,0 +1,52 @@ +ydb_copy = yourls_get_db('read-test_setup'); + yourls_set_db(null); + } + + /** + * Restore original $ydb + */ + public function tearDown(): void { + yourls_set_db($this->ydb_copy); + } + + public function test_set() { + yourls_set_db("hello"); + $this->assertSame( "hello", yourls_get_db('read-test_set') ); + } + + /** + * Note to self: I'm unable to write a test to check that yourls_get_db(null) + * actually unsets $ydb. It seems I'm hitting the limits to my understandings + * of PHPUnit and global vars. + * + * For the record, the following doesn't work: + * + * public function test_unset() { + * $db = yourls_get_db(); + * $this->assertTrue( isset($db) ); // OK + * + * yourls_set_db(null); // should unset $ydb + * global $ydb; + * yourls_ut_var_dump( $ydb ); // $ydb is still set and has the same value + * $this->assertFalse( isset($ydb) ); // Not OK + * } + * + * Oh well. ¯\_(ツ)_/¯ + * + */ + +} diff --git a/tests/tests/db/db.php b/tests/tests/db/db.php deleted file mode 100644 index cd7d93ce3..000000000 --- a/tests/tests/db/db.php +++ /dev/null @@ -1,55 +0,0 @@ -ydb_copy = yourls_get_db(); - yourls_set_db(null); - } - - /** - * Restore original $ydb - */ - public function tearDown(): void { - yourls_set_db($this->ydb_copy); - } - - public function test_get() { - $this->assertInstanceOf( '\YOURLS\Database\YDB', yourls_get_db() ); - } - - public function test_set() { - yourls_set_db("hello"); - $this->assertSame( "hello", yourls_get_db() ); - } - - /** - * Note to self : I'm unable to write a test to check that yourls_get_db(null) - * actually unsets $ydb. It seems I'm hitting the limits to my understandings - * of PHPUnit and global vars. - * - * For the record, the following doesn't work: - * - * public function test_unset() { - * glȍbal $ydb; - * $this->assertTrue( isset($ydb) ); - * yourls_set_db(null); - * $this->assertFalse( isset($ydb) ); - * } - * - * Oh well. ¯\_(ツ)_/¯ - * - */ - - -} diff --git a/tests/tests/db/misc.php b/tests/tests/db/misc.php deleted file mode 100644 index 065ea5675..000000000 --- a/tests/tests/db/misc.php +++ /dev/null @@ -1,16 +0,0 @@ -assertIsInt($num); - } - -} diff --git a/tests/tests/debug/DebugLogTest.php b/tests/tests/debug/DebugLogTest.php new file mode 100644 index 000000000..20b133a0a --- /dev/null +++ b/tests/tests/debug/DebugLogTest.php @@ -0,0 +1,68 @@ +assertIsInt($num_actions_before); + yourls_debug_log( 'test' ); + $num_actions = yourls_did_action( 'debug_log' ); + $this->assertEquals( $num_actions, $num_actions_before + 1); + } + + public function test_get_debug_log_is_array() { + $log = yourls_get_debug_log(); + $this->assertIsArray($log); + $this->assertNotEmpty($log); + } + + public function test_debug_log_stores_str() { + $str = rand_str(); + $log_before = yourls_get_debug_log(); + $this->assertNotEmpty($log_before); + + $this->assertEquals(yourls_debug_log( $str ), $str); + $log = yourls_get_debug_log(); + // last entry of array $log should be $str + $log = end($log); + $this->assertEquals($log, $str); + } + + public function test_get_num_queries() { + $num = yourls_get_num_queries(); + $this->assertIsInt($num); + $this->assertGreaterThan(0, $num); + } + + public function test_get_debug_mode_returns_bool() { + $this->assertIsBool(yourls_get_debug_mode()); + } + + public function test_debug_mode_sets_error_reporting() { + $debug = yourls_get_debug_mode(); + + $str = rand_str(); + yourls_debug_mode(true); + $this->assertEquals( error_reporting(), -1 ); + // SQL queries should be stored + yourls_get_db('read-test_rand')->fetchValue("SELECT RAND('$str')"); + $log = yourls_get_debug_log(); + $this->assertStringContainsString($str, end($log)); + + $str = rand_str(); + yourls_debug_mode(false); + $this->assertEquals( error_reporting(), ( E_ERROR | E_PARSE ) ); + // SQL queries should not be stored + yourls_get_db('read-test_rand')->fetchValue("SELECT RAND('$str')"); + $log = yourls_get_debug_log(); + $this->assertStringNotContainsString($str, end($log)); + + // Restore + yourls_debug_mode($debug); + } + +} diff --git a/tests/tests/format/timedates.php b/tests/tests/format/DatesTest.php similarity index 92% rename from tests/tests/format/timedates.php rename to tests/tests/format/DatesTest.php index 2e8631924..870033833 100644 --- a/tests/tests/format/timedates.php +++ b/tests/tests/format/DatesTest.php @@ -3,11 +3,11 @@ /** * Formatting functions for time & dates * - * @group formatting - * @group timedate * @since 0.1 */ -class Format_Test_Dates extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('formatting')] +#[\PHPUnit\Framework\Attributes\Group('timedate')] +class DatesTest extends PHPUnit\Framework\TestCase { protected function tearDown(): void { yourls_remove_all_filters( 'get_time_offset' ); diff --git a/tests/tests/format/EscTest.php b/tests/tests/format/EscTest.php new file mode 100644 index 000000000..490b29d37 --- /dev/null +++ b/tests/tests/format/EscTest.php @@ -0,0 +1,217 @@ +assertSame( $escaped, yourls_esc_attr( $attr ) ); + } + + /** + * Attribute escaping -- escaping twice shouldn't change + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\DataProvider('html_attributes')] + function test_esc_attr_twice( $attr, $escaped ) { + $this->assertSame( $escaped, yourls_esc_attr( yourls_esc_attr( $attr ) ) ); + } + + /** + * HTML string and how they should be escaped + */ + static function html_strings(): \Iterator + { + // Simple string + yield array( + 'The quick brown fox.', + 'The quick brown fox.', + ); + // URL with & + yield array( + 'https://127.0.0.1/admin/admin-ajax.php?id=y1120844669&action=edit&keyword=1a&nonce=bf3115ac3a', + 'https://127.0.0.1/admin/admin-ajax.php?id=y1120844669&action=edit&keyword=1a&nonce=bf3115ac3a', + ); + // More ampersands + yield array( + 'H&M and Dungeons & Dragons', + 'H&M and Dungeons & Dragons', + ); + // Simple quotes + yield array( + "SELECT stuff FROM table WHERE blah IN ('omg', 'wtf') AND foo = 1", + 'SELECT stuff FROM table WHERE blah IN ('omg', 'wtf') AND foo = 1', + ); + // Double quotes + yield array( + 'I am "special"', + 'I am "special"', + ); + // Greater and less than + yield array( + 'this > that < that ', + 'this > that < that <randomhtml />', + ); + // Ignore actual entities + yield array( + '& £ " &', + '& £ " &', + ); + // Empty string + yield array( + '', + '', + ); + } + + /** + * HTML escaping + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\DataProvider('html_strings')] + function test_esc_html( $html, $escaped ) { + $this->assertSame( $escaped, yourls_esc_html( $html ) ); + } + + /** + * String to escape and what they should look like once escaped + */ + public function strings_to_escape() { + return array( + array( "I'm rock n' rollin'", "I\'m rock n\' rollin\'" ), + array( 'I am "nice"', 'I am \"nice\"' ), + array( 'Back\Slash', 'Back\\\Slash' ), + array( "NULL\0NULL", 'NULL\0NULL' ), // notice the quote change + ); + } + + /** + * List of URLs and how they should be escaped + */ + static function list_of_URLs(): \Iterator + { + yield array( + 'http://example.com/?this=that&that=this', + 'http://example.com/?this=that&that=this', + ); + yield array( + 'http://example.com/?this=that&that="this"', + 'http://example.com/?this=that&that=this', + ); + yield array( + "http://example.com/?this=that&that='this'", + 'http://example.com/?this=that&that='this'', + ); + yield array( + "http://example.com/?this=that&that=", + 'http://example.com/?this=that&that=this', + ); + } + + /** + * Escape URLs for display + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\DataProvider('list_of_URLs')] + #[\PHPUnit\Framework\Attributes\Group('url')] + function test_esc_urls( $url, $escaped ) { + $this->assertEquals( $escaped, yourls_esc_url( $url ) ); + } + + /** + * Some strings and how they should be escaped in javascript + */ + static function list_of_JS(): \Iterator + { + yield array( + 'hello world();', + 'hello world();', + ); + yield array( + 'hello("world");', + 'hello("world");', + ); + yield array( + 'foo & bar &baz; '', + 'foo & bar &baz; '', + ); + } + + /** + * Escape JS + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\DataProvider('list_of_JS')] + function test_esc_js( $js, $escaped ) { + $this->assertEquals( $escaped, yourls_esc_js( $js ) ); + } + + /** + * Strings in a textarea and how they should be escaped + */ + static function list_of_textarea(): \Iterator + { + yield array( + 'hello
world', + 'hello<br/>world', + ); + yield array( + '"omg"', + '"omg"', + ); + yield array( + "'omg'", + ''omg'', + ); + } + + /** + * Escape JS + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\DataProvider('list_of_textarea')] + function test_esc_textarea( $text, $escaped ) { + $this->assertEquals( $escaped, yourls_esc_textarea( $text ) ); + } + +} diff --git a/tests/tests/format/general.php b/tests/tests/format/FormatTest.php similarity index 72% rename from tests/tests/format/general.php rename to tests/tests/format/FormatTest.php index b0476a353..67841bdb8 100644 --- a/tests/tests/format/general.php +++ b/tests/tests/format/FormatTest.php @@ -3,48 +3,46 @@ /** * General formatting functions. * - * @group formatting * @since 0.1 */ -class Format_General extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('formatting')] +class FormatTest extends PHPUnit\Framework\TestCase { /** * Data to serialize */ - function serialize_data() { - return array( - array( null ), - array( true ), - array( false ), - array( -25 ), - array( 25 ), - array( 1.1 ), - array( 'this string will be serialized' ), - array( "a\nb" ), - array( array() ), - array( array(1,1,2,3,5,8,13) ), - array( (object)array('test' => true, '3', 4) ), - ); + static function serialize_data(): \Iterator + { + yield array( null ); + yield array( true ); + yield array( false ); + yield array( -25 ); + yield array( 25 ); + yield array( 1.1 ); + yield array( 'this string will be serialized' ); + yield array( "a\nb" ); + yield array( array() ); + yield array( array(1,1,2,3,5,8,13) ); + yield array( (object)array('test' => true, '3', 4) ); } /** * Unserialized data */ - function not_serialized_data() { - return array( - array( 'a string' ), - array( 'garbage:a:0:garbage;' ), - // array( 'b:4;' ), // this test fails in WP test suite, not sure if intentional or what... - array( 's:4:test;' ), - ); + static function not_serialized_data(): \Iterator + { + yield array( 'a string' ); + yield array( 'garbage:a:0:garbage;' ); + // array( 'b:4;' ), // this test fails in WP test suite, not sure if intentional or what... + yield array( 's:4:test;' ); } /** * Check that yourls_is_serialized detects serialized data * - * @dataProvider serialize_data * @since 0.1 */ + #[\PHPUnit\Framework\Attributes\DataProvider('serialize_data')] public function test_is_serialized( $data ) { $this->assertTrue( yourls_is_serialized( serialize( $data ) ) ); } @@ -52,9 +50,9 @@ public function test_is_serialized( $data ) { /** * Check that yourls_is_serialized doesn't assume garbage is serialized * - * @dataProvider not_serialized_data * @since 0.1 */ + #[\PHPUnit\Framework\Attributes\DataProvider('not_serialized_data')] public function test_is_not_serialized( $data ) { $this->assertFalse( yourls_is_serialized( $data ) ); } @@ -99,26 +97,19 @@ public function test_string_to_int_to_string() { } /** - * Some random keywords - */ - public function some_random_keywords() { - return array( - array( '1' ), - array( 'a' ), - array( 'hello-world' ), - array( '1337ozhOZH' ), - array( '@#!?*' ), - ); - } - - /** - * Checking that string2htmlid is an alphanumeric string + * Checking that yourls_unique_element_id is a unique string * - * @dataProvider some_random_keywords - * @since 0.1 */ - public function test_string2htmlid( $string ) { - $this->assertTrue( ctype_alnum( yourls_string2htmlid( $string ) ) ); + public function test_string2htmlid() { + $id1 = yourls_unique_element_id(); + $id2 = yourls_unique_element_id(); + $id3 = yourls_unique_element_id('foo', 10); + $id4 = yourls_unique_element_id(); + $this->assertIsString($id1); + $this->assertIsString($id2); + $this->assertNotSame($id1, $id2); + $this->assertEquals('foo10', $id3, 'ID is built using the specified prefix and counter value.'); + $this->assertStringEndsWith('11', $id4, 'ID counter continues to increment from the last value.'); } /** @@ -129,16 +120,16 @@ public function test_string2htmlid( $string ) { function test_valid_regexp() { $pattern = yourls_make_regexp_pattern( yourls_get_shorturl_charset() ); - /* To validate a RegExp just run it against null. + /* To validate a RegExp just run it against an empty string. If it returns explicit false (=== false), it's broken. Otherwise it's valid. - From: http://stackoverflow.com/a/12941133/36850 + From: https://stackoverflow.com/a/12941133/36850 Cool to know :) We're testing it as used in yourls_sanitize_keyword() TODO: more random char strings to test? */ - $this->assertFalse( preg_match( '![^' . $pattern . ']!', null ) === false ); + $this->assertNotFalse( preg_match( '![^' . $pattern . ']!', '' ) ); } /** @@ -165,9 +156,9 @@ function test_trim_long_strings() { * * Note: As of 1.7.1, function yourls_seem_utf8() is still unused. In 2.0 consider simply deleting it if still not needed * - * @dataProvider valid_utf8 * @since 0.1 */ + #[\PHPUnit\Framework\Attributes\DataProvider('valid_utf8')] function test_is_utf8( $string ) { $this->assertTrue( yourls_seems_utf8( $string ) ); } @@ -177,25 +168,25 @@ function test_is_utf8( $string ) { * * Note: As of 1.7.1, function yourls_seem_utf8() is still unused. In 2.0 consider simply deleting it if still not needed * - * @dataProvider invalid_utf8 * @since 0.1 */ + #[\PHPUnit\Framework\Attributes\DataProvider('invalid_utf8')] function test_is_not_utf8( $string ) { $this->assertFalse( yourls_seems_utf8( $string ) ); } - function valid_utf8() { - return $this->get_data( YOURLS_TESTDATA_DIR . '/formatting/utf-8.txt' ); + static function valid_utf8() { + return self::get_data( YOURLS_TESTDATA_DIR . '/formatting/utf-8.txt' ); } - function invalid_utf8() { - return $this->get_data( YOURLS_TESTDATA_DIR . '/formatting/big5.txt' ); + static function invalid_utf8() { + return self::get_data( YOURLS_TESTDATA_DIR . '/formatting/big5.txt' ); } /** * Parse a file and return its content as a data provider */ - function get_data( $filename ) { + static function get_data( $filename ) { $strings = file( $filename ); foreach ( $strings as &$string ) { $string = (array) trim( $string ); @@ -210,8 +201,8 @@ function get_data( $filename ) { * @since 0.1 */ function test_backslashit() { - $this->assertSame( yourls_backslashit( 'hello world 123 !' ), '\h\e\l\l\o \w\o\r\l\d 123 !' ); - $this->assertSame( yourls_backslashit( '1, 2, 3' ), '\\\1, 2, 3' ); + $this->assertSame( '\h\e\l\l\o \w\o\r\l\d 123 !', yourls_backslashit( 'hello world 123 !' ) ); + $this->assertSame( '\\\1, 2, 3', yourls_backslashit( '1, 2, 3' ) ); } /** diff --git a/tests/tests/format/JsonpCallbackTest.php b/tests/tests/format/JsonpCallbackTest.php new file mode 100644 index 000000000..c05980511 --- /dev/null +++ b/tests/tests/format/JsonpCallbackTest.php @@ -0,0 +1,50 @@ +' ); + yield array( '$.constructor.prototype.alert(1)//' ); + yield array( 'callback;window.location="https://example.com"' ); + yield array( '"evil"' ); + yield array( "\n\r\tcb()" ); + yield array( "cb\u2028\u2029()" ); + yield array( 'cb\\u2028' ); + yield array( '' ); + } + + #[\PHPUnit\Framework\Attributes\DataProvider('valid_callbacks')] + public function test_valid_callbacks_are_accepted( $callback ) : void { + $result = yourls_validate_jsonp_callback( $callback ); + $this->assertSame( $callback, $result, "Valid callback '$callback' should be returned unchanged" ); + $this->assertNotFalse( $result, "Valid callback '$callback' should not return false" ); + } + + #[\PHPUnit\Framework\Attributes\DataProvider('malicious_callbacks')] + public function test_malicious_callbacks_are_rejected( $callback ) : void { + $result = yourls_validate_jsonp_callback( $callback ); + $this->assertFalse( $result, "Invalid callback '$callback' should return false" ); + } +} diff --git a/tests/tests/format/kses.php b/tests/tests/format/KSESTest.php similarity index 92% rename from tests/tests/format/kses.php rename to tests/tests/format/KSESTest.php index d412df579..11ae86082 100644 --- a/tests/tests/format/kses.php +++ b/tests/tests/format/KSESTest.php @@ -3,10 +3,10 @@ /** * KSES functions. Most are not used in YOURLS, so there's few tests here. * - * @group formatting * @since 0.1 */ -class Format_KSES extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('formatting')] +class KSESTest extends PHPUnit\Framework\TestCase { protected $entitynames, $protocols; diff --git a/tests/tests/format/referrers.php b/tests/tests/format/ReferrerTest.php similarity index 76% rename from tests/tests/format/referrers.php rename to tests/tests/format/ReferrerTest.php index f3bacffbb..c4d99ac05 100644 --- a/tests/tests/format/referrers.php +++ b/tests/tests/format/ReferrerTest.php @@ -3,11 +3,11 @@ /** * Formatting functions for URLs * - * @group formatting - * @group referrer * @since 0.1 */ -class Format_Referrer extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('formatting')] +#[\PHPUnit\Framework\Attributes\Group('referrer')] +class ReferrerTest extends PHPUnit\Framework\TestCase { protected $backup; @@ -21,7 +21,7 @@ protected function tearDown(): void { function test_no_referrer() { unset($_SERVER['HTTP_REFERER']); - $this->assertEquals(yourls_get_referrer(), 'direct'); + $this->assertEquals('direct', yourls_get_referrer()); } function test_referrer() { diff --git a/tests/tests/format/RemoteTitleTest.php b/tests/tests/format/RemoteTitleTest.php new file mode 100644 index 000000000..a6179e5ea --- /dev/null +++ b/tests/tests/format/RemoteTitleTest.php @@ -0,0 +1,76 @@ +raw = 'HTTP/1.1 200 OK'; + $response->url = $url; + $response->body = file_get_contents( YOURLS_TESTDATA_DIR . '/remote-pages/' . $file_name ); + $charset = 'utf-8'; + if ( isset( $url_params['charset'] ) ) { + $charset = $url_params['charset']; + } + $response->headers = new \WpOrg\Requests\Response\Headers([ + 'Content-Type' => 'text/html; charset=' . $charset, + 'Content-Length' => strlen($response->body), + ]); + return $response; + } + + /** + * Sanitize titles + * + * @since 1.10.3 + */ + function test_sanitize_title() { + $expected = "How Will I Laugh Tomorrow When I Can't Even Smile Today"; + $this->assertSame( $expected, yourls_get_remote_title( 'https://example.com/title1.html' ) ); + + $expected = 'Twilight of the Thunder God'; + $this->assertSame( $expected, yourls_get_remote_title( 'https://example.com/title2.html' ) ); + } + + /** + * MB convert encoding tests. + * + * @since 1.10.3 + */ + function test_mb_convert_encoding() { + // Test issue from https://github.com/YOURLS/YOURLS/issues/3708 + // Contains + $expected = "Hello World"; + $this->assertSame( $expected, yourls_get_remote_title( 'https://example.com/mbconvert1.html' ) ); + $this->assertSame( $expected, yourls_get_remote_title( 'https://example.com/mbconvert1.html?charset=invalid' ) ); + } + +} diff --git a/tests/tests/format/sanitizing.php b/tests/tests/format/SanitizeTest.php similarity index 54% rename from tests/tests/format/sanitizing.php rename to tests/tests/format/SanitizeTest.php index fe48137e1..d36e97fd0 100644 --- a/tests/tests/format/sanitizing.php +++ b/tests/tests/format/SanitizeTest.php @@ -3,10 +3,10 @@ /** * Sanitizing functions * - * @group formatting * @since 0.1 */ -class Format_Sanitize extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('formatting')] +class SanitizeTest extends PHPUnit\Framework\TestCase { /** * Sanitize titles @@ -34,6 +34,7 @@ function test_sanitize_title_with_fallback() { $unsane = ''; $this->assertSame( $expected, yourls_sanitize_title( $unsane ) ); $this->assertSame( $fallback, yourls_sanitize_title( $unsane, $fallback ) ); + $this->assertSame( $fallback, yourls_sanitize_title( '', $fallback ) ); } /** @@ -52,24 +53,23 @@ function test_sanitize_int() { /** * Some strings that look like IPs and a boolean showing if they should pass or not */ - function random_ips() { - return array( - array( '255.255.255.255', true ), - array( '127.1', true ), - array( '559.559.559', true ), - array( '::1', true ), - array( '127.0.0.omg', false ), - array( '1:1:omg', false ), - array( '#@~&', false ), - ); + static function random_ips(): \Iterator + { + yield array( '255.255.255.255', true ); + yield array( '127.1', true ); + yield array( '559.559.559', true ); + yield array( '::1', true ); + yield array( '127.0.0.omg', false ); + yield array( '1:1:omg', false ); + yield array( '#@~&', false ); } /** * Sanitize IPs * - * @dataProvider random_ips * @since 0.1 */ + #[\PHPUnit\Framework\Attributes\DataProvider('random_ips')] function test_sanitize_ip( $ip, $is_ip ) { $this->assertSame( $ip == yourls_sanitize_ip( $ip ), $is_ip ); } @@ -77,22 +77,21 @@ function test_sanitize_ip( $ip, $is_ip ) { /** * Some strings that look like m(m)/d(d)/yyyy dates and a boolean showing if they should pass or not */ - function random_dates() { - return array( - array( '1/1/2345' , true ), - array( '12/2/2345', true ), - array( '9/10/2345', true ), - array( '90/99', false ), - array( '90/99/123', false ), - ); + static function random_dates(): \Iterator + { + yield array( '1/1/2345' , true ); + yield array( '12/2/2345', true ); + yield array( '9/10/2345', true ); + yield array( '90/99', false ); + yield array( '90/99/123', false ); } /** * Sanitize dates * - * @dataProvider random_dates * @since 0.1 */ + #[\PHPUnit\Framework\Attributes\DataProvider('random_dates')] function test_sanitize_date( $date, $is_date ) { if( !$is_date ) { $this->assertFalse( yourls_sanitize_date( $date ) ); @@ -104,9 +103,9 @@ function test_sanitize_date( $date, $is_date ) { /** * Sanitize dates for SQL search * - * @dataProvider random_dates * @since 0.1 */ + #[\PHPUnit\Framework\Attributes\DataProvider('random_dates')] function test_sanitize_date_sql( $date, $is_date ) { if( !$is_date ) { $this->assertFalse( yourls_sanitize_date_for_sql( $date ) ); @@ -118,21 +117,20 @@ function test_sanitize_date_sql( $date, $is_date ) { /** * Some strings that look like filenames how they should be sanitized */ - function random_filenames() { - return array( - array( '/home/ozh/plugin.php' , '/home/ozh/plugin.php' ), - array( '\home\ozh\plugin.php' , '/home/ozh/plugin.php' ), - array( '\\home\\ozh\\plugin.php' , '/home/ozh/plugin.php' ), - array( '//home/ozh/plugin.php' , '/home/ozh/plugin.php' ), - ); + static function random_filenames(): \Iterator + { + yield array( '/home/ozh/plugin.php' , '/home/ozh/plugin.php' ); + yield array( '\home\ozh\plugin.php' , '/home/ozh/plugin.php' ); + yield array( '\\home\\ozh\\plugin.php' , '/home/ozh/plugin.php' ); + yield array( '//home/ozh/plugin.php' , '/home/ozh/plugin.php' ); } /** * Sanitize filenames * - * @dataProvider random_filenames * @since 0.1 */ + #[\PHPUnit\Framework\Attributes\DataProvider('random_filenames')] function test_sanitize_filename( $filename, $expected ) { $this->assertSame( $expected, yourls_sanitize_filename( $filename ) ); } @@ -140,36 +138,35 @@ function test_sanitize_filename( $filename, $expected ) { /** * Some strings that look like versions (1.2.3-alpha) how they should be sanitized */ - function random_versions() { - return array( - array('1.2.3', '1.2.3'), - array('1.2.3.4', '1.2.3.4'), - array('1.2.3-leet', '1.2.3'), - array('1.0-RC1-Almost-Final', '1.0'), - array('beta-4', ''), - array('4.something', ''), - array('4-final', ''), - array('1-2-3', ''), - array('omgmysql-5.5-ubuntu-4.20', '5.5'), - array('mysql5.5-ubuntu-4.20', '5.5'), - array('5.5-ubuntu-4.20', '5.5'), - array('5.5-beta2', '5.5'), - array('5.5.beta2', '5.5'), - array('5.5', '5.5'), - array('5.5.', '5.5'), - array('5', ''), - array('5.', ''), - array('100.1', '100.1'), - array('mysql-10.10-beta', '10.10'), - ); + static function random_versions(): \Iterator + { + yield array('1.2.3', '1.2.3'); + yield array('1.2.3.4', '1.2.3.4'); + yield array('1.2.3-leet', '1.2.3'); + yield array('1.0-RC1-Almost-Final', '1.0'); + yield array('beta-4', ''); + yield array('4.something', ''); + yield array('4-final', ''); + yield array('1-2-3', ''); + yield array('omgmysql-5.5-ubuntu-4.20', '5.5'); + yield array('mysql5.5-ubuntu-4.20', '5.5'); + yield array('5.5-ubuntu-4.20', '5.5'); + yield array('5.5-beta2', '5.5'); + yield array('5.5.beta2', '5.5'); + yield array('5.5', '5.5'); + yield array('5.5.', '5.5'); + yield array('5', ''); + yield array('5.', ''); + yield array('100.1', '100.1'); + yield array('mysql-10.10-beta', '10.10'); } /** * Sanitize versions * - * @dataProvider random_versions * @since 0.1 */ + #[\PHPUnit\Framework\Attributes\DataProvider('random_versions')] function test_sanitize_version( $version, $expected ) { $this->assertSame( $expected, yourls_sanitize_version( $version ) ); } @@ -177,21 +174,20 @@ function test_sanitize_version( $version, $expected ) { /** * Some random keywords to sanitize */ - public function keywords_to_sanitize() { - return array( - array( 'hello-world', 'helloworld' ), - array( '1337ozhOZH', '1337ozhOZH' ), - array( 'yeah@#!?*', 'yeah' ), - array( 'Motörhead', 'Motrhead' ), - ); + public static function keywords_to_sanitize(): \Iterator + { + yield array( 'hello-world', 'helloworld' ); + yield array( '1337ozhOZH', '1337ozhOZH' ); + yield array( 'yeah@#!?*', 'yeah' ); + yield array( 'Motörhead', 'Motrhead' ); } - /** - * Checking that keyword are correctly sanitized - * - * @dataProvider keywords_to_sanitize - * @since 0.1 - */ + /** + * Checking that keyword are correctly sanitized + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\DataProvider('keywords_to_sanitize')] public function test_sanitize_keywords( $keyword, $expected ) { // the "soft" way: assume keyword can be anything we have in a URL (here, should remain unchanged) $this->assertSame( $keyword, yourls_sanitize_keyword( $keyword ) ); diff --git a/tests/tests/format/URLTest.php b/tests/tests/format/URLTest.php new file mode 100644 index 000000000..6be9c9365 --- /dev/null +++ b/tests/tests/format/URLTest.php @@ -0,0 +1,320 @@ +assertSame( yourls_get_protocol( $test_this ), $expected ); + } + + + /** + * List of valid URLs that should not be changed when sanitized + */ + static function list_of_valid_URLs(): \Iterator + { + yield array( 'http://example.com' ); + yield array( 'http://example.com/' ); + yield array( 'http://ozh@example.com/' ); + yield array( 'http://example.com/?@OMG' ); + // #1890 + yield array( 'http://ozh@example.com#BLAH' ); + yield array( 'http://Ozh:Password@example.com/' ); + yield array( 'http://Ozh:Password@example.com#OMG' ); + yield array( 'http://Ozh:Password@example.com:1337/' ); + yield array( 'http://Ozh:Password@example.com:1337#OMG' ); + yield array( 'http://Ozh:Password@example.com/hey@ho' ); + yield array( 'http://username:password@example.com:8042/over/there/index.dtb?type=animal&name=narwhal#nose:@:@' ); + yield array( 'mailto:ozh@ozh.org' ); + yield array( 'http://example.com/?watchtheallowedcharacters-~+_.#=&;,/:%!*stay' ); + yield array( 'http://example.com/search.php?search=(amistillhere)' ); + yield array( 'http://example.com/?test=%2812345%29abcdef[gh]' ); + yield array( 'http://example.com/?test=(12345)abcdef[gh]' ); + yield array( 'http://[0:0:0:0:0:0:0:1]/' ); + yield array( 'http://[2001:db8:1f70::999:de8:7648:6e8]:100/' ); + yield array( 'http://example.com/?req=http;//blah' ); + // + yield array( 'relative' ); + yield array( 'Relative/path/' ); + yield array( 'relative/Path/#yes' ); + yield array( '/absolute' ); + yield array( '/Absolute/Path/' ); + yield array( '/absolute/path/?omg#also' ); + yield array( 'http://académie-française.fr' ); + yield array( 'http://www.طارق.net/طارق?hello=%2B' ); + yield array( 'http://%d8%b7%d8%a7%d8%b1%d9%82.net/' ); + // Backslashes should be preserved in URL fragments and queries + yield array( 'https://example.com/path?q=a\\b\\c#x\\y\\z' ); + yield array( 'https://example.com/path?q=a\\b\\c' ); + yield array( 'https://example.com/path#x\\y\\z' ); + yield array( 'https://example.com/path#x\\y\\z?a\\b\\c' ); + yield array( 'mailto:ozh@ozh.ozh?subject=hello\\world&body=this%20is%20%a%20#fragment' ); + // Preserve backslashes in JSON-like fragment (regression for issue #3802) + yield array( 'https://terminal.jcubic.pl/404#[[0,1,%22jargon%20\\%22Don%27t%20do%20that%20then!\\%22%22]]' ); + } + + /** + * Test that valid URLs are not modified + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\DataProvider('list_of_valid_URLs')] + function test_valid_urls( $url ) { + $this->assertEquals( $url, yourls_sanitize_url( $url ) ); + } + + /** + * URL with spaces + * + * @since 0.1 + */ + function test_url_with_spaces() { + $this->assertEquals( 'http://example.com/HelloWorld', yourls_sanitize_url( 'http://example.com/Hello World' ) ); + $this->assertEquals( 'http://example.com/Hello%20World', yourls_sanitize_url( 'http://example.com/Hello%20World' ) ); + $this->assertEquals( 'http://example.com/', yourls_sanitize_url( 'http://example.com/ ' ) ); + $this->assertEquals( 'http://example.com/', yourls_sanitize_url( ' http://example.com/' ) ); + $this->assertEquals( 'http://example.com/', yourls_sanitize_url( ' http://example.com/ ' ) ); + } + + /** + * URL with bad chars + * + * @since 0.1 + */ + function test_url_with_bad_characters() { + // regular sanitize leaves %0A & %0D alone + $this->assertEquals( 'http://example.com/keep%0Dlinefeed%0A', yourls_sanitize_url( 'http://example.com/keep%0Dlinefeed%0A' ) ); + $this->assertEquals( 'http://example.com/%0%0%0DAD', yourls_sanitize_url( 'http://example.com/%0%0%0DAD' ) ); + + // sanitize with anti CRLF + $this->assertEquals( 'http://example.com/watchthelinefeedgo', yourls_sanitize_url_safe( 'http://example.com/watchthelinefeed%0Ago' ) ); + $this->assertEquals( 'http://example.com/watchthelinefeedgo', yourls_sanitize_url_safe( 'http://example.com/watchthelinefeed%0ago' ) ); + $this->assertEquals( 'http://example.com/watchthecarriagereturngo', yourls_sanitize_url_safe( 'http://example.com/watchthecarriagereturn%0Dgo' ) ); + $this->assertEquals( 'http://example.com/watchthecarriagereturngo', yourls_sanitize_url_safe( 'http://example.com/watchthecarriagereturn%0dgo' ) ); + + //Nesting Checks + $this->assertEquals( 'http://example.com/watchthecarriagereturngo', yourls_sanitize_url_safe( 'http://example.com/watchthecarriagereturn%0%0ddgo' ) ); + $this->assertEquals( 'http://example.com/watchthecarriagereturngo', yourls_sanitize_url_safe( 'http://example.com/watchthecarriagereturn%0%0DDgo' ) ); + $this->assertEquals( 'http://example.com/', yourls_sanitize_url_safe( 'http://example.com/%0%0%0DAD' ) ); + $this->assertEquals( 'http://example.com/', yourls_sanitize_url_safe( 'http://example.com/%0%0%0ADA' ) ); + $this->assertEquals( 'http://example.com/', yourls_sanitize_url_safe( 'http://example.com/%0%0%0DAd' ) ); + $this->assertEquals( 'http://example.com/', yourls_sanitize_url_safe( 'http://example.com/%0%0%0ADa' ) ); + + // Backslash tests + $this->assertEquals( 'http://example.com/', yourls_sanitize_url_safe( 'http://exa\\mple.com/' ) ); + $this->assertEquals( 'http://example.com/testingtesting', yourls_sanitize_url_safe( 'http://example.com/testing\\testing' ) ); + $this->assertEquals( 'http://example.com/testingtesting?query=param\\test', yourls_sanitize_url_safe( 'http://example.com/testing\\testing?query=param\\test' ) ); + $this->assertEquals( 'http://example.com/testingtesting?query=param\\test#hash', yourls_sanitize_url_safe( 'http://example.com/testing\\testing?query=param\\test#hash' ) ); + $this->assertEquals( 'http://example.com/testingtesting#hash\\hash', yourls_sanitize_url_safe( 'http://example.com/testing\\testing#hash\\hash' ) ); + } + + /** + * Test valid, missing and fake protocols + * + * @since 0.1 + */ + function test_url_with_protocols() { + $this->assertEquals( 'http://example.com', yourls_sanitize_url( 'http://example.com' ) ); + $this->assertEquals( 'example.php', yourls_sanitize_url( 'example.php' ) ); + $this->assertEquals( '', yourls_sanitize_url( 'htttp://example.com' ) ); + $this->assertEquals( 'mailto:ozh@ozh.org', yourls_sanitize_url( 'mailto:ozh@ozh.org' ) ); + // play with allowed protocols + $this->assertEquals( '', yourls_sanitize_url( 'nasty://example.com/' ) ); + $this->assertEquals( 'nasty://example.com/', yourls_sanitize_url( 'nasty://example.com/', array('nasty://') ) ); + global $yourls_allowedprotocols; + $yourls_allowedprotocols[] = 'evil://'; + $this->assertEquals( 'evil://example.com', yourls_sanitize_url( 'evil://example.com' ) ); + $yourls_allowedprotocols = yourls_kses_allowed_protocols(); + } + + /** + * List of URLs with MiXeD CaSe to test. Structure: array( sanitized url, unsanitized url with mixed case ) + */ + static function list_of_mixed_case(): \Iterator + { + yield array( 'http://example.com' , 'http://example.com' ); + # normal, no trailing slash + yield array( 'http://example.com/' , 'http://example.com/' ); + # normal, trailing slash + yield array( 'http://example.com' , 'HTTP://example.com' ); + yield array( 'http://example.com' , 'Http://example.com' ); + yield array( 'http://example.com' , 'Http://ExAmPlE.com' ); + yield array( 'http://example.com/BLAH' , 'Http://ExAmPlE.com/BLAH' ); + yield array( 'http://http/HTTP?HTTP#HTTP' , 'HTTP://HTTP/HTTP?HTTP#HTTP' ); + yield array( 'http://example.com/?@BLaH' , 'Http://ExAmPlE.com/?@BLaH' ); + #1890 + yield array( 'http://example.com#BLAH' , 'Http://ExAmPlE.com#BLAH' ); + yield array( 'http://example.com#BLAH' , 'Http://@ExAmPlE.com#BLAH' ); + yield array( 'http://example.com#BLAH' , 'Http://:@ExAmPlE.com#BLAH' ); + yield array( 'http://example.com?BLAH' , 'Http://ExAmPlE.com?BLAH' ); + yield array( 'http://Ozh:Password@example.com:1337#OMG' , 'http://Ozh:Password@Example.COM:1337#OMG' ); + yield array( 'http://User:PWd@example.com?User:PWd@Example.com' , 'http://User:PWd@Example.com?User:PWd@Example.com' ); + yield array( 'mailto:Ozh@Ozh.org?omg' , 'MAILTO:Ozh@Ozh.org?omg' ); + yield array( 'http://www.طارق.net/' , 'http://www.طارق.Net/' ); + yield array( 'http://académie-française.fr' , 'http://Académie-française.FR' ); + } + + /** + * Protocol and domain with mixed case + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\DataProvider('list_of_mixed_case')] + function test_url_with_protocol_case( $sanitized, $unsanitized ) { + $this->assertEquals( $sanitized, yourls_sanitize_url( $unsanitized ) ); + } + + /** + * List of URLs with IDN domain, and how YOURLS should sanitize them + */ + static function list_of_IDN(): \Iterator + { + yield array( 'http://www.طارق.Net/Omgطارق' , 'http://www.طارق.net/Omgطارق' ); + yield array( 'http://xn--mgbuq0c.Net/Omgطارق' , 'http://طارق.net/Omgطارق' ); + yield array( 'http://%d8%b7%d8%a7%d8%b1%d9%82.Net/Omgطارق' , 'http://%d8%b7%d8%a7%d8%b1%d9%82.net/Omgطارق' ); + // طارق.net, urlencoded + yield array( 'http://xn--p1ai.РФ' , 'http://рф.рф' ); + // lowercasing where applicable: РФ -> рф + yield array( 'http://РФ.xn--p1ai/' , 'http://рф.рф/' ); + yield array( 'http://xn--p1ai.xn--p1ai' , 'http://рф.рф' ); + } + + /** + * Protocol and domain with mixed case + */ + #[\PHPUnit\Framework\Attributes\DataProvider('list_of_IDN')] + function test_url_with_IDN( $unsanitized, $sanitized ) { + $this->assertEquals( $sanitized, yourls_sanitize_url( $unsanitized ) ); + } + + /** + * List of URLS and expected matches whether we're on SSL or not. + * Structure: array(original URL, expected URL if we're on HTTP, expected URL if we're on HTTPS) + */ + static function list_of_urls_with_and_without_https(): \Iterator + { + yield array( 'http://omg', 'http://omg', 'https://omg' ); + yield array( 'https://omg', 'https://omg', 'https://omg' ); + yield array( 'http://omg?http', 'http://omg?http', 'https://omg?http' ); + yield array( 'https://omg?http', 'https://omg?http', 'https://omg?http' ); + yield array( 'omg?http://bleh', 'omg?http://bleh', 'omg?http://bleh' ); + yield array( 'omg?https://bleh', 'omg?https://bleh', 'omg?https://bleh' ); + yield array( 'http', 'http', 'http' ); + yield array( 'https', 'https', 'https' ); + yield array( 'http://https', 'http://https', 'https://https' ); + yield array( 'https://https', 'https://https', 'https://https' ); + } + /** + * Test matching protocol with no SSL + * + * Feed URL and return a result that matches "http" + */ + #[\PHPUnit\Framework\Attributes\DataProvider('list_of_urls_with_and_without_https')] + function test_matching_protocols_with_no_ssl( $url, $without_ssl, $with_ssl ) { + yourls_add_filter('is_ssl', 'yourls_return_false'); + $this->assertEquals( $without_ssl, yourls_match_current_protocol($url) ); + } + + /** + * Test matching protocol with SSL + * + * Feed URL and return a result that matches "https" + */ + #[\PHPUnit\Framework\Attributes\DataProvider('list_of_urls_with_and_without_https')] + function test_matching_protocols_with_ssl( $url, $without_ssl, $with_ssl ) { + yourls_add_filter('is_ssl', 'yourls_return_true'); + $this->assertEquals( $with_ssl, yourls_match_current_protocol($url) ); + } + + /** + * List of various valid URL with mixed scenarios of IDN + * Structure: array(URL, expected URL after yourls_sanitize_url (and especially yourls_normalize_uri(), which deals with IDN) + */ + static function list_of_idn_punycode_utf8_rtl(): \Iterator + { + yield [ 'http://ua-test.link' , 'http://ua-test.link' ]; + // Ascii.new + yield [ 'http://ua-test.technology' , 'http://ua-test.technology' ]; + // Ascii.long + yield [ 'http://普试.top/' , 'http://普试.top/' ]; + // Idn.ascii + yield [ 'http://ua-test.世界' , 'http://ua-test.世界' ]; + // Ascii.idn + yield [ 'http://普试.世界/' , 'http://普试.世界/' ]; + // Idn.idn + yield [ 'http://ua-test.xn--rhqv96g' , 'http://ua-test.世界' ]; + // Ascii.punycode + yield [ 'http://xn--tkvo64f.top' , 'http://普试.top' ]; + // Punycode.ascii + yield [ 'http://xn--tkvo64f.xn--rhqv96g' , 'http://普试.世界' ]; + // Punycode.punycode + yield [ 'http://اختبار-القبولالعالمي.top' , 'http://اختبار-القبولالعالمي.top' ]; + // RTL.ascii + yield [ 'http://اختبار-القبولالعالمي.شبكة' , 'http://اختبار-القبولالعالمي.شبكة' ]; + // RTL.RTL + yield [ 'http://ua-test.link/我的' , 'http://ua-test.link/我的' ]; + // Ascii.new/Unicode + yield [ 'http://ua-test.technology/我的' , 'http://ua-test.technology/我的' ]; + // Ascii.long/Unicode + yield [ 'http://普试.top/我的' , 'http://普试.top/我的' ]; + // Idn.ascii/Unicode + yield [ 'http://ua-test.世界/我的' , 'http://ua-test.世界/我的' ]; + // Ascii.idn/Unicode + yield [ 'http://普试.世界/我的' , 'http://普试.世界/我的' ]; + // Idn.idn/Unicode + yield [ 'http://ختبار-القبولالعالمي.top/我的' , 'http://ختبار-القبولالعالمي.top/我的' ]; + // RTL.ascii/Unicode + yield [ 'http://اختبار-القبولالعالمي.شبكة/我的' , 'http://اختبار-القبولالعالمي.شبكة/我的' ]; + } + + /** + * Test various cases : domain name / TLD / path with ascii, punycode, utf8 and RTL + */ + #[\PHPUnit\Framework\Attributes\DataProvider('list_of_idn_punycode_utf8_rtl')] + function test_various_idn_cases($url, $expected) { + $this->assertEquals( yourls_sanitize_url($url), $expected ); + } + +} diff --git a/tests/tests/format/escaping.php b/tests/tests/format/escaping.php deleted file mode 100644 index 5bb03c83a..000000000 --- a/tests/tests/format/escaping.php +++ /dev/null @@ -1,222 +0,0 @@ -assertSame( $escaped, yourls_esc_attr( $attr ) ); - } - - /** - * Attribute escaping -- escaping twice shouldn't change - * - * @dataProvider html_attributes - * @since 0.1 - */ - function test_esc_attr_twice( $attr, $escaped ) { - $this->assertSame( $escaped, yourls_esc_attr( yourls_esc_attr( $attr ) ) ); - } - - /** - * HTML string and how they should be escaped - */ - function html_strings() { - return array( - // Simple string - array( - 'The quick brown fox.', - 'The quick brown fox.', - ), - // URL with & - array( - 'https://127.0.0.1/admin/admin-ajax.php?id=y1120844669&action=edit&keyword=1a&nonce=bf3115ac3a', - 'https://127.0.0.1/admin/admin-ajax.php?id=y1120844669&action=edit&keyword=1a&nonce=bf3115ac3a', - ), - // More ampersands - array( - 'H&M and Dungeons & Dragons', - 'H&M and Dungeons & Dragons', - ), - // Simple quotes - array( - "SELECT stuff FROM table WHERE blah IN ('omg', 'wtf') AND foo = 1", - 'SELECT stuff FROM table WHERE blah IN ('omg', 'wtf') AND foo = 1', - ), - // Double quotes - array( - 'I am "special"', - 'I am "special"', - ), - // Greater and less than - array( - 'this > that < that ', - 'this > that < that <randomhtml />', - ), - // Ignore actual entities - array( - '& £ " &', - '& £ " &', - ), - // Empty string - array( - '', - '', - ), - ); - } - - /** - * HTML escaping - * - * @dataProvider html_strings - * @since 0.1 - */ - function test_esc_html( $html, $escaped ) { - $this->assertSame( $escaped, yourls_esc_html( $html ) ); - } - - /** - * String to escape and what they should look like once escaped - */ - public function strings_to_escape() { - return array( - array( "I'm rock n' rollin'", "I\'m rock n\' rollin\'" ), - array( 'I am "nice"', 'I am \"nice\"' ), - array( 'Back\Slash', 'Back\\\Slash' ), - array( "NULL\0NULL", 'NULL\0NULL' ), // notice the quote change - ); - } - - /** - * List of URLs and how they should be escaped - */ - function list_of_URLs() { - return array( - array( - 'http://example.com/?this=that&that=this', - 'http://example.com/?this=that&that=this', - ), - array( - 'http://example.com/?this=that&that="this"', - 'http://example.com/?this=that&that=this', - ), - array( - "http://example.com/?this=that&that='this'", - 'http://example.com/?this=that&that='this'', - ), - array( - "http://example.com/?this=that&that=", - 'http://example.com/?this=that&that=this', - ), - ); - } - - /** - * Escape URLs for display - * - * @since 0.1 - * @group url - * @dataProvider list_of_URLs - */ - function test_esc_urls( $url, $escaped ) { - $this->assertEquals( $escaped, yourls_esc_url( $url ) ); - } - - /** - * Some strings and how they should be escaped in javascript - */ - function list_of_JS() { - return array( - array( - 'hello world();', - 'hello world();', - ), - array( - 'hello("world");', - 'hello("world");', - ), - array( - 'foo & bar &baz; '', - 'foo & bar &baz; '', - ), - ); - } - - /** - * Escape JS - * - * @since 0.1 - * @dataProvider list_of_JS - */ - function test_esc_js( $js, $escaped ) { - $this->assertEquals( $escaped, yourls_esc_js( $js ) ); - } - - /** - * Strings in a textarea and how they should be escaped - */ - function list_of_textarea() { - return array( - array( - 'hello
world', - 'hello<br/>world', - ), - array( - '"omg"', - '"omg"', - ), - array( - "'omg'", - ''omg'', - ), - ); - } - - /** - * Escape JS - * - * @since 0.1 - * @dataProvider list_of_textarea - */ - function test_esc_textarea( $text, $escaped ) { - $this->assertEquals( $escaped, yourls_esc_textarea( $text ) ); - } - -} diff --git a/tests/tests/format/urls.php b/tests/tests/format/urls.php deleted file mode 100644 index 1b5686543..000000000 --- a/tests/tests/format/urls.php +++ /dev/null @@ -1,295 +0,0 @@ -assertSame( yourls_get_protocol( $test_this ), $expected ); - } - - - /** - * List of valid URLs that should not be changed when sanitized - */ - function list_of_valid_URLs() { - return array( - array( 'http://example.com' ), - array( 'http://example.com/' ), - array( 'http://ozh@example.com/' ), - array( 'http://example.com/?@OMG' ), // #1890 - array( 'http://ozh@example.com#BLAH' ), - array( 'http://Ozh:Password@example.com/' ), - array( 'http://Ozh:Password@example.com#OMG' ), - array( 'http://Ozh:Password@example.com:1337/' ), - array( 'http://Ozh:Password@example.com:1337#OMG' ), - array( 'http://Ozh:Password@example.com/hey@ho' ), - array( 'http://username:password@example.com:8042/over/there/index.dtb?type=animal&name=narwhal#nose:@:@' ), - array( 'mailto:ozh@ozh.org' ), - array( 'http://example.com/?watchtheallowedcharacters-~+_.#=&;,/:%!*stay' ), - array( 'http://example.com/search.php?search=(amistillhere)' ), - array( 'http://example.com/?test=%2812345%29abcdef[gh]' ), - array( 'http://example.com/?test=(12345)abcdef[gh]' ), - array( 'http://[0:0:0:0:0:0:0:1]/' ), - array( 'http://[2001:db8:1f70::999:de8:7648:6e8]:100/' ), - array( 'http://example.com/?req=http;//blah' ), // - array( 'relative' ), - array( 'Relative/path/' ), - array( 'relative/Path/#yes' ), - array( '/absolute' ), - array( '/Absolute/Path/' ), - array( '/absolute/path/?omg#also' ), - array( 'http://académie-française.fr' ), - array( 'http://www.طارق.net/طارق?hello=%2B' ), - array( 'http://%d8%b7%d8%a7%d8%b1%d9%82.net/' ), // this is طارق.net, encoded. I _think_ it qualifies as valid - ); - } - - /** - * Test that valid URLs are not modified - * - * @since 0.1 - * @dataProvider list_of_valid_URLs - */ - function test_valid_urls( $url ) { - $this->assertEquals( $url, yourls_sanitize_url( $url ) ); - } - - /** - * URL with spaces - * - * @since 0.1 - */ - function test_url_with_spaces() { - $this->assertEquals( 'http://example.com/HelloWorld', yourls_sanitize_url( 'http://example.com/Hello World' ) ); - $this->assertEquals( 'http://example.com/Hello%20World', yourls_sanitize_url( 'http://example.com/Hello%20World' ) ); - $this->assertEquals( 'http://example.com/', yourls_sanitize_url( 'http://example.com/ ' ) ); - $this->assertEquals( 'http://example.com/', yourls_sanitize_url( ' http://example.com/' ) ); - $this->assertEquals( 'http://example.com/', yourls_sanitize_url( ' http://example.com/ ' ) ); - } - - /** - * URL with bad chars - * - * @since 0.1 - */ - function test_url_with_bad_characters() { - // regular sanitize leaves %0A & %0D alone - $this->assertEquals( 'http://example.com/keep%0Dlinefeed%0A', yourls_sanitize_url( 'http://example.com/keep%0Dlinefeed%0A' ) ); - $this->assertEquals( 'http://example.com/%0%0%0DAD', yourls_sanitize_url( 'http://example.com/%0%0%0DAD' ) ); - - // sanitize with anti CRLF - $this->assertEquals( 'http://example.com/watchthelinefeedgo', yourls_sanitize_url_safe( 'http://example.com/watchthelinefeed%0Ago' ) ); - $this->assertEquals( 'http://example.com/watchthelinefeedgo', yourls_sanitize_url_safe( 'http://example.com/watchthelinefeed%0ago' ) ); - $this->assertEquals( 'http://example.com/watchthecarriagereturngo', yourls_sanitize_url_safe( 'http://example.com/watchthecarriagereturn%0Dgo' ) ); - $this->assertEquals( 'http://example.com/watchthecarriagereturngo', yourls_sanitize_url_safe( 'http://example.com/watchthecarriagereturn%0dgo' ) ); - - //Nesting Checks - $this->assertEquals( 'http://example.com/watchthecarriagereturngo', yourls_sanitize_url_safe( 'http://example.com/watchthecarriagereturn%0%0ddgo' ) ); - $this->assertEquals( 'http://example.com/watchthecarriagereturngo', yourls_sanitize_url_safe( 'http://example.com/watchthecarriagereturn%0%0DDgo' ) ); - $this->assertEquals( 'http://example.com/', yourls_sanitize_url_safe( 'http://example.com/%0%0%0DAD' ) ); - $this->assertEquals( 'http://example.com/', yourls_sanitize_url_safe( 'http://example.com/%0%0%0ADA' ) ); - $this->assertEquals( 'http://example.com/', yourls_sanitize_url_safe( 'http://example.com/%0%0%0DAd' ) ); - $this->assertEquals( 'http://example.com/', yourls_sanitize_url_safe( 'http://example.com/%0%0%0ADa' ) ); - } - - /** - * Test valid, missing and fake protocols - * - * @since 0.1 - */ - function test_url_with_protocols() { - $this->assertEquals( 'http://example.com', yourls_sanitize_url( 'http://example.com' ) ); - $this->assertEquals( 'example.php', yourls_sanitize_url( 'example.php' ) ); - $this->assertEquals( '', yourls_sanitize_url( 'htttp://example.com' ) ); - $this->assertEquals( 'mailto:ozh@ozh.org', yourls_sanitize_url( 'mailto:ozh@ozh.org' ) ); - // play with allowed protocols - $this->assertEquals( '', yourls_sanitize_url( 'nasty://example.com/' ) ); - $this->assertEquals( 'nasty://example.com/', yourls_sanitize_url( 'nasty://example.com/', array('nasty://') ) ); - global $yourls_allowedprotocols; - $yourls_allowedprotocols[] = 'evil://'; - $this->assertEquals( 'evil://example.com', yourls_sanitize_url( 'evil://example.com' ) ); - $yourls_allowedprotocols = yourls_kses_allowed_protocols(); - } - - /** - * List of URLs with MiXeD CaSe to test. Structure: array( sanitized url, unsanitized url with mixed case ) - */ - function list_of_mixed_case() { - return array( - array( 'http://example.com' , 'http://example.com' ), # normal, no trailing slash - array( 'http://example.com/' , 'http://example.com/' ), # normal, trailing slash - array( 'http://example.com' , 'HTTP://example.com' ), - array( 'http://example.com' , 'Http://example.com' ), - array( 'http://example.com' , 'Http://ExAmPlE.com' ), - array( 'http://example.com/BLAH' , 'Http://ExAmPlE.com/BLAH' ), - array( 'http://http/HTTP?HTTP#HTTP' , 'HTTP://HTTP/HTTP?HTTP#HTTP' ), - array( 'http://example.com/?@BLaH' , 'Http://ExAmPlE.com/?@BLaH' ), #1890 - array( 'http://example.com#BLAH' , 'Http://ExAmPlE.com#BLAH' ), - array( 'http://example.com#BLAH' , 'Http://@ExAmPlE.com#BLAH' ), - array( 'http://example.com#BLAH' , 'Http://:@ExAmPlE.com#BLAH' ), - array( 'http://example.com?BLAH' , 'Http://ExAmPlE.com?BLAH' ), - array( 'http://Ozh:Password@example.com:1337#OMG' , 'http://Ozh:Password@Example.COM:1337#OMG' ), - array( 'http://User:PWd@example.com?User:PWd@Example.com' , 'http://User:PWd@Example.com?User:PWd@Example.com' ), - array( 'mailto:Ozh@Ozh.org?omg' , 'MAILTO:Ozh@Ozh.org?omg' ), - array( 'http://www.طارق.net/' , 'http://www.طارق.Net/' ), - array( 'http://académie-française.fr' , 'http://Académie-française.FR' ), - ); - } - - /** - * Protocol and domain with mixed case - * - * @since 0.1 - * @dataProvider list_of_mixed_case - */ - function test_url_with_protocol_case( $sanitized, $unsanitized ) { - $this->assertEquals( $sanitized, yourls_sanitize_url( $unsanitized ) ); - } - - /** - * List of URLs with IDN domain, and how YOURLS should sanitize them - */ - function list_of_IDN() { - return array( - array( 'http://www.طارق.Net/Omgطارق' , 'http://www.طارق.net/Omgطارق' ), - array( 'http://xn--mgbuq0c.Net/Omgطارق' , 'http://طارق.net/Omgطارق' ), - array( 'http://%d8%b7%d8%a7%d8%b1%d9%82.Net/Omgطارق' , 'http://%d8%b7%d8%a7%d8%b1%d9%82.net/Omgطارق' ), // طارق.net, urlencoded - array( 'http://xn--p1ai.РФ' , 'http://рф.рф' ), // lowercasing where applicable: РФ -> рф - array( 'http://РФ.xn--p1ai/' , 'http://рф.рф/' ), - array( 'http://xn--p1ai.xn--p1ai' , 'http://рф.рф' ), - ); - } - - /** - * Protocol and domain with mixed case - * - * @dataProvider list_of_IDN - */ - function test_url_with_IDN( $unsanitized, $sanitized ) { - $this->assertEquals( $sanitized, yourls_sanitize_url( $unsanitized ) ); - } - - /** - * List of URLS and expected matches whether we're on SSL or not. - * Structure: array(original URL, expected URL if we're on HTTP, expected URL if we're on HTTPS) - */ - function list_of_urls_with_and_without_https() { - return array( - array( 'http://omg', 'http://omg', 'https://omg' ), - array( 'https://omg', 'https://omg', 'https://omg' ), - array( 'http://omg?http', 'http://omg?http', 'https://omg?http' ), - array( 'https://omg?http', 'https://omg?http', 'https://omg?http' ), - array( 'omg?http://bleh', 'omg?http://bleh', 'omg?http://bleh' ), - array( 'omg?https://bleh', 'omg?https://bleh', 'omg?https://bleh' ), - array( 'http', 'http', 'http' ), - array( 'https', 'https', 'https' ), - array( 'http://https', 'http://https', 'https://https' ), - array( 'https://https', 'https://https', 'https://https' ), - ); - } - /** - * Test matching protocol with no SSL - * - * Feed URL and return a result that matches "http" - * - * @dataProvider list_of_urls_with_and_without_https - */ - function test_matching_protocols_with_no_ssl( $url, $without_ssl, $with_ssl ) { - yourls_add_filter('is_ssl', 'yourls_return_false'); - $this->assertEquals( $without_ssl, yourls_match_current_protocol($url) ); - } - - /** - * Test matching protocol with SSL - * - * Feed URL and return a result that matches "https" - * - * @dataProvider list_of_urls_with_and_without_https - */ - function test_matching_protocols_with_ssl( $url, $without_ssl, $with_ssl ) { - yourls_add_filter('is_ssl', 'yourls_return_true'); - $this->assertEquals( $with_ssl, yourls_match_current_protocol($url) ); - } - - /** - * List of various valid URL with mixed scenarios of IDN - * Structure: array(URL, expected URL after yourls_sanitize_url (and especially yourls_normalize_uri(), which deals with IDN) - */ - function list_of_idn_punycode_utf8_rtl() { - return array( - [ 'http://ua-test.link' , 'http://ua-test.link' ], // Ascii.new - [ 'http://ua-test.technology' , 'http://ua-test.technology' ], // Ascii.long - [ 'http://普试.top/' , 'http://普试.top/' ], // Idn.ascii - [ 'http://ua-test.世界' , 'http://ua-test.世界' ], // Ascii.idn - [ 'http://普试.世界/' , 'http://普试.世界/' ], // Idn.idn - [ 'http://ua-test.xn--rhqv96g' , 'http://ua-test.世界' ], // Ascii.punycode - [ 'http://xn--tkvo64f.top' , 'http://普试.top' ], // Punycode.ascii - [ 'http://xn--tkvo64f.xn--rhqv96g' , 'http://普试.世界' ], // Punycode.punycode - [ 'http://اختبار-القبولالعالمي.top' , 'http://اختبار-القبولالعالمي.top' ], // RTL.ascii - [ 'http://اختبار-القبولالعالمي.شبكة' , 'http://اختبار-القبولالعالمي.شبكة' ], // RTL.RTL - [ 'http://ua-test.link/我的' , 'http://ua-test.link/我的' ], // Ascii.new/Unicode - [ 'http://ua-test.technology/我的' , 'http://ua-test.technology/我的' ], // Ascii.long/Unicode - [ 'http://普试.top/我的' , 'http://普试.top/我的' ], // Idn.ascii/Unicode - [ 'http://ua-test.世界/我的' , 'http://ua-test.世界/我的' ], // Ascii.idn/Unicode - [ 'http://普试.世界/我的' , 'http://普试.世界/我的' ], // Idn.idn/Unicode - [ 'http://ختبار-القبولالعالمي.top/我的' , 'http://ختبار-القبولالعالمي.top/我的' ], // RTL.ascii/Unicode - [ 'http://اختبار-القبولالعالمي.شبكة/我的' , 'http://اختبار-القبولالعالمي.شبكة/我的' ], // RTL.RTL/Unicode - - // Damn, due to these UTF8 chars not being fixed width, we cannot neatly - // justify the code and comments. How disappointing. - ); - } - - /** - * Test various cases : domain name / TLD / path with ascii, punycode, utf8 and RTL - * - * @dataProvider list_of_idn_punycode_utf8_rtl - */ - function test_various_idn_cases($url, $expected) { - $this->assertEquals( yourls_sanitize_url($url), $expected ); - } - -} diff --git a/tests/tests/geoip/GeoIPTest.php b/tests/tests/geoip/GeoIPTest.php new file mode 100644 index 000000000..ca51143aa --- /dev/null +++ b/tests/tests/geoip/GeoIPTest.php @@ -0,0 +1,77 @@ +assertEquals( $country, yourls_geo_ip_to_countrycode( $ip, 'none' ) ); + } + + /** + * Check that a few IPv6 resolve to the correct country code + */ + #[\PHPUnit\Framework\Attributes\DataProvider('ipv6_samples')] + public function test_ip_to_countrycode_ipv6( $ip, $country ) { + $this->assertEquals( $country, yourls_geo_ip_to_countrycode( $ip, 'none' ) ); + } + + /** + * Check a few country code => country name pairs + */ + #[\PHPUnit\Framework\Attributes\DataProvider('country_codes')] + public function test_countrycode_to_countryname( $code, $country ) { + $this->assertEquals( $country, yourls_geo_countrycode_to_countryname( $code ) ); + } + + /** + * Check a few code return a string when getting their country flag + */ + public function test_country_images() { + $this->assertIsString(yourls_geo_get_flag('AU')); // something like http://yourls/includes/geo/flags/flag_au.gif + $this->assertIsString(yourls_geo_get_flag('')); // something like http://yourls/includes/geo/flags/flag_.gif + $this->assertIsString(yourls_geo_get_flag('OMGLOL')); // fall back to default '' + } + + /** + * Data provider : array of arrays of ( 'ip', 'country code' ) in IPv4 notation + */ + public static function ipv4_samples(): \Iterator + { + yield array( '8.8.8.8', 'US' ); + yield array( '13.37.13.37', 'FR' ); + yield array( '79.79.79.79', 'GB' ); + yield array( '10.0.0.1', 'none' ); + yield array( 'helloworld', 'none' ); + } + + /** + * Data provider : array of arrays of ( 'ip', 'country code' ) in IPv6 various notations + */ + public static function ipv6_samples(): \Iterator + { + yield array( '::80.24.24.24', 'ES' ); + // yield array( '2606:4700:4700::1111', 'US' ); + yield array( '2001:0240:2000::', 'JP' ); + yield array( '::1', 'none' ); + yield array( 'mynameisozh', 'none' ); + } + + /** + * Data provider : array of arrays of ( 'country code', 'country name' ) + */ + public static function country_codes(): \Iterator + { + yield array( 'AU', 'Australia' ); + yield array( 'BZ', 'Belize' ); + yield array( 'CA', 'Canada' ); + yield array( 'WW', '' ); + } + +} diff --git a/tests/tests/geoip/geoip.php b/tests/tests/geoip/geoip.php deleted file mode 100644 index bc00cee95..000000000 --- a/tests/tests/geoip/geoip.php +++ /dev/null @@ -1,86 +0,0 @@ -assertEquals( $country, yourls_geo_ip_to_countrycode( $ip, 'none' ) ); - } - - /** - * Check that a few IPv6 resolve to the correct country code - * - * @dataProvider ipv6_samples - */ - public function test_ip_to_countrycode_ipv6( $ip, $country ) { - $this->assertEquals( $country, yourls_geo_ip_to_countrycode( $ip, 'none' ) ); - } - - /** - * Check a few country code => country name pairs - * - * @dataProvider country_codes - */ - public function test_countrycode_to_countryname( $code, $country ) { - $this->assertEquals( $country, yourls_geo_countrycode_to_countryname( $code ) ); - } - - /** - * Check a few code return a string when getting their country flag - */ - public function test_country_images() { - $this->assertIsString(yourls_geo_get_flag('AU')); // something like http://yourls/includes/geo/flags/flag_au.gif - $this->assertIsString(yourls_geo_get_flag('FR')); - $this->assertIsString(yourls_geo_get_flag('')); // something like http://yourls/includes/geo/flags/flag_.gif - $this->assertIsString(yourls_geo_get_flag('OMGLOL')); // fall back to default '' - } - - /** - * Data provider : array of arrays of ( 'ip', 'country code' ) in IPv4 notation - */ - public function ipv4_samples() { - return array( - array( '8.8.8.8', 'US' ), - array( '13.37.13.37', 'FR' ), - array( '79.79.79.79', 'GB' ), - array( '10.0.0.1', 'none' ), - array( 'helloworld', 'none' ), - ); - } - - /** - * Data provider : array of arrays of ( 'ip', 'country code' ) in IPv6 notation - */ - public function ipv6_samples() { - return array( - array( '::80.24.24.24', 'ES' ), - array( '2001:4860:0:1001::68', 'US' ), - array( '2001:67c:3a0:ffff:ffff:ffff:ffff:ffff', 'NL' ), - array( '::1', 'none' ), - array( 'mynameisozh', 'none' ), - ); - } - - /** - * Data provider : array of arrays of ( 'country code', 'country name' ) - */ - public function country_codes() { - return array( - array( 'AU', 'Australia' ), - array( 'BZ', 'Belize' ), - array( 'CA', 'Canada' ), - array( 'WW', '' ), // fake code - ); - } - -} diff --git a/tests/tests/http/api-check.php b/tests/tests/http/AYOTest.php similarity index 55% rename from tests/tests/http/api-check.php rename to tests/tests/http/AYOTest.php index eb2c92766..431c18f14 100644 --- a/tests/tests/http/api-check.php +++ b/tests/tests/http/AYOTest.php @@ -3,19 +3,29 @@ /** * HTTP functions related to api.yourls.org * - * @group http - * @group AYO * @since 0.1 */ -class HTTP_AYO_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('http')] +#[\PHPUnit\Framework\Attributes\Group('AYO')] +class AYOTest extends PHPUnit\Framework\TestCase { + + protected $actions, $core_version_checks; + + protected function setUp(): void { + global $yourls_actions; + $this->actions = $yourls_actions; + } protected function tearDown(): void { yourls_remove_all_filters( 'is_admin' ); yourls_remove_all_filters( 'shunt_yourls_http_request' ); + global $yourls_actions; + $yourls_actions = $this->actions; + yourls_delete_option('core_version_checks'); } /** - * Emulate succesfull HTTP request to api.yourls.org + * Emulate successful HTTP request to api.yourls.org */ public function fake_http_request_success() { $return = (object) array(); @@ -39,15 +49,14 @@ public function fake_http_request_failure() { * Emulate HTTP request to api.yourls.org with a server error */ public function fake_http_request_server_error() { - $return = (object) array(); + $return = new stdClass; $return->body = 'Error 500'; $return->success = false; - return $return; } /** - * Check that version checking returns false if host is unreachable, and that failed attemps counter increments + * Check that version checking returns false if host is unreachable, and that failed attempts counter increments */ public function test_api_failed_request() { yourls_add_filter('shunt_yourls_http_request', array($this,'fake_http_request_failure') ); @@ -55,7 +64,7 @@ public function test_api_failed_request() { } /** - * Check that version checking returns false if host errors, and that failed attemps counter increments + * Check that version checking returns false if host errors, and that failed attempts counter increments */ public function test_api_failed_request_server_error() { yourls_add_filter('shunt_yourls_http_request', array($this,'fake_http_request_server_error') ); @@ -113,7 +122,7 @@ public function test_check_only_in_admin() { /** * Generate an object to mock last attempt of checking against api.yourls.org */ - public function return_case_object( $failed_attempts, $last_attempt, $version_checked ) { + public static function return_case_object( $failed_attempts, $last_attempt, $version_checked ) { $checks = new stdClass(); $checks->last_result = rand_str(); $checks->failed_attempts = $failed_attempts; @@ -124,9 +133,9 @@ public function return_case_object( $failed_attempts, $last_attempt, $version_ch } /** - * Provider of various test cases + * Provider of various test cases for test_api_check_in_various_scenario() */ - public function case_scenario() { + public static function case_scenario() { $return = array(); @@ -150,7 +159,7 @@ public function case_scenario() { * Then : we DO want to check */ $name = 'Case 1'; - $checks = $this->return_case_object( + $checks = self::return_case_object( 0, // 0 previously failed attempt time() - 26 * 3600, // 26 hours ago YOURLS_VERSION // version match @@ -166,7 +175,7 @@ public function case_scenario() { * Then : we DO want to check */ $name = 'Case 2'; - $checks = $this->return_case_object( + $checks = self::return_case_object( 0, // 0 previously failed attempt time() - 26 * 3600, // 26 hours ago rand_str() // version mismatch @@ -182,7 +191,7 @@ public function case_scenario() { * Then : we DON'T want to check */ $name = 'Case 3'; - $checks = $this->return_case_object( + $checks = self::return_case_object( 0, // 0 previously failed attempt time() - 10 * 3600, // 10 hours ago YOURLS_VERSION // version match @@ -198,7 +207,7 @@ public function case_scenario() { * Then : we DO want to check */ $name = 'Case 4'; - $checks = $this->return_case_object( + $checks = self::return_case_object( 0, // 0 previously failed attempt time() - 10 * 3600, // 10 hours ago rand_str() // version mismatch @@ -214,7 +223,7 @@ public function case_scenario() { * Then : we DO want to check */ $name = 'Case 5'; - $checks = $this->return_case_object( + $checks = self::return_case_object( 1337, // some previously failed attempts time() - 3 * 3600, // 3 hours ago YOURLS_VERSION // version match @@ -230,7 +239,7 @@ public function case_scenario() { * Then : we DO want to check */ $name = 'Case 6'; - $checks = $this->return_case_object( + $checks = self::return_case_object( 1337, // some previously failed attempts time() - 3 * 3600, // 3 hours ago rand_str() // version mismatch @@ -246,7 +255,7 @@ public function case_scenario() { * Then : we DON'T want to check */ $name = 'Case 7'; - $checks = $this->return_case_object( + $checks = self::return_case_object( 1337, // some previously failed attempts time() - 1 * 3600, // 1 hour ago YOURLS_VERSION // version match @@ -262,7 +271,7 @@ public function case_scenario() { * Then : we DO want to check */ $name = 'Case 8'; - $checks = $this->return_case_object( + $checks = self::return_case_object( 1337, // some previously failed attempts time() - 1 * 3600, // 1 hour ago rand_str() // version mismatch @@ -276,9 +285,9 @@ public function case_scenario() { /** * Check if we should poll api.yourls.org under various circumstances * - * @dataProvider case_scenario * @since 0.1 */ + #[\PHPUnit\Framework\Attributes\DataProvider('case_scenario')] public function test_api_check_in_various_scenario( $name, $checks, $expected ) { yourls_add_filter('shunt_yourls_http_request', array($this,'fake_http_request_success') ); @@ -291,58 +300,216 @@ public function test_api_check_in_various_scenario( $name, $checks, $expected ) /** * Provide fake JSON responses from api.yourls.org and a boolean stating if they should be accepted or not */ - public function json_responses() { + public static function json_responses() { $return = array(); - // expected - $return[] = array( + $return['expected'] = array( (object)array( 'latest' => '1.2.3', 'zipurl' => 'https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3', ), true); - // incorrect version number - $return[] = array( + $return['unexpected version number format'] = array( (object)array( 'latest' => '1.2.3-something', 'zipurl' => 'https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3', ), false); - // url not part of github.com - $return[] = array( + $return['version mismatch'] = array( + (object)array( + 'latest' => '1.2.3', + 'zipurl' => 'https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.4', + ), + false); + + $return['not github.com'] = array( (object)array( 'latest' => '1.2.3', 'zipurl' => 'https://notgithub.com/repos/YOURLS/YOURLS/zipball/1.2.3', ), false); - // no version - $return[] = array( + $return['not YOURLS/YOURLS'] = array( + (object)array( + 'latest' => '1.2.3', + 'zipurl' => 'https://api.github.com/repos/Y0URL5/YOURLS/zipball/1.2.3', + ), + false); + + $return['no version'] = array( (object)array( 'zipurl' => 'https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3', ), false); - // no URL - $return[] = array( + $return['no URL'] = array( (object)array( 'latest' => '1.2.3', ), false); + $return['nothing 1'] = array( + (object)[], + false); + + $return['nothing 2'] = array([], + false); + + $return['nothing 3'] = array(false, + false); + return $return; } /** * Validate various json responses from api.yourls.org and make sure they're legit * - * @dataProvider json_responses * @since 0.1 */ + #[\PHPUnit\Framework\Attributes\DataProvider('json_responses')] public function test_validate_api_json_response($json, $expected) { $this->assertSame( $expected, yourls_validate_core_version_response($json) ); } + /** + * Provide fake and true github repo URLs + */ + public static function fake_and_true_github_repo_urls() { + $return = array(); + $return['true'] = ['https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3', true]; + $return['not github'] = ['https://api.g1thub.com/repos/YOURLS/YOURLS/zipball/1.2.3', false]; + $return['not YOURLS'] = ['https://api.github.com/repos/Y0URL5/YOURLS/zipball/1.2.3', false]; + $return['not URL'] = ['nope', false]; + + return $return; + } + + /** + * Test yourls_is_valid_github_repo_url() + */ + #[\PHPUnit\Framework\Attributes\DataProvider('fake_and_true_github_repo_urls')] + public function test_is_valid_github_repo_url($url, $expected) { + $this->assertSame( yourls_is_valid_github_repo_url($url), $expected ); + } + + /** + * Provide various scenarios for version reported by api.yourls.org / current version to check if notice is shown + */ + public static function new_version_scenarios() { + $return = array(); + + // AYO current notice + $return[] = ['1.2.3', '1.2.2', 1]; // new version - display notice + $return[] = ['1.3', '1.2.2', 1]; // new version - display notice + $return[] = ['1.8.22', '1.8.3', 1]; // new version - display notice + $return[] = ['1.2.3', '1.2.3-beta', 1]; // new version - display notice + $return[] = ['1.3', '1.22', 0]; // older version - don't display version + $return[] = ['1.2.2', '1.2.2', 0]; // same version - don't display notice + $return[] = ['1.2.2', '1.2.3', 0]; // older version - don't display version + $return[] = ['99.9.9', false, 1]; // newer version compared to actual current YOURLS version - display notice + $return[] = ['0.1.1', false, 0]; // older version compared to actual current YOURLS version - don't display notice + + return $return; + } + + /** + * Test various YOURLS version strings from api.yourls.org, compare them to the actual version + * and make sure we display the correct update notice + */ + #[\PHPUnit\Framework\Attributes\DataProvider('new_version_scenarios')] + public function test_new_version_notice( $api_version, $current_version, $expected ) { + // fake the api response + $check = (object)array( + 'last_result' => (object)array( + 'latest' => $api_version, + ), + ); + yourls_add_option('core_version_checks', $check); + + // trigger yourls_core_version_notice() and check we had expected action + yourls_new_core_version_notice($current_version); + $this->assertSame($expected, yourls_did_action('new_core_version_notice')); + } + + /** + * Test various zipball URLs and get version number from it + */ + static function various_zipball_url_version() { + $return = []; + + $return[] = ['https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3', '1.2.3']; + $return[] = ['https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3-beta', '1.2.3-beta']; + $return[] = ['https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3/lol', 'lol']; + $return[] = ['http://hey', '']; + $return[] = ['lol', '']; + $return[] = ['', '']; + + return $return; + } + + /** + * Test various zipball URLs and get version number from it + */ + #[\PHPUnit\Framework\Attributes\DataProvider('various_zipball_url_version')] + public function test_get_version_from_zipball_url($url, $expected) { + $this->assertSame($expected, yourls_get_version_from_zipball_url($url)); + } + + + /** + * test various core version JSON responses from api.yourls.org + */ + static function get_various_json_response_keys() { + $return = []; + + $return['latest & zipurl'] = [['latest' => 'ok', 'zipurl' => 'ok'], true]; + $return['no latest'] = [['zipurl' => 'ok'], false]; + $return['no zipurl'] = [['latest' => 'ok'], false]; + $return['latest & other key'] = [['latest' => 'ok', 'other' => 'oops'], false]; + $return['zipurl & other key'] = [['zipurl' => 'ok', 'other' => 'oops'], false]; + $return['nothing'] = [[], false]; + $return['extra key'] = [['latest' => 'ok', 'zipurl' => 'ok', 'extra' => 'oops'], false]; + $return['not strings'] = [['latest' => [], 'zipurl' => 'ok'], false]; + + return $return; + } + + /** + * Check yourls_validate_core_version_response_keys() works as expected + */ + #[\PHPUnit\Framework\Attributes\DataProvider('get_various_json_response_keys')] + function test_yourls_validate_core_version_response_keys($json, $expected) { + $this->assertSame(yourls_validate_core_version_response_keys((object)$json), $expected); + } + + /** + * Return all possible api.yourls.org/core/version URL + */ + static function get_api_yourls_core(): \Iterator + { + yield ['https://api.yourls.org/core/version/1.1/']; + yield ['http://api.yourls.org/core/version/1.0/']; + } + + /** + * Make sure https://api.yourls.org/core/version/1.[0/1]/ returns a valid JSON response + * + * This test may fail is the server is unreachable or the API is down. + * TODO: make this test evolve as the API evolves + */ + #[\PHPUnit\Framework\Attributes\DataProvider('get_api_yourls_core')] + function test_yourls_get_core_version_json($url) { + $req = yourls_http_get($url); + + if ($req->status_code != 200) { + $this->markTestSkipped("Unable to reach $url - test skipped"); + } + + $json = json_decode(trim($req->body)); + $this->assertTrue(is_object($json)); + $this->assertTrue(yourls_validate_core_version_response($json)); + } + } diff --git a/tests/tests/http/HTTPHeadersTest.php b/tests/tests/http/HTTPHeadersTest.php new file mode 100644 index 000000000..41064fa93 --- /dev/null +++ b/tests/tests/http/HTTPHeadersTest.php @@ -0,0 +1,86 @@ +\s*window.location="http://somewhere";!m'; + + $this->expectOutputRegex($regexp); + yourls_redirect_javascript('http://somewhere'); + } + + public static function status_codes(): \Iterator + { + yield array(100, 'Continue'); + yield array(101, 'Switching Protocols'); + yield array(102, 'Processing'); + yield array(200, 'OK'); + yield array(201, 'Created'); + yield array(202, 'Accepted'); + yield array(203, 'Non-Authoritative Information'); + yield array(204, 'No Content'); + yield array(205, 'Reset Content'); + yield array(206, 'Partial Content'); + yield array(207, 'Multi-Status'); + yield array(226, 'IM Used'); + yield array(300, 'Multiple Choices'); + yield array(301, 'Moved Permanently'); + yield array(302, 'Found'); + yield array(303, 'See Other'); + yield array(304, 'Not Modified'); + yield array(305, 'Use Proxy'); + yield array(306, 'Reserved'); + yield array(307, 'Temporary Redirect'); + yield array(400, 'Bad Request'); + yield array(401, 'Unauthorized'); + yield array(402, 'Payment Required'); + yield array(403, 'Forbidden'); + yield array(404, 'Not Found'); + yield array(405, 'Method Not Allowed'); + yield array(406, 'Not Acceptable'); + yield array(407, 'Proxy Authentication Required'); + yield array(408, 'Request Timeout'); + yield array(409, 'Conflict'); + yield array(410, 'Gone'); + yield array(411, 'Length Required'); + yield array(412, 'Precondition Failed'); + yield array(413, 'Request Entity Too Large'); + yield array(414, 'Request-URI Too Long'); + yield array(415, 'Unsupported Media Type'); + yield array(416, 'Requested Range Not Satisfiable'); + yield array(417, 'Expectation Failed'); + yield array(422, 'Unprocessable Entity'); + yield array(423, 'Locked'); + yield array(424, 'Failed Dependency'); + yield array(426, 'Upgrade Required'); + yield array(500, 'Internal Server Error'); + yield array(501, 'Not Implemented'); + yield array(502, 'Bad Gateway'); + yield array(503, 'Service Unavailable'); + yield array(504, 'Gateway Timeout'); + yield array(505, 'HTTP Version Not Supported'); + yield array(506, 'Variant Also Negotiates'); + yield array(507, 'Insufficient Storage'); + yield array(510, 'Not Extended'); + } + + #[\PHPUnit\Framework\Attributes\DataProvider('status_codes')] + public function test_get_HTTP_status($code, $status) { + $this->assertSame(yourls_get_HTTP_status($code), $status); + } + + public function test_get_HTTP_status_invalid() { + $this->assertSame('', yourls_get_HTTP_status(1337)); + } +} diff --git a/tests/tests/http/requests.php b/tests/tests/http/HTTPRequestsTest.php similarity index 89% rename from tests/tests/http/requests.php rename to tests/tests/http/HTTPRequestsTest.php index 1ca98d2cd..9e1ddca21 100644 --- a/tests/tests/http/requests.php +++ b/tests/tests/http/HTTPRequestsTest.php @@ -5,13 +5,13 @@ * * We're not testing the Request library itself, it is fully tested on its own, see https://github.com/rmccue/Requests * - * @group http * @since 0.1 */ -class HTTP_Requests_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('http')] +class HTTPRequestsTest extends PHPUnit\Framework\TestCase { private function url( $what = '' ) { - return 'http://httpbin.org/' . $what; + return 'https://httpbin.io/' . $what; } /** diff --git a/tests/tests/http/misc.php b/tests/tests/http/HTTPTest.php similarity index 83% rename from tests/tests/http/misc.php rename to tests/tests/http/HTTPTest.php index dd3a95bc7..f2d8ad56a 100644 --- a/tests/tests/http/misc.php +++ b/tests/tests/http/HTTPTest.php @@ -2,11 +2,9 @@ /** * Utilities - * - * @group http */ - -class Misc_HTTP_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('http')] +class HTTPTest extends PHPUnit\Framework\TestCase { public function test_get_user_agent() { $this->assertIsString(yourls_get_user_agent()); diff --git a/tests/tests/http/general.php b/tests/tests/http/MiscTest.php similarity index 94% rename from tests/tests/http/general.php rename to tests/tests/http/MiscTest.php index d9527fca6..ad05911d2 100644 --- a/tests/tests/http/general.php +++ b/tests/tests/http/MiscTest.php @@ -3,10 +3,10 @@ /** * HTTP misc utilities and helpers * - * @group http * @since 0.1 */ -class HTTP_Misc_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('http')] +class MiscTest extends PHPUnit\Framework\TestCase { protected function tearDown(): void { yourls_remove_filter( 'http_get_proxy', 'yourls_return_true' ); diff --git a/tests/tests/http/proxy.php b/tests/tests/http/ProxyTest.php similarity index 54% rename from tests/tests/http/proxy.php rename to tests/tests/http/ProxyTest.php index 38be9beed..90171e504 100644 --- a/tests/tests/http/proxy.php +++ b/tests/tests/http/ProxyTest.php @@ -3,10 +3,10 @@ /** * HTTP proxy support functions * - * @group http * @since 0.1 */ -class HTTP_Proxy_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('http')] +class ProxyTest extends PHPUnit\Framework\TestCase { protected function tearDown(): void { yourls_remove_all_filters( 'http_get_proxy_bypass_host' ); @@ -15,27 +15,26 @@ protected function tearDown(): void { /** * List of hosts and wether they should go through proxy or not */ - public function proxy() { - return array( - array( 'invalid', false ), - array( 'http://localhost', false ), - array( 'http://127.0.0.1', false ), - array( 'http://127.1', false ), - array( 'http://[::1]', false ), - array( YOURLS_SITE, false ), - array( 'http://' . rand_str() , true ), - - array( 'http://bypass.me' , true ), // these two will be added to the by-pass list - array( 'http://skipthem.all' , true ), // in the next test - ); + public static function proxy(): \Iterator + { + yield array( 'invalid', false ); + yield array( 'http://localhost', false ); + yield array( 'http://127.0.0.1', false ); + yield array( 'http://127.1', false ); + yield array( 'http://[::1]', false ); + yield array( YOURLS_SITE, false ); + yield array( 'http://' . rand_str() , true ); + yield array( 'http://bypass.me' , true ); + // these two will be added to the by-pass list + yield array( 'http://skipthem.all' , true ); } /** * Check what URLs we should send through a proxy, if defined * - * @dataProvider proxy * @since 0.1 */ + #[\PHPUnit\Framework\Attributes\DataProvider('proxy')] public function test_proxy( $url, $goes_through_proxy ) { $this->assertSame( $goes_through_proxy, yourls_send_through_proxy( $url ) ); } @@ -43,28 +42,25 @@ public function test_proxy( $url, $goes_through_proxy ) { /** * List of hosts and wether they should go through proxy or not, with 'bypass.me, *.skipthem.all' defined as by-passing hosts */ - public function proxy_bypass_wildcard() { - return array( - array( 'invalid', false ), - array( 'http://localhost', false ), - array( 'http://127.0.0.1', false ), - array( 'http://127.1', false ), - array( 'http://[::1]', false ), - array( YOURLS_SITE, false ), - array( 'http://' . rand_str() , true ), - - array( 'http://bypass.me' , false ), - array( 'http://bypass.me/some/thing' , false ), - array( 'http://notbypass.me' , true ), - array( 'http://bypass.menot' , true ), - array( 'http://dont.bypass.me' , true ), - - array( 'http://skipthem.all' , false ), - array( 'http://notskipthem.all' , true ), - array( 'http://skipthem.allnot' , true ), - array( 'http://really.skipthem.all' , false ), - array( 'http://yeah.really.skipthem.all/some/thing' , false ), - ); + public static function proxy_bypass_wildcard(): \Iterator + { + yield array( 'invalid', false ); + yield array( 'http://localhost', false ); + yield array( 'http://127.0.0.1', false ); + yield array( 'http://127.1', false ); + yield array( 'http://[::1]', false ); + yield array( YOURLS_SITE, false ); + yield array( 'http://' . rand_str() , true ); + yield array( 'http://bypass.me' , false ); + yield array( 'http://bypass.me/some/thing' , false ); + yield array( 'http://notbypass.me' , true ); + yield array( 'http://bypass.menot' , true ); + yield array( 'http://dont.bypass.me' , true ); + yield array( 'http://skipthem.all' , false ); + yield array( 'http://notskipthem.all' , true ); + yield array( 'http://skipthem.allnot' , true ); + yield array( 'http://really.skipthem.all' , false ); + yield array( 'http://yeah.really.skipthem.all/some/thing' , false ); } public function bypass_hosts_wildcard() { @@ -74,9 +70,9 @@ public function bypass_hosts_wildcard() { /** * Check what URLs we should send through a proxy with 'bypass.me, *.skipthem.all' defined as by-passing hosts * - * @dataProvider proxy_bypass_wildcard * @since 0.1 */ + #[\PHPUnit\Framework\Attributes\DataProvider('proxy_bypass_wildcard')] public function test_proxy_bypass_wildcard( $url, $goes_through_proxy ) { yourls_add_filter( 'http_get_proxy_bypass_host', array( $this, 'bypass_hosts_wildcard' ) ); $this->assertSame( $goes_through_proxy, yourls_send_through_proxy( $url ) ); diff --git a/tests/tests/http/headers.php b/tests/tests/http/headers.php deleted file mode 100644 index 8b2339a42..000000000 --- a/tests/tests/http/headers.php +++ /dev/null @@ -1,94 +0,0 @@ -\s*window.location="http://somewhere";!m'; - - $this->expectOutputRegex($regexp); - yourls_redirect_javascript('http://somewhere'); - } - - public function status_codes() { - return array( - array(100, 'Continue'), - array(101, 'Switching Protocols'), - array(102, 'Processing'), - - array(200, 'OK'), - array(201, 'Created'), - array(202, 'Accepted'), - array(203, 'Non-Authoritative Information'), - array(204, 'No Content'), - array(205, 'Reset Content'), - array(206, 'Partial Content'), - array(207, 'Multi-Status'), - array(226, 'IM Used'), - - array(300, 'Multiple Choices'), - array(301, 'Moved Permanently'), - array(302, 'Found'), - array(303, 'See Other'), - array(304, 'Not Modified'), - array(305, 'Use Proxy'), - array(306, 'Reserved'), - array(307, 'Temporary Redirect'), - - array(400, 'Bad Request'), - array(401, 'Unauthorized'), - array(402, 'Payment Required'), - array(403, 'Forbidden'), - array(404, 'Not Found'), - array(405, 'Method Not Allowed'), - array(406, 'Not Acceptable'), - array(407, 'Proxy Authentication Required'), - array(408, 'Request Timeout'), - array(409, 'Conflict'), - array(410, 'Gone'), - array(411, 'Length Required'), - array(412, 'Precondition Failed'), - array(413, 'Request Entity Too Large'), - array(414, 'Request-URI Too Long'), - array(415, 'Unsupported Media Type'), - array(416, 'Requested Range Not Satisfiable'), - array(417, 'Expectation Failed'), - array(422, 'Unprocessable Entity'), - array(423, 'Locked'), - array(424, 'Failed Dependency'), - array(426, 'Upgrade Required'), - - array(500, 'Internal Server Error'), - array(501, 'Not Implemented'), - array(502, 'Bad Gateway'), - array(503, 'Service Unavailable'), - array(504, 'Gateway Timeout'), - array(505, 'HTTP Version Not Supported'), - array(506, 'Variant Also Negotiates'), - array(507, 'Insufficient Storage'), - array(510, 'Not Extended'), - ); - } - - /** - * @dataProvider status_codes - */ - public function test_get_HTTP_status($code, $status) { - $this->assertSame(yourls_get_HTTP_status($code), $status); - } - - public function test_get_HTTP_status_invalid() { - $this->assertSame(yourls_get_HTTP_status(1337), ''); - } -} diff --git a/tests/tests/install/htaccess.php b/tests/tests/install/HtaccessTest.php similarity index 63% rename from tests/tests/install/htaccess.php rename to tests/tests/install/HtaccessTest.php index 60d4191f1..0736bada8 100644 --- a/tests/tests/install/htaccess.php +++ b/tests/tests/install/HtaccessTest.php @@ -2,10 +2,9 @@ /** * Test htaccess creation & modification functions - * - * @group install */ -class Install_htaccess_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('install')] +class HtaccessTest extends PHPUnit\Framework\TestCase { protected $server; @@ -27,21 +26,20 @@ public function tearDown(): void { * Provide server signatures, wether they're Apache (true) or something else (false) and * the name of the redirect rule file (.htaccess or web.config) */ - public function servers() { - return array( - array( 'Very Common Apache', true, '.htaccess' ), - array( 'LiteSpeed So Fast', true, '.htaccess' ), - array( 'meh IIS meh', false, 'web.config' ), - ); + public static function servers(): \Iterator + { + yield array( 'Very Common Apache', true, '.htaccess' ); + yield array( 'LiteSpeed So Fast', true, '.htaccess' ); + yield array( 'meh IIS meh', false, 'web.config' ); } - /** - * Check .htaccess creation - general function, checking if file is created - * - * @dataProvider servers - * @since 0.1 - */ - public function test_htaccess( $server, $is_apache, $file ) { + /** + * Check .htaccess creation - general function, checking if file is created + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\DataProvider('servers')] + public function test_htaccess( $server, $is_apache, $file ) { $_SERVER['SERVER_SOFTWARE'] = $server; $this->assertSame( $is_apache, yourls_is_apache() ); @@ -49,30 +47,29 @@ public function test_htaccess( $server, $is_apache, $file ) { if( file_exists( YOURLS_ABSPATH . '/' . $file ) ) @unlink( YOURLS_ABSPATH . '/' . $file ); - $this->assertTrue( yourls_create_htaccess() ); - $this->assertFileExists( YOURLS_ABSPATH . '/' . $file ); - } + $this->assertTrue( yourls_create_htaccess() ); + $this->assertFileExists( YOURLS_ABSPATH . '/' . $file ); + } /** * Files in which we want to insert content */ - public function htaccess_content() { - return array( - array( 'original_nofile.txt' ), - array( 'original_empty.txt' ), - array( 'original_fresh-YOURLS-content.txt' ), - array( 'original_old-YOURLS-content.txt' ), - array( 'original_other-content.txt' ), - ); + public static function htaccess_content(): \Iterator + { + yield array( 'original_nofile.txt' ); + yield array( 'original_empty.txt' ); + yield array( 'original_fresh-YOURLS-content.txt' ); + yield array( 'original_old-YOURLS-content.txt' ); + yield array( 'original_other-content.txt' ); } - /** - * Check .htaccess creation - specific cases, checking file contents - * - * @dataProvider htaccess_content - * @since 0.1 - */ - public function test_htaccess_content( $filename ) { + /** + * Check .htaccess creation - specific cases, checking file contents + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\DataProvider('htaccess_content')] + public function test_htaccess_content( $filename ) { $newfile = str_replace( 'original_', 'test_', $filename ); $expected = str_replace( 'original_', 'expected_', $filename ); @@ -103,6 +100,6 @@ public function test_htaccess_content( $filename ) { $new = array_map( function($line) {return str_replace(array("\r", "\n"), '', $line);}, file($newfile)); $this->assertSame($exp, $new); unlink( $newfile ); - } + } } diff --git a/tests/tests/install/install.php b/tests/tests/install/InstallTest.php similarity index 77% rename from tests/tests/install/install.php rename to tests/tests/install/InstallTest.php index e814fce01..2731f5d28 100644 --- a/tests/tests/install/install.php +++ b/tests/tests/install/InstallTest.php @@ -2,37 +2,36 @@ /** * Checks install misc functions - * - * @group install */ -class Install_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('install')] +class InstallTest extends PHPUnit\Framework\TestCase { /** - * Check if YOURLS is declared installed - */ - public function test_install() { - $this->assertTrue( yourls_is_installed() ); - } - - /** - * Check that tables were correctly populated during install - */ - public function test_init_tables() { - // This should fail because these inserts have been taken care of during install - $this->assertFalse( yourls_initialize_options() ); - $this->assertFalse( yourls_insert_sample_links() ); - } - - /** - * Test (sort of) table creation - */ - public function test_create_tables() { + * Check if YOURLS is declared installed + */ + public function test_install() { + $this->assertTrue( yourls_is_installed() ); + } + + /** + * Check that tables were correctly populated during install + */ + public function test_init_tables() { + // This should fail because these inserts have been taken care of during install + $this->assertFalse( yourls_initialize_options() ); + $this->assertFalse( yourls_insert_sample_links() ); + } + + /** + * Test (sort of) table creation + */ + public function test_create_tables() { /* The expected result has: * - success messages: the table are created with a "CREATE IF NOT EXISTS", * hence, will not be recreated once more, they're already created * upon install procedure - * - error messages: the function cannot initalize options and links, since + * - error messages: the function cannot initialize options and links, since * they have been populated during install procedure as well * * A more thorough test would be to mockup the DB connection and create another @@ -54,11 +53,11 @@ public function test_create_tables() { ); $this->assertSame( $expected, yourls_create_sql_tables() ); - } + } - /** - * Test (sort of) defining constants - */ + /** + * Test (sort of) defining constants + */ public function test_correct_config() { $test = new \YOURLS\Config\Config(YOURLS_CONFIGFILE); @@ -77,9 +76,9 @@ public function test_correct_config() { $this->assertSame($before,$after); } - /** - * Test incorrect config provided - */ + /** + * Test incorrect config provided + */ public function test_incorrect_config() { $this->expectException(YOURLS\Exceptions\ConfigException::class); $this->expectExceptionMessageMatches('/User defined config not found at \'[0-9a-z]+\'/'); @@ -88,9 +87,9 @@ public function test_incorrect_config() { $test->find_config(); } - /** - * Test config not found - */ + /** + * Test config not found + */ public function test_not_found_config() { $this->expectException(YOURLS\Exceptions\ConfigException::class); $this->expectExceptionMessage('Cannot find config.php. Please read the readme.html to learn how to install YOURLS'); @@ -100,15 +99,14 @@ public function test_not_found_config() { $test->find_config(); } - /** - * Test Init actions. Not sure this is a good idea, might become cumbersome to maintain? - */ + /** + * Test Init actions. Not sure this is a good idea, might become cumbersome to maintain? + */ public function test_init_defaults() { $test = new \YOURLS\Config\InitDefaults(); $expected = array ( 'include_core_funcs' => true, - 'include_install_upgrade_funcs' => false, 'default_timezone' => true, 'load_default_textdomain' => true, 'check_maintenance_mode' => true, diff --git a/tests/tests/install/version.php b/tests/tests/install/VersionTest.php similarity index 67% rename from tests/tests/install/version.php rename to tests/tests/install/VersionTest.php index a042156ef..7b1ff630d 100644 --- a/tests/tests/install/version.php +++ b/tests/tests/install/VersionTest.php @@ -2,10 +2,9 @@ /** * Checks version getters & checkers - * - * @group install */ -class Install_Version_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('install')] +class VersionTest extends PHPUnit\Framework\TestCase { protected $ydb_copy; @@ -13,7 +12,7 @@ class Install_Version_Tests extends PHPUnit\Framework\TestCase { * Make a copy of $ydb */ public function setUp(): void { - $this->ydb_copy = yourls_get_db(); + $this->ydb_copy = yourls_get_db('read-test_setup'); } /** @@ -26,22 +25,20 @@ public function tearDown(): void { /** * Provide various real-life-ish versions and how they should be sanitized */ - public function versions() { - return array( - array( 'omgmysql-5.5-ubuntu-4.20', '5.5' ), - array( 'mysql5.5-ubuntu-4.20', '5.5' ), - array( '5.5-ubuntu-4.20', '5.5' ), - array( '5.5-beta2', '5.5' ), - array( 'mysql-5.5', '5.5' ), - array( '5.5', '5.5' ), - ); + public static function versions(): \Iterator + { + yield array( 'omgmysql-5.5-ubuntu-4.20', '5.5' ); + yield array( 'mysql5.5-ubuntu-4.20', '5.5' ); + yield array( '5.5-ubuntu-4.20', '5.5' ); + yield array( '5.5-beta2', '5.5' ); + yield array( 'mysql-5.5', '5.5' ); + yield array( '5.5', '5.5' ); } /** * Test mysql version getter & version comparer - * - * @dataProvider versions */ + #[\PHPUnit\Framework\Attributes\DataProvider('versions')] public function test_mysql_version( $version, $sanitized ) { yourls_set_db( new Mock_Version( $version ) ); diff --git a/tests/tests/l10n/domain.php b/tests/tests/l10n/DomainTest.php similarity index 74% rename from tests/tests/l10n/domain.php rename to tests/tests/l10n/DomainTest.php index d2a3faa41..1a7bb51ee 100644 --- a/tests/tests/l10n/domain.php +++ b/tests/tests/l10n/DomainTest.php @@ -3,10 +3,10 @@ /** * Localization domain functions * - * @group l10n * @since 0.1 */ -class Translation_Domain_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('l10n')] +class DomainTest extends PHPUnit\Framework\TestCase { public static function tearDownAfterClass(): void { yourls_unload_textdomain( 'test' ); @@ -24,15 +24,20 @@ public function test_load_default_textdomain() { } /** - * Load custom fake domains - should raise an error + * Load custom fake domains - should raise a notice * * @since 0.1 */ public function test_custom_fake_domain() { - $this->expectError(); - $this->expectErrorMessageMatches('/Cannot read file [0-9a-z]+\/[0-9a-z]+-fr_FR\.mo\. Make sure there is a language file installed. More info: http:\/\/yourls\.org\/translations/'); + set_error_handler(function($errno, $errstr) { + $this->assertEquals(E_USER_NOTICE, $errno); + $this->assertStringContainsString('Cannot read file', $errstr); + return true; // Prevent PHP's default error handler + }); yourls_load_custom_textdomain( rand_str(), rand_str() ); + + restore_error_handler(); } /** @@ -59,9 +64,9 @@ public function test_load_custom_domain() { /** * Custom domain unloading * - * @depends test_load_custom_domain * @since 0.1 */ + #[\PHPUnit\Framework\Attributes\Depends('test_load_custom_domain')] public function test_custom_domain_unload() { $this->assertTrue( yourls_unload_textdomain( 'test' ) ); $this->assertFalse( yourls_unload_textdomain( 'test' ) ); diff --git a/tests/tests/l10n/general.php b/tests/tests/l10n/GeneralTest.php similarity index 93% rename from tests/tests/l10n/general.php rename to tests/tests/l10n/GeneralTest.php index 74028cee5..93b322faa 100644 --- a/tests/tests/l10n/general.php +++ b/tests/tests/l10n/GeneralTest.php @@ -3,10 +3,10 @@ /** * Localization helper functions * - * @group l10n * @since 0.1 */ -class Translation_General_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('l10n')] +class GeneralTest extends PHPUnit\Framework\TestCase { protected $locale_backup; diff --git a/tests/tests/l10n/formats.php b/tests/tests/l10n/L10nFormatTest.php similarity index 97% rename from tests/tests/l10n/formats.php rename to tests/tests/l10n/L10nFormatTest.php index e457cfa03..fb11bfafa 100644 --- a/tests/tests/l10n/formats.php +++ b/tests/tests/l10n/L10nFormatTest.php @@ -3,10 +3,10 @@ /** * Localization date & calendar & formatting functions * - * @group l10n * @since 0.1 */ -class Translation_Format_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('l10n')] +class L10nFormatTest extends PHPUnit\Framework\TestCase { public function setUp(): void { yourls_load_textdomain( 'default', YOURLS_TESTDATA_DIR . '/pomo/fr_FR.mo' ); diff --git a/tests/tests/l10n/translations.php b/tests/tests/l10n/TranslationTest.php similarity index 94% rename from tests/tests/l10n/translations.php rename to tests/tests/l10n/TranslationTest.php index 417fb1b3e..abc038b8a 100644 --- a/tests/tests/l10n/translations.php +++ b/tests/tests/l10n/TranslationTest.php @@ -3,10 +3,10 @@ /** * Localization functions : helper functions * - * @group l10n * @since 0.1 */ -class Translation_Translation_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('l10n')] +class TranslationTest extends PHPUnit\Framework\TestCase { public static function setUpBeforeClass(): void { yourls_load_textdomain( 'test', YOURLS_TESTDATA_DIR . '/pomo/test-fr_FR.mo' ); @@ -39,7 +39,7 @@ public function test_translation_echo() { } /** - * Check an unstranslated string + * Check an untranslated string * * @since 0.1 */ @@ -85,13 +85,10 @@ public function test_yourls_se() { * @since 0.1 */ public function test_yourls_s_too_few() { - if (PHP_VERSION_ID >= 80000) { - $this->expectException(ArgumentCountError::class); - } else { - $this->expectException(PHPUnit\Framework\Error\Error::class); - } + $this->expectException(ArgumentCountError::class); $this->expectExceptionMessageMatches('/arguments/'); + // this will trigger a Fatal error -- Uncaught ArgumentCountError: 3 arguments are required, 2 given yourls_s( 'Hello %s you are %s', 'Ozh' ); } diff --git a/tests/tests/links/yourls_links.php b/tests/tests/links/LinkTest.php similarity index 77% rename from tests/tests/links/yourls_links.php rename to tests/tests/links/LinkTest.php index 4bb8e695a..6ccecd78a 100644 --- a/tests/tests/links/yourls_links.php +++ b/tests/tests/links/LinkTest.php @@ -2,12 +2,10 @@ /** * Links - * - * @group links - * @group idn */ - -class YOURLS_Link_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('links')] +#[\PHPUnit\Framework\Attributes\Group('idn')] +class LinkTest extends PHPUnit\Framework\TestCase { protected function tearDown(): void { yourls_remove_all_filters( 'get_yourls_site' ); @@ -42,8 +40,8 @@ public function test_yourls_statlink() { */ public function test_yourls_link_IDN() { yourls_add_filter( 'get_yourls_site', function() {return 'http://xn--hh-bjab.com';} ); - $this->assertEquals( yourls_link('suicidal'), 'http://héhé.com/suicidal' ); - $this->assertEquals( yourls_statlink('angels'), 'http://héhé.com/angels+' ); + $this->assertEquals( 'http://héhé.com/suicidal', yourls_link('suicidal') ); + $this->assertEquals( 'http://héhé.com/angels+', yourls_statlink('angels') ); } } diff --git a/tests/tests/options.php b/tests/tests/options.php deleted file mode 100644 index 145a35da6..000000000 --- a/tests/tests/options.php +++ /dev/null @@ -1,135 +0,0 @@ -assertFalse( yourls_get_option( 'doesnotexist' ) ); - $this->assertTrue( yourls_add_option( $key, $value ) ); - $this->assertEquals( $value, yourls_get_option( $key ) ); - $this->assertFalse( yourls_add_option( $key, $value ) ); // Already exists - $this->assertFalse( yourls_update_option( $key, $value ) ); // Value is the same - $this->assertTrue( yourls_update_option( $key, $value2 ) ); - $this->assertEquals( $value2, yourls_get_option( $key ) ); - - $this->assertFalse( yourls_add_option( $key, $value ) ); - $this->assertEquals( $value2, yourls_get_option( $key ) ); - $this->assertTrue( yourls_delete_option( $key ) ); - $this->assertFalse( yourls_get_option( $key ) ); - $this->assertFalse( yourls_delete_option( $key ) ); - - $this->assertTrue( yourls_update_option( $key2, $value2 ) ); - $this->assertEquals( $value2, yourls_get_option( $key2 ) ); - $this->assertTrue( yourls_delete_option( $key2 ) ); - $this->assertFalse( yourls_get_option( $key2 ) ); - } - - /** - * Check with array and objects - * - * @since 0.1 - */ - public function test_serialized_data() { - $key = rand_str(); - $value = array( 'foo' => true, 'bar' => true ); - - $this->assertTrue( yourls_add_option( $key, $value ) ); - $this->assertEquals( $value, yourls_get_option( $key ) ); - - $value = (object) $value; - $this->assertTrue( yourls_update_option( $key, $value ) ); - $this->assertEquals( $value, yourls_get_option( $key ) ); - $this->assertTrue( yourls_delete_option( $key ) ); - } - - /** - * Data provider of bad option names - */ - public function bad_option_names() { - return array( - array( '' ), - array( '0' ), - array( ' ' ), - array( 0 ), - array( false ), - array( null ), - ); - } - - /** - * Check with bad option names - * - * @dataProvider bad_option_names - * @since 0.1 - */ - public function test_bad_option_names($empty) { - $this->assertFalse( yourls_get_option( $empty ) ); - $this->assertFalse( yourls_add_option( $empty, '' ) ); - $this->assertFalse( yourls_update_option( $empty, '' ) ); - $this->assertFalse( yourls_delete_option( $empty ) ); - } - - function setUp(): void { - parent::setUp(); - $this->slash_1 = 'String with 1 slash \\'; - $this->slash_2 = 'String with 2 slashes \\\\'; - $this->slash_3 = 'String with 3 slashes \\\\\\'; - $this->slash_4 = 'String with 4 slashes \\\\\\\\'; - $this->slash_5 = 'String with 5 slashes \\\\\\\\\\'; - $this->slash_6 = 'String with 6 slashes \\\\\\\\\\\\'; - $this->slash_7 = 'String with 7 slashes \\\\\\\\\\\\\\'; - } - - /** - * Tests the model function that expects un-slashed data - * - * @since 0.1 - */ - function test_add_option() { - yourls_add_option( 'slash_test_1', $this->slash_1 ); - yourls_add_option( 'slash_test_2', $this->slash_2 ); - yourls_add_option( 'slash_test_3', $this->slash_3 ); - yourls_add_option( 'slash_test_4', $this->slash_4 ); - - $this->assertEquals( $this->slash_1, yourls_get_option( 'slash_test_1' ) ); - $this->assertEquals( $this->slash_2, yourls_get_option( 'slash_test_2' ) ); - $this->assertEquals( $this->slash_3, yourls_get_option( 'slash_test_3' ) ); - $this->assertEquals( $this->slash_4, yourls_get_option( 'slash_test_4' ) ); - } - - /** - * Tests the model function that expects un-slashed data - * - * @since 0.1 - */ - function test_update_option() { - yourls_add_option( 'slash_test_5', 'foo' ); - - yourls_update_option( 'slash_test_5', $this->slash_1 ); - $this->assertEquals( $this->slash_1, yourls_get_option( 'slash_test_5' ) ); - - yourls_update_option( 'slash_test_5', $this->slash_2 ); - $this->assertEquals( $this->slash_2, yourls_get_option( 'slash_test_5' ) ); - - yourls_update_option( 'slash_test_5', $this->slash_3 ); - $this->assertEquals( $this->slash_3, yourls_get_option( 'slash_test_5' ) ); - - yourls_update_option( 'slash_test_5', $this->slash_4 ); - $this->assertEquals( $this->slash_4, yourls_get_option( 'slash_test_5' ) ); - } -} diff --git a/tests/tests/pages/pages.php b/tests/tests/pages/PagesTest.php similarity index 58% rename from tests/tests/pages/pages.php rename to tests/tests/pages/PagesTest.php index 0c9281af6..2c19333b3 100644 --- a/tests/tests/pages/pages.php +++ b/tests/tests/pages/PagesTest.php @@ -2,20 +2,27 @@ /** * Pages - * - * @group pages */ - -class Pages_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('pages')] +class PagesTest extends PHPUnit\Framework\TestCase { public function test_page_is_reserved() { $this->assertTrue( yourls_keyword_is_reserved('examplepage') ); } + public function test_examplepage() { + $this->assertTrue(yourls_is_page('examplepage')); + } + + public function test_no_page() { + $this->assertFalse(yourls_is_page(rand_str())); + } + public function test_create_page_and_check_is_reserved() { $page = rand_str(); if( touch(YOURLS_PAGEDIR . "/$page.php") ) { $this->assertTrue( yourls_keyword_is_reserved($page) ); + $this->assertTrue( yourls_is_page($page) ); unlink(YOURLS_PAGEDIR . "/$page.php"); } else { $this->markTestSkipped( "Cannot create 'pages/$page'" ); diff --git a/tests/tests/plugins/actions.php b/tests/tests/plugins/ActionsTest.php similarity index 73% rename from tests/tests/plugins/actions.php rename to tests/tests/plugins/ActionsTest.php index 579038e7c..3b57cf31b 100644 --- a/tests/tests/plugins/actions.php +++ b/tests/tests/plugins/ActionsTest.php @@ -3,20 +3,19 @@ /** * Action related tests * - * @group plugins * @since 0.1 */ +#[\PHPUnit\Framework\Attributes\Group('plugins')] +class ActionsTest extends PHPUnit\Framework\TestCase { -class Plugin_Actions_Tests extends PHPUnit\Framework\TestCase { - - /** - * Check adding an action with a simple function name + /** + * Check adding an action with a simple function name * * Syntax tested: yourls_add_action( $hook, 'func_name' ); - * - * @since 0.1 - */ - public function test_add_action_funcname() { + * + * @since 0.1 + */ + public function test_add_action_funcname() { // Random function name $hook = rand_str(); $this->assertFalse( yourls_has_action( $hook ) ); @@ -30,7 +29,7 @@ public function test_add_action_funcname() { $this->assertTrue( yourls_has_action( $hook ) ); return $hook; - } + } /** * Remove an action @@ -65,7 +64,7 @@ public function test_add_several_actions_default_priority() { $this->assertTrue( yourls_has_action( $hook ) ); global $yourls_filters; - $this->assertSame( $times, count( $yourls_filters[ $hook ][10] ) ); + $this->assertCount( $times, $yourls_filters[ $hook ][10] ); } /** @@ -173,13 +172,13 @@ public function test_remove_only_actions_with_given_prio() { $this->assertSame( $remaining, $times - $removed ); } - /** - * Check 'doing' an action hooked with a simple function name - * - * @depends test_add_action_funcname - * @since 0.1 - */ - public function test_do_action_funcname( $hook ) { + /** + * Check 'doing' an action hooked with a simple function name + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\Depends('test_add_action_funcname')] + public function test_do_action_funcname( $hook ) { $var_name = rand_str(); $var_value = rand_str(); $GLOBALS['test_var'] = $var_name; @@ -192,14 +191,14 @@ public function test_do_action_funcname( $hook ) { $this->assertNotSame( $var_value, $GLOBALS[ $var_name ] ); return $hook; - } - - /** - * Check we keep correct track of the number of time an action is done - * - * @since 0.1 - */ - public function test_do_action_several_times_and_count() { + } + + /** + * Check we keep correct track of the number of time an action is done + * + * @since 0.1 + */ + public function test_do_action_several_times_and_count() { $hook = rand_str(); $this->assertSame( 0, yourls_did_action( $hook ) ); @@ -209,17 +208,17 @@ public function test_do_action_several_times_and_count() { } $this->assertSame( $times, yourls_did_action( $hook ) ); - } + } - /** - * Check adding an action with an anonymous function using create_function() + /** + * Check adding an action with an anonymous function using create_function() * * Syntax tested: yourls_add_action( $hook, create_function() ); - * - * @since 0.1 - */ - public function test_add_action_create_function() { + * + * @since 0.1 + */ + public function test_add_action_create_function() { $hook = rand_str(); $this->assertFalse( yourls_has_action( $hook ) ); yourls_add_action( $hook, function() { @@ -228,15 +227,15 @@ public function test_add_action_create_function() { $this->assertTrue( yourls_has_action( $hook ) ); return $hook; - } - - /** - * Check 'doing' an action hooked with an anonymous function using create_function() - * - * @depends test_add_action_create_function - * @since 0.1 - */ - public function test_do_action_create_function( $hook ) { + } + + /** + * Check 'doing' an action hooked with an anonymous function using create_function() + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\Depends('test_add_action_create_function')] + public function test_do_action_create_function( $hook ) { $var_name = rand_str(); $var_value = rand_str(); $GLOBALS['test_var'] = $var_name; @@ -249,32 +248,32 @@ public function test_do_action_create_function( $hook ) { $this->assertNotSame( $var_value, $GLOBALS[ $var_name ] ); return $hook; - } + } - /** - * Check adding an action with function within class + /** + * Check adding an action with function within class * * Syntax tested: yourls_add_action( $hook, 'Class::Function' ); - * - * @since 0.1 - */ - public function test_add_action_within_class() { + * + * @since 0.1 + */ + public function test_add_action_within_class() { $hook = rand_str(); $this->assertFalse( yourls_has_action( $hook ) ); yourls_add_action( $hook, 'Change_One_Global::change_it' ); $this->assertTrue( yourls_has_action( $hook ) ); return $hook; - } - - /** - * Check 'doing' an action hooked with function within class - * - * @depends test_add_action_within_class - * @since 0.1 - */ - public function test_do_action_within_class( $hook ) { + } + + /** + * Check 'doing' an action hooked with function within class + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\Depends('test_add_action_within_class')] + public function test_do_action_within_class( $hook ) { $var_name = rand_str(); $var_value = rand_str(); $GLOBALS['test_var'] = $var_name; @@ -287,32 +286,32 @@ public function test_do_action_within_class( $hook ) { $this->assertNotSame( $var_value, $GLOBALS[ $var_name ] ); return $hook; - } + } - /** - * Check adding an action with function within class using an array + /** + * Check adding an action with function within class using an array * * Syntax tested: yourls_add_action( $hook, array( 'Class', 'Function' ) ); - * - * @since 0.1 - */ - public function test_add_action_within_class_array() { + * + * @since 0.1 + */ + public function test_add_action_within_class_array() { $hook = rand_str(); $this->assertFalse( yourls_has_action( $hook ) ); yourls_add_action( $hook, array( 'Change_One_Global', 'change_it' ) ); $this->assertTrue( yourls_has_action( $hook ) ); return $hook; - } - - /** - * Check 'doing' an action hooked with function within class - * - * @depends test_add_action_within_class_array - * @since 0.1 - */ - public function test_do_action_within_class_array( $hook ) { + } + + /** + * Check 'doing' an action hooked with function within class + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\Depends('test_add_action_within_class_array')] + public function test_do_action_within_class_array( $hook ) { $var_name = rand_str(); $var_value = rand_str(); $GLOBALS['test_var'] = $var_name; @@ -325,32 +324,32 @@ public function test_do_action_within_class_array( $hook ) { $this->assertNotSame( $var_value, $GLOBALS[ $var_name ] ); return $hook; - } + } - /** - * Check adding an action with function within class instance + /** + * Check adding an action with function within class instance * * Syntax tested: yourls_add_action( $hook, array( $class, 'function' ) ); - * - * @since 0.1 - */ - public function test_add_action_within_class_instance() { + * + * @since 0.1 + */ + public function test_add_action_within_class_instance() { $hook = rand_str(); $this->assertFalse( yourls_has_action( $hook ) ); yourls_add_action( $hook, array( $this, 'change_one_global' ) ); $this->assertTrue( yourls_has_action( $hook ) ); return $hook; - } - - /** - * Check 'doing' an action hooked with function within class instance - * - * @depends test_add_action_within_class_instance - * @since 0.1 - */ - public function test_do_action_within_class_instance( $hook ) { + } + + /** + * Check 'doing' an action hooked with function within class instance + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\Depends('test_add_action_within_class_instance')] + public function test_do_action_within_class_instance( $hook ) { $var_name = rand_str(); $var_value = rand_str(); $GLOBALS['test_var'] = $var_name; @@ -363,15 +362,15 @@ public function test_do_action_within_class_instance( $hook ) { $this->assertNotSame( $var_value, $GLOBALS[ $var_name ] ); return $hook; - } + } - /** - * Check that hooking to 'Class::Method' or array( 'Class', 'Method') is the same + /** + * Check that hooking to 'Class::Method' or array( 'Class', 'Method') is the same * - * @since 0.1 - */ - public function test_add_action_class_and_array() { + * @since 0.1 + */ + public function test_add_action_class_and_array() { $hook = rand_str(); $this->assertFalse( yourls_has_action( $hook ) ); @@ -379,32 +378,32 @@ public function test_add_action_class_and_array() { yourls_add_action( $hook, array( 'Class', 'Method' ) ); $this->assertSame( 10, yourls_has_action( $hook, array( 'Class', 'Method' ) ) ); $this->assertSame( 10, yourls_has_action( $hook, 'Class::Method' ) ); - } + } - /** - * Check adding an action with anonymous function using closure + /** + * Check adding an action with anonymous function using closure * * Syntax tested: yourls_add_action( $hook, function(){ // do stuff } ); - * - * @since 0.1 - */ - public function test_add_action_closure() { + * + * @since 0.1 + */ + public function test_add_action_closure() { $hook = rand_str(); $this->assertFalse( yourls_has_action( $hook ) ); yourls_add_action( $hook, function() { $var_name = $GLOBALS['test_var']; $GLOBALS[ $var_name ] = rand_str(); } ); $this->assertTrue( yourls_has_action( $hook ) ); return $hook; - } - - /** - * Check 'doing' an action hooked with anonymous function using closure - * - * @depends test_add_action_closure - * @since 0.1 - */ - public function test_do_action_closure( $hook ) { + } + + /** + * Check 'doing' an action hooked with anonymous function using closure + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\Depends('test_add_action_closure')] + public function test_do_action_closure( $hook ) { $var_name = rand_str(); $var_value = rand_str(); $GLOBALS['test_var'] = $var_name; @@ -417,7 +416,7 @@ public function test_do_action_closure( $hook ) { $this->assertNotSame( $var_value, $GLOBALS[ $var_name ] ); return $hook; - } + } /** * Check that applied function must exist @@ -425,16 +424,12 @@ public function test_do_action_closure( $hook ) { * @since 0.1 */ public function test_function_must_exist_if_applied() { - if (PHP_VERSION_ID >= 80000) { - $this->expectException(TypeError::class); - } else { - $this->expectException(PHPUnit\Framework\Error\Error::class); - } + $this->expectException(TypeError::class); $this->expectExceptionMessageMatches('/call_user_func_array\(\).* a valid callback, function (\'|")[0-9a-z]+(\'|") not found or invalid function name/'); $hook = rand_str(); yourls_add_action( $hook, rand_str() ); - // this will trigger an error, converted to an exception by PHPUnit + // this will trigger a Fatal error -- Uncaught TypeError: call_user_func_array(): Argument #1 ($callback) must be a valid callback yourls_do_action( $hook ); } @@ -483,6 +478,37 @@ public function test_do_action_2_params() { yourls_do_action( $hook, 'hello', 'world' ); } + /** + * Check return values of yourls_has_action() + */ + public function test_has_action_return_values() { + $hook = rand_str(); + + yourls_add_action( $hook, 'some_function' ); + yourls_add_action( $hook, 'some_other_function', 1337 ); + + $this->assertTrue( yourls_has_action( $hook ) ); + $this->assertSame( 10, yourls_has_action( $hook, 'some_function' ) ); + $this->assertSame( 1337, yourls_has_action( $hook, 'some_other_function' ) ); + $this->assertFalse( yourls_has_action( $hook, 'nope_not_this_function' ) ); + } + + /** + * Check that yourls_get_actions() returns expected values + */ + public function test_get_actions() { + $hook = rand_str(); + + yourls_add_action( $hook, 'some_function' ); + yourls_add_action( $hook, 'some_other_function', 1337 ); + + $actions = yourls_get_actions( $hook ); + $this->assertArrayHasKey('some_function', $actions[10]); + $this->assertArrayHasKey('some_other_function', $actions[1337]); + + $this->assertSame( [], yourls_get_actions( rand_str() ) ); + } + /** * Dummy function -- just modifies the value of a global var */ diff --git a/tests/tests/plugins/FilesTest.php b/tests/tests/plugins/FilesTest.php new file mode 100644 index 000000000..e3bc1e1fa --- /dev/null +++ b/tests/tests/plugins/FilesTest.php @@ -0,0 +1,190 @@ +set_plugins( array() ); + } + + /** + * Return array of files from tests/data/plugins/invalid-code + */ + public static function get_invalid_code_plugins() { + $plugins = array(); + foreach ( glob(YOURLS_PLUGINDIR . '/invalid-code/*.php') as $file ) { + $plugins[] = array($file); + } + return $plugins; + } + + /** + * Return one of the "valid" test plugins from tests/data/plugins + */ + public function pick_a_plugin() { + $plugins = array_keys( yourls_get_plugins() ); + $plugin = $plugins[ array_rand( $plugins ) ]; + return $plugin; + } + + /** + * Check that only 2 "valid" plugins are found in tests/data/plugins + */ + public function test_get_plugins() { + $plugins = array_keys( yourls_get_plugins() ); + $expected = [ + '0' => 'test-plugin/plugin.php', + '1' => 'test-plugin2/plugin.php', + ]; + $this->assertSame($expected, $plugins); + } + + /** + * Check that a random "valid" plugin file validates as a plugin file + */ + public function test_plugin_validate() { + $plugin = $this->pick_a_plugin(); + $this->assertTrue( yourls_is_a_plugin_file(YOURLS_PLUGINDIR . '/' . $plugin ) ); + } + + /** + * Check that a nonexistent plugin file does not validate as a plugin file + */ + public function test_missing_plugin_validate() { + $plugin = rand_str(); + $this->assertFalse( yourls_is_a_plugin_file(YOURLS_PLUGINDIR . '/' . $plugin ) ); + } + + /** + * Check that an invalid plugin file does not validate as a plugin file + */ + #[\PHPUnit\Framework\Attributes\DataProvider('get_invalid_code_plugins')] + public function test_invalid_plugin_validate($plugin) { + $this->assertFalse( yourls_is_a_plugin_file($plugin) ); + } + + /** + * Check that a random valid plugin activates correctly + */ + public function test_plugin_activate() { + $plugin = $this->pick_a_plugin(); + + // Make sure the plugin.php is NOT present in get_included_files() + // We sanitize the array to deal with different platforms (D:\hello\Windows vs /home/user/hello/Linux) + $this->assertNotContains(yourls_sanitize_filename(YOURLS_PLUGINDIR.'/'.$plugin), array_map('yourls_sanitize_filename', get_included_files())); + + // Activate the plugin + $this->assertTrue( yourls_activate_plugin( $plugin ) ); + $this->assertGreaterThan( 0, yourls_has_active_plugins() ); + $this->assertTrue( yourls_is_active_plugin( $plugin ) ); + + // Make sure the plugin.php is now present in get_included_files() + $included_files = array_map('yourls_sanitize_filename', get_included_files()) ; + $this->assertContains(yourls_sanitize_filename(YOURLS_PLUGINDIR.'/'.$plugin), $included_files); + + // Make sure the plugin's uninstall.php is NOT present in get_included_files() + $this->assertNotContains(yourls_sanitize_filename(YOURLS_PLUGINDIR.'/'.dirname($plugin).'/uninstall.php'), $included_files); + + // We should NOT have YOURLS_UNINSTALL_PLUGIN defined + $this->assertFalse(defined('YOURLS_UNINSTALL_PLUGIN')); + + return $plugin; + } + + /** + * Check that an active plugin does not activate + */ + #[\PHPUnit\Framework\Attributes\Depends('test_plugin_activate')] + public function test_plugin_activate_twice( $plugin ) { + $this->assertSame( yourls__( 'Plugin already activated' ), yourls_activate_plugin( $plugin ) ); + } + + /** + * Simulate initial plugin loading + */ + #[\PHPUnit\Framework\Attributes\Depends('test_plugin_activate')] + public function test_load_plugins( $plugin ) { + $ydb = yourls_get_db('read-test_load_plugins'); + + // at this point, we have exactly 1 plugin activated + $this->assertSame( $ydb->get_plugins(), array( $plugin ) ); + + // Register a nonexistent plugin to simulate one that was once activated but deleted since + $fake_plugin = rand_str() . '/plugin.php'; + $ydb->add_plugin($fake_plugin); + + // Register a broken code plugin to simulate one that was once activated but now is broken + $broken_plugin = $this->get_invalid_code_plugins()[ array_rand( $this->get_invalid_code_plugins() ) ][0]; + $ydb->add_plugin($broken_plugin); + + yourls_update_option( 'active_plugins', $ydb->get_plugins() ); + + // Check we have 1 activated and 2 removed + $load = yourls_load_plugins(); + $this->assertTrue( $load['loaded'] ); + $this->assertSame( '1 activated, 2 removed', $load['info'] ); + + // Check only our valid plugin is left registered + $this->assertSame( $ydb->get_plugins(), array( $plugin ) ); + $this->assertSame( 1, yourls_has_active_plugins() ); + } + + /** + * Check that valid plugin deactivates correctly + */ + #[\PHPUnit\Framework\Attributes\Depends('test_plugin_activate')] + public function test_plugin_deactivate( $plugin ) { + $this->assertTrue( yourls_deactivate_plugin($plugin) ); + $this->assertSame( 0, yourls_has_active_plugins() ); + $this->assertFalse( yourls_is_active_plugin($plugin) ); + return $plugin; + } + + /** + * Check that deactivating a plugin correctly ran the uninstall script + */ + #[\PHPUnit\Framework\Attributes\Depends('test_plugin_deactivate')] + public function test_plugin_uninstall( $plugin ) { + // Make sure uninstall.php is NOW present in get_included_files() + $this->assertContains(yourls_sanitize_filename(YOURLS_PLUGINDIR . '/' . dirname($plugin) . '/uninstall.php'), array_map('yourls_sanitize_filename', get_included_files())); + + // we should now have YOURLS_UNINSTALL_PLUGIN set to true + $this->assertTrue( defined('YOURLS_UNINSTALL_PLUGIN') && YOURLS_UNINSTALL_PLUGIN ); + } + + /** + * Check that an missing plugin does not activate + */ + public function test_invalid_plugin_activate() { + $plugin = rand_str(); + + $this->assertSame( yourls__( 'Not a valid plugin file' ), yourls_activate_plugin( $plugin ) ); + $this->assertFalse( yourls_is_active_plugin( $plugin ) ); + } + + /** + * Check that a missing plugin does not deactivate + */ + public function test_invalid_plugin_deactivate() { + $plugin = rand_str(); + + $this->assertFalse( yourls_is_active_plugin( $plugin ) ); + $this->assertSame( yourls__( 'Plugin not active' ), yourls_deactivate_plugin( $plugin ) ); + } + + /** + * Check that a plugin with invalid code does not activate + */ + #[\PHPUnit\Framework\Attributes\DataProvider('get_invalid_code_plugins')] + public function test_invalid_plugin_does_not_activate($plugin) { + $this->assertNotTrue( yourls_include_file_sandbox( $plugin ) ); + $this->assertNotTrue( yourls_activate_plugin( $plugin ) ); + $this->assertNotTrue( yourls_is_active_plugin( $plugin ) ); + } +} diff --git a/tests/tests/plugins/filters.php b/tests/tests/plugins/FiltersTest.php similarity index 72% rename from tests/tests/plugins/filters.php rename to tests/tests/plugins/FiltersTest.php index 8c96a8d8f..cf191ab0d 100644 --- a/tests/tests/plugins/filters.php +++ b/tests/tests/plugins/FiltersTest.php @@ -3,25 +3,24 @@ /** * Filter related tests * - * @group plugins * @since 0.1 */ - -class Plugin_Filters_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('plugins')] +class FiltersTest extends PHPUnit\Framework\TestCase { /** * this var will allow to share "$this" across multiple tests here */ public static $instance; - /** - * Check adding a filter with a simple function name + /** + * Check adding a filter with a simple function name * * Syntax tested: yourls_add_filter( $hook, 'func_name' ); - * - * @since 0.1 - */ - public function test_add_filter_funcname() { + * + * @since 0.1 + */ + public function test_add_filter_funcname() { // Random function name $hook = rand_str(); $this->assertFalse( yourls_has_filter( $hook ) ); @@ -35,20 +34,20 @@ public function test_add_filter_funcname() { $this->assertTrue( yourls_has_filter( $hook ) ); return $hook; - } - - /** - * Check applying a filter hooked with a simple function name - * - * @depends test_add_filter_funcname - * @since 0.1 - */ - public function test_apply_filter_funcname( $hook ) { + } + + /** + * Check applying a filter hooked with a simple function name + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\Depends('test_add_filter_funcname')] + public function test_apply_filter_funcname( $hook ) { $var = rand_str(); $filtered = yourls_apply_filter( $hook, $var ); $this->assertNotSame( $var, $filtered ); - } + } /** @@ -109,14 +108,14 @@ public function test_remove_filter_priority() { } - /** - * Check adding a filter with an anonymous function using create_function() + /** + * Check adding a filter with an anonymous function using create_function() * * Syntax tested: yourls_add_filter( $hook, create_function() ); - * - * @since 0.1 - */ - public function test_add_filter_create_function() { + * + * @since 0.1 + */ + public function test_add_filter_create_function() { $hook = rand_str(); $this->assertFalse( yourls_has_filter( $hook ) ); yourls_add_filter( $hook, function() { @@ -125,57 +124,57 @@ public function test_add_filter_create_function() { $this->assertTrue( yourls_has_filter( $hook ) ); return $hook; - } - - /** - * Check applying a filter hooked with an anonymous function using create_function() - * - * @depends test_add_filter_create_function - * @since 0.1 - */ - public function test_apply_filter_create_function( $hook ) { + } + + /** + * Check applying a filter hooked with an anonymous function using create_function() + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\Depends('test_add_filter_create_function')] + public function test_apply_filter_create_function( $hook ) { $var = rand_str(); $filtered = yourls_apply_filter( $hook, $var ); $this->assertNotSame( $var, $filtered ); - } + } - /** - * Check adding a filter with function within class + /** + * Check adding a filter with function within class * * Syntax tested: yourls_add_filter( $hook, 'Class::Function' ); - * - * @since 0.1 - */ - public function test_add_filter_within_class() { + * + * @since 0.1 + */ + public function test_add_filter_within_class() { $hook = rand_str(); $this->assertFalse( yourls_has_filter( $hook ) ); yourls_add_filter( $hook, 'Change_Variable::change_it' ); $this->assertTrue( yourls_has_filter( $hook ) ); return $hook; - } - - /** - * Check applying a filter hooked with function within class - * - * @depends test_add_filter_within_class - * @since 0.1 - */ - public function test_apply_filter_within_class( $hook ) { + } + + /** + * Check applying a filter hooked with function within class + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\Depends('test_add_filter_within_class')] + public function test_apply_filter_within_class( $hook ) { $var = rand_str(); $filtered = yourls_apply_filter( $hook, $var ); $this->assertNotSame( $var, $filtered ); - } + } /** * Check removing a filter hooked with function within class * - * @depends test_add_filter_within_class * @since 0.1 */ + #[\PHPUnit\Framework\Attributes\Depends('test_add_filter_within_class')] public function test_remove_filter_within_class( $hook ) { $removed = yourls_remove_filter( $hook, 'Change_Variable::change_it' ); $this->assertTrue( $removed ); @@ -183,40 +182,40 @@ public function test_remove_filter_within_class( $hook ) { } - /** - * Check adding filter with function within class using an array + /** + * Check adding filter with function within class using an array * * Syntax tested: yourls_add_filter( $hook, array( 'Class', 'Function' ) ); - * - * @since 0.1 - */ - public function test_add_filter_within_class_array() { + * + * @since 0.1 + */ + public function test_add_filter_within_class_array() { $hook = rand_str(); $this->assertFalse( yourls_has_filter( $hook ) ); yourls_add_filter( $hook, array( 'Change_Variable', 'change_it' ) ); $this->assertTrue( yourls_has_filter( $hook ) ); return $hook; - } - - /** - * Check applying a filter hooked with function within class - * - * @depends test_add_filter_within_class_array - * @since 0.1 - */ - public function test_apply_filter_within_class_array( $hook ) { + } + + /** + * Check applying a filter hooked with function within class + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\Depends('test_add_filter_within_class_array')] + public function test_apply_filter_within_class_array( $hook ) { $var = rand_str(); $filtered = yourls_apply_filter( $hook, $var ); $this->assertNotSame( $var, $filtered ); - } + } /** * Check removing a filter hooked with function within class using an array * - * @depends test_add_filter_within_class_array * @since 0.1 */ + #[\PHPUnit\Framework\Attributes\Depends('test_add_filter_within_class_array')] public function test_remove_filter_within_class_array( $hook ) { $removed = yourls_remove_filter( $hook, array( 'Change_Variable', 'change_it' ) ); $this->assertTrue( $removed ); @@ -224,14 +223,14 @@ public function test_remove_filter_within_class_array( $hook ) { } - /** - * Check adding a filter with function within class instance + /** + * Check adding a filter with function within class instance * * Syntax tested: yourls_add_filter( $hook, array( $class, 'function' ) ); - * - * @since 0.1 - */ - public function test_add_filter_within_class_instance() { + * + * @since 0.1 + */ + public function test_add_filter_within_class_instance() { /* Note : in the unit tests context, we cannot rely on "$this" keeping the same * between tests, whereas it totally works in a "normal" class context * For this reason, using yourls_add_filter($hook, array($this, 'some_func')) in one test and @@ -245,26 +244,26 @@ public function test_add_filter_within_class_instance() { $this->assertTrue( yourls_has_filter( $hook ) ); return $hook; - } - - /** - * Check applying a filter hooked with function within class instance - * - * @depends test_add_filter_within_class_instance - * @since 0.1 - */ - public function test_apply_filter_within_class_instance( $hook ) { + } + + /** + * Check applying a filter hooked with function within class instance + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\Depends('test_add_filter_within_class_instance')] + public function test_apply_filter_within_class_instance( $hook ) { $var = rand_str(); $filtered = yourls_apply_filter( $hook, $var ); $this->assertNotSame( $var, $filtered ); - } + } /** * Check removing a filter hooked with function within class * - * @depends test_add_filter_within_class_instance * @since 0.1 */ + #[\PHPUnit\Framework\Attributes\Depends('test_add_filter_within_class_instance')] public function test_remove_filter_within_class_instance( $hook ) { $this->assertTrue( yourls_has_filter( $hook ) ); $removed = yourls_remove_filter( $hook, array( self::$instance, 'change_variable' ) ); @@ -272,12 +271,12 @@ public function test_remove_filter_within_class_instance( $hook ) { $this->assertFalse( yourls_has_filter( $hook ) ); } - /** - * Check that hooking to 'Class::Method' or array( 'Class', 'Method') is the same + /** + * Check that hooking to 'Class::Method' or array( 'Class', 'Method') is the same * - * @since 0.1 - */ - public function test_add_filter_class_and_array() { + * @since 0.1 + */ + public function test_add_filter_class_and_array() { $hook = rand_str(); $this->assertFalse( yourls_has_filter( $hook ) ); @@ -285,44 +284,44 @@ public function test_add_filter_class_and_array() { yourls_add_filter( $hook, array( 'Class', 'Method' ) ); $this->assertSame( 10, yourls_has_filter( $hook, array( 'Class', 'Method' ) ) ); $this->assertSame( 10, yourls_has_filter( $hook, 'Class::Method' ) ); - } + } - /** - * Check adding a filter with anonymous function using closure + /** + * Check adding a filter with anonymous function using closure * * Syntax tested: yourls_add_filter( $hook, function(){ // do stuff } ); - * - * @since 0.1 - */ - public function test_add_filter_closure() { + * + * @since 0.1 + */ + public function test_add_filter_closure() { $hook = rand_str(); $this->assertFalse( yourls_has_filter( $hook ) ); yourls_add_filter( $hook, function() { return rand_str(); } ); $this->assertTrue( yourls_has_filter( $hook ) ); return $hook; - } - - /** - * Check applying a filter hooked with anonymous function using closure - * - * @depends test_add_filter_closure - * @since 0.1 - */ - public function test_apply_filter_closure( $hook ) { + } + + /** + * Check applying a filter hooked with anonymous function using closure + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\Depends('test_add_filter_closure')] + public function test_apply_filter_closure( $hook ) { $var = rand_str(); $filtered = yourls_apply_filter( $hook, $var ); $this->assertNotSame( $var, $filtered ); - } - - /** - * Check applying multiple filters to one hook - * - * @since 0.1 - */ - public function test_multiple_filter() { + } + + /** + * Check applying multiple filters to one hook + * + * @since 0.1 + */ + public function test_multiple_filter() { $hook = rand_str(); $var = rand_str(); @@ -331,7 +330,7 @@ public function test_multiple_filter() { $filtered = yourls_apply_filter( $hook, $var ); $this->assertSame( $var . "1" . "2", $filtered ); - } + } /** * Check applying multiple filters with priorities to one hook @@ -375,22 +374,34 @@ public function test_has_filter_return_values() { $this->assertFalse( yourls_has_filter( $hook, 'nope_not_this_function' ) ); } + /** + * Check that yourls_get_filters() returns expected values + */ + public function test_get_filters() { + $hook = rand_str(); + + yourls_add_filter( $hook, 'some_function' ); + yourls_add_filter( $hook, 'some_other_function', 1337 ); + + $filters = yourls_get_filters( $hook ); + $this->assertArrayHasKey('some_function', $filters[10]); + $this->assertArrayHasKey('some_other_function', $filters[1337]); + + $this->assertSame( [], yourls_get_filters( rand_str() ) ); + } + /** * Check that applied function must exist * * @since 0.1 */ public function test_function_must_exist_if_applied() { - if (PHP_VERSION_ID >= 80000) { - $this->expectException(TypeError::class); - } else { - $this->expectException(PHPUnit\Framework\Error\Error::class); - } + $this->expectException(TypeError::class); $this->expectExceptionMessageMatches('/call_user_func_array\(\).* a valid callback, function (\'|")[0-9a-z]+(\'|") not found or invalid function name/'); $hook = rand_str(); yourls_add_filter( $hook, rand_str() ); - // this will trigger an error, converted to an exception by PHPUnit + // this will trigger a Fatal error -- Uncaught TypeError: call_user_func_array(): Argument #1 ($callback) must be a valid callback $test = yourls_apply_filter( $hook, rand_str() ); } @@ -404,27 +415,27 @@ public function test_filter_specified_arguments() { $hook = rand_str(); yourls_add_filter( $hook, function( $var1 = '', $var2 = '' ) { return "$var1 $var2"; }, 10, 2 ); $test = yourls_apply_filter( $hook, 'hello', 'world' ); - $this->assertSame( $test, 'hello world' ); + $this->assertSame( 'hello world', $test ); // Ask for 1 argument and provide 2 $hook = rand_str(); yourls_add_filter( $hook, function( $var1 = '', $var2 = '' ) { return "$var1 $var2"; }, 10, 1 ); $test = yourls_apply_filter( $hook, 'hello', 'world' ); - $this->assertSame( $test, 'hello ' ); + $this->assertSame( 'hello ', $test ); // Ask for 2 arguments and provide 1 $hook = rand_str(); yourls_add_filter( $hook, function( $var1 = '', $var2 = '' ) { return "$var1 $var2"; }, 10, 2 ); $test = yourls_apply_filter( $hook, 'hello' ); - $this->assertSame( $test, 'hello ' ); + $this->assertSame( 'hello ', $test ); } - /** - * Make sure yourls_apply_filter accepts an arbitrary number of elements if unspecified - * - * @since 0.1 - */ - public function test_filter_arbitrary_arguments() { + /** + * Make sure yourls_apply_filter accepts an arbitrary number of elements if unspecified + * + * @since 0.1 + */ + public function test_filter_arbitrary_arguments() { $hook = rand_str(); $var1 = rand_str(); $var2 = rand_str(); diff --git a/tests/tests/plugins/headers.php b/tests/tests/plugins/HeadersTest.php similarity index 71% rename from tests/tests/plugins/headers.php rename to tests/tests/plugins/HeadersTest.php index 20fcda5dc..7327340bd 100644 --- a/tests/tests/plugins/headers.php +++ b/tests/tests/plugins/HeadersTest.php @@ -3,15 +3,15 @@ /** * Header plugin functions * - * @group plugins * @since 0.1 */ -class Plugin_Header_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('plugins')] +class HeadersTest extends PHPUnit\Framework\TestCase { /** - * Regular header - */ - public function test_regular_header() { + * Regular header + */ + public function test_regular_header() { $expected = array( 'Plugin Name' => 'regular', 'Plugin URI' => 'regular', @@ -24,9 +24,9 @@ public function test_regular_header() { } /** - * PHPDoc header - */ - public function test_phpdoc_header() { + * PHPDoc header + */ + public function test_phpdoc_header() { $expected = array( 'Plugin Name' => 'phpdoc', 'Description' => 'phpdoc', @@ -39,9 +39,9 @@ public function test_phpdoc_header() { } /** - * Incomplete header - */ - public function test_incomplete_header() { + * Incomplete header + */ + public function test_incomplete_header() { $expected = array( 'Plugin Name' => 'incomplete', 'Description' => 'incomplete', @@ -51,23 +51,23 @@ public function test_incomplete_header() { } /** - * Incorrect header - */ - public function test_incorrect_header() { + * Incorrect header + */ + public function test_incorrect_header() { $this->assertEquals( [] , yourls_get_plugin_data( YOURLS_PLUGINDIR . '/headers/header_incorrect.php' ) ); } /** - * Missing header - */ - public function test_missing_header() { + * Missing header + */ + public function test_missing_header() { $this->assertEquals( [] , yourls_get_plugin_data( YOURLS_PLUGINDIR . '/headers/header_missing.php' ) ); } /** - * Missing header - no comment at all - */ - public function test_missing_header_no_comment() { + * Missing header - no comment at all + */ + public function test_missing_header_no_comment() { $this->assertEquals( [] , yourls_get_plugin_data( YOURLS_PLUGINDIR . '/headers/header_nocomment.php' ) ); } diff --git a/tests/tests/plugins/HelpersTest.php b/tests/tests/plugins/HelpersTest.php new file mode 100644 index 000000000..e19df3f34 --- /dev/null +++ b/tests/tests/plugins/HelpersTest.php @@ -0,0 +1,43 @@ +assertSame( $value, call_user_func($func) ); + } + + /** + * Test return values of yourls_filter_unique_id() + */ + function test_yourls_filter_unique_id() { + $func_name = rand_str(); + + $this->assertSame( $func_name, yourls_filter_unique_id($func_name) ); + $this->assertIsString( yourls_filter_unique_id( function(){return rand_str();} ) ); // unpredictable string + $this->assertSame('SomeClass::SomeMethod', yourls_filter_unique_id( 'SomeClass::SomeMethod' )); + $this->assertSame('SomeClass::SomeMethod', yourls_filter_unique_id( array( 'SomeClass', 'SomeMethod' ) )); + $this->assertIsString( yourls_filter_unique_id( array( $this, 'test_check_timestamp' ) )); // unpredictable string + } + +} diff --git a/tests/tests/plugins/pages.php b/tests/tests/plugins/PluginPagesTest.php similarity index 93% rename from tests/tests/plugins/pages.php rename to tests/tests/plugins/PluginPagesTest.php index ef6657f49..9db184bb6 100644 --- a/tests/tests/plugins/pages.php +++ b/tests/tests/plugins/PluginPagesTest.php @@ -6,10 +6,10 @@ * This test class should revert everything before each test: be cautious not to introduce * tests with a "depends" annotation * - * @group plugins * @since 0.1 */ -class Plugin_Pages_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('plugins')] +class PluginPagesTest extends PHPUnit\Framework\TestCase { protected function tearDown(): void { // remove filters and actions @@ -18,7 +18,7 @@ protected function tearDown(): void { yourls_remove_all_actions('pre_yourls_die'); // unregister plugin pages - yourls_get_db()->set_plugin_pages(array()); + yourls_get_db('read-test_plugins')->set_plugin_pages(array()); } /** @@ -83,17 +83,17 @@ public function test_yourls_plugin_url_ssl_mode_4() { * @since 0.1 */ public function test_register_plugin_page() { - $ydb = yourls_get_db(); + $ydb = yourls_get_db('read-test_plugins'); $plugin = rand_str(); $title = rand_str(); $func = rand_str(); // no plugin page registered - $this->assertEquals( 0, count( $ydb->get_plugin_pages() ) ); + $this->assertEmpty($ydb->get_plugin_pages()); // register one and check yourls_register_plugin_page( $plugin, $title, $func ); - $this->assertEquals( 1, count( $ydb->get_plugin_pages() ) ); + $this->assertCount( 1, $ydb->get_plugin_pages() ); $expected = array( 'slug' => $plugin, 'title' => $title, @@ -123,7 +123,7 @@ public function test_list_plugin_page() { yourls_register_plugin_page( $plugin, $title, $func ); $pages = yourls_list_plugin_admin_pages(); - $this->assertSame( 1, count( $pages ) ); + $this->assertCount( 1, $pages ); $this->assertArrayHasKey( 'url', $pages[ $plugin ] ); $this->assertArrayHasKey( 'anchor', $pages[ $plugin ] ); } diff --git a/tests/tests/plugins/files.php b/tests/tests/plugins/files.php deleted file mode 100644 index 047b4ee7d..000000000 --- a/tests/tests/plugins/files.php +++ /dev/null @@ -1,143 +0,0 @@ -set_plugins( array() ); - } - - /** - * Return one of the core plugins - */ - public function pick_a_plugin() { - $plugins = array_keys( yourls_get_plugins() ); - $plugin = $plugins[ array_rand( $plugins ) ]; - return $plugin; - } - - /** - * Check that valid plugins are found - * - * @since 0.1 - */ - public function test_get_plugins() { - $plugins = array_keys( yourls_get_plugins() ); - $this->assertNotEmpty( $plugins ); - } - - /** - * Check that a random valid plugin file validates as a plugin file - * - * @since 0.1 - */ - public function test_plugin_validate() { - $plugin = $this->pick_a_plugin(); - $this->assertTrue( yourls_validate_plugin_file( YOURLS_PLUGINDIR . '/' . $plugin ) ); - } - - /** - * Check that an invalid plugin file does not validate as a plugin file - * - * @since 0.1 - */ - public function test_invalid_plugin_validate() { - $plugin = rand_str(); - $this->assertFalse( yourls_validate_plugin_file( YOURLS_PLUGINDIR . '/' . $plugin ) ); - } - - /** - * Check that a random valid plugin activates correctly - * - * @since 0.1 - */ - public function test_plugin_activate() { - $plugin = $this->pick_a_plugin(); - $this->assertTrue( yourls_activate_plugin( $plugin ) ); - $this->assertGreaterThan( 0, yourls_has_active_plugins() ); - $this->assertTrue( yourls_is_active_plugin( $plugin ) ); - return $plugin; - } - - /** - * Check that an active plugin does not activate - * - * @depends test_plugin_activate - * @since 0.1 - */ - public function test_plugin_activate_twice( $plugin ) { - $this->assertNotSame( true, yourls_activate_plugin( $plugin ) ); - return $plugin; - } - - /** - * Simulate initial plugin loading - * - * @depends test_plugin_activate - * @since 0.1 - */ - public function test_load_plugins( $plugin ) { - $ydb = yourls_get_db(); - - // at this point, we have a plugin activated - $this->assertSame( $ydb->get_plugins(), array( $plugin ) ); - - // Register a fake plugin to simulate one that was once activated but deleted since - $fake_plugin = rand_str() . '/plugin.php'; - $ydb->add_plugin($fake_plugin); - yourls_update_option( 'active_plugins', $ydb->get_plugins() ); - - // Check we have activated 1 and removed 1 - $load = yourls_load_plugins(); - $this->assertTrue( $load['loaded'] ); - $this->assertSame( $load['info'], '1 activated, 1 removed' ); - - // Check only our valid plugin is left registered - $this->assertSame( $ydb->get_plugins(), array( $plugin ) ); - } - - /** - * Check that valid plugin deactivates correctly - * - * @depends test_plugin_activate - * @since 0.1 - */ - public function test_plugin_deactivate( $plugin ) { - $this->assertTrue( yourls_deactivate_plugin( $plugin ) ); - $this->assertSame( 0, yourls_has_active_plugins() ); - $this->assertFalse( yourls_is_active_plugin( $plugin ) ); - } - - /** - * Check that an invalid plugin does not activate - * - * @since 0.1 - */ - public function test_invalid_plugin_activate() { - $plugin = rand_str(); - - $this->assertNotSame( true, yourls_activate_plugin( $plugin ) ); - $this->assertFalse( yourls_is_active_plugin( $plugin ) ); - } - - /** - * Check that an invalid plugin does not deactivate - * - * @since 0.1 - */ - public function test_invalid_plugin_deactivate() { - $plugin = rand_str(); - - $this->assertFalse( yourls_is_active_plugin( $plugin ) ); - $this->assertNotSame( true, yourls_deactivate_plugin( $plugin ) ); - } - -} diff --git a/tests/tests/plugins/helpers.php b/tests/tests/plugins/helpers.php deleted file mode 100644 index b662e8492..000000000 --- a/tests/tests/plugins/helpers.php +++ /dev/null @@ -1,33 +0,0 @@ -assertSame( $value, call_user_func($func) ); - } - -} diff --git a/tests/tests/shorturl/CRUDTest.php b/tests/tests/shorturl/CRUDTest.php new file mode 100644 index 000000000..056df0eb8 --- /dev/null +++ b/tests/tests/shorturl/CRUDTest.php @@ -0,0 +1,195 @@ +assertEquals( 'success', $newurl['status'] ); + + $fail = yourls_add_new_link( $url, $keyword, $title ); + $this->assertEquals( 'fail', $fail['status'] ); + + $fail = yourls_add_new_link( $url, rand_str(), rand_str() ); + $this->assertEquals( 'fail', $fail['status'] ); + $this->assertEquals( 'error:url', $fail['code'] ); + + $fail = yourls_add_new_link( 'http://' . rand_str(), $keyword, $title ); + $this->assertEquals( 'fail', $fail['status'] ); + $this->assertEquals( 'error:keyword', $fail['code'] ); + + $this->assertEquals( $title, yourls_get_keyword_title( $keyword ) ); + $this->assertEquals( $url, yourls_get_keyword_longurl( $keyword ) ); + $this->assertEquals( 0, yourls_get_keyword_clicks( $keyword ) ); + + return $keyword; + } + + public function test_add_url_cache() { + $keyword = rand_str(); + $title = rand_str(); + $url = 'http://' . rand_str(); + + $infos = yourls_get_keyword_infos( $keyword ); + $this->assertFalse( $infos ); + + $newurl = yourls_add_new_link( $url, $keyword, $title ); + $this->assertEquals( 'success', $newurl['status'] ); + + $updated_infos = yourls_get_keyword_infos( $keyword ); + $this->assertEquals( $keyword, $updated_infos['keyword'] ); + $this->assertEquals( $title, $updated_infos['title'] ); + $this->assertEquals( $url, $updated_infos['url'] ); + $this->assertEquals( 0, $updated_infos['clicks'] ); + } + + #[\PHPUnit\Framework\Attributes\Depends('test_add_url')] + public function test_edit_title( $original_keyword ) { + $new_keyword = rand_str(); + $new_title = rand_str(); + $new_url = 'http://' . rand_str(); + + $edit = yourls_edit_link_title( $original_keyword, $new_title ); + $this->assertEquals( 1, $edit ); + // purge cache + $original = yourls_get_keyword_infos( $original_keyword, false ); + $this->assertEquals( $new_title, yourls_get_keyword_title( $original_keyword ) ); + + return $original_keyword; + } + #[\PHPUnit\Framework\Attributes\Depends('test_add_url')] + public function test_edit_title_cache( $original_keyword ) { + $new_keyword = rand_str(); + $new_title = rand_str(); + $new_url = 'http://' . rand_str(); + + $edit = yourls_edit_link_title( $original_keyword, $new_title ); + $this->assertEquals( 1, $edit ); + $this->assertEquals( $new_title, yourls_get_keyword_title( $original_keyword ) ); + + return $original_keyword; + } + #[\PHPUnit\Framework\Attributes\Depends('test_add_url')] + public function test_is_shorturl( $keyword ) { + $this->assertFalse( yourls_is_shorturl( rand_str() ) ); + $this->assertTrue( yourls_is_shorturl( $keyword ) ); + $this->assertTrue( yourls_is_shorturl( yourls_link( $keyword ) ) ); + } + + #[\PHPUnit\Framework\Attributes\Depends('test_add_url')] + public function test_update_hits( $keyword ) { + // purge cache + $cache = yourls_get_keyword_infos( $keyword, false ); + $this->assertEquals( 0, yourls_get_keyword_clicks( $keyword ) ); + + // Increment by 1 + $this->assertEquals( 1, yourls_update_clicks( $keyword ) ); + // purge cache + yourls_get_keyword_infos( $keyword, false ); + $this->assertEquals( 1, yourls_get_keyword_clicks( $keyword ) ); + + // Set to a specified number + $this->assertEquals( 1, yourls_update_clicks( $keyword, 10 ) ); + // purge cache + yourls_get_keyword_infos( $keyword, false ); + $this->assertEquals( 10, yourls_get_keyword_clicks( $keyword ) ); + } + + #[\PHPUnit\Framework\Attributes\Depends('test_add_url')] + public function test_update_hits_cache( $keyword ) { + // Starting at 10 from test_update_hits + $this->assertEquals( 10, yourls_get_keyword_clicks( $keyword ) ); + + // Increment by 1 + $this->assertEquals( 1, yourls_update_clicks( $keyword ) ); + $this->assertEquals( 11, yourls_get_keyword_clicks( $keyword ) ); + + // Set to a specified number + $this->assertEquals( 1, yourls_update_clicks( $keyword, 17 ) ); + $this->assertEquals( 17, yourls_get_keyword_clicks( $keyword ) ); + } + + #[\PHPUnit\Framework\Attributes\Depends('test_edit_title')] + public function test_edit_url( $original_keyword ) { + $new_keyword = rand_str(); + $new_title = rand_str(); + $new_url = 'http://' . rand_str(); + + // purge cache + $original = yourls_get_keyword_infos( $original_keyword, false ); + + $edit = yourls_edit_link( $original['url'], $original_keyword, $new_keyword, $new_title ); + $this->assertEquals( $edit['url']['title'], $new_title ); + $this->assertEquals( $edit['url']['keyword'], $new_keyword ); + + $edit = yourls_edit_link( $new_url, $new_keyword, $new_keyword, $new_title ); + $this->assertEquals( $edit['url']['url'], $new_url ); + + return $new_keyword; + } + public function test_edit_url_cache() { + $keyword = rand_str(); + $title = rand_str(); + $url = 'http://' . rand_str(); + + $new_title = rand_str(); + $new_url = 'http://' . rand_str(); + + $infos = yourls_get_keyword_infos( $keyword ); + $this->assertFalse( $infos ); + + $newurl = yourls_add_new_link( $url, $keyword, $title ); + $this->assertEquals( 'success', $newurl['status'] ); + + $edit = yourls_edit_link( $new_url, $keyword, $keyword, $new_title ); + $this->assertEquals( $edit['url']['title'], $new_title ); + $this->assertEquals( $edit['url']['url'], $new_url ); + $this->assertEquals( $edit['url']['keyword'], $keyword ); + + $updated_data = yourls_get_keyword_infos( $keyword ); + $this->assertEquals( $updated_data['url'], $new_url ); + $this->assertEquals( $updated_data['title'], $new_title ); + $this->assertEquals( $updated_data['keyword'], $keyword ); + } + + #[\PHPUnit\Framework\Attributes\Depends('test_edit_url')] + public function test_delete_url( $keyword ) { + $delete = yourls_delete_link_by_keyword( rand_str() ); + $this->assertEquals( 0, $delete ); + $delete = yourls_delete_link_by_keyword( $keyword ); + $this->assertEquals( 1, $delete ); + $this->assertFalse( yourls_is_shorturl( $keyword ) ); + } + + public function test_delete_url_cache() { + $keyword = rand_str(); + $title = rand_str(); + $url = 'http://' . rand_str(); + + $this->assertFalse( yourls_get_keyword_infos( $keyword ) ); + + $newurl = yourls_add_new_link( $url, $keyword, $title ); + $this->assertEquals( 'success', $newurl['status'] ); + $this->assertTrue( yourls_is_shorturl( $keyword ) ); + + $infos = yourls_get_keyword_infos( $keyword ); + $this->assertEquals( $keyword, $infos['keyword'] ); + $this->assertEquals( $title, $infos['title'] ); + $this->assertEquals( $url, $infos['url'] ); + + $delete = yourls_delete_link_by_keyword( $keyword ); + $this->assertEquals( 1, $delete ); + $this->assertFalse( yourls_is_shorturl( $keyword ) ); + $this->assertFalse( yourls_get_keyword_infos( $keyword ) ); + } + +} diff --git a/tests/tests/shorturl/duplicate.php b/tests/tests/shorturl/DuplicateLongURLTest.php similarity index 88% rename from tests/tests/shorturl/duplicate.php rename to tests/tests/shorturl/DuplicateLongURLTest.php index 3aacf52f8..94d4f262d 100644 --- a/tests/tests/shorturl/duplicate.php +++ b/tests/tests/shorturl/DuplicateLongURLTest.php @@ -3,11 +3,10 @@ /** * Short URLs : test with "allow duplicate long URL" * - * @group shorturls * @since 0.1 */ - -class ShortURL_Duplicate_Long_URL_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('shorturls')] +class DuplicateLongURLTest extends PHPUnit\Framework\TestCase { public function test_yourls_allow_duplicate_longurls_is_bool() { $this->assertIsBool(yourls_allow_duplicate_longurls()); diff --git a/tests/tests/shorturl/misc.php b/tests/tests/shorturl/ShortURLTest.php similarity index 58% rename from tests/tests/shorturl/misc.php rename to tests/tests/shorturl/ShortURLTest.php index ab1a708d2..38d57bc19 100644 --- a/tests/tests/shorturl/misc.php +++ b/tests/tests/shorturl/ShortURLTest.php @@ -3,21 +3,29 @@ /** * Short URLs : misc functions * - * @group shorturls * @since 0.1 */ - -class ShortURL_Misc_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('shorturls')] +class ShortURLTest extends PHPUnit\Framework\TestCase { public function test_reserved_keywords() { - global $yourls_reserved_URL; + $yourls_reserved_URL = yourls_get_reserved_URL(); $reserved = $yourls_reserved_URL[ array_rand( $yourls_reserved_URL, 1 ) ]; $this->assertTrue( yourls_keyword_is_reserved( $reserved ) ); $this->assertFalse( yourls_keyword_is_reserved( rand_str() ) ); } - public function test_free_keywords() { + public function test_no_reserved_keywords() { global $yourls_reserved_URL; + $existing_keywords = $yourls_reserved_URL; + $yourls_reserved_URL = null; + $this->assertFalse( yourls_keyword_is_reserved( rand_str() ) ); + // put it back for other tests. + $yourls_reserved_URL = $existing_keywords; + } + + public function test_free_keywords() { + $yourls_reserved_URL = yourls_get_reserved_URL(); $reserved = $yourls_reserved_URL[ array_rand( $yourls_reserved_URL, 1 ) ]; $this->assertFalse( yourls_keyword_is_free( $reserved ) ); $this->assertFalse( yourls_keyword_is_free( 'ozh' ) ); @@ -25,7 +33,7 @@ public function test_free_keywords() { } public function test_url_exists() { - $exists = yourls_long_url_exists( 'http://ozh.org/' ); + $exists = yourls_long_url_exists( 'https://ozh.org/' ); $this->assertEquals( 'ozh', $exists->keyword ); $this->assertNull( yourls_long_url_exists( rand_str() ) ); } @@ -36,4 +44,9 @@ public function test_log_hits_unknown() { $this->assertEquals( 0, yourls_get_keyword_clicks( $rand ) ); } + public function test_get_shorturl_charset() { + $this->assertIsString(yourls_get_shorturl_charset()); + $this->assertNotEmpty(yourls_get_shorturl_charset()); + } + } diff --git a/tests/tests/shorturl/crud.php b/tests/tests/shorturl/crud.php deleted file mode 100644 index 5335c1cd1..000000000 --- a/tests/tests/shorturl/crud.php +++ /dev/null @@ -1,109 +0,0 @@ -assertEquals( 'success', $newurl['status'] ); - - $fail = yourls_add_new_link( $url, $keyword, $title ); - $this->assertEquals( 'fail', $fail['status'] ); - - $fail = yourls_add_new_link( $url, rand_str(), rand_str() ); - $this->assertEquals( 'fail', $fail['status'] ); - $this->assertEquals( 'error:url', $fail['code'] ); - - $fail = yourls_add_new_link( 'http://' . rand_str(), $keyword, $title ); - $this->assertEquals( 'fail', $fail['status'] ); - $this->assertEquals( 'error:keyword', $fail['code'] ); - - $this->assertEquals( $title, yourls_get_keyword_title( $keyword ) ); - $this->assertEquals( $url, yourls_get_keyword_longurl( $keyword ) ); - $this->assertEquals( 0, yourls_get_keyword_clicks( $keyword ) ); - - return $keyword; - } - - /** - * @depends test_add_url - */ - public function test_edit_title( $original_keyword ) { - $new_keyword = rand_str(); - $new_title = rand_str(); - $new_url = 'http://' . rand_str(); - - $edit = yourls_edit_link_title( $original_keyword, $new_title ); - $this->assertEquals( 1, $edit ); - // purge cache - $original = yourls_get_keyword_infos( $original_keyword, false ); - $this->assertEquals( $new_title, yourls_get_keyword_title( $original_keyword ) ); - - return $original_keyword; - } - /** - * @depends test_add_url - */ - public function test_is_shorturl( $keyword ) { - $this->assertFalse( yourls_is_shorturl( rand_str() ) ); - $this->assertTrue( yourls_is_shorturl( $keyword ) ); - $this->assertTrue( yourls_is_shorturl( yourls_link( $keyword ) ) ); - } - - /** - * @depends test_add_url - */ - public function test_update_hits( $keyword ) { - // purge cache - $cache = yourls_get_keyword_infos( $keyword, false ); - $this->assertEquals( 0, yourls_get_keyword_clicks( $keyword ) ); - - $this->assertEquals( 1, yourls_update_clicks( $keyword ) ); - // purge cache - yourls_get_keyword_infos( $keyword, false ); - $this->assertEquals( 1, yourls_get_keyword_clicks( $keyword ) ); - } - - /** - * @depends test_edit_title - */ - public function test_edit_url( $original_keyword ) { - $new_keyword = rand_str(); - $new_title = rand_str(); - $new_url = 'http://' . rand_str(); - - // purge cache - $original = yourls_get_keyword_infos( $original_keyword, false ); - - $edit = yourls_edit_link( $original['url'], $original_keyword, $new_keyword, $new_title ); - $this->assertEquals( $edit['url']['title'], $new_title ); - $this->assertEquals( $edit['url']['keyword'], $new_keyword ); - - $edit = yourls_edit_link( $new_url, $new_keyword, $new_keyword, $new_title ); - $this->assertEquals( $edit['url']['url'], $new_url ); - - return $new_keyword; - } - - /** - * @depends test_edit_url - */ - public function test_delete_url( $keyword ) { - $delete = yourls_delete_link_by_keyword( rand_str() ); - $this->assertEquals( 0, $delete ); - $delete = yourls_delete_link_by_keyword( $keyword ); - $this->assertEquals( 1, $delete ); - $this->assertFalse( yourls_is_shorturl( $keyword ) ); - } - -} diff --git a/tests/tests/stats/misc.php b/tests/tests/stats/StatsTest.php similarity index 58% rename from tests/tests/stats/misc.php rename to tests/tests/stats/StatsTest.php index e229eba87..5cbb34209 100644 --- a/tests/tests/stats/misc.php +++ b/tests/tests/stats/StatsTest.php @@ -2,11 +2,9 @@ /** * Stats functions - * - * @group stats */ - -class Misc_Stats_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('stats')] +class StatsTest extends PHPUnit\Framework\TestCase { public function test_do_log_redirect() { $this->assertIsBool(yourls_do_log_redirect()); diff --git a/tests/tests/themes/ThemesTest.php b/tests/tests/themes/ThemesTest.php new file mode 100644 index 000000000..aa2a67d44 --- /dev/null +++ b/tests/tests/themes/ThemesTest.php @@ -0,0 +1,36 @@ +assertNotEmpty( $themes ); + + // Pick one random theme + $theme = $themes[ array_rand( $themes ) ]; + return dirname( $theme ); + } + + /** + * Check that a random valid theme activates correctly + * + * @since 0.1 + */ + #[\PHPUnit\Framework\Attributes\Depends('test_get_themes')] + public function test_theme_activate( $theme ) { + $this->assertTrue( yourls_activate_theme( $theme ) ); + $this->assertTrue( yourls_load_theme( $theme ) ); + $this->assertTrue( yourls_is_style_queued( $theme ) ); + $this->assertEquals( $theme, yourls_get_active_theme() ); + return $theme; + } +} diff --git a/tests/tests/themes/themes.php b/tests/tests/themes/themes.php deleted file mode 100644 index 7551e5f60..000000000 --- a/tests/tests/themes/themes.php +++ /dev/null @@ -1,43 +0,0 @@ -assertNotEmpty( $themes ); - - // Pick one random theme - $theme = $themes[ array_rand( $themes ) ]; - return dirname( $theme ); - } - - /** - * Check that a random valid theme activates correctly - * - * @depends test_get_themes - * @since 0.1 - */ - public function test_theme_activate( $theme ) { - $this->assertTrue( yourls_activate_theme( $theme ) ); - $this->assertTrue( yourls_load_theme( $theme ) ); - $this->assertTrue( yourls_is_style_queued( $theme ) ); - $this->assertEquals( $theme, yourls_get_active_theme() ); - return $theme; - } - -} - -endif; diff --git a/tests/tests/utilities/FileLoaderTest.php b/tests/tests/utilities/FileLoaderTest.php new file mode 100644 index 000000000..7cae4b5d8 --- /dev/null +++ b/tests/tests/utilities/FileLoaderTest.php @@ -0,0 +1,35 @@ +assertTrue( yourls_include_file_sandbox( $file ) ); + unlink("$file"); + } else { + $this->markTestSkipped( "Cannot create test '$file"); + } + } + + /** + * Load missing file = string + */ + public function test_load_file_not_exists() { + $this->assertNull( yourls_include_file_sandbox( YOURLS_TESTDATA_DIR . "/" . rand_str() . ".php" ) ); + } + + /** + * For tests to load valid and broken PHP code: see in tests/plugins/files.php + */ + +} diff --git a/tests/tests/utilities/GetRequestTest.php b/tests/tests/utilities/GetRequestTest.php new file mode 100644 index 000000000..c624c0d43 --- /dev/null +++ b/tests/tests/utilities/GetRequestTest.php @@ -0,0 +1,90 @@ +assertSame( $expected, yourls_get_request($yourls_site, $uri) ); + } +} diff --git a/tests/tests/utilities/next_decimal.php b/tests/tests/utilities/NextDecimalTest.php similarity index 85% rename from tests/tests/utilities/next_decimal.php rename to tests/tests/utilities/NextDecimalTest.php index 8c491a59d..b83fef281 100644 --- a/tests/tests/utilities/next_decimal.php +++ b/tests/tests/utilities/NextDecimalTest.php @@ -2,11 +2,9 @@ /** * Utilities - * - * @group utils */ - -class NextDecimal_Tests extends PHPUnit\Framework\TestCase { +#[\PHPUnit\Framework\Attributes\Group('utils')] +class NextDecimalTest extends PHPUnit\Framework\TestCase { public function test_get_next_decimal() { $id = yourls_get_next_decimal(); diff --git a/tests/tests/utilities/get_request.php b/tests/tests/utilities/get_request.php deleted file mode 100644 index ecdc748b3..000000000 --- a/tests/tests/utilities/get_request.php +++ /dev/null @@ -1,113 +0,0 @@ -assertSame( $expected, yourls_get_request($yourls_site, $uri) ); - } -} diff --git a/user/config-sample.php b/user/config-sample.php index e0013553b..7cfc3483f 100644 --- a/user/config-sample.php +++ b/user/config-sample.php @@ -35,14 +35,14 @@ /** YOURLS installation URL ** All lowercase, no trailing slash at the end. - ** If you define it to "http://sho.rt", don't use "http://www.sho.rt" in your browser (and vice-versa) - ** To use an IDN domain (eg http://héhé.com), write its ascii form here (eg http://xn--hh-bjab.com) */ -define( 'YOURLS_SITE', 'http://your-own-domain-here.com' ); + ** If you define it to "https://sho.rt", don't use "https://www.sho.rt" in your browser (and vice-versa) + ** To use an IDN domain (eg https://héhé.com), write its ascii form here (eg https://xn--hh-bjab.com) */ +define( 'YOURLS_SITE', 'https://your-own-domain-here.com' ); /** YOURLS language ** Change this setting to use a translation file for your language, instead of the default English. ** That translation file (a .mo file) must be installed in the user/language directory. - ** See http://yourls.org/translations for more information */ + ** See https://yourls.org/translations for more information */ define( 'YOURLS_LANG', '' ); /** Allow multiple short URLs for a same long URL @@ -52,20 +52,20 @@ /** Private means the Admin area will be protected with login/pass as defined below. ** Set to false for public usage (eg on a restricted intranet or for test setups) - ** Read http://yourls.org/privatepublic for more details if you're unsure */ + ** Read https://yourls.org/privatepublic for more details if you're unsure */ define( 'YOURLS_PRIVATE', true ); /** A random secret hash used to encrypt cookies. You don't have to remember it, make it long and complicated - ** Hint: copy from http://yourls.org/cookie */ + ** Hint: copy from https://yourls.org/cookie */ define( 'YOURLS_COOKIEKEY', 'modify this text with something random' ); /** Username(s) and password(s) allowed to access the site. Passwords either in plain text or as encrypted hashes ** YOURLS will auto encrypt plain text passwords in this file - ** Read http://yourls.org/userpassword for more information */ + ** Read https://yourls.org/userpassword for more information */ $yourls_user_passwords = [ - 'username' => 'password', - // 'username2' => 'password2', - // You can have one or more 'login'=>'password' lines + 'username' => 'password', + // 'username2' => 'password2', + // You can have one or more 'login'=>'password' lines ]; /** URL shortening method: either 36 or 62 @@ -83,7 +83,13 @@ * Define here negative, unwanted or potentially misleading keywords. */ $yourls_reserved_URL = [ - 'porn', 'faggot', 'sex', 'nigger', 'fuck', 'cunt', 'dick', + 'porn', + 'faggot', + 'sex', + 'nigger', + 'fuck', + 'cunt', + 'dick', ]; /* diff --git a/user/pages/examplepage.php b/user/pages/examplepage.php index f02d6ec35..76f07762f 100644 --- a/user/pages/examplepage.php +++ b/user/pages/examplepage.php @@ -2,8 +2,8 @@ // Make sure we're in YOURLS context if( !defined( 'YOURLS_ABSPATH' ) ) { - echo "Try using a URL without the /pages/ part"; - die(); + echo "Try using a URL without the /pages/ part"; + die(); } // Display page content. Any PHP, HTML and YOURLS function can go here. diff --git a/user/plugins/hyphens-in-urls/plugin.php b/user/plugins/hyphens-in-urls/plugin.php index 380341214..727d369ba 100644 --- a/user/plugins/hyphens-in-urls/plugin.php +++ b/user/plugins/hyphens-in-urls/plugin.php @@ -1,19 +1,27 @@ http://sho.rt/hello-world) -Version: 1.0 -Author: Ozh -Author URI: http://ozh.org/ -*/ +/** + * Plugin Name: Allow Hyphens in Short URLs + * Plugin URI: http://yourls.org/ + * Description: Allow hyphens in short URLs (like http://sho.rt/hello-world) + * Version: 1.1 + * Author: Ozh + * Author URI: http://ozh.org/ + */ + +/** Release History: + * + * 1.0 Initial release + * 1.1 Modified: Make random keywords hyphen free + */ // No direct call if( !defined( 'YOURLS_ABSPATH' ) ) die(); +// Add hyphen to the allowed character set yourls_add_filter( 'get_shorturl_charset', 'ozh_hyphen_in_charset' ); +// Unless we are crafting a random keyword +yourls_add_action('add_new_link_create_keyword', function() {yourls_remove_filter('get_shorturl_charset', 'ozh_hyphen_in_charset');}); + function ozh_hyphen_in_charset( $in ) { - return $in.'-'; + return $in.'-'; } - - diff --git a/user/plugins/random-bg/plugin.php b/user/plugins/random-bg/plugin.php index a6768ff0d..8bba3f425 100644 --- a/user/plugins/random-bg/plugin.php +++ b/user/plugins/random-bg/plugin.php @@ -14,13 +14,13 @@ // Add the inline style yourls_add_action( 'html_head', 'ozh_yourls_randombg' ); function ozh_yourls_randombg() { - $bg = glob( __DIR__.'/img/*png' ); - $url = yourls_plugin_url( __DIR__ ); - $rnd = yourls_plugin_url( $bg[ mt_rand( 0, count( $bg ) - 1 ) ] ); - echo << - body {background:#e3f3ff url($rnd) repeat;} - + body {background:#e3f3ff url($rnd) repeat;} + CSS; } diff --git a/user/plugins/sample-page/plugin.php b/user/plugins/sample-page/plugin.php index 5f5479a87..41953454b 100644 --- a/user/plugins/sample-page/plugin.php +++ b/user/plugins/sample-page/plugin.php @@ -14,50 +14,50 @@ // Register our plugin admin page yourls_add_action( 'plugins_loaded', 'ozh_yourls_samplepage_add_page' ); function ozh_yourls_samplepage_add_page() { - yourls_register_plugin_page( 'sample_page', 'Sample Admin Page', 'ozh_yourls_samplepage_do_page' ); - // parameters: page slug, page title, and function that will display the page itself + yourls_register_plugin_page( 'sample_page', 'Sample Admin Page', 'ozh_yourls_samplepage_do_page' ); + // parameters: page slug, page title, and function that will display the page itself } // Display admin page function ozh_yourls_samplepage_do_page() { - // Check if a form was submitted - if( isset( $_POST['test_option'] ) ) { - // Check nonce - yourls_verify_nonce( 'sample_page' ); + // Check if a form was submitted + if( isset( $_POST['test_option'] ) ) { + // Check nonce + yourls_verify_nonce( 'sample_page' ); - // Process form - ozh_yourls_samplepage_update_option(); - } + // Process form + ozh_yourls_samplepage_update_option(); + } - // Get value from database - $test_option = yourls_get_option( 'test_option' ); + // Get value from database + $test_option = yourls_get_option( 'test_option' ); - // Create nonce - $nonce = yourls_create_nonce( 'sample_page' ); + // Create nonce + $nonce = yourls_create_nonce( 'sample_page' ); - echo <<Sample Plugin Administration Page -

This plugin stores an integer in the option database

-
- -

-

- + echo <<Sample Plugin Administration Page +

This plugin stores an integer in the option database

+
+ +

+

+ HTML; } // Update option in database function ozh_yourls_samplepage_update_option() { - $in = $_POST['test_option']; + $in = $_POST['test_option']; - if( $in ) { - // Validate test_option. ALWAYS validate and sanitize user input. - // Here, we want an integer - $in = intval( $in); + if( $in ) { + // Validate test_option. ALWAYS validate and sanitize user input. + // Here, we want an integer + $in = intval( $in); - // Update value in database - yourls_update_option( 'test_option', $in ); - } + // Update value in database + yourls_update_option( 'test_option', $in ); + } } diff --git a/user/plugins/sample-plugin/plugin.php b/user/plugins/sample-plugin/plugin.php index 40dc1ab9a..dcfdc4edf 100644 --- a/user/plugins/sample-plugin/plugin.php +++ b/user/plugins/sample-plugin/plugin.php @@ -28,7 +28,7 @@ */ function ozh_sample_add_menu() { - echo '
  • Ozh
  • '; + echo '
  • Ozh
  • '; } /* And that's it. Activate the plugin and notice the new menu entry. */ @@ -54,8 +54,8 @@ function ozh_sample_add_menu() { */ function ozh_sample_change_title( $value ) { - $value = $value . ' -- the sample plugin is activated'; - return $value; // a filter *always* has to return a value + $value = $value . ' -- the sample plugin is activated'; + return $value; // a filter *always* has to return a value } /* And that's it. Activate the plugin and notice how the page title changes */ diff --git a/user/plugins/sample-toolbar/plugin.php b/user/plugins/sample-toolbar/plugin.php index d48c7bcf1..7fde678bd 100644 --- a/user/plugins/sample-toolbar/plugin.php +++ b/user/plugins/sample-toolbar/plugin.php @@ -19,78 +19,78 @@ // When a redirection to a shorturl is about to happen, register variables yourls_add_action( 'redirect_shorturl', 'ozh_toolbar_add' ); function ozh_toolbar_add( $args ) { - global $ozh_toolbar; - $ozh_toolbar['do'] = true; - $ozh_toolbar['keyword'] = $args[1]; + global $ozh_toolbar; + $ozh_toolbar['do'] = true; + $ozh_toolbar['keyword'] = $args[1]; } // On redirection, check if this is a toolbar and draw it if needed yourls_add_action( 'pre_redirect', 'ozh_toolbar_do' ); function ozh_toolbar_do( $args ) { - global $ozh_toolbar; + global $ozh_toolbar; - // Does this redirection need a toolbar? - if( !$ozh_toolbar['do'] ) { - return; + // Does this redirection need a toolbar? + if( !$ozh_toolbar['do'] ) { + return; } - // Do we have a cookie stating the user doesn't want a toolbar? - if( isset( $_COOKIE['yourls_no_toolbar'] ) && $_COOKIE['yourls_no_toolbar'] == 1 ) { - return; + // Do we have a cookie stating the user doesn't want a toolbar? + if( isset( $_COOKIE['yourls_no_toolbar'] ) && $_COOKIE['yourls_no_toolbar'] == 1 ) { + return; } - // Get URL and page title - $url = $args[0]; - $pagetitle = yourls_get_keyword_title( $ozh_toolbar['keyword'] ); + // Get URL and page title + $url = $args[0]; + $pagetitle = yourls_get_keyword_title( $ozh_toolbar['keyword'] ); - // Update title if it hasn't been stored yet - if( $pagetitle == '' ) { - $pagetitle = yourls_get_remote_title( $url ); - yourls_edit_link_title( $ozh_toolbar['keyword'], $pagetitle ); - } - $_pagetitle = htmlentities( yourls_get_remote_title( $url ) ); + // Update title if it hasn't been stored yet + if( $pagetitle == '' ) { + $pagetitle = yourls_get_remote_title( $url ); + yourls_edit_link_title( $ozh_toolbar['keyword'], $pagetitle ); + } + $_pagetitle = htmlentities( yourls_get_remote_title( $url ) ); - $www = YOURLS_SITE; - $ver = YOURLS_VERSION; + $www = YOURLS_SITE; + $ver = YOURLS_VERSION; $favicon = yourls_get_yourls_favicon_url(false); - // When was the link created (in days) - $diff = abs( time() - strtotime( yourls_get_keyword_timestamp( $ozh_toolbar['keyword'] ) ) ); - $days = floor( $diff / (60*60*24) ); - if( $days == 0 ) { - $created = 'today'; - } else { - $created = $days . ' ' . yourls_n( 'day', 'days', $days ) . ' ago'; - } + // When was the link created (in days) + $diff = abs( time() - strtotime( yourls_get_keyword_timestamp( $ozh_toolbar['keyword'] ) ) ); + $days = floor( $diff / (60*60*24) ); + if( $days == 0 ) { + $created = 'today'; + } else { + $created = $days . ' ' . yourls_n( 'day', 'days', $days ) . ' ago'; + } - // How many hits on the page - $hits = 1 + yourls_get_keyword_clicks( $ozh_toolbar['keyword'] ); - $hits = $hits . ' ' . yourls_n( 'view', 'views', $hits ); + // How many hits on the page + $hits = 1 + yourls_get_keyword_clicks( $ozh_toolbar['keyword'] ); + $hits = $hits . ' ' . yourls_n( 'view', 'views', $hits ); - // Plugin URL (no URL is hardcoded) - $pluginurl = YOURLS_PLUGINURL . '/'.yourls_plugin_basename( __DIR__ ); + // Plugin URL (no URL is hardcoded) + $pluginurl = YOURLS_PLUGINURL . '/'.yourls_plugin_basename( __DIR__ ); - // All set. Draw the toolbar itself. - echo << - $pagetitle — YOURLS - - - - - + $pagetitle — YOURLS + + + + +
    -
    - Short link powered by YOURLS and created $created. $hits. -
    - -
    - close - close -
    +
    + Short link powered by YOURLS and created $created. $hits. +
    + +
    + close + close +
    @@ -99,6 +99,6 @@ function ozh_toolbar_do( $args ) { PAGE; - // Don't forget to die, to interrupt the flow of normal events (ie redirecting to long URL) - die(); + // Don't forget to die, to interrupt the flow of normal events (ie redirecting to long URL) + die(); } diff --git a/yourls-api.php b/yourls-api.php index 413abad55..8f5420653 100644 --- a/yourls-api.php +++ b/yourls-api.php @@ -17,34 +17,34 @@ // Define standard API actions $api_actions = array( - 'shorturl' => 'yourls_api_action_shorturl', - 'stats' => 'yourls_api_action_stats', - 'db-stats' => 'yourls_api_action_db_stats', - 'url-stats' => 'yourls_api_action_url_stats', - 'expand' => 'yourls_api_action_expand', - 'version' => 'yourls_api_action_version', + 'shorturl' => 'yourls_api_action_shorturl', + 'stats' => 'yourls_api_action_stats', + 'db-stats' => 'yourls_api_action_db_stats', + 'url-stats' => 'yourls_api_action_url_stats', + 'expand' => 'yourls_api_action_expand', + 'version' => 'yourls_api_action_version', ); $api_actions = yourls_apply_filter( 'api_actions', $api_actions ); // Register API actions foreach( (array) $api_actions as $_action => $_callback ) { - yourls_add_filter( 'api_action_' . $_action, $_callback, 99 ); + yourls_add_filter( 'api_action_' . $_action, $_callback, 99 ); } // Try requested API method. Properly registered actions should return an array. $return = yourls_apply_filter( 'api_action_' . $action, false ); if ( false === $return ) { - $return = array( - 'errorCode' => 400, - 'message' => 'Unknown or missing "action" parameter', - 'simple' => 'Unknown or missing "action" parameter', - ); + $return = array( + 'errorCode' => '400', + 'message' => 'Unknown or missing "action" parameter', + 'simple' => 'Unknown or missing "action" parameter', + ); } if( isset( $_REQUEST['callback'] ) ) - $return['callback'] = $_REQUEST['callback']; + $return['callback'] = $_REQUEST['callback']; elseif ( isset( $_REQUEST['jsonp'] ) ) - $return['callback'] = $_REQUEST['jsonp']; + $return['callback'] = $_REQUEST['jsonp']; $format = ( isset( $_REQUEST['format'] ) ? $_REQUEST['format'] : 'xml' ); diff --git a/yourls-go.php b/yourls-go.php index 51968dd92..fd26075db 100644 --- a/yourls-go.php +++ b/yourls-go.php @@ -4,8 +4,8 @@ // Variables should be defined in yourls-loader.php if( !isset( $keyword ) ) { - yourls_do_action( 'redirect_no_keyword' ); - yourls_redirect( YOURLS_SITE, 301 ); + yourls_do_action( 'redirect_no_keyword' ); + yourls_redirect( YOURLS_SITE, 301 ); } $keyword = yourls_sanitize_keyword($keyword); diff --git a/yourls-infos.php b/yourls-infos.php index f48280875..a90c86039 100644 --- a/yourls-infos.php +++ b/yourls-infos.php @@ -6,8 +6,9 @@ // Variables should be defined in yourls-loader.php if ( !isset( $keyword ) ) { - yourls_do_action( 'infos_no_keyword' ); - yourls_redirect( YOURLS_SITE, 302 ); + yourls_do_action( 'infos_no_keyword' ); + yourls_redirect( YOURLS_SITE, 302 ); + exit; } // Get basic infos for this shortened URL @@ -19,13 +20,14 @@ // Update title if it hasn't been stored yet if( $title == '' ) { - $title = yourls_get_remote_title( $longurl ); - yourls_edit_link_title( $keyword, $title ); + $title = yourls_get_remote_title( $longurl ); + yourls_edit_link_title( $keyword, $title ); } if ( $longurl === false ) { - yourls_do_action( 'infos_keyword_not_found' ); - yourls_redirect( YOURLS_SITE, 302 ); + yourls_do_action( 'infos_keyword_not_found' ); + yourls_redirect( YOURLS_SITE, 302 ); + exit; } yourls_do_action( 'pre_yourls_infos', $keyword ); @@ -33,180 +35,184 @@ if( yourls_do_log_redirect() ) { - $table = YOURLS_DB_TABLE_LOG; - $referrers = array(); - $direct = $notdirect = 0; - $countries = array(); - $dates = array(); - $list_of_days = array(); - $list_of_months = array(); - $list_of_years = array(); - $last_24h = array(); - - if( yourls_allow_duplicate_longurls() ) - $keyword_list = yourls_get_longurl_keywords( $longurl ); - // Define keyword query range : either a single keyword or a list of keywords - if( $aggregate ) { - $keyword_range = 'IN ( :list )'; + $table = YOURLS_DB_TABLE_LOG; + $referrers = array(); + $direct = $notdirect = 0; + $countries = array(); + $dates = array(); + $list_of_days = array(); + $list_of_months = array(); + $list_of_years = array(); + $last_24h = array(); + + if( yourls_allow_duplicate_longurls() ) + $keyword_list = yourls_get_longurl_keywords( $longurl ); + // Define keyword query range : either a single keyword or a list of keywords + if( $aggregate ) { + $keyword_range = 'IN ( :list )'; $keyword_binds = array('list' => $keyword_list); - } else { - $keyword_range = '= :keyword'; + } else { + $keyword_range = '= :keyword'; $keyword_binds = array('keyword' => $keyword); - } + } - // *** Referrers *** + // *** Referrers *** $sql = "SELECT `referrer`, COUNT(*) AS `count` FROM `$table` WHERE `shorturl` $keyword_range GROUP BY `referrer`;"; $sql = yourls_apply_filter('stat_query_referrer', $sql); - $rows = $ydb->fetchObjects($sql, $keyword_binds); - - // Loop through all results and build list of referrers, countries and hits per day - foreach( (array)$rows as $row ) { - if ( $row->referrer == 'direct' ) { - $direct = $row->count; - continue; - } - - $host = yourls_get_domain( $row->referrer ); - if( !array_key_exists( $host, $referrers ) ) - $referrers[$host] = array( ); - if( !array_key_exists( $row->referrer, $referrers[$host] ) ) { - $referrers[$host][$row->referrer] = $row->count; - $notdirect += $row->count; - } else { - $referrers[$host][$row->referrer] += $row->count; - $notdirect += $row->count; - } - } - - // Sort referrers. $referrer_sort is a array of most frequent domains - arsort( $referrers ); - $referrer_sort = array(); - $number_of_sites = count( array_keys( $referrers ) ); - foreach( $referrers as $site => $urls ) { - if( count($urls) > 1 || $number_of_sites == 1 ) - $referrer_sort[$site] = array_sum( $urls ); - } - arsort($referrer_sort); - - - // *** Countries *** - $sql = "SELECT `country_code`, COUNT(*) AS `count` FROM `$table` WHERE `shorturl` $keyword_range GROUP BY `country_code`;"; + $rows = $ydb->fetchObjects($sql, $keyword_binds); + + // Loop through all results and build list of referrers, countries and hits per day + foreach( (array)$rows as $row ) { + if ( $row->referrer == 'direct' ) { + $direct = $row->count; + continue; + } + + $host = yourls_get_domain( $row->referrer ); + if( !array_key_exists( $host, $referrers ) ) + $referrers[$host] = array( ); + if( !array_key_exists( $row->referrer, $referrers[$host] ) ) { + $referrers[$host][$row->referrer] = $row->count; + $notdirect += $row->count; + } else { + $referrers[$host][$row->referrer] += $row->count; + $notdirect += $row->count; + } + } + + // Sort referrers. $referrer_sort is a array of most frequent domains + arsort( $referrers ); + $referrer_sort = array(); + $number_of_sites = count( array_keys( $referrers ) ); + foreach( $referrers as $site => $urls ) { + if( count($urls) > 1 || $number_of_sites == 1 ) + $referrer_sort[$site] = array_sum( $urls ); + } + arsort($referrer_sort); + + + // *** Countries *** + $sql = "SELECT `country_code`, COUNT(*) AS `count` FROM `$table` WHERE `shorturl` $keyword_range GROUP BY `country_code`;"; $sql = yourls_apply_filter('stat_query_country', $sql); - $rows = $ydb->fetchObjects($sql, $keyword_binds); - - // Loop through all results and build list of countries and hits - foreach( (array)$rows as $row ) { - if ("$row->country_code") - $countries["$row->country_code"] = $row->count; - } - - // Sort countries, most frequent first - if ( $countries ) - arsort( $countries ); - - - // *** Dates : array of $dates[$year][$month][$day] = number of clicks *** - $sql = "SELECT - DATE_FORMAT(`click_time`, '%Y') AS `year`, - DATE_FORMAT(`click_time`, '%m') AS `month`, - DATE_FORMAT(`click_time`, '%d') AS `day`, - COUNT(*) AS `count` - FROM `$table` - WHERE `shorturl` $keyword_range - GROUP BY `year`, `month`, `day`;"; + $rows = $ydb->fetchObjects($sql, $keyword_binds); + + // Loop through all results and build list of countries and hits + foreach( (array)$rows as $row ) { + if ("$row->country_code") + $countries["$row->country_code"] = $row->count; + } + + // Sort countries, most frequent first + if ( $countries ) + arsort( $countries ); + + + // *** Dates : array of $dates[$year][$month][$day] = number of clicks *** + $sql = "SELECT + DATE_FORMAT(`click_time`, '%Y') AS `year`, + DATE_FORMAT(`click_time`, '%m') AS `month`, + DATE_FORMAT(`click_time`, '%d') AS `day`, + COUNT(*) AS `count` + FROM `$table` + WHERE `shorturl` $keyword_range + GROUP BY `year`, `month`, `day`;"; $sql = yourls_apply_filter('stat_query_dates', $sql); - $rows = $ydb->fetchObjects($sql, $keyword_binds); - - // Loop through all results and fill blanks - foreach( (array)$rows as $row ) { - if( !array_key_exists($row->year, $dates ) ) - $dates[$row->year] = array(); - if( !array_key_exists( $row->month, $dates[$row->year] ) ) - $dates[$row->year][$row->month] = array(); - if( !array_key_exists( $row->day, $dates[$row->year][$row->month] ) ) - $dates[$row->year][$row->month][$row->day] = $row->count; - else - $dates[$row->year][$row->month][$row->day] += $row->count; - } - - // Sort dates, chronologically from [2007][12][24] to [2009][02][19] - ksort( $dates ); - foreach( $dates as $year=>$months ) { - ksort( $dates[$year] ); - foreach( $months as $month=>$day ) { - ksort( $dates[$year][$month] ); - } - } - - // Get $list_of_days, $list_of_months, $list_of_years - reset( $dates ); - if( $dates ) { + $rows = $ydb->fetchObjects($sql, $keyword_binds); + + // Loop through all results and fill blanks + foreach( (array)$rows as $row ) { + if( !array_key_exists($row->year, $dates ) ) + $dates[$row->year] = array(); + if( !array_key_exists( $row->month, $dates[$row->year] ) ) + $dates[$row->year][$row->month] = array(); + if( !array_key_exists( $row->day, $dates[$row->year][$row->month] ) ) + $dates[$row->year][$row->month][$row->day] = $row->count; + else + $dates[$row->year][$row->month][$row->day] += $row->count; + } + + // Sort dates, chronologically from [2007][12][24] to [2009][02][19] + ksort( $dates ); + foreach( $dates as $year=>$months ) { + ksort( $dates[$year] ); + foreach( $months as $month=>$day ) { + ksort( $dates[$year][$month] ); + } + } + + // Get $list_of_days, $list_of_months, $list_of_years + reset( $dates ); + if( $dates ) { $_lists = yourls_build_list_of_days( $dates ); $list_of_days = $_lists['list_of_days']; $list_of_months = $_lists['list_of_months']; $list_of_years = $_lists['list_of_years']; unset($_lists); - } + } - $offset = yourls_get_time_offset(); + $offset = yourls_get_time_offset(); - // *** Last 24 hours : array of $last_24h[ $hour ] = number of click *** - $sql = "SELECT - DATE_FORMAT(DATE_ADD(`click_time`, INTERVAL " . $offset . " HOUR), '%H %p') AS `time`, - COUNT(*) AS `count` - FROM `$table` - WHERE `shorturl` $keyword_range AND DATE_ADD(`click_time`, INTERVAL " . $offset . " HOUR) > (DATE_ADD(CURRENT_TIMESTAMP, INTERVAL " . $offset . " HOUR) - INTERVAL 1 DAY) - GROUP BY `time`;"; + // *** Last 24 hours : array of $last_24h[ $hour ] = number of click *** + $sql = "SELECT + DATE_FORMAT(DATE_ADD(`click_time`, INTERVAL " . $offset . " HOUR), '%H %p') AS `time`, + COUNT(*) AS `count` + FROM `$table` + WHERE `shorturl` $keyword_range AND DATE_ADD(`click_time`, INTERVAL " . $offset . " HOUR) > (DATE_ADD(CURRENT_TIMESTAMP, INTERVAL " . $offset . " HOUR) - INTERVAL 1 DAY) + GROUP BY `time`;"; $sql = yourls_apply_filter('stat_query_last24h', $sql); - $rows = $ydb->fetchObjects($sql, $keyword_binds); - - $_last_24h = array(); - foreach( (array)$rows as $row ) { - if ( isset( $row->time ) ) - $_last_24h[ "$row->time" ] = $row->count; - } - - $now = intval( date('U') ); - for ($i = 23; $i >= 0; $i--) { - $h = date('H A', ($now - ($i * 60 * 60) + ($offset * 60 * 60)) ); - // If the $last_24h doesn't have all the hours, insert missing hours with value 0 - $last_24h[ $h ] = array_key_exists( $h, $_last_24h ) ? $_last_24h[ $h ] : 0 ; - } - unset( $_last_24h ); - - // *** Queries all done, phew *** - - // Filter all this junk if applicable. Be warned, some are possibly huge datasets. - $referrers = yourls_apply_filter( 'pre_yourls_info_referrers', $referrers ); - $referrer_sort = yourls_apply_filter( 'pre_yourls_info_referrer_sort', $referrer_sort ); - $direct = yourls_apply_filter( 'pre_yourls_info_direct', $direct ); - $notdirect = yourls_apply_filter( 'pre_yourls_info_notdirect', $notdirect ); - $dates = yourls_apply_filter( 'pre_yourls_info_dates', $dates ); - $list_of_days = yourls_apply_filter( 'pre_yourls_info_list_of_days', $list_of_days ); - $list_of_months = yourls_apply_filter( 'pre_yourls_info_list_of_months', $list_of_months ); - $list_of_years = yourls_apply_filter( 'pre_yourls_info_list_of_years', $list_of_years ); - $last_24h = yourls_apply_filter( 'pre_yourls_info_last_24h', $last_24h ); - $countries = yourls_apply_filter( 'pre_yourls_info_countries', $countries ); - - // I can haz debug data - /** - echo "
    ";
    -	echo "referrers: "; print_r( $referrers );
    -	echo "referrer sort: "; print_r( $referrer_sort );
    -	echo "direct: $direct\n";
    -	echo "notdirect: $notdirect\n";
    -	echo "dates: "; print_r( $dates );
    -	echo "list of days: "; print_r( $list_of_days );
    -	echo "list_of_months: "; print_r( $list_of_months );
    -	echo "list_of_years: "; print_r( $list_of_years );
    -	echo "last_24h: "; print_r( $last_24h );
    -	echo "countries: "; print_r( $countries );
    -	die();
    -	**/
    +    $rows = $ydb->fetchObjects($sql, $keyword_binds);
    +
    +    $_last_24h = array();
    +    foreach( (array)$rows as $row ) {
    +        if ( isset( $row->time ) )
    +            $_last_24h[ "$row->time" ] = $row->count;
    +    }
    +
    +    $now = intval( date('U') );
    +    for ($i = 23; $i >= 0; $i--) {
    +        $h = date('H A', ($now - ($i * 60 * 60) + ($offset * 60 * 60)) );
    +        // If the $last_24h doesn't have all the hours, insert missing hours with value 0
    +        $last_24h[ $h ] = array_key_exists( $h, $_last_24h ) ? $_last_24h[ $h ] : 0 ;
    +    }
    +    unset( $_last_24h );
    +
    +    // *** Queries all done, phew ***
    +
    +    // Filter all this junk if applicable. Be warned, some are possibly huge datasets.
    +    $referrers      = yourls_apply_filter( 'pre_yourls_info_referrers', $referrers );
    +    $referrer_sort  = yourls_apply_filter( 'pre_yourls_info_referrer_sort', $referrer_sort );
    +    $direct         = yourls_apply_filter( 'pre_yourls_info_direct', $direct );
    +    $notdirect      = yourls_apply_filter( 'pre_yourls_info_notdirect', $notdirect );
    +    $dates          = yourls_apply_filter( 'pre_yourls_info_dates', $dates );
    +    $list_of_days   = yourls_apply_filter( 'pre_yourls_info_list_of_days', $list_of_days );
    +    $list_of_months = yourls_apply_filter( 'pre_yourls_info_list_of_months', $list_of_months );
    +    $list_of_years  = yourls_apply_filter( 'pre_yourls_info_list_of_years', $list_of_years );
    +    $last_24h       = yourls_apply_filter( 'pre_yourls_info_last_24h', $last_24h );
    +    $countries      = yourls_apply_filter( 'pre_yourls_info_countries', $countries );
    +
    +    // I can haz debug data
    +    /**
    +    echo "
    ";
    +    echo "referrers: "; print_r( $referrers );
    +    echo "referrer sort: "; print_r( $referrer_sort );
    +    echo "direct: $direct\n";
    +    echo "notdirect: $notdirect\n";
    +    echo "dates: "; print_r( $dates );
    +    echo "list of days: "; print_r( $list_of_days );
    +    echo "list_of_months: "; print_r( $list_of_months );
    +    echo "list_of_years: "; print_r( $list_of_years );
    +    echo "last_24h: "; print_r( $last_24h );
    +    echo "countries: "; print_r( $countries );
    +    die();
    +    **/
     
     }
     
    +// Whether to show referrers on the statistics page
    +// Default: show only on private installs; hide on public installs to prevent referrer spam (filterable)
    +$show_referrers = yourls_apply_filter( 'statistics_show_referrers', yourls_is_private() );
    +
     yourls_html_head( 'infos', yourls_s( 'Statistics for %s', YOURLS_SITE.'/'.$keyword ) );
     yourls_html_logo();
     yourls_html_menu();
    @@ -216,338 +222,341 @@
     
     

    : 1 ) - echo ' '; + yourls_html_link( yourls_link($keyword) ); + if( isset( $keyword_list ) && count( $keyword_list ) > 1 ) + echo ' '; } ?>

    :

    -
    -
      - -
    • -
    • -
    • - -
    • -
    -
    +
    +
      + +
    • +
    • + +
    • + + +
    • +
    +
    -
    -

    - - - - - - yourls__( 'Last 24 hours' ), - '7' => yourls__( 'Last 7 days' ), - '30' => yourls__( 'Last 30 days' ), - 'all'=> yourls__( 'All time' ), - ); - - // Which graph to generate ? - $do_all = $do_30 = $do_7 = $do_24 = false; - $hits_all = array_sum( $list_of_days ); - $hits_30 = array_sum( array_slice( $list_of_days, -30 ) ); - $hits_7 = array_sum( array_slice( $list_of_days, -7 ) ); - $hits_24 = array_sum( $last_24h ); - if( $hits_all > 0 ) - $do_all = true; // graph for all days range - if( $hits_30 > 0 && count( array_slice( $list_of_days, -30 ) ) == 30 ) - $do_30 = true; // graph for last 30 days - if( $hits_7 > 0 && count( array_slice( $list_of_days, -7 ) ) == 7 ) - $do_7 = true; // graph for last 7 days - if( $hits_24 > 0 ) - $do_24 = true; // graph for last 24 hours - - // Which graph to display ? - $display_all = $display_30 = $display_7 = $display_24 = false; - if( $do_24 ) { - $display_24 = true; - } elseif ( $do_7 ) { - $display_7 = true; - } elseif ( $do_30 ) { - $display_30 = true; - } elseif ( $do_all ) { - $display_all = true; - } - ?> - -
    - - - - - -
    - - $graphtitle ) { - if( ${'do_'.$graph} == true ) { - $display = ( ${'display_'.$graph} === true ? 'display:block' : 'display:none' ); - echo "
    "; - echo '

    ' . yourls_s( 'Number of hits : %s' , $graphtitle ) . '

    '; - switch( $graph ) { - case '24': - yourls_stats_line( $last_24h, "stat_line_$graph" ); - break; - - case '7': - case '30': - $slice = array_slice( $list_of_days, intval( $graph ) * -1 ); - yourls_stats_line( $slice, "stat_line_$graph" ); - unset( $slice ); - break; - - case 'all': - yourls_stats_line( $list_of_days, "stat_line_$graph" ); - break; - } - echo "
    \n"; - } - } ?> - -
    -

    - -

    -
    -
      - $graphtitle ) { - if ( ${'do_'.$graph} ) { - $link = "$graphtitle"; - } else { - $link = $graphtitle; - } - $stat = ''; - if( ${'do_'.$graph} ) { - switch( $graph ) { - case '7': - case '30': - $stat = yourls_s( '%s per day', round( ( ${'hits_'.$graph} / intval( $graph ) ) * 100 ) / 100 ); - break; - case '24': - $stat = yourls_s( '%s per hour', round( ( ${'hits_'.$graph} / 24 ) * 100 ) / 100 ); - break; - case 'all': - if( $ago > 0 ) - $stat = yourls_s( '%s per day', round( ( ${'hits_'.$graph} / $ago ) * 100 ) / 100 ); - } - } - $hits = sprintf( yourls_n( '%s hit', '%s hits', ${'hits_'.$graph} ), ${'hits_'.$graph} ); - echo "
    • $link $hits $stat
    • \n"; - } - ?> -
    -
    - -

    - -

    %1$s hit on %2$s', '%1$s hits on %2$s', $best['max'] ), $best['max'], yourls_date_i18n( yourls_get_date_format("F j, Y"), strtotime( $best['day'] ) ) ); ?>. -

    - - -
    - - - - ' . yourls__( 'No traffic yet. Get some clicks first!' ) . '

    '; - } ?> - - - -
    -

    - - - - - - - - - - -
    -

    - -

    - - -
    -

    - -
    - - - - ' . yourls__( 'No country data.' ) . '

    '; - } ?> -
    - - -
    -

    - - - - - - - - - - - -
    -

    - 1 ) - $referrer_sort[ yourls__( 'Others' ) ] = count( $referrers ); - yourls_stats_pie( $referrer_sort, 5, '440x220', 'stat_tab_source_ref' ); - unset( $referrer_sort[yourls__('Others')] ); - ?> -

    -
      - $count ) { - $i++; - $favicon = yourls_get_favicon_url( $site ); - echo "
    • $site: $count " . yourls__( '(details)' ) . "
    • \n"; - echo "\n"; - unset( $referrers[$site] ); - } - // Any referrer left? Group in "various" - if ( $referrers ) { - echo "
    • " . yourls__( 'Various:' ) . " ". count( $referrers ). " " . yourls__( '(details)' ) . "
    • \n"; - echo "\n"; - } - ?> - -
    - -
    -

    - $direct, yourls__( 'Referrers' ) => $notdirect ), 5, '440x220', 'stat_tab_source_direct' ); - ?> -

    %s hit', '%s hits', $direct ), $direct ); ?>

    -

    %s hit', '%s hits', $notdirect ), $notdirect ); ?>

    - -
    - - - - ' . yourls__( 'No referrer data.' ) . '

    '; - } ?> - -
    +
    +

    + + + + + + yourls__( 'Last 24 hours' ), + '7' => yourls__( 'Last 7 days' ), + '30' => yourls__( 'Last 30 days' ), + 'all'=> yourls__( 'All time' ), + ); + + // Which graph to generate ? + $do_all = $do_30 = $do_7 = $do_24 = false; + $hits_all = array_sum( $list_of_days ); + $hits_30 = array_sum( array_slice( $list_of_days, -30 ) ); + $hits_7 = array_sum( array_slice( $list_of_days, -7 ) ); + $hits_24 = array_sum( $last_24h ); + if( $hits_all > 0 ) + $do_all = true; // graph for all days range + if( $hits_30 > 0 && count( array_slice( $list_of_days, -30 ) ) == 30 ) + $do_30 = true; // graph for last 30 days + if( $hits_7 > 0 && count( array_slice( $list_of_days, -7 ) ) == 7 ) + $do_7 = true; // graph for last 7 days + if( $hits_24 > 0 ) + $do_24 = true; // graph for last 24 hours + + // Which graph to display ? + $display_all = $display_30 = $display_7 = $display_24 = false; + if( $do_24 ) { + $display_24 = true; + } elseif ( $do_7 ) { + $display_7 = true; + } elseif ( $do_30 ) { + $display_30 = true; + } elseif ( $do_all ) { + $display_all = true; + } + ?> + + + + + + + +
    + + $graphtitle ) { + if( ${'do_'.$graph} == true ) { + $display = ( ${'display_'.$graph} === true ? 'display:block' : 'display:none' ); + echo "
    "; + echo '

    ' . yourls_s( 'Number of hits : %s' , $graphtitle ) . '

    '; + switch( $graph ) { + case '24': + yourls_stats_line( $last_24h, "stat_line_$graph" ); + break; + + case '7': + case '30': + $slice = array_slice( $list_of_days, intval( $graph ) * -1 ); + yourls_stats_line( $slice, "stat_line_$graph" ); + unset( $slice ); + break; + + case 'all': + yourls_stats_line( $list_of_days, "stat_line_$graph" ); + break; + } + echo "
    \n"; + } + } ?> + +
    +

    + +

    +
    +
      + $graphtitle ) { + if ( ${'do_'.$graph} ) { + $link = "$graphtitle"; + } else { + $link = $graphtitle; + } + $stat = ''; + if( ${'do_'.$graph} ) { + switch( $graph ) { + case '7': + case '30': + $stat = yourls_s( '%s per day', round( ( ${'hits_'.$graph} / intval( $graph ) ) * 100 ) / 100 ); + break; + case '24': + $stat = yourls_s( '%s per hour', round( ( ${'hits_'.$graph} / 24 ) * 100 ) / 100 ); + break; + case 'all': + if( $ago > 0 ) + $stat = yourls_s( '%s per day', round( ( ${'hits_'.$graph} / $ago ) * 100 ) / 100 ); + } + } + $hits = sprintf( yourls_n( '%s hit', '%s hits', ${'hits_'.$graph} ), ${'hits_'.$graph} ); + echo "
    • $link $hits $stat
    • \n"; + } + ?> +
    +
    + +

    + +

    %1$s hit on %2$s', '%1$s hits on %2$s', $best['max'] ), $best['max'], yourls_date_i18n( yourls_get_date_format("F j, Y"), strtotime( $best['day'] ) ) ); ?>. +

    + + +
    + + + + ' . yourls__( 'No traffic yet. Get some clicks first!' ) . '

    '; + } ?> +
    + + +
    +

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

    + +

    + + +
    +

    + +
    + + + + ' . yourls__( 'No country data.' ) . '

    '; + } ?> +
    + + +
    +

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

    + 1 ) + $referrer_sort[ yourls__( 'Others' ) ] = count( $referrers ); + yourls_stats_pie( $referrer_sort, 5, '440x220', 'stat_tab_source_ref' ); + unset( $referrer_sort[yourls__('Others')] ); + ?> +

    +
      + $count ) { + $i++; + $favicon = yourls_get_favicon_url( $site ); + echo "
    • $site: $count " . yourls__( '(details)' ) . "
    • \n"; + echo "\n"; + unset( $referrers[$site] ); + } + // Any referrer left? Group in "various" + if ( $referrers ) { + echo "
    • " . yourls__( 'Various:' ) . " ". count( $referrers ). " " . yourls__( '(details)' ) . "
    • \n"; + echo "\n"; + } + ?> + +
    + +
    +

    + $direct, yourls__( 'Referrers' ) => $notdirect ), 5, '440x220', 'stat_tab_source_direct' ); + ?> +

    %s hit', '%s hits', $direct ), $direct ); ?>

    +

    %s hit', '%s hits', $notdirect ), $notdirect ); ?>

    + +
    + + + + ' . yourls__( 'No referrer data.' ) . '

    '; + } ?> + +
    + -
    -

    +
    +

    - ' . yourls__( 'Short link' ) . '', '

    ' . yourls__( 'Quick Share' ) . '

    '); ?> + ' . yourls__( 'Short link' ) . '', '

    ' . yourls__( 'Quick Share' ) . '

    '); ?> -
    +
    diff --git a/yourls-loader.php b/yourls-loader.php index cd9d2db2c..12fb67b6c 100644 --- a/yourls-loader.php +++ b/yourls-loader.php @@ -1,17 +1,17 @@